16

事前にお詫び申し上げます。ここですぐに回答を受け入れることはできません。問題が発生している間に、これを書き留めておきたいと思いました...

簡単に言うと、Linuxでユーザー空間Cコードを使用してUSBシリアルポートへの書き込みを開始すると、3つの異なるバッファーサイズを観察できます-問題は、ユーザー空間Cからこれらすべてのサイズを取得したいということですコード自体。


たとえば、私は FTDI FT232 チップを搭載した Arduino Duemillanove を持っているとしましょう - 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。これらは、本質的にOSの観点からシリアルポートftdi_sioと呼ばれるファイル(デバイスノード)を作成します。また、デバイスのエンドポイントに起因する 64 バイト/dev/ttyUSB0があることもわかります。MaxPacketSizeMaxPacketSize を介してクエリを実行することでも取得できます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

/dev/ttyUSB0ここで、次の 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;
}

このプログラムは、意図的に 1 回の呼び出しで大量のデータを書き込みます。何が起こっているのかを確認するために、まず Linux の機能を介して USB URB リクエストをキャプチャしましょう。つまりusbmon、1 つのターミナルで次のコマンドを実行します。

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

...そして、testusw をコンパイルして実行した後、別のターミナルで次の情報を取得します。

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

(testusw上記の呼び出しは Arduino をリセットする可能性があることに注意してください)。の後testusw、最初のターミナルに戻り、+でcatプロセスを中断できます。ログファイルが残っています。このログファイルはVirtual USB Analyzerで開くことができます:CTRLCtestusw.2u.mon

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

...そして、次の視覚化を取得します。

vusb-analyzer.png

「EP2 OUT」に示されている 2*9 = 18 個の URB 要求が書き込みを実行し、それぞれ 0x0100 = 256 バイトを運ぶことに注意してください。上記の「書き込まれたバイト数」で報告されているように、合計で 18*256 = 4608 バイトが書き込まれましたtestusw。また、EP1 IN のデータを無視します (これは、私の Arduino コードが送信しているジャンクであり、「ステータス: -2」エラーで終了します)。


したがって、次のことを確認できます。

  • C プログラムから、100000 バイトの書き込みを開始します
  • その結果、4608バイトのみが書き込まれ、事実上、最初のバッファー サイズとして機能します。
  • usbmon256次に、このチャンクがそれぞれバイトの 18 個の URB 要求にシーケンス化されていることを報告します
  • 最後に、MaxPacketSize は、各 URB 要求が (おそらく) 64USB ワイヤ上のバイトの (4) パケットに順序付けられていることを示しています

実際には、3 つのバッファー サイズ4608256あり64ます。Serial HOWTO: Serial Port Basics: 4.7 Data Flow Pathに記載されている内容と同様です。バッファ:

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

それで、私の質問は次のとおりです。これらのバッファ サイズは、ユーザー空間の C コード自体からどのように取得できますか?ただし、/dev/ttyUSB0唯一の入力パラメータとしてデバイス ノード パスからのみ取得できますか?

popenシステムコマンドを介して外部プログラムを実行し、出力を解析しても問題ありません。たとえば、 MaxPacketSize を介して取得できますlsusb -v -d 0403:6001 | grep MaxPacketSizeが、それにはベンダー/製品 ID が必要であり、情報の一部のみが device node 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また、デバイス ノード パスに関連するデータのクエリに使用できることもわかってい/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 シリアル書き込み転送に関連する、遭遇したバッファー サイズを取得できますか? もしそうなら - どのように?

ご回答ありがとうございます。
乾杯!

4

3 に答える 3

2

なぜこれを知りたいのかわかりません。Linux では、ioctl を使用して、フィールドを持つTIOCGSERIALを取得できます。多くの USB シリアル ドライバがわざわざそこに何か意味のあることを書き込んでいるとしたら、私は驚かれることでしょう。struct serial_structxmit_fifo_size

于 2013-04-23T20:49:02.760 に答える
1

私はあなたが尋ねる質問と同様の問題に取り組んできました。答えはありませんが、役立つ情報がもう 1 つあります。

Mac OS X では、ioctl を使用して、現在バッファーにある文字数を確認できます。次のコードはあなたに数字を与えるでしょう

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

私はこれを使用して、シリアル回線で大きなファイル転送がいつ完了したかを試してみました (マイクロはソフトウェアフロー制御を使用するため、転送速度を予測するのは困難です)。

この方法はかなりうまく機能しますが、完全ではありません。ioctl 呼び出しがどのバッファにアクセスできるかわかりません。ioctl 関数呼び出しがバッファーに 0 バイトの値を返す場合、ファイル転送はさらに数秒間続きます。私のケーブルの USB チップは、私のボーレートで 0.3 秒以内に空にすべき 128 バイトの送信バッファしかないと主張しています。

于 2013-10-21T23:05:17.320 に答える
0

これは古いタイトルですが、疑問に思っている人のために: 関連する pdf はこちら(0453:6001 ic について)

On page (end of)13 and (start) 14 :
TX Size : 256 Bytes
RX Size : 128 Bytes

良い(+健康な)一日を!

于 2020-07-07T21:16:55.100 に答える