/* USB Standard Device Descriptor */
const uint8_t RHID_DeviceDescriptor[RHID_SIZ_DEVICE_DESC] =
{
RHID_SIZ_DEVICE_DESC, // общая длина дескриптора устройства в байтах
USB_DEVICE_DESCRIPTOR_TYPE, // bDescriptorType - показывает, что это за дескриптор. В данном случае - Device descriptor
0x00, 0x02, // bcdUSB - какую версию стандарта USB поддерживает устройство. 2.0
// класс, подкласс устройства и протокол, по стандарту USB. У нас нули, означает каждый интерфейс сам за себя
0x00, //bDeviceClass
0x00, //bDeviceSubClass
0x00, //bDeviceProtocol
0x40, //bMaxPacketSize - максимальный размер пакетов для Endpoint 0 (при конфигурировании)
// те самые пресловутые VID и PID, по которым и определяется, что же это за устройство.
0x83, 0x04, //idVendor (0x0483)
0x11, 0x57, //idProduct (0x5711)
DEVICE_VER_L, DEVICE_VER_H, // bcdDevice rel. DEVICE_VER_H.DEVICE_VER_L номер релиза устройства
// дальше идут индексы строк, описывающих производителя, устройство и серийный номер.
// Отображаются в свойствах устройства в диспетчере устройств
// А по серийному номеру подключенные устройства с одинаковым VID/PID различаются системой.
1, //Index of string descriptor describing manufacturer
2, //Index of string descriptor describing product
3, //Index of string descriptor describing the device serial number
0x01 // bNumConfigurations - количество возможных конфигураций. У нас одна.
}
; /* CustomHID_DeviceDescriptor */
/* USB Configuration Descriptor */ /* All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */ const uint8_t RHID_ConfigDescriptor[RHID_SIZ_CONFIG_DESC] = { 0x09, // bLength: длина дескриптора конфигурации USB_CONFIGURATION_DESCRIPTOR_TYPE, // bDescriptorType: тип дескриптора - конфигурация RHID_SIZ_CONFIG_DESC, 0x00, // wTotalLength: общий размер всего дерева под данной конфигурацией в байтах 0x01, // bNumInterfaces: в конфигурации всего один интерфейс 0x01, // bConfigurationValue: индекс данной конфигурации 0x00, // iConfiguration: индекс строки, которая описывает эту конфигурацию 0xE0, // bmAttributes: признак того, что устройство будет питаться от шины USB 0x32, // MaxPower 100 mA: и ему хватит 100 мА /************** Дескриптор интерфейса ****************/ 0x09, // bLength: размер дескриптора интерфейса USB_INTERFACE_DESCRIPTOR_TYPE, // bDescriptorType: тип дескриптора - интерфейс 0x00, // bInterfaceNumber: порядковый номер интерфейса - 0 0x00, // bAlternateSetting: признак альтернативного интерфейса, у нас не используется 0x02, // bNumEndpoints - количество эндпоинтов. 0x03, // bInterfaceClass: класс интерфеса - HID // если бы мы косили под стандартное устройство, например клавиатуру или мышь, то надо было бы указать правильно класс и подкласс // а так у нас общее HID-устройство 0x00, // bInterfaceSubClass : подкласс интерфейса. 0x00, // nInterfaceProtocol : протокол интерфейса 0, // iInterface: индекс строки, описывающей интерфейс // теперь отдельный дескриптор для уточнения того, что данный интерфейс - это HID устройство /******************** HID дескриптор ********************/ 0x09, // bLength: длина HID-дескриптора HID_DESCRIPTOR_TYPE, // bDescriptorType: тип дескриптора - HID 0x01, 0x01, // bcdHID: номер версии HID 1.1 0x00, // bCountryCode: код страны (если нужен) 0x01, // bNumDescriptors: Сколько дальше будет report дескрипторов HID_REPORT_DESCRIPTOR_TYPE, // bDescriptorType: Тип дескриптора - report RHID_SIZ_REPORT_DESC, 0x00, // wItemLength: длина report-дескриптора /******************** дескриптор конечных точек (endpoints) ********************/ 0x07, // bLength: длина дескриптора USB_ENDPOINT_DESCRIPTOR_TYPE, // тип дескриптора - endpoints 0x81, // bEndpointAddress: адрес конечной точки и направление 1(IN) 0x03, // bmAttributes: тип конечной точки - Interrupt endpoint wMaxPacketSize, 0x00, // wMaxPacketSize: Bytes max 0x20, // bInterval: Polling Interval (32 ms) 0x07, /* bLength: Endpoint Descriptor size */ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: */ /* Endpoint descriptor type */ 0x01, /* bEndpointAddress: */ /* Endpoint Address (OUT) */ 0x03, /* bmAttributes: Interrupt endpoint */ wMaxPacketSize, /* wMaxPacketSize: Bytes max */ 0x00, 0x20, /* bInterval: Polling Interval (32 ms) */ } ; /* RHID_ConfigDescriptor */
const uint8_t RHID_ReportDescriptor[RHID_SIZ_REPORT_DESC] = { 0x06, 0x00, 0xff, // USAGE_PAGE (Generic Desktop) 0x09, 0x01, // USAGE (Vendor Usage 1) 0xa1, 0x01, // COLLECTION (Application) 0x85, 0x01, // REPORT_ID (1) 0x09, 0x01, // USAGE (Vendor Usage 1) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x01, // REPORT_COUNT (1) 0xb1, 0x82, // FEATURE (Data,Var,Abs,Vol) 0x85, 0x01, // REPORT_ID (1) 0x09, 0x01, // USAGE (Vendor Usage 1) 0x91, 0x82, // OUTPUT (Data,Var,Abs,Vol) 0x85, 0x02, // REPORT_ID (2) 0x09, 0x02, // USAGE (Vendor Usage 2) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x01, // REPORT_COUNT (1) 0xb1, 0x82, // FEATURE (Data,Var,Abs,Vol) 0x85, 0x02, // REPORT_ID (2) 0x09, 0x02, // USAGE (Vendor Usage 2) 0x91, 0x82, // OUTPUT (Data,Var,Abs,Vol) 0x85, 0x03, // REPORT_ID (3) 0x09, 0x03, // USAGE (Vendor Usage 3) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) 0x75, 0x08, // REPORT_SIZE (8) 0x95, RPT3_COUNT, // REPORT_COUNT (N) 0xb1, 0x82, // FEATURE (Data,Var,Abs,Vol) 0x85, 0x03, // REPORT_ID (3) 0x09, 0x03, // USAGE (Vendor Usage 3) 0x91, 0x82, // OUTPUT (Data,Var,Abs,Vol) 0x85, 0x04, // REPORT_ID (4) 0x09, 0x04, // USAGE (Vendor Usage 4) 0x75, 0x08, // REPORT_SIZE (8) 0x95, RPT4_COUNT, // REPORT_COUNT (N) 0x81, 0x82, // INPUT (Data,Var,Abs,Vol) 0xc0 // END_COLLECTION }
Report
Хост (ПК) и девайс (МК) обмениваются пакетами данных заранее оговоренной структуры — report. Пакетов может быть весьма много, их можно предусмотреть на все случаи жизни — например пакет с данными о каких-то событиях в устройстве, пакет с данными, которые запрашивал ПК, пакет с командой для МК. Все, что угодно. Но структура всех пакетов должна быть описана в структуре RHID_ReportDescriptor.
ПК и МК различают репорты по ID, который идет первым байтом в пакете.
Если вы не до конца разобрались в том, как формировать дескриптор репортов, то просто меняйте константы RPT3_COUNT и RPT4_COUNT, устанавливая нужный размер исходящих и входящих (с точки зрения ПК) пакетов. Остальные репорты можно просто не трогать, они не помешают. Не забывайте, что первым байтом должен быть ID репорта.
https://habrahabr.ru/post/208026/
/* USB Configuration Descriptor */ /* All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */ const uint8_t RHID_ConfigDescriptor[RHID_SIZ_CONFIG_DESC] = { 0x09, // bLength: длина дескриптора конфигурации USB_CONFIGURATION_DESCRIPTOR_TYPE, // bDescriptorType: тип дескриптора - конфигурация RHID_SIZ_CONFIG_DESC, 0x00, // wTotalLength: общий размер всего дерева под данной конфигурацией в байтах 0x01, // bNumInterfaces: в конфигурации всего один интерфейс 0x01, // bConfigurationValue: индекс данной конфигурации 0x00, // iConfiguration: индекс строки, которая описывает эту конфигурацию 0xE0, // bmAttributes: признак того, что устройство будет питаться от шины USB 0x32, // MaxPower 100 mA: и ему хватит 100 мА /************** Дескриптор интерфейса ****************/ 0x09, // bLength: размер дескриптора интерфейса USB_INTERFACE_DESCRIPTOR_TYPE, // bDescriptorType: тип дескриптора - интерфейс 0x00, // bInterfaceNumber: порядковый номер интерфейса - 0 0x00, // bAlternateSetting: признак альтернативного интерфейса, у нас не используется 0x02, // bNumEndpoints - количество эндпоинтов. 0x03, // bInterfaceClass: класс интерфеса - HID // если бы мы косили под стандартное устройство, например клавиатуру или мышь, то надо было бы указать правильно класс и подкласс // а так у нас общее HID-устройство 0x00, // bInterfaceSubClass : подкласс интерфейса. 0x00, // nInterfaceProtocol : протокол интерфейса 0, // iInterface: индекс строки, описывающей интерфейс // теперь отдельный дескриптор для уточнения того, что данный интерфейс - это HID устройство /******************** HID дескриптор ********************/ 0x09, // bLength: длина HID-дескриптора HID_DESCRIPTOR_TYPE, // bDescriptorType: тип дескриптора - HID 0x01, 0x01, // bcdHID: номер версии HID 1.1 0x00, // bCountryCode: код страны (если нужен) 0x01, // bNumDescriptors: Сколько дальше будет report дескрипторов HID_REPORT_DESCRIPTOR_TYPE, // bDescriptorType: Тип дескриптора - report RHID_SIZ_REPORT_DESC, 0x00, // wItemLength: длина report-дескриптора /******************** дескриптор конечных точек (endpoints) ********************/ 0x07, // bLength: длина дескриптора USB_ENDPOINT_DESCRIPTOR_TYPE, // тип дескриптора - endpoints 0x81, // bEndpointAddress: адрес конечной точки и направление 1(IN) 0x03, // bmAttributes: тип конечной точки - Interrupt endpoint wMaxPacketSize, 0x00, // wMaxPacketSize: Bytes max 0x20, // bInterval: Polling Interval (32 ms) 0x07, /* bLength: Endpoint Descriptor size */ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: */ /* Endpoint descriptor type */ 0x01, /* bEndpointAddress: */ /* Endpoint Address (OUT) */ 0x03, /* bmAttributes: Interrupt endpoint */ wMaxPacketSize, /* wMaxPacketSize: Bytes max */ 0x00, 0x20, /* bInterval: Polling Interval (32 ms) */ } ; /* RHID_ConfigDescriptor */
const uint8_t RHID_ReportDescriptor[RHID_SIZ_REPORT_DESC] = { 0x06, 0x00, 0xff, // USAGE_PAGE (Generic Desktop) 0x09, 0x01, // USAGE (Vendor Usage 1) 0xa1, 0x01, // COLLECTION (Application) 0x85, 0x01, // REPORT_ID (1) 0x09, 0x01, // USAGE (Vendor Usage 1) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x01, // REPORT_COUNT (1) 0xb1, 0x82, // FEATURE (Data,Var,Abs,Vol) 0x85, 0x01, // REPORT_ID (1) 0x09, 0x01, // USAGE (Vendor Usage 1) 0x91, 0x82, // OUTPUT (Data,Var,Abs,Vol) 0x85, 0x02, // REPORT_ID (2) 0x09, 0x02, // USAGE (Vendor Usage 2) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x01, // REPORT_COUNT (1) 0xb1, 0x82, // FEATURE (Data,Var,Abs,Vol) 0x85, 0x02, // REPORT_ID (2) 0x09, 0x02, // USAGE (Vendor Usage 2) 0x91, 0x82, // OUTPUT (Data,Var,Abs,Vol) 0x85, 0x03, // REPORT_ID (3) 0x09, 0x03, // USAGE (Vendor Usage 3) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) 0x75, 0x08, // REPORT_SIZE (8) 0x95, RPT3_COUNT, // REPORT_COUNT (N) 0xb1, 0x82, // FEATURE (Data,Var,Abs,Vol) 0x85, 0x03, // REPORT_ID (3) 0x09, 0x03, // USAGE (Vendor Usage 3) 0x91, 0x82, // OUTPUT (Data,Var,Abs,Vol) 0x85, 0x04, // REPORT_ID (4) 0x09, 0x04, // USAGE (Vendor Usage 4) 0x75, 0x08, // REPORT_SIZE (8) 0x95, RPT4_COUNT, // REPORT_COUNT (N) 0x81, 0x82, // INPUT (Data,Var,Abs,Vol) 0xc0 // END_COLLECTION }
Описывает протокол обмена и функционал устройства.
HID Description tool
Файл «RHID.hid» с описанным выше дескриптором для редактирования в этой утилите.
RPT3_COUNT — размер OUTPUT буфера в байтах для передачи пакета в МК
RPT4_COUNT — размер INPUT буфера в байтах для передачи пакета в ПК
Размер любого из этих буферов не должен превышать wMaxPacketSize. Меньше — можно.
Кстати, превратить Custom HID в другой HID девайс, например, клавиатуру или джойстик можно фактически только переписав ReportDescriptor и изменив класс и подкласс устройства в дескрипторе конфигурации.
HID Description tool
Файл «RHID.hid» с описанным выше дескриптором для редактирования в этой утилите.
RPT3_COUNT — размер OUTPUT буфера в байтах для передачи пакета в МК
RPT4_COUNT — размер INPUT буфера в байтах для передачи пакета в ПК
Размер любого из этих буферов не должен превышать wMaxPacketSize. Меньше — можно.
Кстати, превратить Custom HID в другой HID девайс, например, клавиатуру или джойстик можно фактически только переписав ReportDescriptor и изменив класс и подкласс устройства в дескрипторе конфигурации.
Report
Хост (ПК) и девайс (МК) обмениваются пакетами данных заранее оговоренной структуры — report. Пакетов может быть весьма много, их можно предусмотреть на все случаи жизни — например пакет с данными о каких-то событиях в устройстве, пакет с данными, которые запрашивал ПК, пакет с командой для МК. Все, что угодно. Но структура всех пакетов должна быть описана в структуре RHID_ReportDescriptor.
ПК и МК различают репорты по ID, который идет первым байтом в пакете.
- REPORT_ID = 1 и 2 — команда МК включить/выключить LED1/LED2. Содержит поле размером 1 бит с желаемым состоянием светодиода и поддерживает отправку как методом SET_REPORT так и методом SET_FEATURE (об этом чуть позже).
- REPORT_ID = 3 — передает один байт в МК. Просто, чтобы показать, как передать данные МК. Мы будем передавать положение ползунка.
- REPORT_ID = 4 — это репорт для передачи данных ПК. Возвращает информацию о текущем состоянии светодиодов, кнопок (если они есть) и возвращает переданный в репорте с ID=3 байт, чтобы показать, что данные приняты.
Если вы не до конца разобрались в том, как формировать дескриптор репортов, то просто меняйте константы RPT3_COUNT и RPT4_COUNT, устанавливая нужный размер исходящих и входящих (с точки зрения ПК) пакетов. Остальные репорты можно просто не трогать, они не помешают. Не забывайте, что первым байтом должен быть ID репорта.
https://habrahabr.ru/post/208026/
Комментариев нет:
Отправить комментарий