[英]Retrieving buffer/packet/payload sizes for USB serial write transfer in userspace Linux C code
Apologies in advance I won't be able to accept an answer here immediately - just thought I'd like to jot this down, while I have the problem...提前道歉,我将无法立即在这里接受答案-只是想记下来,而我遇到了问题...
In brief: I can observe three different buffer sizes, when I initiate a write to an usb-serial port using user-space C code under Linux - and the problem is, I would like to retrieve all these sizes from the user-space C code itself.简而言之:当我在 Linux 下使用用户空间 C 代码启动对 USB 串行端口的写入时,我可以观察到三种不同的缓冲区大小 - 问题是,我想从用户空间 C 中检索所有这些大小代码本身。
Let's say, I have an Arduino Duemillanove, with an FTDI FT232 chip - programmed to read incoming bytes from usb/serial connection from PC, and discard them.比方说,我有一个带有 FTDI FT232 芯片的 Arduino Duemillanove - 编程为从 PC 的 USB/串行连接读取传入字节,并丢弃它们。 When I plug in this device in the system (did this on Ubunty 11.04 Natty), I can observe the following via
tail -f /var/log/syslog
:当我将此设备插入系统时(在 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
...
This tells me first that the drivers (kernel modules) usbserial
and ftdi_sio
have been hooked/loaded to handle the device;这首先告诉我驱动程序(内核模块)
usbserial
和ftdi_sio
已经被挂钩/加载来处理设备; these create a file (device node) called /dev/ttyUSB0
- essentially a serial port from the OS perspective.这些创建了一个名为
/dev/ttyUSB0
的文件(设备节点)——从操作系统的角度来看,本质上是一个串行端口。 It also tells me that there is a MaxPacketSize
of 64 bytes attributed to the device's endpoints.它还告诉我有一个 64 字节的
MaxPacketSize
归因于设备的端点。 I can get the MaxPacketSize also by querying via lsusb
:我也可以通过
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
Now, let's say I want to write to the device node /dev/ttyUSB0
using the following C program, testusw.c
:现在,假设我想使用以下 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;
}
This program deliberately writes a big chunk of data in one call.这个程序故意在一次调用中写入一大块数据。 To see what is happening, first let's capture USB URB requests via Linux's
usbmon
facility - so in one terminal, we run:要查看发生了什么,首先让我们通过 Linux 的
usbmon
工具捕获 USB URB 请求 - 因此在一个终端中,我们运行:
$ sudo cat /sys/kernel/debug/usb/usbmon/2u > testusw.2u.mon
... and in another terminal, after compiling and running testusw, we obtain: ...在另一个终端中,编译并运行 testusw 后,我们得到:
$ gcc -o testusw -Wall -g testusw.c
$ ./testusw /dev/ttyUSB0
//ª»ÌÝþª»ÌÝþ//
Writing 100000 bytes
bytes written: 4608
$
(Note that the testusw
call above will likely reset the Arduino). (请注意,上面的
testusw
调用可能会重置 Arduino)。 After testusw
, we can go back to the first terminal, and interrupt the cat
process with CTRL + C ; testusw
之后,我们可以回到第一个终端,用CTRL + C中断cat
进程; we are left with a logfile, testusw.2u.mon
.我们留下了一个日志文件
testusw.2u.mon
。 We can open this logfile with Virtual USB Analyzer :我们可以使用Virtual USB Analyzer打开此日志文件:
$ ./vusb-analyzer testusw.2u.mon
... and obtain the following visualization: ...并获得以下可视化:
Note that there are 2*9 = 18 URB requests shown for "EP2 OUT" that perform the writing, carrying 0x0100 = 256 bytes each;请注意,对于执行写入的“EP2 OUT”显示了 2*9 = 18 个 URB 请求,每个请求携带 0x0100 = 256 个字节; so in total, 18*256 = 4608 bytes were written - as reported by "bytes written" by
testusw
above.所以总共写入了 18*256 = 4608 个字节 - 正如上面
testusw
的“写入的字节数”所报告的testusw
。 Also, ignore the data on EP1 IN (that is some junk my Arduino code is sending - which ends with a "Status: -2" error).另外,忽略 EP1 IN 上的数据(这是我的 Arduino 代码正在发送的一些垃圾 - 以“状态:-2”错误结尾)。
Thus, I can observe the following:因此,我可以观察到以下几点:
4608
bytes are written - effectively acting as a first buffer size4608
个字节 - 有效地充当第一个缓冲区大小usbmon
then reports this chunk is sequenced into 18 URB requests of 256
bytes each usbmon
然后报告这个块被排序为 18 个256
字节的 URB 请求64
bytes on USB wire64
字节的数据包In effect, I have three buffer sizes: 4608
, 256
and 64
bytes;实际上,我有三个缓冲区大小:
4608
、 256
和64
字节; similar to what is mentioned in Serial HOWTO: Serial Port Basics: 4.7 Data Flow Path;类似于Serial HOWTO: Serial Port Basics: 4.7 Data Flow Path 中提到的内容; Buffers :
缓冲器:
application 8k-byte 16-byte 1k-byte tele-
BROWSER ------- MEMORY -------- FIFO --------- MODEM -------- phone
program buffer buffer buffer line
So, my question is: how can these buffer sizes be retrieved from the userspace C code itself - however, only from the device node path /dev/ttyUSB0
as the only input parameter?所以,我的问题是:如何从用户空间 C 代码本身检索这些缓冲区大小——但是,只能从设备节点路径
/dev/ttyUSB0
作为唯一的输入参数?
I would be OK with running external programs via a system popen
command, and parsing the output.我可以通过系统
popen
命令运行外部程序并解析输出。 For instance, I could obtain MaxPacketSize via lsusb -v -d 0403:6001 | grep MaxPacketSize
例如,我可以通过
lsusb -v -d 0403:6001 | grep MaxPacketSize
获得 MaxPacketSize lsusb -v -d 0403:6001 | grep MaxPacketSize
- but that requires vendor/product ID, and I don't know how to obtain that, if only piece of information is the device node path /dev/ttyUSB0
. lsusb -v -d 0403:6001 | grep MaxPacketSize
- 但这需要供应商/产品ID,我不知道如何获取,如果只有一条信息是设备节点路径/dev/ttyUSB0
。
Given that /dev/ttyUSB0
is essentially treated as a serial port, I thought querying via stty
would provide something - however, I cannot see anything related to buffer sizes there:鉴于
/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
I also know I can use udevadm
to query for data related to the device node path /dev/ttyUSB0
:我也知道我可以使用
udevadm
查询与设备节点路径/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
... but again, I cannot see much related to the encountered buffer sizes. ...但同样,我看不到与遇到的缓冲区大小有太大关系。
To wrap this up, the question again: can I retrieve the encountered buffer sizes related to the usb-serial write transfer from a user-space C application;最后,再次提出问题:我可以从用户空间 C 应用程序中检索遇到的与 USB 串行写入传输相关的缓冲区大小吗? and if so - how?
如果是这样 - 如何?
Many thanks in advance for any answers,非常感谢您的任何答案,
Cheers!干杯!
Don't see why you'd want to know this.不明白你为什么想知道这个。 Linux allows you to use the
TIOCGSERIAL
ioctl to retrieve a struct serial_struct
which has a xmit_fifo_size
field. Linux 允许您使用
TIOCGSERIAL
ioctl 来检索具有xmit_fifo_size
字段的struct serial_struct
。 Though I'd be surprised if many USB serial driver bother to write something meaningful there.虽然如果许多 USB 串行驱动程序费心在那里写一些有意义的东西,我会感到惊讶。
I've been grappling with similar problems to the question you ask.我一直在努力解决与您提出的问题类似的问题。 I don't have an answer for you but have one other bit of information that you might find useful.
我没有给你答案,但还有一点你可能会觉得有用的信息。
On Mac OS X you can use ioctl to find out how many characters are currently in the buffer.在 Mac OS X 上,您可以使用 ioctl 来找出当前缓冲区中的字符数。 The following code will give you the figure
下面的代码会给你图
uint ioctlBytestInBuffer;
int returnCode = ioctl(fileDescriptor, TIOCOUTQ, &ioctlBytestInBuffer);
I have been using this to try and find when a large file transfer has completed over a serial line (The micro uses Software flow control so it is hard to predict the rate of transfer).我一直在使用它来尝试查找通过串行线路完成大文件传输的时间(微型使用软件流控制,因此很难预测传输速率)。
This method works reasonably well however it is not perfect.这种方法相当有效,但并不完美。 I'm not sure which buffer the ioctl call is able to access.
我不确定 ioctl 调用能够访问哪个缓冲区。 When the ioctl function call returns a value of 0 bytes in the buffer the file transfer still continues for several seconds longer.
当 ioctl 函数调用在缓冲区中返回 0 字节的值时,文件传输仍会继续多几秒钟。 The USB chip in my cable claims to only have a 128 byte transmit buffer which should be emptied within 0.3 of a second at my baud rate.
我的电缆中的 USB 芯片声称只有一个 128 字节的传输缓冲区,以我的波特率应该在 0.3 秒内清空。
This is an old title but for those who wonder: here related pdf (About of 0453:6001 ic's)这是一个旧标题,但对于那些想知道的人: 这里有相关的 pdf (关于 0453:6001 ic)
On page (end of)13 and (start) 14 :
TX Size : 256 Bytes
RX Size : 128 Bytes
Have nice(+Healthy) day!祝您有美好(+健康)的一天!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.