Сенсорный экран USB не регистрирует несколько контактов

Я пытаюсь реализовать сенсорный экран 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. Но мне кажется, что это была самая сложная часть, поэтому надеюсь, что в этой транзакции есть что-то, что кто-то увидит не так.

Полагаю, последнее место, где может быть проблема, это с драйверами, но я очень сомневаюсь, что это так, потому что там написано, что все ок и драйвер установлен в диспетчере устройств.

Так есть ли у кого-нибудь идеи, что может происходить?

Я предполагаю, что, возможно, количество контактов указывает на количество записей в массиве контактов, которые будет проверен драйвером. В этом случае, может быть, его следует установить на 2 постоянно? (просто предположение, но попробовать стоит)

aja 23.06.2024 13:08

@aja Забавно, я как раз пробовал hidrdd в тот день, когда опубликовал это. В любом случае, это не так, но я нашел решение в том же ключе. Спасибо.

Blob Ross 25.06.2024 21:41
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
56
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема была в упорядочивании контактов. Я предполагал, что могу просто рассматривать массив контактов, о которых сообщается, как карту, где индекс каждого контакта также является идентификатором контакта. Это не так. Массив зарегистрированных контактов должен быть заполнен от первого зарегистрированного контакта до последнего зарегистрированного контакта, без каких-либо пробелов.

Например, что-то вроде этого действительно:

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 контактов действительно работает, а независимое нажатие - нет.

Другие вопросы по теме