Как сказано в стандарте, дескрипторы это база данных устройства. Причем база данных жестко формализованная и гибко структурируемая. И несмотря на то, как это серьезно звучит, улетает она практически моментально по запросу хоста. Ведь фактически это просто один массив, который помещается чуть ли не в один стандартный пакетик. И запросив их, драйвер компьютера, до этой минуты не догадывающийся о том, что ему подключили, узнает абсолютно все о вновь добавленном устройстве. А эта статья по сути сборник скучных комментариев на тему этих самых дескрипторов.
Итак, основные типы:
- Device - содержит основную информацию об устройстве
- Configuration - тут уже особенности
- Interface - у каждого устройства может быть несколько интерфейсов, в простейшем случае он один
- Endpoint - если совсем грубо то ендпоинт = канал связи, тут он конфигурируется, определяются размеры пакетов и частота их передачи
- String - так вот откуда берутся все эти надписи в строке авторана, KYE Systems mouse + keyboard + snowboard mega combo device legalize готово к использованию
const uint8_t gamepadDeviseDesc[gamepadDeviseDescSize] =
{
0x18, // bLenght
0x01, // bDescriptorType, Device descriptor
0x00,0x02, // bcdUSB, usb 2.0
0x03, // bDeviceClass, HID
0x00, // bDeviceSubclass, not used
0x00, // bDeviceProtocol, not used
0x40, // bMaxPacketSize0, maximum size 64 byte
0xC4,0x10, // idVendor, SiLabs
0x00,0x00, // idProduct
0x00,0x01, // bcdDevice
0x01, // iManufacter
0x02, // iProduct
0x00, // iSerialNumber
0x01 // bNumConfigurations
};
bLenbght = 18 - длина дескриптора в байтах, стандартно первый параметр для любого дескриптора
bDescriptorType = 0x01 - тип дескриптора, так же, стандартно второй параметр дескриптора, единица означает device дескриптор
bcdUSB = 0x0200 - 16 битный параметр, обозначающий текущую версию спецификации USB, у меня уже USB 2.0 (если что, то вышел уже четвертый).
bDeviceClass = 0x03 - класс устройства, в моем случае USB HID, все остальные константы ищите в стандарте.
Далее извините, тут вам не стандарт, не используемые в моем случае параметры описывать не буду.
bMaxPacketSize0 = 0x40 - означает максимально возможный размер в 64 байта, определенный для нулевого endpoint, в котором и происходит вся конфигурация устройства.
idVendor = 0xc410 - для каждого производителя зарегистрирован отдельный ID, как правило это производители чипов, я использую STM.
idProduct = 0x0000 - ID продукта, так же регистрируются USB форумом, от балды тут ничего написать нельзя, пишем то, что советует datasheet нашего чипа.
bcdDevice = 0x0001 - номер релиза устройства по порядку
iManufacter = 0x01 - номер строки содержащей информацию о производителе устройства
iProduct = 0x02 - номер строки, с информацией о самом устройстве
iSerialNumber = 0x00 - строка с серийным номером устройства (в моем случае не используется)
bNumConfigurations = 0x01 - помните про configuration дескриптор, так вот их бывает так же несколько, но в моем случае, само собой один.
const uint8_t gamepadConfigurationDesc[gamepadConfigurationDescSize] =
{
0x09, // bLenght
0x02, // bDescriptorType, Configuration descriptor
0x22, 0x00, // TotalLenght
0x01, // bNumInterfaces
0x01, // bConfigurationValue
0x00, // iConfiguration
0xe0, // bmAttributes, self-powered
0x32 // maxPower, 100mA
};
TotalLenght = 0x0022 - общий размер почти всех дескрипторов, что есть (configuration, interface, endpoint 1, hid)
bNumInterfaces = 0x01 - количество интерфейсов, у меня он просто есть, потому что так надо
bConfigurationValue = 0x01 - номер описываемой в дескрипторе конфигурации, что бы host мог их выбирать, в случае если их несколько
iConfiguration = 0x00 - и для каждой конфигурации так же можно определить строку с описанием
bmAttributes = 0xe0 - стандартные функции устройства, в моем случае сообщим только, что устройcтво может может уходить в сон и будиться удаленно и запитано от шины USB (бывают и те что запитаны от отдельного блока питания, отключаемого по тому же USB)
maxPower = 0x32 максимальный ток, выставим нереальные для моего скромного конфига 100 мА
const uint8_t gamepadInterfaceDesc[gamepadInterfaceDescSize] =
{
0x09, // bLenght
0x04, // bDescriptorType, Interface descriptor
0x00, // bInterfaceNumber
0x00, // bAlternateSetting
0x01, // bNumEndpoints
0x03, // bInterfaceClass, HID
0x00, // bInterfaceSubClass,
0x00, // bInterfaceProtocol
0x00 // bInterface
};
bNumEndpoints = 0x01 - общее количество endpoint за исключением endpoint 0, который по умолчанию
bInterfaceClass = 0x03 - на самом деле о том, что у нас HID устройство, нужно говорить тут
const uint8_t gamepadInEndpDesc[gamepadInEndpDescSize] =
{
0x07, // bLenght
0x05, // bDescriptorType, endpoint descriptor
0x81, // bEndpointAddress, IN endpoint 1
0x03, // bMattributes, interrupt endpoint
0x04,0x00, // MaxPacketSize, 4 bytes
0x20 // bInterval 32 ms
};
bEndpointAddress = 0x81 - endpoint с адресом 1 типа IN (направление данных от устройства к хосту)
bMattributes = 0x03 - тип передачи данных по endpoint, в моем случае interrupt endpoint, самый простой, не нагруженный
MaxPacketSize = 0x0004 - максимальный размер пакета в 4 байта, что бы сообщить о состоянии кнопок нужно немного.
bInterval = 0x20 - интервал запроса данных хостом в 32 мс.
const uint8_t stringLangId[stringLangIdSize] =
{
0x04, 0x03, 0x09, 0x04
};
0x09 English
0x03 U.S. English
const uint8_t gamepadStringVendor[gamepadStringVendorSize] =
{
0x08,
0x03,
'z',0,'x',0
};
const uint8_t gamepadStringProduct[gamepadStringProductSize] =
{
0x06,
0x03,
'j',0,'o',0,'y',0
};
Как вы понимаете, размер дескриптора, тип дескриптора (строка), далее сама строка в двухбайтовом юникоде.
- HID - определяет то, сколько report будет передаваться между хостом и устройством
- Report - собственно то, ради чего все и затевалось, в моем случае всего один байт информации о нажатых кнопках на джойстике, к слову у мышек три. А вот описывает их дескриптор чуть ли не на все 64 байта.
const uint8_t gamepadHidDesc[gamepadHidDescSize] =
{
0x09, // bLenght
0x21, // bDescriptorType, HID descriptor
0x00,0x01, // bcdHID, HID spec 1.01
0x33, // country code SU
0x01, // bNumDescriptors
0x22, // bDescriptorType, report descriptor
0x55,0x00 // wDescriptorLenght
};
bcdHID = 0x0101 - версия HID спецификации, которую читал
country code = 0x33 - региональный код, нужен для клавиатур, и там даже есть советский союз
wDescriptorLenght = 0x0055 - размер report дескриптора для этого устройства
const uint8_t gamepadReportDesc[gamepadreportDescSize] =
{
0x05, 0x01, // usage_page(Generic Desctop)
0x09, 0x05, // usage(Game pad)
0xa1, 0x01, // collection(Application)
0x05, 0x01, // usage_page(Generic Desctop)
0x09, 0x01, // usage(Pointer)
0xa1, 0x00, // collection(Physical)
0x09, 0x39, // usage(Hat switch)
0x15, 0x00, // logical minimum(0)
0x25, 0x07, // logical maximum(7)
0x35, 0x00, // physical minimum(0)
0x46, 0x3b, 0x01, // physical maximum(315)
0x65, 0x14, // unit(Eng Rot:Angular Pos)
0x95, 0x01, // report_count(1)
0x75, 0x04, // report_size(4)
0x81, 0x42, // input(Data,Var,Abs,Null)
0xc0, // end_collection
0x05, 0x09, // usage_page(Button)
0x15, 0x00, // logical minimum(0)
0x25, 0x01, // logical maximum(1)
0x95, 0x02, // report_count(2)
0x75, 0x01, // report_size(1)
0x81, 0x02, // input(Data,Var,Abs)
// byte alingment
0x95, 0x01, // report_count(1)
0x75, 0x02, // report_size(2)
0x81, 0x01, // input(Const)
0xc0 // end_collection
};
Если совсем коротко, то в туториале на google code назвали то, что происходит в report descriptor мясом, а я бы сказал что там какой то фарш. Подробно опишу в следующей статье. Здесь только скажу, что данный дескриптор сгенерирован стандартной утилитой (под вайном юзабельно). В нем подробно описаны типы данных, которые будут передаваться собственно в самих report.
А теперь о самих запросах, в минимальной стандартной конфигурации их определено десять. Но на самом деле полезны только два, тот что нумерует устройство, и тот что запрашивает дескрипторы. Все остальное, как обычно нужно как то реализовать для полной совместимости со стандартом, проще говоря что бы было.
Комментариев нет :
Отправить комментарий