Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

USB CDCの挙動の改善 #69

Open
wants to merge 10 commits into
base: master
Choose a base branch
from

Conversation

mikecat
Copy link
Contributor

@mikecat mikecat commented Sep 19, 2022

USB CDCの挙動を改善し、 usbtest コマンドで公式のArduino UNOのUSB-シリアル変換を通じたシリアル通信ができるようにします。

通信相手 (Arduino) のスケッチ
void setup() {
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);
  Serial.begin(9600);
}

bool isHigh = false;

void loop() {
  int c = Serial.read();
  if (c >= 0) {
    Serial.write((c + 1) % 256);
    isHigh = !isHigh;
    digitalWrite(13, isHigh ? HIGH : LOW);
  }
}
  • ConfigurationDescriptorReader::Next() が次のディスクリプタではなく今のディスクリプタを返すようにします。
    • 変更前は、コンフィグレーションディスクリプタが読み飛ばされていました。
      ここにはインターフェイスディスクリプタの個数などがあり、将来役立つかもしれません。
  • 3引数の NewClassDriver() において、エンドポイントディスクリプタのみをエンドポイントとして数えるようにします。
    • ファンクショナルディスクリプタを数えないようにし、エンドポイントディスクリプタを規定数読み込んでからループを抜けるようにします。
      確実にエンドポイントの情報を得られるようになり、またファンクショナルディスクリプタの情報も得られるようになります。
  • CDCDriver::SetLineCoding() において、 if_data ではなく if_comminterface_number を用いるようにします。
    • Bmax B2Sと公式のArduino UNOの組み合わせにおいて、 setup_data.index1 を入れるとStall Errorとなってしまいましたが、 0 を入れるとうまく動きそうでした。
      if_comminterface_number0 で辻褄が合うので、採用しました。
      本当に適切かはわかりません。
  • 初期化時に通信設定を取得し、ボーレートが0の場合は適当に設定を行うようにします。
    • 初期状態ではシリアル通信が動作しませんでしたが、 setbaud コマンドを実行すると動作するようになりました。
      パケットキャプチャの結果を見ると、最初はGET LINE CODINGの結果が全て0となっていました。
      そこで、初期化時に通信設定を取得し、ボーレートが0の場合は設定を行うようにすることで、明示的に setbaud コマンドを実行しなくても9600bpsで通信できるようにしました。
  • 受信を送信とは独立に行い、受信完了時に次の受信を行うようにします。
    • 変更前は、送信時に受信も1回行うようになっていました。
      送信しないと受信できないというのは不自然だと考え、MikanOSがHIDではどのように受信しているのかを調べたところ、受信完了時に次の受信を行っているようでした。
      そこで、CDCでも同様に受信完了時に次の受信を行うようにしました。
  • usbtest コマンドが、送信した長さ分受信するまで受信するようにします。
    • 受信完了のログを出力するとうまく動くようでしたが、ログを出力しないと数文字しか受信できませんでした。
      これは、変更前の usbtest コマンドは正の長さのデータを1回受信できたら受信を打ち切る仕様になっているためであると考えられます。
      さらに、次の usbtest コマンドの実行時に前の usbtest コマンドで受信したかったデータが読み込まれ、不自然な挙動となりました。
      そこで、送信した長さ分受信するまで受信する仕様にすることで、これを改善しました。

…LineCoding

Based on test with Arduino UNO:
* Using if_data->interface_number (1) resulted in Stall Error
* Using if_comm->interface_number (0) looked working
* Set baud rate on initialize if not set
* Make receiving be independent from sending (like receiving from HID)
…criptor instead of next one"

This reverts commit 0ecc571.

The first descriptor (ConfigurationDescriptor) is read in
the function InitializePhase2(),
so reading it again doesn't make sense.
@mikecat
Copy link
Contributor Author

mikecat commented Sep 20, 2022

  • ConfigurationDescriptorReader::Next() の変更を取り消しました。
    • コンフィギュレーションディスクリプタは InitializePhase2() の最初に読んでいることに気が付きました。
  • 複合デバイス(中の最初の対応する種類のデバイス)に対応しました。
    • USB-UARTコンバータ - aitendousbtest で動くようになりました。
    • TXとRXを電線で直結した状態で確認しました。
    • ただし、
      • 最初に setbaud をしないと動きませんでした。
      • 10文字以上送るとBabble Detected Errorが出てしまうようです。

@mikecat
Copy link
Contributor Author

mikecat commented Sep 20, 2022

  • 通信速度が設定されているかに関わらず最初に kSetLineCoding を送るようにしました。
    • 明示的に setbaud をしなくても usbtest が動くようになりました。
  • 8バイト固定ではなく、パケットの最大サイズを受信用に確保するようにしました。
    • 10文字以上送っても Babble Detected Error が出なくなりました。

@mikecat
Copy link
Contributor Author

mikecat commented Sep 22, 2022

クラス番号が0のデバイスに対する処理も、複合デバイス用の処理を使うようにしました。

