提前道歉我不能马上在这里接受答案 – 只是想我想记下来,而我有这个问题…
简而言之:当我在Linux下使用用户空间C代码开始写入USB串行端口时,我可以观察到三种不同的缓冲区大小,问题是,我想从用户空间C中检索所有这些大小代码本身。
比方说,我有一个Arduino Duemillanove,带有一个FTDI FT232芯片 – 编程为从PC机的USB /串行连接读取传入字节,并丢弃它们。 当我在系统中插入这个设备(在Ubunty 11.04 Natty上做这个)时,我可以通过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 ...
这首先告诉我,驱动程序(内核模块) usbserial
和ftdi_sio
已经挂钩/加载来处理设备; 这些文件创build一个名为/dev/ttyUSB0
的文件(设备节点) – 本质上是从操作系统angular度来看的一个串行端口。 它还告诉我有一个64字节的MaxPacketSize
归因于设备的端点。 我也可以通过lsusb
查询MaxPacketSize:
$ 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
现在,假设我想使用以下C程序testusw.c
写入设备节点/dev/ttyUSB0
:
#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; }
这个程序故意在一次调用中写入大量的数据。 为了看看发生了什么,首先让我们通过Linux的usbmon
工具捕获USB URB请求 – 所以在一个terminal中,我们运行:
$ sudo cat /sys/kernel/debug/usb/usbmon/2u > testusw.2u.mon
…在另一个terminal,在编译和运行testusw后,我们得到:
$ gcc -o testusw -Wall -g testusw.c $ ./testusw /dev/ttyUSB0 //ª»ÌÝþª»ÌÝþ// Writing 100000 bytes bytes written: 4608 $
(注意上面的testusw
调用可能会重置Arduino)。 经过testusw
,我们可以回到第一个terminal,用CTRL + C中断cat
进程。 我们剩下一个日志文件testusw.2u.mon
。 我们可以用Virtual USB Analyzer打开这个日志文件:
$ ./vusb-analyzer testusw.2u.mon
…并获得以下可视化:
请注意,对于执行写操作的“EP2 OUT”,显示了2 * 9 = 18个URB请求,每个请求携带0x0100 = 256个字节; 所以总共写了18 * 256 = 4608字节 – 正如上面testusw
写的“bytes”所报告的testusw
。 另外,忽略EP1 IN上的数据(这是我的Arduino代码发送的一些垃圾 – 以“Status:-2”错误结束)。
因此,我可以观察到以下几点:
4608
字节被写入 – 有效地作为第一缓冲区大小 usbmon
报告这个块被sorting成每个256
字节的18个URB请求 64
字节的数据包 实际上,我有三种缓冲区大小: 4608
和64
字节; 类似于串行HOWTO中提到的:串行端口基础:4.7数据streampath; 缓冲区 :
application 8k-byte 16-byte 1k-byte tele- BROWSER ------- MEMORY -------- FIFO --------- MODEM -------- phone program buffer buffer buffer line
所以,我的问题是:如何从用户空间C代码本身检索这些缓冲区大小 – 但是,仅从设备节点path/dev/ttyUSB0
作为唯一的input参数?
我可以通过系统popen
命令运行外部程序,并parsing输出。 例如,我可以通过lsusb -v -d 0403:6001 | grep MaxPacketSize
获得MaxPacketSize lsusb -v -d 0403:6001 | grep MaxPacketSize
– 但是那需要厂商/产品ID,而且我不知道如何获取,如果只有一条信息是设备节点path/dev/ttyUSB0
。
鉴于/dev/ttyUSB0
基本上被视为一个串行端口,我以为通过stty
查询会提供一些东西 – 但是,我看不到有关缓冲区大小的任何东西:
$ 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
我也知道我可以使用udevadm
查询与设备节点path/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
…但是再次,我看不出与遇到的缓冲区大小有很大关系。
为了解决这个问题,我再次提出这个问题:我能否从用户空间C应用程序中检索与usb串行写入传输相关的遇到的缓冲区大小; 如果是的话 – 如何?
非常感谢任何答案,
干杯!
不明白为什么你想知道这一点。 Linux允许你使用TIOCGSERIAL
ioctl来检索一个struct serial_struct
,它具有一个xmit_fifo_size
字段。 尽管如果很多USB串口驱动程序在那里写一些有意义的东西,我会感到惊讶。
我一直在解决你所问的问题。 我没有对你的答案,但有一点你可能会发现有用的信息。
在Mac OS X上,您可以使用ioctl来确定缓冲区中当前有多少个字符。 下面的代码会给你这个数字
uint ioctlBytestInBuffer; int returnCode = ioctl(fileDescriptor, TIOCOUTQ, &ioctlBytestInBuffer);
我一直在使用它来试图找到一个大的文件传输已经完成了一个串行线(微使用软件流量控制,所以很难预测传输速率)。
这种方法工作得相当好,但它并不完美。 我不确定ioctl调用哪个缓冲区能够访问。 当ioctl函数调用在缓冲区中返回0字节的值时,文件传输仍会持续数秒。 我的电缆中的USB芯片声称只有一个128字节的发送缓冲区,应该在我的波特率的0.3秒内清空。