Я пытаюсь реализовать сенсорный экран USB на STM32. Я создаю полноскоростное устройство, используя USB-библиотеку ST, и тестирую его на хосте с Windows 10. Первый контакт регистрируется, но при попытке нажать другой - нет. Это происходит даже тогда, когда контакты нажимаются самостоятельно.
Я использую образцы дескрипторов отчетов , представленные в документации Windows Hardware Developer, измененные таким образом, что использование X и Y сообщает только о предполагаемых касаниях. Для простоты я также исключил отчет о статусе сертификации устройства. Мой дескриптор отчета выглядит следующим образом:
/* USER CODE BEGIN 0 */
0x05, 0x0d, // USAGE_PAGE (Digitizers)
0x09, 0x04, // USAGE (Touch Screen)
0xa1, 0x01, // COLLECTION (Application)
0x85, 0x01, // REPORT_ID (Touch)
0x09, 0x22, // USAGE (Finger)
0xa1, 0x02, // COLLECTION (Logical)
0x09, 0x42, // USAGE (Tip Switch)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x07, // REPORT_COUNT (7)
0x81, 0x03, // INPUT (Cnst,Ary,Abs)
0x75, 0x08, // REPORT_SIZE (8)
0x09, 0x51, // USAGE (Contact Identifier)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desk..
0x26, 0xff, 0x0f, // LOGICAL_MAXIMUM (4095)
0x75, 0x10, // REPORT_SIZE (16)
0x55, 0x0e, // UNIT_EXPONENT (-2)
0x65, 0x13, // UNIT(Inch,EngLinear)
0x09, 0x30, // USAGE (X)
0x35, 0x00, // PHYSICAL_MINIMUM (0)
0x46, 0xb5, 0x04, // PHYSICAL_MAXIMUM (1205)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x46, 0x8a, 0x03, // PHYSICAL_MAXIMUM (906)
0x09, 0x31, // USAGE (Y)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x05, 0x0d, // USAGE_PAGE (Digitizers)
0x09, 0x48, // USAGE (Width)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x09, 0x49, // USAGE (Height)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x55, 0x0C, // UNIT_EXPONENT (-4)
0x65, 0x12, // UNIT (Radians,SIROtation)
0x35, 0x00, // PHYSICAL_MINIMUM (0)
0x47, 0x6f, 0xf5, 0x00, 0x00, // PHYSICAL_MAXIMUM (62831)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x27, 0x6f, 0xf5, 0x00, 0x00, // LOGICAL_MAXIMUM (62831)
0x09, 0x3f, // USAGE (Azimuth[Orientation])
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0, // END_COLLECTION
0x09, 0x22, // USAGE (Finger)
0xa1, 0x02, // COLLECTION (Logical)
0x09, 0x42, // USAGE (Tip Switch)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x07, // REPORT_COUNT (7)
0x81, 0x03, // INPUT (Cnst,Ary,Abs)
0x75, 0x08, // REPORT_SIZE (8)
0x09, 0x51, // USAGE (Contact Identifier)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desk..
0x26, 0xff, 0x0f, // LOGICAL_MAXIMUM (4095)
0x75, 0x10, // REPORT_SIZE (16)
0x55, 0x0e, // UNIT_EXPONENT (-2)
0x65, 0x13, // UNIT(Inch,EngLinear)
0x09, 0x30, // USAGE (X)
0x35, 0x00, // PHYSICAL_MINIMUM (0)
0x46, 0xb5, 0x04, // PHYSICAL_MAXIMUM (1205)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x46, 0x8a, 0x03, // PHYSICAL_MAXIMUM (906)
0x09, 0x31, // USAGE (Y)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x05, 0x0d, // USAGE_PAGE (Digitizers)
0x09, 0x48, // USAGE (Width)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x09, 0x49, // USAGE (Height)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x55, 0x0C, // UNIT_EXPONENT (-4)
0x65, 0x12, // UNIT (Radians,SIROtation)
0x35, 0x00, // PHYSICAL_MINIMUM (0)
0x47, 0x6f, 0xf5, 0x00, 0x00, // PHYSICAL_MAXIMUM (62831)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x27, 0x6f, 0xf5, 0x00, 0x00, // LOGICAL_MAXIMUM (62831)
0x09, 0x3f, // USAGE (Azimuth[Orientation])
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0, // END_COLLECTION
0x05, 0x0d, // USAGE_PAGE (Digitizers)
0x55, 0x0C, // UNIT_EXPONENT (-4)
0x66, 0x01, 0x10, // UNIT (Seconds)
0x47, 0xff, 0xff, 0x00, 0x00, // PHYSICAL_MAXIMUM (65535)
0x27, 0xff, 0xff, 0x00, 0x00, // LOGICAL_MAXIMUM (65535)
0x75, 0x10, // REPORT_SIZE (16)
0x95, 0x01, // REPORT_COUNT (1)
0x09, 0x56, // USAGE (Scan Time)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x09, 0x54, // USAGE (Contact count)
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x85, REPORTID_MAX_COUNT, // REPORT_ID (Feature)
0x09, 0x55, // USAGE(Contact Count Maximum)
0x95, 0x01, // REPORT_COUNT (1)
0x25, 0x02, // LOGICAL_MAXIMUM (2)
0xb1, 0x02, // FEATURE (Data,Var,Abs)
/* USER CODE END 0 */
0xC0 /* END_COLLECTION */
Я представляю входной отчет с помощью структуры TouchReport
, которая содержит массив структур Contact
. Обратите внимание, что TOUCHSCREEN_MAX_CONTACTS
— это 2.
typedef struct __attribute__((packed))
{
uint8_t report_ID;
Contact contacts[TOUCHSCREEN_MAX_CONTACTS];
uint16_t scan_time;
uint8_t contact_count;
} TouchReport;
typedef struct __attribute__((packed))
{
uint8_t tip_switch;
uint8_t contact_ID;
uint16_t x;
uint16_t y;
uint16_t width;
uint16_t height;
uint16_t azimuth;
} Contact;
Когда я устанавливаю для контакта значения contact_ID
, равные 0, и отправляю отчет, я вижу сенсорное нажатие на своем экране. В Wireshark транзакция выглядит так:
// DEVICE TO HOST
Frame 30811: 55 bytes on wire (440 bits), 55 bytes captured (440 bits) on interface \\.\USBPcap3, id 0
USB URB
[Source: 3.26.1]
[Destination: host]
USBPcap pseudoheader length: 27
IRP ID: 0xffff830badc6aa40
IRP USBD_STATUS: USBD_STATUS_SUCCESS (0x00000000)
URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER (0x0009)
IRP information: 0x01, Direction: PDO -> FDO
URB bus id: 3
Device address: 26
Endpoint: 0x81, Direction: IN
URB transfer type: URB_INTERRUPT (0x01)
Packet Data Length: 28
[Request in: 26783]
[Time from request: 15.207822000 seconds]
[bInterfaceClass: HID (0x03)]
HID Data: 010100ff07ff070000000000000001000000000000000000002a5b01
Report ID: 0x01
.... ...1 = Usage: Tip Switch: 1
Padding: 00
0000 0000 = Usage: Contact Identifier: 0
0000 0111 1111 1111 = X Axis: 2047
0000 0111 1111 1111 = Y Axis: 2047
0000 0000 0000 0000 = Usage: Width: 0
0000 0000 0000 0000 = Usage: Height: 0
0000 0000 0000 0000 = Usage: Azimuth: 0
.... ...0 = Usage: Tip Switch: 0
Padding: 00
0000 0001 = Usage: Contact Identifier: 1
0000 0000 0000 0000 = X Axis: 0
0000 0000 0000 0000 = Y Axis: 0
0000 0000 0000 0000 = Usage: Width: 0
0000 0000 0000 0000 = Usage: Height: 0
0000 0000 0000 0000 = Usage: Azimuth: 0
0101 1011 0010 1010 = Usage: Scan Time: 23338
0000 0001 = Usage: Contact Count: 1
// HOST TO DEVICE
Frame 30812: 27 bytes on wire (216 bits), 27 bytes captured (216 bits) on interface \\.\USBPcap3, id 0
USB URB
[Source: host]
[Destination: 3.26.1]
USBPcap pseudoheader length: 27
IRP ID: 0xffff830badc6aa40
IRP USBD_STATUS: USBD_STATUS_SUCCESS (0x00000000)
URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER (0x0009)
IRP information: 0x00, Direction: FDO -> PDO
URB bus id: 3
Device address: 26
Endpoint: 0x81, Direction: IN
URB transfer type: URB_INTERRUPT (0x01)
Packet Data Length: 0
[Response in: 30939]
[bInterfaceClass: HID (0x03)]
Однако, когда я пробую то же самое для второго контакта с contact_ID
, равным 1, на моем экране не регистрируется прикосновение. Вот как выглядит эта транзакция:
// DEVICE TO HOST
Frame 30401: 55 bytes on wire (440 bits), 55 bytes captured (440 bits) on interface \\.\USBPcap3, id 0
USB URB
[Source: 3.28.1]
[Destination: host]
USBPcap pseudoheader length: 27
IRP ID: 0xffff830bb0eb5010
IRP USBD_STATUS: USBD_STATUS_SUCCESS (0x00000000)
URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER (0x0009)
IRP information: 0x01, Direction: PDO -> FDO
URB bus id: 3
Device address: 28
Endpoint: 0x81, Direction: IN
URB transfer type: URB_INTERRUPT (0x01)
Packet Data Length: 28
[Request in: 18793]
[Time from request: 36.682296000 seconds]
[bInterfaceClass: HID (0x03)]
HID Data: 010000000000000000000000000101ff07ff07000000000000eaa101
Report ID: 0x01
.... ...0 = Usage: Tip Switch: 0
Padding: 00
0000 0000 = Usage: Contact Identifier: 0
0000 0000 0000 0000 = X Axis: 0
0000 0000 0000 0000 = Y Axis: 0
0000 0000 0000 0000 = Usage: Width: 0
0000 0000 0000 0000 = Usage: Height: 0
0000 0000 0000 0000 = Usage: Azimuth: 0
.... ...1 = Usage: Tip Switch: 1
Padding: 00
0000 0001 = Usage: Contact Identifier: 1
0000 0111 1111 1111 = X Axis: 2047
0000 0111 1111 1111 = Y Axis: 2047
0000 0000 0000 0000 = Usage: Width: 0
0000 0000 0000 0000 = Usage: Height: 0
0000 0000 0000 0000 = Usage: Azimuth: 0
1010 0001 1110 1010 = Usage: Scan Time: 41450
0000 0001 = Usage: Contact Count: 1
// HOST TO DEVICE
Frame 30402: 27 bytes on wire (216 bits), 27 bytes captured (216 bits) on interface \\.\USBPcap3, id 0
USB URB
[Source: host]
[Destination: 3.28.1]
USBPcap pseudoheader length: 27
IRP ID: 0xffff830bb0eb5010
IRP USBD_STATUS: USBD_STATUS_SUCCESS (0x00000000)
URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER (0x0009)
IRP information: 0x00, Direction: FDO -> PDO
URB bus id: 3
Device address: 28
Endpoint: 0x81, Direction: IN
URB transfer type: URB_INTERRUPT (0x01)
Packet Data Length: 0
[Response in: 30585]
[bInterfaceClass: HID (0x03)]
Если это еще не было очевидно, я сообщаю о пакетах в параллельном режиме . Насколько я могу судить, данные из входных отчетов передаются успешно, поскольку данные HID практически идентичны, за исключением того, какой контакт нажимается.
Следующее место, где что-то может пойти наперекосяк, — это отчеты о функциях. Я представил отчет о максимальном количестве контактов, который требуется Windows, с помощью следующего массива:
uint8_t maxCountFeatureReport[2] = {REPORTID_MAX_COUNT, TOUCHSCREEN_MAX_CONTACTS};
Обратите внимание, что TOUCHSCREEN_MAX_CONTACTS
равен 2. В процессе установки происходит транзакция Get_Report, как показывают данные Wireshark:
// HOST TO DEVICE (REQUEST)
Frame 18799: 36 bytes on wire (288 bits), 36 bytes captured (288 bits) on interface \\.\USBPcap3, id 0
USB URB
[Source: host]
[Destination: 3.28.0]
USBPcap pseudoheader length: 28
IRP ID: 0xffff830bb56f7700
IRP USBD_STATUS: USBD_STATUS_SUCCESS (0x00000000)
URB Function: URB_FUNCTION_CLASS_INTERFACE (0x001b)
IRP information: 0x00, Direction: FDO -> PDO
URB bus id: 3
Device address: 28
Endpoint: 0x80, Direction: IN
URB transfer type: URB_CONTROL (0x02)
Packet Data Length: 8
[Response in: 18800]
Control transfer stage: Setup (0)
[bInterfaceClass: HID (0x03)]
Setup Data
bmRequestType: 0xa1
1... .... = Direction: Device-to-host
.01. .... = Type: Class (0x1)
...0 0001 = Recipient: Interface (0x01)
bRequest: GET_REPORT (0x01)
wValue: 0x0302
ReportID: 2
ReportType: Feature (3)
wIndex: 0
wLength: 2
// DEVICE TO HOST (RESPONSE)
Frame 18800: 30 bytes on wire (240 bits), 30 bytes captured (240 bits) on interface \\.\USBPcap3, id 0
USB URB
[Source: 3.28.0]
[Destination: host]
USBPcap pseudoheader length: 28
IRP ID: 0xffff830bb56f7700
IRP USBD_STATUS: USBD_STATUS_SUCCESS (0x00000000)
URB Function: URB_FUNCTION_CONTROL_TRANSFER (0x0008)
IRP information: 0x01, Direction: PDO -> FDO
URB bus id: 3
Device address: 28
Endpoint: 0x80, Direction: IN
URB transfer type: URB_CONTROL (0x02)
Packet Data Length: 2
[Request in: 18799]
[Time from request: 0.000207000 seconds]
Control transfer stage: Complete (3)
[bInterfaceClass: HID (0x03)]
Поскольку Wireshark не декодирует его, вот шестнадцатеричный дамп ответного пакета:
0000 1c 00 00 77 6f b5 0b 83 ff ff 00 00 00 00 08 00
0010 01 03 00 1c 00 80 02 02 00 00 00 03 02 02
Насколько я могу судить, что-то здесь правильное, поскольку буквальные значения массива отчета о функциях равны {2, 2}
, а последние два байта пакета — 02 02
. Но мне кажется, что это была самая сложная часть, поэтому надеюсь, что в этой транзакции есть что-то, что кто-то увидит не так.
Полагаю, последнее место, где может быть проблема, это с драйверами, но я очень сомневаюсь, что это так, потому что там написано, что все ок и драйвер установлен в диспетчере устройств.
Так есть ли у кого-нибудь идеи, что может происходить?
@aja Забавно, я как раз пробовал hidrdd в тот день, когда опубликовал это. В любом случае, это не так, но я нашел решение в том же ключе. Спасибо.
Проблема была в упорядочивании контактов. Я предполагал, что могу просто рассматривать массив контактов, о которых сообщается, как карту, где индекс каждого контакта также является идентификатором контакта. Это не так. Массив зарегистрированных контактов должен быть заполнен от первого зарегистрированного контакта до последнего зарегистрированного контакта, без каких-либо пробелов.
Например, что-то вроде этого действительно:
Contacts[0]: contact with contact_ID=2, tip_switch=1
Contacts[1]: empty
Contacts[2]: empty
Но что-то вроде этого нет:
Contacts[0]: empty
Contacts[1]: empty
Contacts[2]: contact with contact_ID=2, tip_switch=1
Я также понял, что допустил ошибку в своем сообщении. Оказалось, что одновременное нажатие 2/2 контактов действительно работает, а независимое нажатие - нет.
Я предполагаю, что, возможно, количество контактов указывает на количество записей в массиве контактов, которые будет проверен драйвером. В этом случае, может быть, его следует установить на 2 постоянно? (просто предположение, но попробовать стоит)