简体   繁体   English

在用户空间 Linux C 代码中检索用于 USB 串行写入传输的缓冲区/数据包/有效负载大小

[英]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;这首先告诉我驱动程序(内核模块) usbserialftdi_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: ...并获得以下可视化:

vusb-analyzer.png

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:因此,我可以观察到以下几点:

  • From the C program, I initiate a write of 100000 bytes从 C 程序中,我开始写入 100000 字节
  • As a result, only 4608 bytes are written - effectively acting as a first buffer size结果,只写入了4608个字节 - 有效地充当第一个缓冲区大小
  • usbmon then reports this chunk is sequenced into 18 URB requests of 256 bytes each usbmon然后报告这个块被排序为 18 个256字节的 URB 请求
  • finally, MaxPacketSize tells me that each URB request is (probably) seqenced into (four) packets of 64 bytes on USB wire最后,MaxPacketSize 告诉我每个 URB 请求(可能)在 USB 线上被排序为(四个) 64字节的数据包

In effect, I have three buffer sizes: 4608 , 256 and 64 bytes;实际上,我有三个缓冲区大小: 460825664字节; 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM