Nous fabriquons une carte réseau USB externe à partir de ENC28J60

ENC28J60 est un simple contrôleur Ethernet qui peut agir comme une carte réseau externe pour les ordinateurs monocarte avec GPIO (il existe même un pilote prêt à l'emploi pour raspberry) et d'autres arduins. Les GPIO ne sont pas affichés sur mon ordinateur portable, essayons de corriger cette faille et vissez-y ENC28J60 en utilisant STM32F103 et une lanière USB.





Voyons comment vous pouvez faire cela.





Nous avons besoin:





  • ENC28J60





  • Carte de débogage avec STM32 avec prise en charge des périphériques USB (par exemple, celui-ci):





  • Linux ( Ubuntu 16)





  • Ethernet ( raspberry pi), wi-fi ( )





STM32F103 , . ENC28J60 ( c ). ENC28J60 STM32F103 SPI1 .





(usb) -> stm32(SPI) -> ENC28J60(Ethernet ) -> raspberry





, user space. tap ( , Ethernet , tun , ip ), ( tap_handler.c). Linux, tap_handler' tap . , , tap , tap_handler', - . , tap_handler tap , /dev/ttyACM0 ( USB Linux). /dev/ttyACM0, tap .





( vpn). , .





STM32 CubeMX USB CDC (virtual com port). SMT32 Linux /dev/ttyACM0 ( ). , STM32, , STM32.





STM32 . ( CDC_Receive_FS



usbd_cdc_if.c) ENC28J60, , ENC28J60 CDC_Transmit_FS



.





, CDC . , . , ( , wireshark usb). , - - STM32, , .. . .





:





sudo openvpn --mktun --dev tap0

      
      



ip :





sudo ifconfig tap0 10.0.0.1/24 up

      
      



tap_handler.

/dev/ttyACM0 raw (, .). :





char cdc_name[20]="/dev/ttyACM0";
int tty_fd = open(cdc_name, O_RDWR | O_NOCTTY); 
struct termios portSettings;
tcgetattr(tty_fd, &portSettings);
cfmakeraw(&portSettings);
tcsetattr(tty_fd, TCSANOW, &portSettings);
tcflush(tty_fd, TCOFLUSH);

      
      



tap_handler tap0:





/*  dev      tap0*/
int tun_alloc(char *dev, int flags) {
    struct ifreq ifr;
    int fd, err;
    char *clonedev = "/dev/net/tun";
    /*     /dev/net/tun */
    if( (fd = open(clonedev , O_RDWR)) < 0 ) {
        perror("Opening /dev/net/tun");
        return fd;
    }    
    memset(&ifr, 0, sizeof(ifr));

    ifr.ifr_flags = flags;
    
    /*    tap0 */
    if (*dev) {
        strncpy(ifr.ifr_name, dev, IFNAMSIZ);
    }
    /*    */
    if( (err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0 ) {
        perror("ioctl(TUNSETIFF)");        
        close(fd);
        return err;
    }
    
    strcpy(dev, ifr.ifr_name);

    return fd;
}
      
      



main.c :





strcpy(tun_name, "tap0");
int tap_fd = tun_alloc(tun_name, IFF_TAP | IFF_NO_PI);

      
      



IFF_TAP (tap). IFF_NO_PI , .





tap0 /dev/ttyACM0. , tap_handler select:





while(1) {
    int ret;
    fd_set rd_set;

    FD_ZERO(&rd_set);
    /* tap_fd - tap inteface descriptor */
    FD_SET(tap_fd, &rd_set);
    /* tty_fd - /dev/ttyACM0 descriptor */
    FD_SET(tty_fd, &rd_set);

    ret = select(maxfd + 1, &rd_set, NULL, NULL, NULL);
      
      



. tap0 tap_handler STM32 ( : - 4 , , 2 - , ) /dev/ttyACM0. , :





if(FD_ISSET(tap_fd, &rd_set)) {    
    uint16_t nread = cread(tap_fd, buffer, BUFSIZE);   
    uint8_t buf[6];
    *(uint32_t *)buf = PACKET_START_SIGN;
    *(uint16_t *)(buf + 4) = nread;    
    cwrite(tty_fd,(char *)buf,6);    
    cwrite(tty_fd, buffer, nread);
    delay_micro(delay_m);    
}
      
      



/dev/ttyACM0, ( 4 ), , . tap :





if(FD_ISSET(tty_fd, &rd_set)) {
    uint32_t sign;
    /*   */
    int nread = read_n(tty_fd, (char *)&sign, sizeof(sign));
    /*  ,    */
    if(nread == 0) {        
      break;
    }
    /*   ,      4  */
    if(sign != PACKET_START_SIGN){       
      continue;
    }
    /*    */
    nread = read_n(tty_fd, (char *)&plength, 2);
    if(nread == 0) {        
      break;
    }

    if (nread != 2){        
      continue;
    }
  /*   ,        */
    if(flag){
      flag = 0;
      nread = cread(tty_fd, buffer, sizeof(buffer));
      if(nread != 6){        
        continue;
      }
    }
  /*    ,   */
    if(plength > BUFSIZE){      
      break;
    }

    /*   (plength )      tap interface*/
    nread = read_n(tty_fd, buffer, plength);            
    if (nread != 0){            
        cwrite(tap_fd, buffer, nread);            
        delay_micro(delay_m);
    }
  }
      
      



STM32

USB CDC CubeMX HAL SPI1 .





callback' CDC_Receive_FS



( usbd_cdc_if.c), USB. , , ENC28J60. :





/* USB_POINTERS_ARRAY_SIZE -  array_pos */
/* MAX_FRAMELEN -    */
/* USB_BUFSIZE -    */

extern uint8_t usb_buf[]; /*        */
extern uint32_t pos_int; /*         */
extern uint32_t array_pos[]; /*    ,         */
extern uint32_t p_a; /*     array_pos  CDC_Receive_FS*/
extern uint32_t pl_a;/*     array_pos    */

/* USB_POINTERS_ARRAY_SIZE -  array_pos */
/* MAX_FRAMELEN -    */
/* USB_BUFSIZE -    */

static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
  int8_t memok = 1;
  /*   ,        */
  if( pl_a !=0 && p_a !=0){
    int32_t mem_lag = array_pos[(p_a - 1) % USB_POINTERS_ARRAY_SIZE] - array_pos[(pl_a - 1) % USB_POINTERS_ARRAY_SIZE];
    if(mem_lag > USB_BUFSIZE - MAX_FRAMELEN)
      memok = 0;
  }
  /*      ,
         (array_pos) */
  if(*Len < USB_BUFSIZE && *Len != 0 && memok){
    uint16_t offset = pos_int % USB_BUFSIZE;
    uint16_t new_pos = offset + *Len;
    uint8_t split = 0;
    if (new_pos > USB_BUFSIZE){
      split = 1;
    }
    if(split){
      int len1 = USB_BUFSIZE - offset;
      int len2 = *Len - len1;
      memcpy(usb_buf + offset, Buf, len1);
      memcpy(usb_buf, Buf + len1, len2);
    }
    else
      memcpy(usb_buf + offset, Buf, *Len);
    pos_int += *Len;

    array_pos[p_a % USB_POINTERS_ARRAY_SIZE] = pos_int;
    p_a++;
  }
  USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
  USBD_CDC_ReceivePacket(&hUsbDeviceFS);
  return (USBD_OK);
}
      
      



(main.c) ENC28J60:





if(pl_a < p_a){    
  uint32_t prev = 0;
  if(pl_a > 0)
    prev = array_pos[(pl_a - 1) % USB_POINTERS_ARRAY_SIZE];
  /*   ( ),   CDC_Receive_FS */
  int32_t n = array_pos[pl_a % USB_POINTERS_ARRAY_SIZE] - prev;//usb frame size
  /*      */
  uint8_t *from = usb_buf + prev % USB_BUFSIZE;
  /*    */
  uint8_t right_n = 1;
  if (n < 0 || n > MAX_FRAMELEN){
    right_n = 0;
  }

  /*    .      6  ( 4   2  ) */
  if((packet_len == 0) && packet_start && (n > 5) && right_n){
    /* .       */
    uint32_t sign = read32(from,usb_buf); 
    /*      4  */
    uint8_t *next = next_usb_ptr(from,usb_buf,4);
    /*    */
    packet_size = read16(next,usb_buf);// 2 bytes after sign is packet length
    /*    */
    if (packet_size > MAX_FRAMELEN || sign != PACKET_START_SIGN){      
      packet_size = 0;
    }
    else{
      /*        */
      next = next_usb_ptr(from,usb_buf,6);
      copy_buf(packet_buf, next, usb_buf, n - 6);      
      packet_len = n - 6;
      packet_next_ptr = packet_buf + packet_len;
      packet_start = 0;
    }

  }
  /*      */
  else if(packet_len < packet_size && right_n){
  /*        */    
    copy_buf(packet_next_ptr, from, usb_buf, n);    
    packet_len += n;
    packet_next_ptr = packet_buf + packet_len;
  }
  /*    */
  else if (packet_len > packet_size){    
    packet_len = 0;
    packet_start = 1;
  }
  /*    enc28j60 */
  if(packet_len == packet_size && packet_size > 0){    
    enc28j60_packetSend(packet_buf, packet_size);
    packet_len = 0;
    packet_start = 1;
  }

  pl_a++;
}
      
      



ENC28J60 USB :





len = enc28j60_packetReceive(net_buf,sizeof(net_buf));
if (len > 0) {
  *((uint16_t*)(sign_buf + 4)) = len;
  while(CDC_Transmit_FS(sign_buf, sizeof(sign_buf)) == USBD_BUSY_CDC_TRANSMIT);
  while(CDC_Transmit_FS(net_buf, len) == USBD_BUSY_CDC_TRANSMIT);
  HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
}
      
      



CDC_Transmit_FS



, while. CDC_Transmit_FS



USBD_BUSY_CDC_TRANSMIT



USBD_BUSY



. :





if (hcdc->TxState != 0){
    return USBD_BUSY_CDC_TRANSMIT;
}

      
      



ENC28J60 enc28j60_ini



, (promiscuous mode):





enc28j60_writeRegByte(ERXFCON,0);

      
      



Raspberry

eth0 ip . ping





sudo ifconfig eth0 up 10.0.0.2/24
ping 10.0.0.2

      
      



tcpdump:





sudo tcpdump -i eth0

      
      



STM32 , ENC28J60 raspberry. STM32 , arp / icmp ( ping). , /dev/ttyACM0:





ls /dev/ttyACM*

      
      



tap_handler:





gcc tap_handler.c -o tap_handler
./tap_handler

      
      



tap_handler - raspberry, tap0, , STM32, raspberry , .





.





raspberry ssh wi-fi , , default gateway. , raspberry :





sudo route del default gateway 192.168.1.1
sudo route add default gateway 10.0.0.2

      
      



DNS ( /etc/resolv.conf nameserver, , 8.8.8.8).





Raspberry

eth0 wlan0 NAT:





echo 1 | sudo tee -a /proc/sys/net/ipv4/ip_forward
sudo iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE

      
      



. , ( 0.5 /).





Vous n'avez pas à vous soucier de la framboise, mais connectez directement le câble réseau du routeur au ENC28J60 (vous devez désactiver le Wi-Fi sur votre ordinateur et définir la bonne adresse tap0). Mais les tests sont plus faciles avec Raspberry, vous pouvez voir tout ce qui se passe dans tcpdump.





Pourquoi tout ça

Utiliser un tel bundle dans la vie n'est probablement pas très pratique (surtout s'il y a des adaptateurs USB ethernet bon marché en vente), mais c'était très intéressant de le faire. Merci pour l'attention. Lien de code (projet dans Atollic TrueStudio).








All Articles