CY7C65213搭載 USBシリアル変換アダプタ — スイッチサイエンス
がクラス番号0でInterface Association Descriptorを持つ仕様だったので、これに対応します。

Wiresharkによる当該デバイスの情報のキャプチャ結果
DEVICE DESCRIPTOR
    bLength: 18
    bDescriptorType: 0x01 (DEVICE)
    bcdUSB: 0x0200
    bDeviceClass: Device (0x00)
    bDeviceSubClass: 0
    bDeviceProtocol: 0 (Use class code info from Interface Descriptors)
    bMaxPacketSize0: 8
    idVendor: Cypress Semiconductor Corp. (0x04b4)
    idProduct: Unknown (0x0003)
    bcdDevice: 0x0000
    iManufacturer: 1
    iProduct: 2
    iSerialNumber: 0
    bNumConfigurations: 1
CONFIGURATION DESCRIPTOR
    bLength: 9
    bDescriptorType: 0x02 (CONFIGURATION)
    wTotalLength: 84
    bNumInterfaces: 3
    bConfigurationValue: 1
    iConfiguration: 0
    Configuration bmAttributes: 0xa0  NOT SELF-POWERED  REMOTE-WAKEUP
    bMaxPower: 50  (100mA)
INTERFACE ASSOCIATION DESCRIPTOR
    bLength: 8
    bDescriptorType: 0x0b (INTERFACE ASSOCIATION)
    bFirstInterface: 0
    bInterfaceCount: 2
    bFunctionClass: Communications and CDC Control (0x02)
    bFunctionSubClass: 0x02
    bFunctionProtocol: 0x01
    iFunction: 0
INTERFACE DESCRIPTOR (0.0): class Communications and CDC Control
    bLength: 9
    bDescriptorType: 0x04 (INTERFACE)
    bInterfaceNumber: 0
    bAlternateSetting: 0
    bNumEndpoints: 1
    bInterfaceClass: Communications and CDC Control (0x02)
    bInterfaceSubClass: Abstract Control Model (0x02)
    bInterfaceProtocol: AT Commands: V.250 etc (0x01)
    iInterface: 0
COMMUNICATIONS DESCRIPTOR
    bLength: 5
    bDescriptorType: 0x24 (CS_INTERFACE)
    Descriptor Subtype: Header Functional Descriptor (0x00)
    CDC: 0x0110
COMMUNICATIONS DESCRIPTOR
    bLength: 4
    bDescriptorType: 0x24 (CS_INTERFACE)
    Descriptor Subtype: Abstract Control Management Functional Descriptor (0x02)
    bmCapabilities: 0x02
COMMUNICATIONS DESCRIPTOR
    bLength: 5
    bDescriptorType: 0x24 (CS_INTERFACE)
    Descriptor Subtype: Union Functional Descriptor (0x06)
    Control Interface: 0x00
    Subordinate Interface: 0x01
COMMUNICATIONS DESCRIPTOR
    bLength: 5
    bDescriptorType: 0x24 (CS_INTERFACE)
    Descriptor Subtype: Call Management Functional Descriptor (0x01)
    bmCapabilities: 0x00
    Data Interface: 0x01
ENDPOINT DESCRIPTOR
    bLength: 7
    bDescriptorType: 0x05 (ENDPOINT)
    bEndpointAddress: 0x83  IN  Endpoint:3
    bmAttributes: 0x03
    wMaxPacketSize: 64
    bInterval: 10
INTERFACE DESCRIPTOR (1.0): class CDC-Data
    bLength: 9
    bDescriptorType: 0x04 (INTERFACE)
    bInterfaceNumber: 1
    bAlternateSetting: 0
    bNumEndpoints: 2
    bInterfaceClass: CDC-Data (0x0a)
    bInterfaceSubClass: 0x00
    bInterfaceProtocol: No class specific protocol required (0x00)
    iInterface: 0
ENDPOINT DESCRIPTOR
    bLength: 7
    bDescriptorType: 0x05 (ENDPOINT)
    bEndpointAddress: 0x01  OUT  Endpoint:1
    bmAttributes: 0x02
    wMaxPacketSize: 64
    bInterval: 0
ENDPOINT DESCRIPTOR
    bLength: 7
    bDescriptorType: 0x05 (ENDPOINT)
    bEndpointAddress: 0x82  IN  Endpoint:2
    bmAttributes: 0x02
    wMaxPacketSize: 64
    bInterval: 0
INTERFACE DESCRIPTOR (2.0): class Vendor Specific
    bLength: 9
    bDescriptorType: 0x04 (INTERFACE)
    bInterfaceNumber: 2
    bAlternateSetting: 0
    bNumEndpoints: 0
    bInterfaceClass: Vendor Specific (0xff)
    bInterfaceSubClass: 0x05
    bInterfaceProtocol: 0x00
    iInterface: 0

ついでに、役目が同じようなコードの重複の削減にもなります。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant