c linux buffer packet usbserial

Recuperación de tamaños de búfer/paquete/carga útil para la transferencia de escritura serial USB en el espacio de usuario Código C de Linux



buffer packet (2)

Disculpas de antemano. No podré aceptar una respuesta aquí inmediatamente. Solo pensé que me gustaría anotar esto, mientras tengo el problema ...

En resumen: puedo observar tres tamaños de búfer diferentes, cuando inicio una escritura en un puerto USB de serie utilizando el código C de espacio de usuario en Linux, y el problema es que me gustaría recuperar todos estos tamaños del espacio C de usuario. código en sí mismo.

Digamos, tengo un Arduino Duemillanove, con un chip FTDI FT232 programado para leer los bytes entrantes de la conexión USB / serie de la PC, y descartarlos. Cuando conecto este dispositivo en el sistema (hice esto en Ubunty 11.04 Natty), puedo observar lo siguiente a través de tail -f /var/log/syslog :

Mar 21 08:05:05 mypc kernel: [ 679.197982] usbserial: USB Serial Driver core Mar 21 08:05:05 mypc kernel: [ 679.223954] USB Serial support registered for FTDI USB Serial Device Mar 21 08:05:05 mypc kernel: [ 679.227354] ftdi_sio 2-2:1.0: FTDI USB Serial Device converter detected Mar 21 08:05:05 mypc kernel: [ 679.227633] usb 2-2: Detected FT232RL Mar 21 08:05:05 mypc kernel: [ 679.227644] usb 2-2: Number of endpoints 2 Mar 21 08:05:05 mypc kernel: [ 679.227652] usb 2-2: Endpoint 1 MaxPacketSize 64 Mar 21 08:05:05 mypc kernel: [ 679.227660] usb 2-2: Endpoint 2 MaxPacketSize 64 Mar 21 08:05:05 mypc kernel: [ 679.227667] usb 2-2: Setting MaxPacketSize 64 ...

Esto me dice primero que los controladores (módulos del kernel) usbserial y ftdi_sio se han enganchado / cargado para manejar el dispositivo; estos crean un archivo (nodo de dispositivo) llamado /dev/ttyUSB0 , esencialmente un puerto serie desde la perspectiva del sistema operativo. También me dice que hay un MaxPacketSize de 64 bytes atribuido a los puntos finales del dispositivo. También puedo obtener el MaxPacketSize consultando a través de lsusb :

$ lsusb | grep FT Bus 002 Device 002: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC $ lsusb -t | grep -B1 ft /: Bus 02.Port 1: Dev 1, Class=root_hub, Driver=uhci_hcd/2p, 12M |__ Port 2: Dev 2, If 0, Class=vend., Driver=ftdi_sio, 12M $ sudo lsusb -v -d 0403:6001 | grep ''bEndpointAddress/|wMaxPacketSize/|idVendor/|idProduct'' idVendor 0x0403 Future Technology Devices International, Ltd idProduct 0x6001 FT232 USB-Serial (UART) IC bEndpointAddress 0x81 EP 1 IN wMaxPacketSize 0x0040 1x 64 bytes bEndpointAddress 0x02 EP 2 OUT wMaxPacketSize 0x0040 1x 64 bytes

Ahora, digamos que quiero escribir en el nodo del dispositivo /dev/ttyUSB0 utilizando el siguiente programa C, testusw.c :

#include <stdio.h> /* Standard input/output definitions */ #include <string.h> /* String function definitions */ #include <unistd.h> /* UNIX standard function definitions */ #include <fcntl.h> /* File control definitions */ #include <errno.h> /* Error number definitions */ #include <termios.h> /* POSIX terminal control definitions */ // testusw.c // build with: gcc -o testusw -Wall -g testusw.c int main( int argc, char **argv ) { char *serportdevfile; int serport_fd; char writeData[20000*5]; //100000 bytes data unsigned char snippet[] = {0xAA, 0xBB, 0xCC, 0xDD, 0xFE}; int i; int bytesWritten; if( argc != 2 ) { fprintf(stdout, "Usage:/n"); fprintf(stdout, "%s port baudrate file/string/n", argv[0]); return 1; } //populate write data for (i=0; i<20000; i++) { memcpy(&writeData[5*i], &snippet[0], 5); } // for strlen, fix (after) last byte to 0 writeData[20000*5] = 0x00; // show writeData - truncate to 10 bytes (.10): fprintf(stdout, "//%.10s///n", writeData); serportdevfile = argv[1]; serport_fd = open( serportdevfile, O_RDWR | O_NOCTTY | O_NONBLOCK ); if ( serport_fd < 0 ) { perror(serportdevfile); return 1; } // do a write: fprintf(stdout, "Writing %d bytes/n", strlen(writeData)); bytesWritten = write( serport_fd, writeData, strlen(writeData) ); fprintf(stdout, " bytes written: %d /n", bytesWritten); return 0; }

Este programa escribe deliberadamente una gran parte de los datos en una llamada. Para ver lo que está sucediendo, primero usbmon las solicitudes URB de USB a través de la instalación usbmon de Linux, así que en un terminal ejecutamos:

$ sudo cat /sys/kernel/debug/usb/usbmon/2u > testusw.2u.mon

... y en otra terminal, después de compilar y ejecutar testusw, obtenemos:

$ gcc -o testusw -Wall -g testusw.c $ ./testusw /dev/ttyUSB0 //ª»ÌÝþª»ÌÝþ// Writing 100000 bytes bytes written: 4608 $

(Tenga en cuenta que la llamada de testusw anterior probablemente reiniciará el Arduino). Después de testusw , podemos volver al primer terminal e interrumpir el proceso cat con CTRL + C ; Nos quedamos con un archivo de registro, testusw.2u.mon . Podemos abrir este archivo de registro con Virtual USB Analyzer :

$ ./vusb-analyzer testusw.2u.mon

... y obtener la siguiente visualización:

Tenga en cuenta que se muestran 2 * 9 = 18 solicitudes de URB para "EP2 OUT" que realizan la escritura, con 0x0100 = 256 bytes cada una; por lo tanto, en total, se escribieron 18 * 256 = 4608 bytes, como se indica en "bytes escritos" por testusw arriba. Además, ignore los datos en EP1 IN (es decir, algo de correo no deseado que está enviando el código de Arduino, que termina con un error "Estado: -2").

Así, puedo observar lo siguiente:

  • Desde el programa C, inicio una escritura de 100000 bytes.
  • Como resultado, solo se escriben 4608 bytes, actuando efectivamente como un primer tamaño de búfer
  • usbmon luego informa que este fragmento está secuenciado en 18 solicitudes URB de 256 bytes cada una
  • Finalmente, MaxPacketSize me dice que cada solicitud de URB está (probablemente) secuenciada en (cuatro) paquetes de 64 bytes en el cable USB

En efecto, tengo tres tamaños de búfer: 4608 , 256 y 64 bytes; similar a lo que se menciona en el CÓMO serie: Conceptos básicos sobre el puerto serie: 4.7 Ruta de flujo de datos; Buffers :

application 8k-byte 16-byte 1k-byte tele- BROWSER ------- MEMORY -------- FIFO --------- MODEM -------- phone program buffer buffer buffer line

Entonces, mi pregunta es: ¿cómo se pueden recuperar estos tamaños de búfer del propio código C del espacio de usuario? Sin embargo, solo de la ruta del nodo del dispositivo /dev/ttyUSB0 como el único parámetro de entrada.

Estaría bien con ejecutar programas externos a través de un comando popen sistema y analizar la salida. Por ejemplo, podría obtener MaxPacketSize a través de lsusb -v -d 0403:6001 | grep MaxPacketSize lsusb -v -d 0403:6001 | grep MaxPacketSize - pero eso requiere una identificación del proveedor / producto, y no sé cómo obtener eso, si solo la información es la ruta del nodo del dispositivo /dev/ttyUSB0 .

Dado que /dev/ttyUSB0 se trata esencialmente como un puerto serie, pensé que la consulta a través de stty proporcionaría algo; sin embargo, no puedo ver nada relacionado con el tamaño del búfer allí:

