Объединить клавиатуру и контроль потребителя в дескрипторе - PullRequest
0 голосов
/ 14 марта 2019

У меня есть hid_discriptor, который выглядит так:

// from USB HID Specification 1.1, Appendix B.1
const uint8_t hid_descriptor_keyboard_boot_mode[] = {
    /*
       Keyboard
     */
    0x05, 0x01,                    // Usage Page (Generic Desktop)
    0x09, 0x06,                    // Usage (Keyboard)
    0xa1, 0x01,                    // Collection (Application)

    0x85,  0x01,                   // Report ID 1

    // Modifier byte

    0x75, 0x01,                    //   Report Size (1)
    0x95, 0x08,                    //   Report Count (8)
    0x05, 0x07,                    //   Usage Page (Key codes)
    0x19, 0xe0,                    //   Usage Minimum (Keyboard LeftControl)
    0x29, 0xe7,                    //   Usage Maxium (Keyboard Right GUI)
    0x15, 0x00,                    //   Logical Minimum (0)
    0x25, 0x01,                    //   Logical Maximum (1)
    0x81, 0x02,                    //   Input (Data, Variable, Absolute)

    // Reserved byte

    0x75, 0x01,                    //   Report Size (1)
    0x95, 0x08,                    //   Report Count (8)
    0x81, 0x03,                    //   Input (Constant, Variable, Absolute)

    // LED report + padding

    0x95, 0x05,                    //   Report Count (5)
    0x75, 0x01,                    //   Report Size (1)
    0x05, 0x08,                    //   Usage Page (LEDs)
    0x19, 0x01,                    //   Usage Minimum (Num Lock)
    0x29, 0x05,                    //   Usage Maxium (Kana)
    0x91, 0x02,                    //   Output (Data, Variable, Absolute)

    0x95, 0x01,                    //   Report Count (1)
    0x75, 0x03,                    //   Report Size (3)
    0x91, 0x03,                    //   Output (Constant, Variable, Absolute)

    // Keycodes

    0x95, 0x06,                    //   Report Count (6)
    0x75, 0x08,                    //   Report Size (8)
    0x15, 0x00,                    //   Logical Minimum (0)
    0x25, 0xff,                    //   Logical Maximum (1)
    0x05, 0x07,                    //   Usage Page (Key codes)
    0x19, 0x00,                    //   Usage Minimum (Reserved (no event indicated))
    0x29, 0xff,                    //   Usage Maxium (Reserved)
    0x81, 0x00,                    //   Input (Data, Array)
    0xc0,                          // End collection
};

, который работает для кодов клавиатуры;

Однако я также хотел бы добавить потребительский контроль к своему образцу, чтобы я также мог отправлять громкость вверх / вниз и т. Д.

    /*
       Consumer Control
     */
    0x05, 0x0C,                     // Usage Page (Consumer Devices)
    0x09, 0x01,                     // Usage (Consumer Control)
    0xA1, 0x01,                     // Collection (Application)
    0x85, 0x02,                     //      Report ID
    0x75, 0x09, 0x01,               //      Report Size
    0x95, 0x09, 0x01,               //     Report Count
    0x15, 0x00,                     //      Logical Minimum (0)
    0x26, 0xFF, 0x07,               //      Logical Maximum (2047)
    0x19, 0x00,                     //      Usage Minimum (0)
    0x2A, 0xFF, 0x07,               //      Usage Maximum (2047)
    0x81, 0x00,                     //      Input (Data, Ary, Abs)
    0xC0,

Вопрос в том, что в предоставленном демо-коде ; код для отправки отчета: 1011 *

static void send_report(int modifier, int keycode){
    uint8_t report[] = { /* 0xa1, */ modifier, 0, 0, keycode, 0, 0, 0, 0, 0};
    hids_device_send_input_report(con_handle, report, sizeof(report));
}

Это работает с точки зрения отправки нажатий клавиш; когда я отслеживаю этот вызов в исходном коде, он переходит к этой функции ;

void hids_device_send_input_report(hci_con_handle_t con_handle, const uint8_t * report, uint16_t report_len){
    hids_device_t * instance = hids_device_get_instance_for_con_handle(con_handle);
    if (!instance){
        log_error("no instance for handle 0x%02x", con_handle);
        return;
    }
    att_server_notify(con_handle, instance->hid_report_input_value_handle, report, report_len);
}

Который на самом деле использует instance->hid_report_input_value_handle вместо hid_descriptor_keyboard_boot_mode; я также знаю почему (если люди задаются вопросом); В спецификации упоминается ;

Подкласс 1 HID определяет два дескриптора для загрузочных устройств. Устройства могут добавьте дополнительные данные в эти отчеты о загрузке, но первые 8 байтов отчетов с клавиатуры и первые 3 байта отчетов мыши должны соответствовать формату, определенному дескриптором Boot Report, чтобы данные правильно интерпретировались BIOS.

... чик ...

Когда драйвер класса HID загружен, он выдаст протокол изменения, переход от протокола загрузки к протоколу отчета после прочтения дескриптора отчета интерфейса загрузки.

Так после протокола изменения вызывается; отчет загружается в hid_report_input_value_handle. Так что до сих пор все ясно.

Тогда возникает главный вопрос; КАК мне отправить контроль потребителя на мое сопряженное устройство? Это просто вопрос добавления reportId? например, * 1 037 *

Для клавиш клавиатуры в качестве события нажатия клавиши:

uint8_t report[] = { 0x01, modifier, 0, 0, keycode, 0, 0, 0, 0, 0};
hids_device_send_input_report(con_handle, report, sizeof(report));

И для контроля потребителя (воспроизведение / пауза) в качестве события нажатия клавиши:

uint8_t report[] = { 0x02, 0xCD, 0x00};
hids_device_send_input_report(con_handle, report, sizeof(report));

Это правильно? Любое руководство будет приветствоваться, BLE является новым для меня, поэтому вопрос.

1 Ответ

0 голосов
/ 18 марта 2019

Для дескриптора HID клавиатуры, учитывая, что он представляет следующую структуру C:

//--------------------------------------------------------------------------------
// Keyboard/Keypad Page inputReport 01 (Device --> Host)
//--------------------------------------------------------------------------------

typedef struct
{
  uint8_t  reportId;                                 // Report ID = 0x01 (1)
                                                     // Collection: CA:Keyboard
  uint8_t  KB_KeyboardKeyboardLeftControl : 1;       // Usage 0x000700E0: Keyboard Left Control, Value = 0 to 1
  uint8_t  KB_KeyboardKeyboardLeftShift : 1;         // Usage 0x000700E1: Keyboard Left Shift, Value = 0 to 1
  uint8_t  KB_KeyboardKeyboardLeftAlt : 1;           // Usage 0x000700E2: Keyboard Left Alt, Value = 0 to 1
  uint8_t  KB_KeyboardKeyboardLeftGui : 1;           // Usage 0x000700E3: Keyboard Left GUI, Value = 0 to 1
  uint8_t  KB_KeyboardKeyboardRightControl : 1;      // Usage 0x000700E4: Keyboard Right Control, Value = 0 to 1
  uint8_t  KB_KeyboardKeyboardRightShift : 1;        // Usage 0x000700E5: Keyboard Right Shift, Value = 0 to 1
  uint8_t  KB_KeyboardKeyboardRightAlt : 1;          // Usage 0x000700E6: Keyboard Right Alt, Value = 0 to 1
  uint8_t  KB_KeyboardKeyboardRightGui : 1;          // Usage 0x000700E7: Keyboard Right GUI, Value = 0 to 1
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  Keyboard[6];                              // Value = 0 to 255
} inputReport01_t;

... тогда я ожидал бы, что функция отправки будет выглядеть так:

uint8_t report[] = { 0x01, modifier, 0, keycode, 0, 0, 0, 0, 0}; // <-- i.e. one less byte
hids_device_send_input_report(con_handle, report, sizeof(report));

Что касается отчета Consumer Device, дескриптор отчета HID выглядит совершенно неверно. Это должно быть что-то вроде (при условии, что оно соединено с дескриптором отчета клавиатуры):

/*
   Consumer Control
 */
0x05, 0x0C,                     // Usage Page (Consumer Devices)
0x09, 0x01,                     // Usage (Consumer Control)
0xA1, 0x01,                     // Collection (Application)
0x85, 0x02,                     //      Report ID
0x75, 0x10,                     //      Report Size (16)
0x95, 0x01,                     //     Report Count (1)
0x26, 0xFF, 0x07,               //      Logical Maximum (2047)
0x19, 0x00,                     //      Usage Minimum (0)
0x2A, 0xFF, 0x07,               //      Usage Maximum (2047)
0x81, 0x00,                     //      Input (Data, Ary, Abs)
0xC0,

... которая представляет следующую структуру C:

//--------------------------------------------------------------------------------
// Decoded Application Collection
//--------------------------------------------------------------------------------

/*
05 0C        (GLOBAL) USAGE_PAGE         0x000C Consumer Device Page 
09 01        (LOCAL)  USAGE              0x000C0001 Consumer Control (Application Collection)  
A1 01        (MAIN)   COLLECTION         0x01 Application (Usage=0x000C0001: Page=Consumer Device Page, Usage=Consumer Control, Type=Application Collection)
85 02          (GLOBAL) REPORT_ID          0x02 (2)  
75 10          (GLOBAL) REPORT_SIZE        0x10 (16) Number of bits per field  
95 01          (GLOBAL) REPORT_COUNT       0x01 (1) Number of fields  
26 FF07        (GLOBAL) LOGICAL_MAXIMUM    0x07FF (2047)  
19 00          (LOCAL)  USAGE_MINIMUM      0x000C0000 Unassigned  <-- Info: Consider replacing 19 00 with 18
2A FF07        (LOCAL)  USAGE_MAXIMUM      0x000C07FF 
81 00          (MAIN)   INPUT              0x00000000 (1 field x 16 bits) 0=Data 0=Array 0=Absolute 
C0           (MAIN)   END_COLLECTION     Application 
*/
//--------------------------------------------------------------------------------
// Consumer Device Page inputReport 02 (Device --> Host)
//--------------------------------------------------------------------------------

typedef struct
{
  uint8_t  reportId;                                 // Report ID = 0x02 (2)
                                                     // Collection: CA:ConsumerControl
  uint16_t ConsumerControl;                          // Value = 0 to 2047
} inputReport02_t;

... в этом случае ваша функция отправки запроса Consumer Device должна работать без изменений:

uint8_t report[] = { 0x02, 0xCD, 0x00};
hids_device_send_input_report(con_handle, report, sizeof(report));

... для отправки запроса на воспроизведение / паузу.

Не забудьте указать, что «ни одна клавиша не нажата», следуя каждой посылке с помощью (в случае клавиатуры):

uint8_t report[] = { 0x01, modifier, 0, 0, 0, 0, 0, 0, 0}; // no keys pressed
hids_device_send_input_report(con_handle, report, sizeof(report));

Это эквивалент традиционного уведомления "key up".

...