SSブログ

macOSからPi Picoを使う - その26 [Pi Pico]

今、久しぶりに工場に出張している。設備のホストに使っているMac(ほとんどがMac mini)がもう古くてみんなHDDなので、アプリケーションの起動だけでもかなり遅く感じるようになってきた、と現場から言われた。そこでHDDをSSDに換装して少しでもマシにしよう、ということになってその作業を僕がしている。Mid 2011やLate 2012はすごく分解しづらい。終わるとネジがいっぱい余る。とりあえず今週中にMac mini5台をバックアップ取って換装してリストアする。会社を辞めたらMac miniの修理屋でもやろう。ネジを余らせるような修理屋には誰も頼まないか。

ところでlibusbの続き。「macOSから」というタイトルにしてるけど、最近はmacOS固有の問題はほとんどない。看板に偽りあり、と言えばそう。本来ならそんな重箱の隅をつつくような話ではなくて、もっと一般的な記事にしたほうがいい、というのはもっともな意見。でもまあ、僕がヒット数を目指したとしても、きっとどうせ今とほとんど変わらないだろうから、別にいいや。自分が面白いと思うことをやろう。

というわけでlibusbのおさらいを続ける...

17.3.4  デバイス情報の取得

libusb_device構造体からデバイスの情報を得るにはそれぞれ専用の関数が用意されている。
uint8_t libusb_get_bus_number(libusb_device *dev);
uint8_t libusb_get_port_number(libusb_device *dev);
uint8_t libusb_get_device_address(libusb_device *dev);
int     libusb_get_device_speed(libusb_device *dev);
読んで字のごとくだけど、libusbプログラマにとって便利な情報はあんまりない。

バススピードは

LIBUSB_SPEED_UNKNOWN わからん場合
LIBUSB_SPEED_LOW 1.5MBit/s
LIBUSB_SPEE_FULL 12MBit/s
LIBUSB_SPEED_HIGH 480MBit/s
LIBUSB_SPEED_SUPER 5000MBit/s
LIBUSB_SPEED_SUPER_PLUS 10000MBit/s

だそうである。

もう少し詳しい情報を得ようとすると結局デスクリプタを読むことになる。デスクリプタは構造体としてlibusb.hに定義されてて
struct libusb_device_descriptor {
    uint8_t  bLength;           /** Size of this descriptor (in bytes) */
    uint8_t  bDescriptorType;   /** Descriptor type. */
    uint16_t bcdUSB;            /** USB specification release number in binary-
    uint8_t  bDeviceClass;      /** USB-IF class code for the device.*/
    uint8_t  bDeviceSubClass;   /** USB-IF subclass code for the device, */
    uint8_t  bDeviceProtocol;   /** USB-IF protocol code for the device */
    uint8_t  bMaxPacketSize0;   /** Maximum packet size for endpoint 0 */
    uint16_t idVendor;          /** USB-IF vendor ID */
    uint16_t idProduct;         /** USB-IF product ID */
    uint16_t bcdDevice;         /** Device release number in binary-coded
    uint8_t  iManufacturer;     /** Index of string descriptor describing manu
    uint8_t  iProduct;          /** Index of string descriptor describ
    uint8_t  iSerialNumber;     /** Index of string descriptor containing device
    uint8_t  bNumConfigurations;/** Number of possible
};
となっている。この構造体はopaqueではない。USBの規格を見慣れた人ならまんまであるこがわかるので、opaqueにする必要がない、ということだろう。当然、この前見たTinyUSBのdevice descriptorとメンバ名までまったくいっしょである。

device descriptor構造体はlibusb_device構造体から
int libusb_get_device_descriptor(libusb_device                      *dev,
                                 struct libusb_device_descriptor    *desc);
の関数で得ることができる。0が返れば成功。VendorIDとproductIDでデバイスで特定するなら、まずこのデスクリプタを読むことになる。また、汎用のデバイスを呼びたいならやはりこのデスクリプタを読んでデバイスクラスを頼りに特定することになる。

17.4  configuration descriptorの取得

configuration descriptorも同じように
int libusb_get_active_config_descriptor(libusb_device                   *dev,
                                        struct libusb_config_descriptor **config);

int libusb_get_config_descriptor(libusb_device                      *dev,
                                 uint8_t                            config_index,
                                 struct libusb_config_descriptor    **config);

void libusb_free_config_descriptor(struct libusb_config_descriptor  *config);
getするとconfiguration descriptorへのポインタがconfig変数に設定される。これは使い終わったらfreeする必要がある。

TinyUSBと同じでconfiguration descriptor単独ではなくdescriptorのあとにinterface descriptorとendpoint descriptorが含まれた形になっている。
struct libusb_config_descriptor {
    uint8_t  bLength;
    uint8_t  bDescriptorType;
    uint16_t wTotalLength;
    uint8_t  bNumInterfaces;
    uint8_t  bConfigurationValue;
    uint8_t  iConfiguration;
    uint8_t  bmAttributes;
    uint8_t  MaxPower;
    const struct libusb_interface *interface;
    const unsigned char *extra;
    int extra_length;
};
struct libusb_interface {
    const struct libusb_interface_descriptor *altsetting;
    int num_altsetting;
};

struct libusb_interface_descriptor {
    uint8_t  bLength;
    uint8_t  bDescriptorType;
    uint8_t  bInterfaceNumber;
    uint8_t  bAlternateSetting;
    uint8_t  bNumEndpoints;
    uint8_t  bInterfaceClass;
    uint8_t  bInterfaceSubClass;
    uint8_t  bInterfaceProtocol;
    uint8_t  iInterface;
    const struct libusb_endpoint_descriptor *endpoint;
    const unsigned char *extra;
    int extra_length;
};

struct libusb_endpoint_descriptor {
    uint8_t  bLength;
    uint8_t  bDescriptorType;
    uint8_t  bEndpointAddress;
    uint8_t  bmAttributes;
    uint16_t wMaxPacketSize;
    uint8_t  bInterval;
    uint8_t  bRefresh;
    uint8_t  bSynchAddress;
    const unsigned char *extra;
    int extra_length;
};
ずらずら書くとわかりにくいけど、ほとんどがUSB規格の通りになっていて、下位のdescriptorはその配列へのポインタになっている。構造を描くとこの図のようになってる。
0812configdescriptor.png
TinyUSBと違ってホスト上ではstructにpaddingが入っている可能性がある。従ってTinyUSBのようにバイト数で次のstructを選ぶのではなくコンパイラに任せて
    struct libusb_config_descriptor  *config;
    struct libusb_interface *next = config->interface + 1;
などとした方がいい。
nice!(0)  コメント(0) 

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。