$ stty -a -F /dev/ttyUSB0 speed 115200 baud; rows 0; columns 0; line = 0; intr = ^C; quit = ^/; erase = ^?; kill = ^U; eof = ^A; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0; -parenb -parodd cs8 hupcl -cstopb cread -clocal -crtscts -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany -imaxbel -iutf8 -opost -olcuc -ocrnl -onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 -isig -icanon -iexten -echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt -echoctl -echoke

También sé que puedo usar udevadm para consultar datos relacionados con la ruta del nodo del dispositivo /dev/ttyUSB0 :

$ udevadm info --query=all --name=/dev/ttyUSB0 P: /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.0/ttyUSB0/tty/ttyUSB0 N: ttyUSB0 S: serial/by-path/pci-0000:00:1d.0-usb-0:2:1.0-port0 S: serial/by-id/usb-FTDI_FT232R_USB_UART_A9007OH3-if00-port0 E: UDEV_LOG=3 E: DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.0/ttyUSB0/tty/ttyUSB0 E: MAJOR=188 E: MINOR=0 E: DEVNAME=/dev/ttyUSB0 E: SUBSYSTEM=tty E: ID_PORT=0 E: ID_PATH=pci-0000:00:1d.0-usb-0:2:1.0 E: ID_VENDOR=FTDI E: ID_VENDOR_ENC=FTDI E: ID_VENDOR_ID=0403 E: ID_MODEL=FT232R_USB_UART E: ID_MODEL_ENC=FT232R/x20USB/x20UART E: ID_MODEL_ID=6001 E: ID_REVISION=0600 E: ID_SERIAL=FTDI_FT232R_USB_UART_A9007OH3 E: ID_SERIAL_SHORT=A9007OH3 E: ID_TYPE=generic E: ID_BUS=usb E: ID_USB_INTERFACES=:ffffff: E: ID_USB_INTERFACE_NUM=00 E: ID_USB_DRIVER=ftdi_sio E: ID_IFACE=00 E: ID_VENDOR_FROM_DATABASE=Future Technology Devices International, Ltd E: ID_MODEL_FROM_DATABASE=FT232 USB-Serial (UART) IC E: ID_MM_CANDIDATE=1 E: DEVLINKS=/dev/serial/by-path/pci-0000:00:1d.0-usb-0:2:1.0-port0 /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A9007OH3-if00-port0 # the below has huge output, so pipe it to `less` $ udevadm info --attribute-walk --name=/dev/ttyUSB0 | less

... pero nuevamente, no puedo ver mucho relacionado con los tamaños de búfer encontrados.

Para resumir esto, nuevamente la pregunta: ¿puedo recuperar los tamaños de búfer encontrados relacionados con la transferencia de escritura usb-serial desde una aplicación C de espacio de usuario; Y si es así, ¿cómo?

Muchas gracias de antemano por cualquier respuesta,
¡Aclamaciones!


He estado lidiando con problemas similares a la pregunta que haces. No tengo una respuesta para usted, pero tengo otra información que puede serle útil.

En Mac OS X puede usar ioctl para averiguar cuántos caracteres hay actualmente en el búfer. El siguiente código te dará la figura.

uint ioctlBytestInBuffer; int returnCode = ioctl(fileDescriptor, TIOCOUTQ, &ioctlBytestInBuffer);

He estado usando esto para intentar encontrar cuando se ha completado una transferencia de archivos grandes a través de una línea serie (el micro usa el control de flujo del software, por lo que es difícil predecir la tasa de transferencia).

Este método funciona razonablemente bien, pero no es perfecto. No estoy seguro de a qué búfer puede acceder la llamada ioctl. Cuando la llamada a la función ioctl devuelve un valor de 0 bytes en el búfer, la transferencia de archivos continúa por varios segundos más. El chip USB en mi cable dice que solo tiene un búfer de transmisión de 128 bytes que debe vaciarse a 0.3 de segundo a mi velocidad de transmisión.


No veo por qué querría saber esto. Linux le permite usar el ioctl TIOCGSERIAL para recuperar una struct serial_struct que tiene un campo xmit_fifo_size . Aunque me sorprendería si muchos controladores serie USB se molestan en escribir algo significativo allí.