Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ESP32-S3: USB Host HID] How to handle 2 HID interface for the same device? (IDFGH-11546) #12667

Closed
rtek1000 opened this issue Nov 26, 2023 · 9 comments
Labels
Resolution: Won't Do This will not be worked on Status: Done Issue is done internally Type: Feature Request Feature request for IDF

Comments

@rtek1000
Copy link

Is your feature request related to a problem?

Hi,

How to handle 2 HID interface for the same device?

In 'USB Host HID' project: Only the keyboard part works, but the touchpad part does not work. The multimedia keys don't work either.

The mini keyboard has an additional interface for the touchpad.

Mini_Keyboard_Colors

Below is the serial monitor dump for the project ../examples/peripherals/usb/host/hid/ (mini keyboard attached):

Executing action: monitor
Running idf_monitor in directory /home/user/esp/hid
Executing "/home/user/.espressif/python_env/idf5.3_py3.10_env/bin/python /home/user/esp/esp-idf/tools/idf_monitor.py -p /dev/ttyACM0 -b 115200 --toolchain-prefix xtensa-esp32s3-elf- --target esp32s3 --revision 0 /home/user/esp/hid/build/hid.elf -m '/home/user/.espressif/python_env/idf5.3_py3.10_env/bin/python' '/home/user/esp/esp-idf/tools/idf.py' '-p' '/dev/ttyACM0'"...
--- esp-idf-monitor 1.3.3 on /dev/ttyACM0 115200 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
SP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x1 (POWERON),boot:0x8 (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce3810,len:0x178c
load:0x403c9700,len:0x4
load:0x403c9704,len:0xcb8
load:0x403cc700,len:0x2d84
entry 0x403c9914
I (27) boot: ESP-IDF v5.3-dev-422-ga7fbf452fa 2nd stage bootloader
I (27) boot: compile time Nov 26 2023 00:55:55
I (27) boot: Multicore bootloader
I (31) boot: chip revision: v0.2
I (35) boot.esp32s3: Boot SPI Speed : 80MHz
I (40) boot.esp32s3: SPI Mode : DIO
I (45) boot.esp32s3: SPI Flash Size : 2MB
I (49) boot: Enabling RNG early entropy source...
I (55) boot: Partition Table:
I (58) boot: ## Label Usage Type ST Offset Length
I (66) boot: 0 nvs WiFi data 01 02 00009000 00006000
I (73) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (81) boot: 2 factory factory app 00 00 00010000 00100000
I (88) boot: End of partition table
I (92) esp_image: segment 0: paddr=00010020 vaddr=3c020020 size=0c5fch ( 50684) map
I (110) esp_image: segment 1: paddr=0001c624 vaddr=3fc92400 size=027b0h ( 10160) load
I (112) esp_image: segment 2: paddr=0001eddc vaddr=40374000 size=0123ch ( 4668) load
I (119) esp_image: segment 3: paddr=00020020 vaddr=42000020 size=1f494h (128148) map
I (149) esp_image: segment 4: paddr=0003f4bc vaddr=4037523c size=0d158h ( 53592) load
I (167) boot: Loaded app from partition at offset 0x10000
I (167) boot: Disabling RNG early entropy source...
I (178) cpu_start: Multicore app
I (188) cpu_start: Pro cpu start user code
I (188) cpu_start: cpu freq: 160000000 Hz
I (188) cpu_start: Application information:
I (191) cpu_start: Project name: hid
I (196) cpu_start: App version: 1
I (200) cpu_start: Compile time: Nov 26 2023 00:55:43
I (206) cpu_start: ELF file SHA256: c7a7b152f...
I (212) cpu_start: ESP-IDF: v5.3-dev-422-ga7fbf452fa
I (218) cpu_start: Min chip rev: v0.0
I (223) cpu_start: Max chip rev: v0.99
I (228) cpu_start: Chip rev: v0.2
I (232) heap_init: Initializing. RAM available for dynamic allocation:
I (240) heap_init: At 3FC95420 len 000542F0 (336 KiB): RAM
I (246) heap_init: At 3FCE9710 len 00005724 (21 KiB): RAM
I (252) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
I (258) heap_init: At 600FE010 len 00001FD8 (7 KiB): RTCRAM
I (265) spi_flash: detected chip: generic
I (269) spi_flash: flash io: dio
W (273) spi_flash: Detected size(16384k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (286) sleep: Configure to isolate all GPIO pins in sleep state
I (293) sleep: Enable automatic switching of GPIO sleep configuration
I (300) main_task: Started on CPU0
I (310) main_task: Calling app_main()
I (310) example: HID Host example
I (310) gpio: GPIO[0]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:2
I (350) example: Waiting for HID Device to be connected
I (730) example: HID Device, protocol 'KEYBOARD' CONNECTED
I (730) example: HID Device, protocol 'MOUSE' CONNECTED

Below is the serial monitor dump for the project ../examples/peripherals/usb/host/usb_host_lib/:

Executing action: monitor
Running idf_monitor in directory /home/user/esp/usb_host_lib
Executing "/home/user/.espressif/python_env/idf5.3_py3.10_env/bin/python /home/user/esp/esp-idf/tools/idf_monitor.py -p /dev/ttyACM0 -b 115200 --toolchain-prefix xtensa-esp32s3-elf- --target esp32s3 --revision 0 /home/user/esp/usb_host_lib/build/usb_host_lib_example.elf -m '/home/user/.espressif/python_env/idf5.3_py3.10_env/bin/python' '/home/user/esp/esp-idf/tools/idf.py' '-p' '/dev/ttyACM0'"...
--- esp-idf-monitor 1.3.3 on /dev/ttyACM0 115200 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
SP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x1 (POWERON),boot:0x8 (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce3810,len:0x178c
load:0x403c9700,len:0x4
load:0x403c9704,len:0xcb8
load:0x403cc700,len:0x2d84
entry 0x403c9914
I (27) boot: ESP-IDF v5.3-dev-422-ga7fbf452fa 2nd stage bootloader
I (27) boot: compile time Nov 26 2023 01:42:17
I (27) boot: Multicore bootloader
I (31) boot: chip revision: v0.2
I (35) boot.esp32s3: Boot SPI Speed : 80MHz
I (40) boot.esp32s3: SPI Mode : DIO
I (45) boot.esp32s3: SPI Flash Size : 2MB
I (49) boot: Enabling RNG early entropy source...
I (55) boot: Partition Table:
I (58) boot: ## Label Usage Type ST Offset Length
I (66) boot: 0 nvs WiFi data 01 02 00009000 00006000
I (73) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (81) boot: 2 factory factory app 00 00 00010000 00100000
I (88) boot: End of partition table
I (92) esp_image: segment 0: paddr=00010020 vaddr=3c020020 size=0b95ch ( 47452) map
I (109) esp_image: segment 1: paddr=0001b984 vaddr=3fc92500 size=027b0h ( 10160) load
I (112) esp_image: segment 2: paddr=0001e13c vaddr=40374000 size=01edch ( 7900) load
I (119) esp_image: segment 3: paddr=00020020 vaddr=42000020 size=1d404h (119812) map
I (148) esp_image: segment 4: paddr=0003d42c vaddr=40375edc size=0c5e4h ( 50660) load
I (165) boot: Loaded app from partition at offset 0x10000
I (165) boot: Disabling RNG early entropy source...
I (176) cpu_start: Multicore app
I (186) cpu_start: Pro cpu start user code
I (186) cpu_start: cpu freq: 160000000 Hz
I (186) cpu_start: Application information:
I (189) cpu_start: Project name: usb_host_lib_example
I (195) cpu_start: App version: 1
I (199) cpu_start: Compile time: Nov 26 2023 01:42:05
I (206) cpu_start: ELF file SHA256: 27ef6eb44...
I (211) cpu_start: ESP-IDF: v5.3-dev-422-ga7fbf452fa
I (217) cpu_start: Min chip rev: v0.0
I (222) cpu_start: Max chip rev: v0.99
I (227) cpu_start: Chip rev: v0.2
I (232) heap_init: Initializing. RAM available for dynamic allocation:
I (239) heap_init: At 3FC95510 len 00054200 (336 KiB): RAM
I (245) heap_init: At 3FCE9710 len 00005724 (21 KiB): RAM
I (251) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
I (257) heap_init: At 600FE010 len 00001FD8 (7 KiB): RTCRAM
I (264) spi_flash: detected chip: generic
I (268) spi_flash: flash io: dio
W (272) spi_flash: Detected size(16384k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (285) sleep: Configure to isolate all GPIO pins in sleep state
I (292) sleep: Enable automatic switching of GPIO sleep configuration
I (300) main_task: Started on CPU0
I (310) main_task: Calling app_main()
I (310) USB host lib: USB host library example
I (310) gpio: GPIO[0]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:2
I (320) USB host lib: Installing USB Host Library
I (360) CLASS: Registering Client
I (740) CLASS: Opening device at address 1
I (740) CLASS: Getting device information
I (740) CLASS: Low speed
I (740) CLASS: bConfigurationValue 1
I (750) CLASS: Getting device descriptor
*** Device descriptor ***
bLength 18
bDescriptorType 1
bcdUSB 1.10
bDeviceClass 0x0
bDeviceSubClass 0x0
bDeviceProtocol 0x0
bMaxPacketSize0 8
idVendor 0x513
idProduct 0x318
bcdDevice 1.00
iManufacturer 0
iProduct 0
iSerialNumber 0
bNumConfigurations 1
I (770) CLASS: Getting config descriptor
*** Configuration descriptor ***
bLength 9
bDescriptorType 2
wTotalLength 59
bNumInterfaces 2
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xa0
bMaxPower 100mA
*** Interface descriptor ***
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 0x3
bInterfaceSubClass 0x1
bInterfaceProtocol 0x1
iInterface 0
*** Endpoint descriptor ***
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 0x3 INT
wMaxPacketSize 8
bInterval 8
*** Interface descriptor ***
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 0x3
bInterfaceSubClass 0x1
bInterfaceProtocol 0x2
iInterface 0
*** Endpoint descriptor ***
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 0x3 INT
wMaxPacketSize 8
bInterval 8

Board: YD-ESP32-23 (using USB C OTG cable too):

yd_esp32_s3-23

Describe the solution you'd like.

It would be interesting if the USB Host HID example can already handle the two HID interfaces of this mini keyboard with touchpad, because there are many such keyboards for sale in Chinese markets (Aliexpress etc).

Describe alternatives you've considered.

I would like tips on how to handle the second HID interface.

Additional context.

As the mouse already works well with the project (USB Host HID), and the keyboard works well with the same project, the only thing missing is that both can be operated at the same time.

I made some modifications to a design for STM32F4 that allowed me to scan both interfaces, but I noticed that the ESP32-S3 performance seems to be better than the STM32 performance, which may be due to the use of interrupts in the ESP32, while STM32 appears to be operating in polling mode.

@rtek1000 rtek1000 added the Type: Feature Request Feature request for IDF label Nov 26, 2023
@espressif-bot espressif-bot added the Status: Opened Issue is new label Nov 26, 2023
@github-actions github-actions bot changed the title [ESP32-S3: USB Host HID] How to handle 2 HID interface for the same device? [ESP32-S3: USB Host HID] How to handle 2 HID interface for the same device? (IDFGH-11546) Nov 26, 2023
@roma-jam
Copy link
Collaborator

Hi @rtek1000,

HID example already displayed the information, that mouse interface has been connected.
Is there any display output when:

  • Keys on keyboard were pressed;
  • Touch pad is in use;
  • Key that emulate left-right mouse buttons were pressed (they are on the left side of the keyboard);

Could you share the log during all these scenarious?
Thanks.

@rtek1000
Copy link
Author

Hi @rtek1000,

HID example already displayed the information, that mouse interface has been connected. Is there any display output when:

  • Keys on keyboard were pressed;
  • Touch pad is in use;
  • Key that emulate left-right mouse buttons were pressed (they are on the left side of the keyboard);

Could you share the log during all these scenarious? Thanks.

Hi @roma-jam ,

Where can I find information on how to generate the requested log? I'm not familiar with generating this log.

  • When I press any touchpad related key, no hid_host_mouse_report_callback() interaction occurs
  • I added a flag and there was no sign of activity:
static void hid_host_mouse_report_callback(const uint8_t *const data, const int length)
{
    hid_mouse_input_report_boot_t *mouse_report = (hid_mouse_input_report_boot_t *)data;

    if (length < sizeof(hid_mouse_input_report_boot_t)) {
        printf("mouse return"); // <-------------------- flag
        return;
    }

    static int x_pos = 0;
    static int y_pos = 0;

    // Calculate absolute position from displacement
    x_pos += mouse_report->x_displacement;
    y_pos += mouse_report->y_displacement;

    hid_print_new_device_report_header(HID_PROTOCOL_MOUSE);

    printf("X: %06d\tY: %06d\t|%c|%c|\r",
           x_pos, y_pos,
           (mouse_report->buttons.button1 ? 'o' : ' '),
           (mouse_report->buttons.button2 ? 'o' : ' '));
    fflush(stdout);
}

Thanks.

@rtek1000
Copy link
Author

Hi, I added other flags to each subroutine that I think are relevant for monitoring the return of events, and as you can see, when you put a cable mouse into the USB port, the mouse routines are executed, but when you put the mini keyboard with touchpad, only keyboard subroutines are executed.

At the bottom of this message the modified code has been added, similar to this one:
printf("%lu - hid_host_keyboard_report_callback()\r\n", log_cnt1++);

Log from 'idf.py -p /dev/ttyACM0 monitor':

ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x1 (POWERON),boot:0x8 (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce3810,len:0x178c
load:0x403c9700,len:0x4
load:0x403c9704,len:0xcb8
load:0x403cc700,len:0x2d84
entry 0x403c9914
I (27) boot: ESP-IDF v5.3-dev-422-ga7fbf452fa 2nd stage bootloader
I (27) boot: compile time Nov 26 2023 00:55:55
I (27) boot: Multicore bootloader
I (31) boot: chip revision: v0.2
I (35) boot.esp32s3: Boot SPI Speed : 80MHz
I (40) boot.esp32s3: SPI Mode : DIO
I (45) boot.esp32s3: SPI Flash Size : 2MB
I (49) boot: Enabling RNG early entropy source...
I (55) boot: Partition Table:
I (58) boot: ## Label Usage Type ST Offset Length
I (66) boot: 0 nvs WiFi data 01 02 00009000 00006000
I (73) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (81) boot: 2 factory factory app 00 00 00010000 00100000
I (88) boot: End of partition table
I (92) esp_image: segment 0: paddr=00010020 vaddr=3c020020 size=0c5fch ( 50684) map
I (110) esp_image: segment 1: paddr=0001c624 vaddr=3fc92400 size=027b0h ( 10160) load
I (112) esp_image: segment 2: paddr=0001eddc vaddr=40374000 size=0123ch ( 4668) load
I (119) esp_image: segment 3: paddr=00020020 vaddr=42000020 size=1f450h (128080) map
I (149) esp_image: segment 4: paddr=0003f478 vaddr=4037523c size=0d158h ( 53592) load
I (167) boot: Loaded app from partition at offset 0x10000
I (167) boot: Disabling RNG early entropy source...
I (178) cpu_start: Multicore app
I (188) cpu_start: Pro cpu start user code
I (188) cpu_start: cpu freq: 160000000 Hz
I (188) cpu_start: Application information:
I (191) cpu_start: Project name: hid
I (196) cpu_start: App version: 1
I (200) cpu_start: Compile time: Nov 26 2023 00:55:43
I (206) cpu_start: ELF file SHA256: 58a98384c...
I (212) cpu_start: ESP-IDF: v5.3-dev-422-ga7fbf452fa
I (218) cpu_start: Min chip rev: v0.0
I (223) cpu_start: Max chip rev: v0.99
I (227) cpu_start: Chip rev: v0.2
I (232) heap_init: Initializing. RAM available for dynamic allocation:
I (240) heap_init: At 3FC95420 len 000542F0 (336 KiB): RAM
I (246) heap_init: At 3FCE9710 len 00005724 (21 KiB): RAM
I (252) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
I (258) heap_init: At 600FE010 len 00001FD8 (7 KiB): RTCRAM
I (265) spi_flash: detected chip: generic
I (269) spi_flash: flash io: dio
W (273) spi_flash: Detected size(16384k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (286) sleep: Configure to isolate all GPIO pins in sleep state
I (293) sleep: Enable automatic switching of GPIO sleep configuration
I (300) main_task: Started on CPU0
I (310) main_task: Calling app_main()
I (310) example: HID Host example
I (310) gpio: GPIO[0]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:2
I (350) example: Waiting for HID Device to be connected
0 - hid_host_device_callback()
1 - hid_host_device_event()
I (1970) example: HID Device, protocol 'MOUSE' CONNECTED (regular mouse)
2 - hid_host_interface_callback()
3 - hid_host_mouse_report_callback()

Mouse
4 - hid_host_interface_callback()
5 - hid_host_mouse_report_callback()
6 - hid_host_interface_callback()
7 - hid_host_mouse_report_callback()
8 - hid_host_interface_callback()
9 - hid_host_mouse_report_callback()
10 - hid_host_interface_callback()
11 - hid_host_mouse_report_callback()
12 - hid_host_interface_callback()
13 - hid_host_mouse_report_callback()
E (12790) USBH: Device 1 gone
14 - hid_host_interface_callback()
I (12790) example: HID Device, protocol 'MOUSE' DISCONNECTED (regular mouse)
E (13050) HUB: Root port reset failed
15 - hid_host_device_callback()
16 - hid_host_device_callback()
17 - hid_host_device_event()
I (25250) example: HID Device, protocol 'KEYBOARD' CONNECTED (mini keyboard w/ touchpad)
18 - hid_host_device_event()
I (25260) example: HID Device, protocol 'MOUSE' CONNECTED (mini keyboard w/ touchpad)
19 - hid_host_interface_callback()
20 - hid_host_keyboard_report_callback()
21 - hid_host_interface_callback()
22 - hid_host_keyboard_report_callback()

Keyboard
23 - hid_host_interface_callback()
24 - hid_host_keyboard_report_callback()
25 - hid_host_interface_callback()
26 - hid_host_keyboard_report_callback()
27 - hid_host_interface_callback()
28 - hid_host_keyboard_report_callback()
29 - hid_host_interface_callback()
30 - hid_host_keyboard_report_callback()
31 - hid_host_interface_callback()
32 - hid_host_keyboard_report_callback()
33 - hid_host_interface_callback()
34 - hid_host_keyboard_report_callback()

/*
 * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Unlicense OR CC0-1.0
 */

#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "freertos/queue.h"
#include "esp_err.h"
#include "esp_log.h"
#include "usb/usb_host.h"
#include "errno.h"
#include "driver/gpio.h"

#include "usb/hid_host.h"
#include "usb/hid_usage_keyboard.h"
#include "usb/hid_usage_mouse.h"

/* GPIO Pin number for quit from example logic */
#define APP_QUIT_PIN                GPIO_NUM_0

static const char *TAG = "example";

uint32_t log_cnt1 = 0;

QueueHandle_t app_event_queue = NULL;

/**
 * @brief APP event group
 *
 * Application logic can be different. There is a one among other ways to distingiush the
 * event by application event group.
 * In this example we have two event groups:
 * APP_EVENT            - General event, which is APP_QUIT_PIN press event (Generally, it is IO0).
 * APP_EVENT_HID_HOST   - HID Host Driver event, such as device connection/disconnection or input report.
 */
typedef enum {
    APP_EVENT = 0,
    APP_EVENT_HID_HOST
} app_event_group_t;

/**
 * @brief APP event queue
 *
 * This event is used for delivering the HID Host event from callback to a task.
 */
typedef struct {
    app_event_group_t event_group;
    /* HID Host - Device related info */
    struct {
        hid_host_device_handle_t handle;
        hid_host_driver_event_t event;
        void *arg;
    } hid_host_device;
} app_event_queue_t;

/**
 * @brief HID Protocol string names
 */
static const char *hid_proto_name_str[] = {
    "NONE",
    "KEYBOARD",
    "MOUSE"
};

/**
 * @brief Key event
 */
typedef struct {
    enum key_state {
        KEY_STATE_PRESSED = 0x00,
        KEY_STATE_RELEASED = 0x01
    } state;
    uint8_t modifier;
    uint8_t key_code;
} key_event_t;

/* Main char symbol for ENTER key */
#define KEYBOARD_ENTER_MAIN_CHAR    '\r'
/* When set to 1 pressing ENTER will be extending with LineFeed during serial debug output */
#define KEYBOARD_ENTER_LF_EXTEND    1

/**
 * @brief Scancode to ascii table
 */
const uint8_t keycode2ascii [57][2] = {
    {0, 0}, /* HID_KEY_NO_PRESS        */
    {0, 0}, /* HID_KEY_ROLLOVER        */
    {0, 0}, /* HID_KEY_POST_FAIL       */
    {0, 0}, /* HID_KEY_ERROR_UNDEFINED */
    {'a', 'A'}, /* HID_KEY_A               */
    {'b', 'B'}, /* HID_KEY_B               */
    {'c', 'C'}, /* HID_KEY_C               */
    {'d', 'D'}, /* HID_KEY_D               */
    {'e', 'E'}, /* HID_KEY_E               */
    {'f', 'F'}, /* HID_KEY_F               */
    {'g', 'G'}, /* HID_KEY_G               */
    {'h', 'H'}, /* HID_KEY_H               */
    {'i', 'I'}, /* HID_KEY_I               */
    {'j', 'J'}, /* HID_KEY_J               */
    {'k', 'K'}, /* HID_KEY_K               */
    {'l', 'L'}, /* HID_KEY_L               */
    {'m', 'M'}, /* HID_KEY_M               */
    {'n', 'N'}, /* HID_KEY_N               */
    {'o', 'O'}, /* HID_KEY_O               */
    {'p', 'P'}, /* HID_KEY_P               */
    {'q', 'Q'}, /* HID_KEY_Q               */
    {'r', 'R'}, /* HID_KEY_R               */
    {'s', 'S'}, /* HID_KEY_S               */
    {'t', 'T'}, /* HID_KEY_T               */
    {'u', 'U'}, /* HID_KEY_U               */
    {'v', 'V'}, /* HID_KEY_V               */
    {'w', 'W'}, /* HID_KEY_W               */
    {'x', 'X'}, /* HID_KEY_X               */
    {'y', 'Y'}, /* HID_KEY_Y               */
    {'z', 'Z'}, /* HID_KEY_Z               */
    {'1', '!'}, /* HID_KEY_1               */
    {'2', '@'}, /* HID_KEY_2               */
    {'3', '#'}, /* HID_KEY_3               */
    {'4', '$'}, /* HID_KEY_4               */
    {'5', '%'}, /* HID_KEY_5               */
    {'6', '^'}, /* HID_KEY_6               */
    {'7', '&'}, /* HID_KEY_7               */
    {'8', '*'}, /* HID_KEY_8               */
    {'9', '('}, /* HID_KEY_9               */
    {'0', ')'}, /* HID_KEY_0               */
    {KEYBOARD_ENTER_MAIN_CHAR, KEYBOARD_ENTER_MAIN_CHAR}, /* HID_KEY_ENTER           */
    {0, 0}, /* HID_KEY_ESC             */
    {'\b', 0}, /* HID_KEY_DEL             */
    {0, 0}, /* HID_KEY_TAB             */
    {' ', ' '}, /* HID_KEY_SPACE           */
    {'-', '_'}, /* HID_KEY_MINUS           */
    {'=', '+'}, /* HID_KEY_EQUAL           */
    {'[', '{'}, /* HID_KEY_OPEN_BRACKET    */
    {']', '}'}, /* HID_KEY_CLOSE_BRACKET   */
    {'\\', '|'}, /* HID_KEY_BACK_SLASH      */
    {'\\', '|'}, /* HID_KEY_SHARP           */  // HOTFIX: for NonUS Keyboards repeat HID_KEY_BACK_SLASH
    {';', ':'}, /* HID_KEY_COLON           */
    {'\'', '"'}, /* HID_KEY_QUOTE           */
    {'`', '~'}, /* HID_KEY_TILDE           */
    {',', '<'}, /* HID_KEY_LESS            */
    {'.', '>'}, /* HID_KEY_GREATER         */
    {'/', '?'} /* HID_KEY_SLASH           */
};

/**
 * @brief Makes new line depending on report output protocol type
 *
 * @param[in] proto Current protocol to output
 */
static void hid_print_new_device_report_header(hid_protocol_t proto)
{
    static hid_protocol_t prev_proto_output = -1;

    if (prev_proto_output != proto) {
        prev_proto_output = proto;
        printf("\r\n");
        if (proto == HID_PROTOCOL_MOUSE) {
            printf("Mouse\r\n");
        } else if (proto == HID_PROTOCOL_KEYBOARD) {
            printf("Keyboard\r\n");
        } else {
            printf("Generic\r\n");
        }
        fflush(stdout);
    }
}

/**
 * @brief HID Keyboard modifier verification for capitalization application (right or left shift)
 *
 * @param[in] modifier
 * @return true  Modifier was pressed (left or right shift)
 * @return false Modifier was not pressed (left or right shift)
 *
 */
static inline bool hid_keyboard_is_modifier_shift(uint8_t modifier)
{
    if (((modifier & HID_LEFT_SHIFT) == HID_LEFT_SHIFT) ||
            ((modifier & HID_RIGHT_SHIFT) == HID_RIGHT_SHIFT)) {
        return true;
    }
    return false;
}

/**
 * @brief HID Keyboard get char symbol from key code
 *
 * @param[in] modifier  Keyboard modifier data
 * @param[in] key_code  Keyboard key code
 * @param[in] key_char  Pointer to key char data
 *
 * @return true  Key scancode converted successfully
 * @return false Key scancode unknown
 */
static inline bool hid_keyboard_get_char(uint8_t modifier,
                                         uint8_t key_code,
                                         unsigned char *key_char)
{
    uint8_t mod = (hid_keyboard_is_modifier_shift(modifier)) ? 1 : 0;

    if ((key_code >= HID_KEY_A) && (key_code <= HID_KEY_SLASH)) {
        *key_char = keycode2ascii[key_code][mod];
    } else {
        // All other key pressed
        return false;
    }

    return true;
}

/**
 * @brief HID Keyboard print char symbol
 *
 * @param[in] key_char  Keyboard char to stdout
 */
static inline void hid_keyboard_print_char(unsigned int key_char)
{
    if (!!key_char) {
        putchar(key_char);
#if (KEYBOARD_ENTER_LF_EXTEND)
        if (KEYBOARD_ENTER_MAIN_CHAR == key_char) {
            putchar('\n');
        }
#endif // KEYBOARD_ENTER_LF_EXTEND
        fflush(stdout);
    }
}

/**
 * @brief Key Event. Key event with the key code, state and modifier.
 *
 * @param[in] key_event Pointer to Key Event structure
 *
 */
static void key_event_callback(key_event_t *key_event)
{
    unsigned char key_char;

    hid_print_new_device_report_header(HID_PROTOCOL_KEYBOARD);

    if (key_event->state == KEY_STATE_PRESSED) {
        //printf("KEY PRESSED\r\n");
        if (hid_keyboard_get_char(key_event->modifier,
                                  key_event->key_code, &key_char)) {

            //hid_keyboard_print_char(key_char);

        }
    //} else if (key_event->state == KEY_STATE_RELEASED) {
        //printf("KEY RELEASED\r\n");
    }
}

/**
 * @brief Key buffer scan code search.
 *
 * @param[in] src       Pointer to source buffer where to search
 * @param[in] key       Key scancode to search
 * @param[in] length    Size of the source buffer
 */
static inline bool key_found(const uint8_t *const src,
                             uint8_t key,
                             unsigned int length)
{
    for (unsigned int i = 0; i < length; i++) {
        if (src[i] == key) {
            return true;
        }
    }
    return false;
}

/**
 * @brief USB HID Host Keyboard Interface report callback handler
 *
 * @param[in] data    Pointer to input report data buffer
 * @param[in] length  Length of input report data buffer
 */
static void hid_host_keyboard_report_callback(const uint8_t *const data, const int length)
{
    printf("%lu - hid_host_keyboard_report_callback()\r\n", log_cnt1++);
    
    hid_keyboard_input_report_boot_t *kb_report = (hid_keyboard_input_report_boot_t *)data;

    if (length < sizeof(hid_keyboard_input_report_boot_t)) {
        return;
    }

    static uint8_t prev_keys[HID_KEYBOARD_KEY_MAX] = { 0 };
    key_event_t key_event;

    for (int i = 0; i < HID_KEYBOARD_KEY_MAX; i++) {

        // key has been released verification
        if (prev_keys[i] > HID_KEY_ERROR_UNDEFINED &&
                !key_found(kb_report->key, prev_keys[i], HID_KEYBOARD_KEY_MAX)) {
            key_event.key_code = prev_keys[i];
            key_event.modifier = 0;
            key_event.state = KEY_STATE_RELEASED;
            key_event_callback(&key_event);
        }

        // key has been pressed verification
        if (kb_report->key[i] > HID_KEY_ERROR_UNDEFINED &&
                !key_found(prev_keys, kb_report->key[i], HID_KEYBOARD_KEY_MAX)) {
            key_event.key_code = kb_report->key[i];
            key_event.modifier = kb_report->modifier.val;
            key_event.state = KEY_STATE_PRESSED;
            key_event_callback(&key_event);
        }
    }

    memcpy(prev_keys, &kb_report->key, HID_KEYBOARD_KEY_MAX);
}

/**
 * @brief USB HID Host Mouse Interface report callback handler
 *
 * @param[in] data    Pointer to input report data buffer
 * @param[in] length  Length of input report data buffer
 */
static void hid_host_mouse_report_callback(const uint8_t *const data, const int length)
{
    printf("%lu - hid_host_mouse_report_callback()\r\n", log_cnt1++);
    
    hid_mouse_input_report_boot_t *mouse_report = (hid_mouse_input_report_boot_t *)data;

    if (length < sizeof(hid_mouse_input_report_boot_t)) {
        return;
    }

    static int x_pos = 0;
    static int y_pos = 0;

    // Calculate absolute position from displacement
    x_pos += mouse_report->x_displacement;
    y_pos += mouse_report->y_displacement;

    hid_print_new_device_report_header(HID_PROTOCOL_MOUSE);

//    printf("X: %06d\tY: %06d\t|%c|%c|\r",
//           x_pos, y_pos,
//           (mouse_report->buttons.button1 ? 'o' : ' '),
//           (mouse_report->buttons.button2 ? 'o' : ' '));
    fflush(stdout);
}

/**
 * @brief USB HID Host Generic Interface report callback handler
 *
 * 'generic' means anything else than mouse or keyboard
 *
 * @param[in] data    Pointer to input report data buffer
 * @param[in] length  Length of input report data buffer
 */
static void hid_host_generic_report_callback(const uint8_t *const data, const int length)
{
    hid_print_new_device_report_header(HID_PROTOCOL_NONE);
    for (int i = 0; i < length; i++) {
        printf("%02X", data[i]);
    }
    putchar('\r');
}

/**
 * @brief USB HID Host interface callback
 *
 * @param[in] hid_device_handle  HID Device handle
 * @param[in] event              HID Host interface event
 * @param[in] arg                Pointer to arguments, does not used
 */
void hid_host_interface_callback(hid_host_device_handle_t hid_device_handle,
                                 const hid_host_interface_event_t event,
                                 void *arg)
{
    printf("%lu - hid_host_interface_callback()\r\n", log_cnt1++);
    
    uint8_t data[64] = { 0 };
    size_t data_length = 0;
    hid_host_dev_params_t dev_params;
    ESP_ERROR_CHECK(hid_host_device_get_params(hid_device_handle, &dev_params));

    switch (event) {
    case HID_HOST_INTERFACE_EVENT_INPUT_REPORT:
        ESP_ERROR_CHECK(hid_host_device_get_raw_input_report_data(hid_device_handle,
                                                                  data,
                                                                  64,
                                                                  &data_length));

        if (HID_SUBCLASS_BOOT_INTERFACE == dev_params.sub_class) {
            if (HID_PROTOCOL_KEYBOARD == dev_params.proto) {
                hid_host_keyboard_report_callback(data, data_length);
            } else if (HID_PROTOCOL_MOUSE == dev_params.proto) {
                hid_host_mouse_report_callback(data, data_length);
            }
        } else {
            hid_host_generic_report_callback(data, data_length);
        }

        break;
    case HID_HOST_INTERFACE_EVENT_DISCONNECTED:
        ESP_LOGI(TAG, "HID Device, protocol '%s' DISCONNECTED",
                 hid_proto_name_str[dev_params.proto]);
        ESP_ERROR_CHECK(hid_host_device_close(hid_device_handle));
        break;
    case HID_HOST_INTERFACE_EVENT_TRANSFER_ERROR:
        ESP_LOGI(TAG, "HID Device, protocol '%s' TRANSFER_ERROR",
                 hid_proto_name_str[dev_params.proto]);
        break;
    default:
        ESP_LOGE(TAG, "HID Device, protocol '%s' Unhandled event",
                 hid_proto_name_str[dev_params.proto]);
        break;
    }
}

/**
 * @brief USB HID Host Device event
 *
 * @param[in] hid_device_handle  HID Device handle
 * @param[in] event              HID Host Device event
 * @param[in] arg                Pointer to arguments, does not used
 */
void hid_host_device_event(hid_host_device_handle_t hid_device_handle,
                           const hid_host_driver_event_t event,
                           void *arg)
{
    printf("%lu - hid_host_device_event()\r\n", log_cnt1++);
    
    hid_host_dev_params_t dev_params;
    ESP_ERROR_CHECK(hid_host_device_get_params(hid_device_handle, &dev_params));

    switch (event) {
    case HID_HOST_DRIVER_EVENT_CONNECTED:
        ESP_LOGI(TAG, "HID Device, protocol '%s' CONNECTED",
                 hid_proto_name_str[dev_params.proto]);

        const hid_host_device_config_t dev_config = {
            .callback = hid_host_interface_callback,
            .callback_arg = NULL
        };

        ESP_ERROR_CHECK(hid_host_device_open(hid_device_handle, &dev_config));
        if (HID_SUBCLASS_BOOT_INTERFACE == dev_params.sub_class) {
            ESP_ERROR_CHECK(hid_class_request_set_protocol(hid_device_handle, HID_REPORT_PROTOCOL_BOOT));
            if (HID_PROTOCOL_KEYBOARD == dev_params.proto) {
                ESP_ERROR_CHECK(hid_class_request_set_idle(hid_device_handle, 0, 0));
            }
        }
        ESP_ERROR_CHECK(hid_host_device_start(hid_device_handle));
        break;
    default:
        break;
    }
}

/**
 * @brief Start USB Host install and handle common USB host library events while app pin not low
 *
 * @param[in] arg  Not used
 */
static void usb_lib_task(void *arg)
{
    const usb_host_config_t host_config = {
        .skip_phy_setup = false,
        .intr_flags = ESP_INTR_FLAG_LEVEL1,
    };

    ESP_ERROR_CHECK(usb_host_install(&host_config));
    xTaskNotifyGive(arg);

    while (true) {
        uint32_t event_flags;
        usb_host_lib_handle_events(portMAX_DELAY, &event_flags);
        // In this example, there is only one client registered
        // So, once we deregister the client, this call must succeed with ESP_OK
        if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) {
            ESP_ERROR_CHECK(usb_host_device_free_all());
            break;
        }
    }

    ESP_LOGI(TAG, "USB shutdown");
    // Clean up USB Host
    vTaskDelay(10); // Short delay to allow clients clean-up
    ESP_ERROR_CHECK(usb_host_uninstall());
    vTaskDelete(NULL);
}

/**
 * @brief BOOT button pressed callback
 *
 * Signal application to exit the HID Host task
 *
 * @param[in] arg Unused
 */
static void gpio_isr_cb(void *arg)
{
    BaseType_t xTaskWoken = pdFALSE;
    const app_event_queue_t evt_queue = {
        .event_group = APP_EVENT,
    };

    if (app_event_queue) {
        xQueueSendFromISR(app_event_queue, &evt_queue, &xTaskWoken);
    }

    if (xTaskWoken == pdTRUE) {
        portYIELD_FROM_ISR();
    }
}

/**
 * @brief HID Host Device callback
 *
 * Puts new HID Device event to the queue
 *
 * @param[in] hid_device_handle HID Device handle
 * @param[in] event             HID Device event
 * @param[in] arg               Not used
 */
void hid_host_device_callback(hid_host_device_handle_t hid_device_handle,
                              const hid_host_driver_event_t event,
                              void *arg)
{
    printf("%lu - hid_host_device_callback()\r\n", log_cnt1++);
    
    const app_event_queue_t evt_queue = {
        .event_group = APP_EVENT_HID_HOST,
        // HID Host Device related info
        .hid_host_device.handle = hid_device_handle,
        .hid_host_device.event = event,
        .hid_host_device.arg = arg
    };

    if (app_event_queue) {
        xQueueSend(app_event_queue, &evt_queue, 0);
    }
}

void app_main(void)
{
    BaseType_t task_created;
    app_event_queue_t evt_queue;
    ESP_LOGI(TAG, "HID Host example");

    // Init BOOT button: Pressing the button simulates app request to exit
    // It will disconnect the USB device and uninstall the HID driver and USB Host Lib
    const gpio_config_t input_pin = {
        .pin_bit_mask = BIT64(APP_QUIT_PIN),
        .mode = GPIO_MODE_INPUT,
        .pull_up_en = GPIO_PULLUP_ENABLE,
        .intr_type = GPIO_INTR_NEGEDGE,
    };
    ESP_ERROR_CHECK(gpio_config(&input_pin));
    ESP_ERROR_CHECK(gpio_install_isr_service(ESP_INTR_FLAG_LEVEL1));
    ESP_ERROR_CHECK(gpio_isr_handler_add(APP_QUIT_PIN, gpio_isr_cb, NULL));

    /*
    * Create usb_lib_task to:
    * - initialize USB Host library
    * - Handle USB Host events while APP pin in in HIGH state
    */
    task_created = xTaskCreatePinnedToCore(usb_lib_task,
                                           "usb_events",
                                           4096,
                                           xTaskGetCurrentTaskHandle(),
                                           2, NULL, 0);
    assert(task_created == pdTRUE);

    // Wait for notification from usb_lib_task to proceed
    ulTaskNotifyTake(false, 1000);

    /*
    * HID host driver configuration
    * - create background task for handling low level event inside the HID driver
    * - provide the device callback to get new HID Device connection event
    */
    const hid_host_driver_config_t hid_host_driver_config = {
        .create_background_task = true,
        .task_priority = 5,
        .stack_size = 4096,
        .core_id = 0,
        .callback = hid_host_device_callback,
        .callback_arg = NULL
    };

    ESP_ERROR_CHECK(hid_host_install(&hid_host_driver_config));

    // Create queue
    app_event_queue = xQueueCreate(10, sizeof(app_event_queue_t));

    ESP_LOGI(TAG, "Waiting for HID Device to be connected");

    while (1) {
        // Wait queue
        if (xQueueReceive(app_event_queue, &evt_queue, portMAX_DELAY)) {
            if (APP_EVENT == evt_queue.event_group) {
                // User pressed button
                usb_host_lib_info_t lib_info;
                ESP_ERROR_CHECK(usb_host_lib_info(&lib_info));
                if (lib_info.num_devices == 0) {
                    // End while cycle
                    break;
                } else {
                    ESP_LOGW(TAG, "To shutdown example, remove all USB devices and press button again.");
                    // Keep polling
                }
            }

            if (APP_EVENT_HID_HOST ==  evt_queue.event_group) {
                hid_host_device_event(evt_queue.hid_host_device.handle,
                                      evt_queue.hid_host_device.event,
                                      evt_queue.hid_host_device.arg);
            }
        }
    }

    ESP_LOGI(TAG, "HID Driver uninstall");
    ESP_ERROR_CHECK(hid_host_uninstall());
    gpio_isr_handler_remove(APP_QUIT_PIN);
    xQueueReset(app_event_queue);
    vQueueDelete(app_event_queue);
}

@roma-jam
Copy link
Collaborator

Hi @rtek1000,

Where can I find information on how to generate the requested log?

You already provided the log I asked for. This is exactly the log from idf.py -p /dev/ttyACM0 monitor. Thanks.

Regarding the example, right now the HID Driver parses only reports when HID device support BOOT protocol.
Otherwise, the general output report should be present.

Based on the USB descriptor and log output you have provided, both interfaces were connected and should work as a HID devices by boot protocol.

Could you annotate the forcing BOOT protocol for both (Keyboards and Mice) protocols and try the HID example again?
This could be achieved with the annotating lines 438-443 in hid_host_example.c.

ESP_ERROR_CHECK(hid_host_device_open(hid_device_handle, &dev_config));
// if (HID_SUBCLASS_BOOT_INTERFACE == dev_params.sub_class) {
//    ESP_ERROR_CHECK(hid_class_request_set_protocol(hid_device_handle, HID_REPORT_PROTOCOL_BOOT));
//    if (HID_PROTOCOL_KEYBOARD == dev_params.proto) {
//        ESP_ERROR_CHECK(hid_class_request_set_idle(hid_device_handle, 0, 0));
//    }
}
ESP_ERROR_CHECK(hid_host_device_start(hid_device_handle));

And share the log again after:

  1. Attach device to the ESP32 Host (keyboard+touchpad)
  2. Press several keys on a keyboard (for example qwerty)
  3. Press one of the left buttons with mouse on them (left click or right click)
  4. Press the touchpad with one finger
  5. Press the touchpad with two fingers and slide them up-down
  6. Press the touchpad with three fingers
  7. Press "up-left-down-right" arrows on the joystick in the top-right of the device.
  8. Detach device.

Thanks.

@rtek1000
Copy link
Author

Could you annotate the forcing BOOT protocol for both (Keyboards and Mice) protocols and try the HID example again? This could be achieved with the annotating lines 438-443 in hid_host_example.c.

ESP_ERROR_CHECK(hid_host_device_open(hid_device_handle, &dev_config));
// if (HID_SUBCLASS_BOOT_INTERFACE == dev_params.sub_class) {
//    ESP_ERROR_CHECK(hid_class_request_set_protocol(hid_device_handle, HID_REPORT_PROTOCOL_BOOT));
//    if (HID_PROTOCOL_KEYBOARD == dev_params.proto) {
//        ESP_ERROR_CHECK(hid_class_request_set_idle(hid_device_handle, 0, 0));
//    }
}
ESP_ERROR_CHECK(hid_host_device_start(hid_device_handle));

And share the log again after:

1. Attach device to the ESP32 Host (keyboard+touchpad)

2. Press several keys on a keyboard (for example `qwerty`)

3. Press one of the left buttons with mouse on them (left click or right click)

4. Press the touchpad with one finger

5. Press the touchpad with two fingers and slide them up-down

6. Press the touchpad with three fingers

7. Press "up-left-down-right" arrows on the joystick in the top-right of the device.

8. Detach device.

Thanks.

  • Ok, the log from idf.py -p /dev/ttyACM0 monitor:

Executing action: monitor
Running idf_monitor in directory /home/user/esp/hid
Executing "/home/user/.espressif/python_env/idf5.3_py3.10_env/bin/python /home/user/esp/esp-idf/tools/idf_monitor.py -p /dev/ttyACM0 -b 115200 --toolchain-prefix xtensa-esp32s3-elf- --target esp32s3 --revision 0 /home/user/esp/hid/build/hid.elf -m '/home/user/.espressif/python_env/idf5.3_py3.10_env/bin/python' '/home/user/esp/esp-idf/tools/idf.py' '-p' '/dev/ttyACM0'"...
--- esp-idf-monitor 1.3.3 on /dev/ttyACM0 115200 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
SP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x1 (POWERON),boot:0x8 (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce3810,len:0x178c
load:0x403c9700,len:0x4
load:0x403c9704,len:0xcb8
load:0x403cc700,len:0x2d84
entry 0x403c9914
I (27) boot: ESP-IDF v5.3-dev-422-ga7fbf452fa 2nd stage bootloader
I (27) boot: compile time Nov 26 2023 00:55:55
I (27) boot: Multicore bootloader
I (31) boot: chip revision: v0.2
I (35) boot.esp32s3: Boot SPI Speed : 80MHz
I (40) boot.esp32s3: SPI Mode : DIO
I (45) boot.esp32s3: SPI Flash Size : 2MB
I (49) boot: Enabling RNG early entropy source...
I (55) boot: Partition Table:
I (58) boot: ## Label Usage Type ST Offset Length
I (66) boot: 0 nvs WiFi data 01 02 00009000 00006000
I (73) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (81) boot: 2 factory factory app 00 00 00010000 00100000
I (88) boot: End of partition table
I (92) esp_image: segment 0: paddr=00010020 vaddr=3c020020 size=0c38ch ( 50060) map
I (110) esp_image: segment 1: paddr=0001c3b4 vaddr=3fc92400 size=027b0h ( 10160) load
I (112) esp_image: segment 2: paddr=0001eb6c vaddr=40374000 size=014ach ( 5292) load
I (119) esp_image: segment 3: paddr=00020020 vaddr=42000020 size=1f004h (126980) map
I (149) esp_image: segment 4: paddr=0003f02c vaddr=403754ac size=0cee8h ( 52968) load
I (167) boot: Loaded app from partition at offset 0x10000
I (167) boot: Disabling RNG early entropy source...
I (178) cpu_start: Multicore app
I (188) cpu_start: Pro cpu start user code
I (188) cpu_start: cpu freq: 160000000 Hz
I (188) cpu_start: Application information:
I (191) cpu_start: Project name: hid
I (195) cpu_start: App version: 1
I (200) cpu_start: Compile time: Nov 26 2023 00:55:43
I (206) cpu_start: ELF file SHA256: ac0b9e848...
I (211) cpu_start: ESP-IDF: v5.3-dev-422-ga7fbf452fa
I (218) cpu_start: Min chip rev: v0.0
I (222) cpu_start: Max chip rev: v0.99
I (227) cpu_start: Chip rev: v0.2
I (232) heap_init: Initializing. RAM available for dynamic allocation:
I (239) heap_init: At 3FC95420 len 000542F0 (336 KiB): RAM
I (245) heap_init: At 3FCE9710 len 00005724 (21 KiB): RAM
I (251) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
I (257) heap_init: At 600FE010 len 00001FD8 (7 KiB): RTCRAM
I (264) spi_flash: detected chip: generic
I (268) spi_flash: flash io: dio
W (272) spi_flash: Detected size(16384k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (286) sleep: Configure to isolate all GPIO pins in sleep state
I (292) sleep: Enable automatic switching of GPIO sleep configuration
I (300) main_task: Started on CPU0
I (310) main_task: Calling app_main()
I (310) example: HID Host example
I (310) gpio: GPIO[0]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:2
I (350) example: Waiting for HID Device to be connected
I (10090) example: HID Device, protocol 'KEYBOARD' CONNECTED
I (10090) example: HID Device, protocol 'MOUSE' CONNECTED

Mouse
X: 000000 Y: 000000 | |o|
Keyboard
qwerty
Mouse
X: 000110 Y: -00003 |o| |
Keyboard
E (111000) USBH: Device 1 gone
I (111000) example: HID Device, protocol 'KEYBOARD' DISCONNECTED
I (111000) example: HID Device, protocol 'MOUSE' DISCONNECTED

  • I noticed that when pressing the multimedia keys the mouse's X axis is being changed, it should just be a matter of remapping the commands. But it's already functional, we have keyboard and touchpad response.

  • The log from idf.py -p /dev/ttyACM0 monitor for modified code with flags:

Executing action: monitor
Running idf_monitor in directory /home/user/esp/hid
Executing "/home/user/.espressif/python_env/idf5.3_py3.10_env/bin/python /home/user/esp/esp-idf/tools/idf_monitor.py -p /dev/ttyACM0 -b 115200 --toolchain-prefix xtensa-esp32s3-elf- --target esp32s3 --revision 0 /home/user/esp/hid/build/hid.elf -m '/home/user/.espressif/python_env/idf5.3_py3.10_env/bin/python' '/home/user/esp/esp-idf/tools/idf.py' '-p' '/dev/ttyACM0'"...
--- esp-idf-monitor 1.3.3 on /dev/ttyACM0 115200 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---

SP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x1 (POWERON),boot:0x8 (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce3810,len:0x178c
load:0x403c9700,len:0x4
load:0x403c9704,len:0xcb8
load:0x403cc700,len:0x2d84
entry 0x403c9914
I (27) boot: ESP-IDF v5.3-dev-422-ga7fbf452fa 2nd stage bootloader
I (27) boot: compile time Nov 26 2023 00:55:55
I (27) boot: Multicore bootloader
I (31) boot: chip revision: v0.2
I (35) boot.esp32s3: Boot SPI Speed : 80MHz
I (40) boot.esp32s3: SPI Mode : DIO
I (45) boot.esp32s3: SPI Flash Size : 2MB
I (49) boot: Enabling RNG early entropy source...
I (55) boot: Partition Table:
I (58) boot: ## Label Usage Type ST Offset Length
I (66) boot: 0 nvs WiFi data 01 02 00009000 00006000
I (73) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (81) boot: 2 factory factory app 00 00 00010000 00100000
I (88) boot: End of partition table
I (92) esp_image: segment 0: paddr=00010020 vaddr=3c020020 size=0c3bch ( 50108) map
I (110) esp_image: segment 1: paddr=0001c3e4 vaddr=3fc92400 size=027b0h ( 10160) load
I (112) esp_image: segment 2: paddr=0001eb9c vaddr=40374000 size=0147ch ( 5244) load
I (119) esp_image: segment 3: paddr=00020020 vaddr=42000020 size=1efe8h (126952) map
I (149) esp_image: segment 4: paddr=0003f010 vaddr=4037547c size=0cf18h ( 53016) load
I (167) boot: Loaded app from partition at offset 0x10000
I (167) boot: Disabling RNG early entropy source...
I (178) cpu_start: Multicore app
I (188) cpu_start: Pro cpu start user code
I (188) cpu_start: cpu freq: 160000000 Hz
I (188) cpu_start: Application information:
I (191) cpu_start: Project name: hid
I (195) cpu_start: App version: 1
I (200) cpu_start: Compile time: Nov 26 2023 00:55:43
I (206) cpu_start: ELF file SHA256: aa0528de3...
I (211) cpu_start: ESP-IDF: v5.3-dev-422-ga7fbf452fa
I (218) cpu_start: Min chip rev: v0.0
I (222) cpu_start: Max chip rev: v0.99
I (227) cpu_start: Chip rev: v0.2
I (232) heap_init: Initializing. RAM available for dynamic allocation:
I (239) heap_init: At 3FC95420 len 000542F0 (336 KiB): RAM
I (245) heap_init: At 3FCE9710 len 00005724 (21 KiB): RAM
I (251) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
I (257) heap_init: At 600FE010 len 00001FD8 (7 KiB): RTCRAM
I (264) spi_flash: detected chip: generic
I (268) spi_flash: flash io: dio
W (272) spi_flash: Detected size(16384k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (286) sleep: Configure to isolate all GPIO pins in sleep state
I (292) sleep: Enable automatic switching of GPIO sleep configuration
I (300) main_task: Started on CPU0
I (310) main_task: Calling app_main()
I (310) example: HID Host example
I (310) gpio: GPIO[0]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:2
I (350) example: Waiting for HID Device to be connected
0 - hid_host_device_callback()
1 - hid_host_device_callback()
2 - hid_host_device_event()
I (6440) example: HID Device, protocol 'KEYBOARD' CONNECTED
3 - hid_host_device_event()
I (6450) example: HID Device, protocol 'MOUSE' CONNECTED
4 - hid_host_interface_callback()
5 - hid_host_keyboard_report_callback()
6 - hid_host_interface_callback()
7 - hid_host_mouse_report_callback()

Mouse
8 - hid_host_interface_callback()
9 - hid_host_mouse_report_callback()
10 - hid_host_interface_callback()
11 - hid_host_keyboard_report_callback()

Keyboard
12 - hid_host_interface_callback()
13 - hid_host_keyboard_report_callback()
14 - hid_host_interface_callback()
15 - hid_host_keyboard_report_callback()
16 - hid_host_interface_callback()
17 - hid_host_keyboard_report_callback()
18 - hid_host_interface_callback()
19 - hid_host_keyboard_report_callback()
20 - hid_host_interface_callback()
21 - hid_host_keyboard_report_callback()
22 - hid_host_interface_callback()
23 - hid_host_keyboard_report_callback()
24 - hid_host_interface_callback()
25 - hid_host_keyboard_report_callback()
26 - hid_host_interface_callback()
27 - hid_host_keyboard_report_callback()
28 - hid_host_interface_callback()
29 - hid_host_keyboard_report_callback()
30 - hid_host_interface_callback()
31 - hid_host_keyboard_report_callback()
32 - hid_host_interface_callback()
33 - hid_host_keyboard_report_callback()
34 - hid_host_interface_callback()
35 - hid_host_mouse_report_callback()

Mouse
36 - hid_host_interface_callback()
37 - hid_host_mouse_report_callback()
38 - hid_host_interface_callback()
39 - hid_host_mouse_report_callback()
40 - hid_host_interface_callback()
41 - hid_host_mouse_report_callback()
42 - hid_host_interface_callback()
43 - hid_host_mouse_report_callback()
44 - hid_host_interface_callback()
45 - hid_host_mouse_report_callback()
46 - hid_host_interface_callback()
47 - hid_host_mouse_report_callback()
48 - hid_host_interface_callback()
49 - hid_host_mouse_report_callback()
50 - hid_host_interface_callback()
51 - hid_host_keyboard_report_callback()

Keyboard
52 - hid_host_interface_callback()
53 - hid_host_keyboard_report_callback()
54 - hid_host_interface_callback()
55 - hid_host_keyboard_report_callback()
56 - hid_host_interface_callback()
57 - hid_host_keyboard_report_callback()
58 - hid_host_interface_callback()
59 - hid_host_keyboard_report_callback()
60 - hid_host_interface_callback()
61 - hid_host_keyboard_report_callback()
62 - hid_host_interface_callback()
63 - hid_host_keyboard_report_callback()
64 - hid_host_interface_callback()
65 - hid_host_keyboard_report_callback()
E (68750) USBH: Device 1 gone
66 - hid_host_interface_callback()
I (68750) example: HID Device, protocol 'KEYBOARD' DISCONNECTED
67 - hid_host_interface_callback()
I (68760) example: HID Device, protocol 'MOUSE' DISCONNECTED

  • The log from idf.py -p /dev/ttyACM0 monitor for modified code with flags, only Multimedia keys:

68 - hid_host_device_callback()
69 - hid_host_device_callback()
70 - hid_host_device_event()
I (76810) example: HID Device, protocol 'KEYBOARD' CONNECTED
71 - hid_host_device_event()
I (76820) example: HID Device, protocol 'MOUSE' CONNECTED
72 - hid_host_interface_callback()
73 - hid_host_mouse_report_callback()

Mouse
74 - hid_host_interface_callback()
75 - hid_host_keyboard_report_callback()
76 - hid_host_interface_callback()
77 - hid_host_mouse_report_callback()
78 - hid_host_interface_callback()
79 - hid_host_mouse_report_callback()
80 - hid_host_interface_callback()
81 - hid_host_mouse_report_callback()
82 - hid_host_interface_callback()
83 - hid_host_mouse_report_callback()
84 - hid_host_interface_callback()
85 - hid_host_mouse_report_callback()
86 - hid_host_interface_callback()
87 - hid_host_mouse_report_callback()
88 - hid_host_interface_callback()
89 - hid_host_mouse_report_callback()
90 - hid_host_interface_callback()
91 - hid_host_mouse_report_callback()
92 - hid_host_interface_callback()
93 - hid_host_mouse_report_callback()
94 - hid_host_interface_callback()
95 - hid_host_mouse_report_callback()
96 - hid_host_interface_callback()
97 - hid_host_mouse_report_callback()
98 - hid_host_interface_callback()
99 - hid_host_mouse_report_callback()
100 - hid_host_interface_callback()
101 - hid_host_mouse_report_callback()
102 - hid_host_interface_callback()
103 - hid_host_mouse_report_callback()
104 - hid_host_interface_callback()
105 - hid_host_mouse_report_callback()
106 - hid_host_interface_callback()
107 - hid_host_mouse_report_callback()
108 - hid_host_interface_callback()
109 - hid_host_mouse_report_callback()
110 - hid_host_interface_callback()
111 - hid_host_mouse_report_callback()
112 - hid_host_interface_callback()
113 - hid_host_mouse_report_callback()
114 - hid_host_interface_callback()
115 - hid_host_mouse_report_callback()
116 - hid_host_interface_callback()
117 - hid_host_mouse_report_callback()
E (111140) USBH: Device 1 gone
118 - hid_host_interface_callback()
I (111140) example: HID Device, protocol 'KEYBOARD' DISCONNECTED
119 - hid_host_interface_callback()
I (111150) example: HID Device, protocol 'MOUSE' DISCONNECTED


  • An additional question, about using a USB HUB, to use a regular mouse in one port of the HUB and a regular keyboard in another port (without touchpad), is it possible?

    • I tried to use a HUB but it didn't recognize either the mouse or the keyboard. Although both keyboard and mouse are recognized if they are inserted directly into the ESP32-S3's USB port one at a time.

@roma-jam
Copy link
Collaborator

Hi @rtek1000,
Thanks for the additional info.

Could you please make the same things on the clean example code?
The idea here is to get the raw report data and see what we can do with it.

Right now it looks like both (Keyboard and Mouse) interfaces are working, the goal is to understand how to parse the data when touchpad is active.

An additional question, about using a USB HUB, to use a regular mouse in one port of the HUB and a regular keyboard in another port (without touchpad), is it possible?

Technically, it is possible but right now it is not implemented in usb_host library, so any external HUBs is just a regular USB device for ESP32.

But we have it in our TODO list and we have plans to implement it.

@rtek1000
Copy link
Author

rtek1000 commented Nov 27, 2023

Could you please make the same things on the clean example code? The idea here is to get the raw report data and see what we can do with it.

  • I modified the hid_host_mouse_report_callback() sub to provide the raw data values:
/**
 * @brief USB HID Host Mouse Interface report callback handler
 *
 * @param[in] data    Pointer to input report data buffer
 * @param[in] length  Length of input report data buffer
 */
static void hid_host_mouse_report_callback(const uint8_t *const data, const int length)
{
    hid_mouse_input_report_boot_t *mouse_report = (hid_mouse_input_report_boot_t *)data;

    if (length < sizeof(hid_mouse_input_report_boot_t)) {
        return;
    }
    
    printf("Mouse data[0-4]: %d; %d; %d; %d; %d\r\n", data[0], data[1], data[2], data[3], data[4]);

    static int x_pos = 0;
    static int y_pos = 0;

    // Calculate absolute position from displacement
    x_pos += mouse_report->x_displacement;
    y_pos += mouse_report->y_displacement;

    hid_print_new_device_report_header(HID_PROTOCOL_MOUSE);

    printf("X: %06d\tY: %06d\t|%c|%c|\r\n",
           x_pos, y_pos,
           (mouse_report->buttons.button1 ? 'o' : ' '),
           (mouse_report->buttons.button2 ? 'o' : ' '));
    fflush(stdout);
}
  • The log from idf.py -p /dev/ttyACM0 monitor for Multimedia keys and touchpad functions:

Mouse data[0-4]: 2; 233; 0; 0; 0 <----- "V+" (directional Up button)
Mouse
X: -00023 Y: 000000 | |o|
Mouse data[0-4]: 2; 0; 0; 0; 0
X: -00023 Y: 000000 | |o|
Mouse data[0-4]: 2; 181; 0; 0; 0 <----- ">>|" (directional Right button)
X: -00098 Y: 000000 | |o|
Mouse data[0-4]: 2; 0; 0; 0; 0
X: -00098 Y: 000000 | |o|
Mouse data[0-4]: 2; 234; 0; 0; 0 <----- "V-" (directional Down button)
X: -00120 Y: 000000 | |o|
Mouse data[0-4]: 2; 0; 0; 0; 0
X: -00120 Y: 000000 | |o|
Mouse data[0-4]: 2; 182; 0; 0; 0 <----- "|<<" (directional Left button)
X: -00194 Y: 000000 | |o|
Mouse data[0-4]: 2; 0; 0; 0; 0
X: -00194 Y: 000000 | |o|
Mouse data[0-4]: 2; 205; 0; 0; 0 <----- ">||" (directional Center button)
X: -00245 Y: 000000 | |o|
Mouse data[0-4]: 2; 0; 0; 0; 0
X: -00245 Y: 000000 | |o|
Mouse data[0-4]: 2; 131; 1; 0; 0 <----- "Media Player button"
X: -00370 Y: 000001 | |o|
Mouse data[0-4]: 2; 0; 0; 0; 0
X: -00370 Y: 000001 | |o|
Mouse data[0-4]: 2; 138; 1; 0; 0 <----- "e-mail button"
X: -00488 Y: 000002 | |o|
Mouse data[0-4]: 2; 0; 0; 0; 0
X: -00488 Y: 000002 | |o|
Mouse data[0-4]: 2; 226; 0; 0; 0 <----- "Mute button"
X: -00518 Y: 000002 | |o|
Mouse data[0-4]: 2; 0; 0; 0; 0
X: -00518 Y: 000002 | |o|
Mouse data[0-4]: 2; 33; 2; 0; 0 <----- "Search button"
X: -00485 Y: 000004 | |o|
Mouse data[0-4]: 2; 0; 0; 0; 0
X: -00485 Y: 000004 | |o|
Mouse data[0-4]: 2; 35; 2; 0; 0 <----- "Home button"
X: -00450 Y: 000006 | |o|
Mouse data[0-4]: 2; 0; 0; 0; 0
X: -00450 Y: 000006 | |o|
Mouse data[0-4]: 2; 150; 1; 0; 0 <----- "Browser 'e' button"
X: -00556 Y: 000007 | |o|
Mouse data[0-4]: 2; 0; 0; 0; 0
X: -00556 Y: 000007 | |o|
Mouse data[0-4]: 1; 1; 0; 0; 0 <----- "Touchpad left click"
X: -00555 Y: 000007 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 0
X: -00555 Y: 000007 |o| |
Mouse data[0-4]: 1; 2; 0; 0; 0 <----- "Touchpad right click"
X: -00553 Y: 000007 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 0
X: -00553 Y: 000007 |o| |
Mouse data[0-4]: 1; 0; 0; 251; 0 <----- "Touchpad move Up"
X: -00553 Y: 000007 |o| |
Mouse data[0-4]: 1; 0; 2; 248; 0
X: -00553 Y: 000009 |o| |
Mouse data[0-4]: 1; 0; 2; 245; 0
X: -00553 Y: 000011 |o| |
Mouse data[0-4]: 1; 1; 0; 0; 0 <----- "Touchpad 1 finger" (left click)
X: -00552 Y: 000011 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 0
X: -00552 Y: 000011 |o| |
Mouse data[0-4]: 1; 0; 19; 248; 0
X: -00552 Y: 000030 |o| |
Mouse data[0-4]: 1; 0; 21; 249; 0
X: -00552 Y: 000051 |o| |
Mouse data[0-4]: 1; 0; 21; 248; 0
X: -00552 Y: 000072 |o| |
Mouse data[0-4]: 1; 0; 22; 250; 0
X: -00552 Y: 000094 |o| |
Mouse data[0-4]: 1; 0; 18; 252; 0
X: -00552 Y: 000112 |o| |
Mouse data[0-4]: 1; 0; 0; 255; 0
X: -00552 Y: 000112 |o| |
Mouse data[0-4]: 1; 0; 255; 0; 0
X: -00552 Y: 000111 |o| |
Mouse data[0-4]: 1; 1; 0; 0; 0
X: -00551 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 0
X: -00551 Y: 000111 |o| |
Mouse data[0-4]: 1; 2; 0; 0; 0
X: -00549 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 0
X: -00549 Y: 000111 |o| |
Mouse data[0-4]: 1; 2; 0; 0; 0
X: -00547 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 0
X: -00547 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 1
X: -00547 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 1 <----- "Touchpad 2 fingers" (Down-Up)
X: -00547 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 1
X: -00547 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 1
X: -00547 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 1
X: -00547 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 1
X: -00547 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 1
X: -00547 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 1
X: -00547 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 1
X: -00547 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 1
X: -00547 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 1
X: -00547 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 1
X: -00547 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 1
X: -00547 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 1
X: -00547 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 255 <----- "Touchpad 2 fingers" (Up-Down)
X: -00547 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 255
X: -00547 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 255
X: -00547 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 255
X: -00547 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 255
X: -00547 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 255
X: -00547 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 255
X: -00547 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 255
X: -00547 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 255
X: -00547 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 255
X: -00547 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 255
X: -00547 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 255
X: -00547 Y: 000111 |o| |
Mouse data[0-4]: 1; 0; 0; 0; 255
X: -00547 Y: 000111 |o| |

Touchpad / multimedia map:

    • data[0]: touchpad: 0x01; multimedia: 0x02 (button released: (touchpad: 0x01; multimedia: 0x02))
    • data[1]: touchpad button (left: 0x01 [1 finger]; right: 0x02 [3 fingers]) (button released: 0x00)
    • data[2]: touchpad move X (left-right: <= 0x09; right-left: >= 0xFA) (button released: 0x00)
    • data[3]: touchpad move Y (up-down: <= 0x09; down-up: >= 0xFA) (button released: 0x00)
    • data[4]: touchpad scroll (2 fingers) (up-down: == 0xFF; down-up: == 0x01) (button released: 0x00)

Right now it looks like both (Keyboard and Mouse) interfaces are working, the goal is to understand how to parse the data when touchpad is active.

  • Yes, thanks!

An additional question, about using a USB HUB, to use a regular mouse in one port of the HUB and a regular keyboard in another port (without touchpad), is it possible?

Technically, it is possible but right now it is not implemented in usb_host library, so any external HUBs is just a regular USB device for ESP32.

But we have it in our TODO list and we have plans to implement it.

  • Ok, thanks. Is there an issue that can be followed up?

@roma-jam
Copy link
Collaborator

Hi @rtek1000,
Thanks for the log, seems that the USB HID Driver works fine.
The report handling is a part of a higher logic now and can be done above easily.

Yes, for the external HUBs support we have couple of tickets, this is the last one: #12554 (comment)

Is there anything else I can help with or we can close this issue?

@rtek1000
Copy link
Author

rtek1000 commented Nov 27, 2023

Hi @rtek1000, Thanks for the log, seems that the USB HID Driver works fine. The report handling is a part of a higher logic now and can be done above easily.

  • Yes, thanks!

For STM32, some tags are used, which might be interesting to have a pattern for keys that do not have characters:

#define KEY_NONE                               0x00
#define KEY_ERRORROLLOVER                      0x01
#define KEY_POSTFAIL                           0x02
#define KEY_ERRORUNDEFINED                     0x03
#define KEY_A                                  0x04
#define KEY_B                                  0x05
#define KEY_C                                  0x06
#define KEY_D                                  0x07
#define KEY_E                                  0x08
#define KEY_F                                  0x09
#define KEY_G                                  0x0A
#define KEY_H                                  0x0B
#define KEY_I                                  0x0C
#define KEY_J                                  0x0D
#define KEY_K                                  0x0E
#define KEY_L                                  0x0F
#define KEY_M                                  0x10
#define KEY_N                                  0x11
#define KEY_O                                  0x12
#define KEY_P                                  0x13
#define KEY_Q                                  0x14
#define KEY_R                                  0x15
#define KEY_S                                  0x16
#define KEY_T                                  0x17
#define KEY_U                                  0x18
#define KEY_V                                  0x19
#define KEY_W                                  0x1A
#define KEY_X                                  0x1B
#define KEY_Y                                  0x1C
#define KEY_Z                                  0x1D
#define KEY_1_EXCLAMATION_MARK                 0x1E
#define KEY_2_AT                               0x1F
#define KEY_3_NUMBER_SIGN                      0x20
#define KEY_4_DOLLAR                           0x21
#define KEY_5_PERCENT                          0x22
#define KEY_6_CARET                            0x23
#define KEY_7_AMPERSAND                        0x24
#define KEY_8_ASTERISK                         0x25
#define KEY_9_OPARENTHESIS                     0x26
#define KEY_0_CPARENTHESIS                     0x27
#define KEY_ENTER                              0x28
#define KEY_ESCAPE                             0x29
#define KEY_BACKSPACE                          0x2A
#define KEY_TAB                                0x2B
#define KEY_SPACEBAR                           0x2C
#define KEY_MINUS_UNDERSCORE                   0x2D
#define KEY_EQUAL_PLUS                         0x2E
#define KEY_OBRACKET_AND_OBRACE                0x2F
#define KEY_CBRACKET_AND_CBRACE                0x30
#define KEY_BACKSLASH_VERTICAL_BAR             0x31
#define KEY_NONUS_NUMBER_SIGN_TILDE            0x32
#define KEY_SEMICOLON_COLON                    0x33
#define KEY_SINGLE_AND_DOUBLE_QUOTE            0x34
#define KEY_GRAVE_ACCENT_AND_TILDE             0x35
#define KEY_COMMA_AND_LESS                     0x36
#define KEY_DOT_GREATER                        0x37
#define KEY_SLASH_QUESTION                     0x38
#define KEY_CAPS_LOCK                          0x39
#define KEY_F1                                 0x3A
#define KEY_F2                                 0x3B
#define KEY_F3                                 0x3C
#define KEY_F4                                 0x3D
#define KEY_F5                                 0x3E
#define KEY_F6                                 0x3F
#define KEY_F7                                 0x40
#define KEY_F8                                 0x41
#define KEY_F9                                 0x42
#define KEY_F10                                0x43
#define KEY_F11                                0x44
#define KEY_F12                                0x45
#define KEY_PRINTSCREEN                        0x46
#define KEY_SCROLL_LOCK                        0x47
#define KEY_PAUSE                              0x48
#define KEY_INSERT                             0x49
#define KEY_HOME                               0x4A
#define KEY_PAGEUP                             0x4B
#define KEY_DELETE                             0x4C
#define KEY_END1                               0x4D
#define KEY_PAGEDOWN                           0x4E
#define KEY_RIGHTARROW                         0x4F
#define KEY_LEFTARROW                          0x50
#define KEY_DOWNARROW                          0x51
#define KEY_UPARROW                            0x52
#define KEY_KEYPAD_NUM_LOCK_AND_CLEAR          0x53
#define KEY_KEYPAD_SLASH                       0x54
#define KEY_KEYPAD_ASTERIKS                    0x55
#define KEY_KEYPAD_MINUS                       0x56
#define KEY_KEYPAD_PLUS                        0x57
#define KEY_KEYPAD_ENTER                       0x58
#define KEY_KEYPAD_1_END                       0x59
#define KEY_KEYPAD_2_DOWN_ARROW                0x5A
#define KEY_KEYPAD_3_PAGEDN                    0x5B
#define KEY_KEYPAD_4_LEFT_ARROW                0x5C
#define KEY_KEYPAD_5                           0x5D
#define KEY_KEYPAD_6_RIGHT_ARROW               0x5E
#define KEY_KEYPAD_7_HOME                      0x5F
#define KEY_KEYPAD_8_UP_ARROW                  0x60
#define KEY_KEYPAD_9_PAGEUP                    0x61
#define KEY_KEYPAD_0_INSERT                    0x62
#define KEY_KEYPAD_DECIMAL_SEPARATOR_DELETE    0x63
#define KEY_NONUS_BACK_SLASH_VERTICAL_BAR      0x64
#define KEY_APPLICATION                        0x65
#define KEY_POWER                              0x66
#define KEY_KEYPAD_EQUAL                       0x67
#define KEY_F13                                0x68
#define KEY_F14                                0x69
#define KEY_F15                                0x6A
#define KEY_F16                                0x6B
#define KEY_F17                                0x6C
#define KEY_F18                                0x6D
#define KEY_F19                                0x6E
#define KEY_F20                                0x6F
#define KEY_F21                                0x70
#define KEY_F22                                0x71
#define KEY_F23                                0x72
#define KEY_F24                                0x73
#define KEY_EXECUTE                            0x74
#define KEY_HELP                               0x75
#define KEY_MENU                               0x76
#define KEY_SELECT                             0x77
#define KEY_STOP                               0x78
#define KEY_AGAIN                              0x79
#define KEY_UNDO                               0x7A
#define KEY_CUT                                0x7B
#define KEY_COPY                               0x7C
#define KEY_PASTE                              0x7D
#define KEY_FIND                               0x7E
#define KEY_MUTE                               0x7F
#define KEY_VOLUME_UP                          0x80
#define KEY_VOLUME_DOWN                        0x81
#define KEY_LOCKING_CAPS_LOCK                  0x82
#define KEY_LOCKING_NUM_LOCK                   0x83
#define KEY_LOCKING_SCROLL_LOCK                0x84
#define KEY_KEYPAD_COMMA                       0x85
#define KEY_KEYPAD_EQUAL_SIGN                  0x86
#define KEY_INTERNATIONAL1                     0x87
#define KEY_INTERNATIONAL2                     0x88
#define KEY_INTERNATIONAL3                     0x89
#define KEY_INTERNATIONAL4                     0x8A
#define KEY_INTERNATIONAL5                     0x8B
#define KEY_INTERNATIONAL6                     0x8C
#define KEY_INTERNATIONAL7                     0x8D
#define KEY_INTERNATIONAL8                     0x8E
#define KEY_INTERNATIONAL9                     0x8F
#define KEY_LANG1                              0x90
#define KEY_LANG2                              0x91
#define KEY_LANG3                              0x92
#define KEY_LANG4                              0x93
#define KEY_LANG5                              0x94
#define KEY_LANG6                              0x95
#define KEY_LANG7                              0x96
#define KEY_LANG8                              0x97
#define KEY_LANG9                              0x98
#define KEY_ALTERNATE_ERASE                    0x99
#define KEY_SYSREQ                             0x9A
#define KEY_CANCEL                             0x9B
#define KEY_CLEAR                              0x9C
#define KEY_PRIOR                              0x9D
#define KEY_RETURN                             0x9E
#define KEY_SEPARATOR                          0x9F
#define KEY_OUT                                0xA0
#define KEY_OPER                               0xA1
#define KEY_CLEAR_AGAIN                        0xA2
#define KEY_CRSEL                              0xA3
#define KEY_EXSEL                              0xA4
#define KEY_KEYPAD_00                          0xB0
#define KEY_KEYPAD_000                         0xB1
#define KEY_THOUSANDS_SEPARATOR                0xB2
#define KEY_DECIMAL_SEPARATOR                  0xB3
#define KEY_CURRENCY_UNIT                      0xB4
#define KEY_CURRENCY_SUB_UNIT                  0xB5
#define KEY_KEYPAD_OPARENTHESIS                0xB6
#define KEY_KEYPAD_CPARENTHESIS                0xB7
#define KEY_KEYPAD_OBRACE                      0xB8
#define KEY_KEYPAD_CBRACE                      0xB9
#define KEY_KEYPAD_TAB                         0xBA
#define KEY_KEYPAD_BACKSPACE                   0xBB
#define KEY_KEYPAD_A                           0xBC
#define KEY_KEYPAD_B                           0xBD
#define KEY_KEYPAD_C                           0xBE
#define KEY_KEYPAD_D                           0xBF
#define KEY_KEYPAD_E                           0xC0
#define KEY_KEYPAD_F                           0xC1
#define KEY_KEYPAD_XOR                         0xC2
#define KEY_KEYPAD_CARET                       0xC3
#define KEY_KEYPAD_PERCENT                     0xC4
#define KEY_KEYPAD_LESS                        0xC5
#define KEY_KEYPAD_GREATER                     0xC6
#define KEY_KEYPAD_AMPERSAND                   0xC7
#define KEY_KEYPAD_LOGICAL_AND                 0xC8
#define KEY_KEYPAD_VERTICAL_BAR                0xC9
#define KEY_KEYPAD_LOGIACL_OR                  0xCA
#define KEY_KEYPAD_COLON                       0xCB
#define KEY_KEYPAD_NUMBER_SIGN                 0xCC
#define KEY_KEYPAD_SPACE                       0xCD
#define KEY_KEYPAD_AT                          0xCE
#define KEY_KEYPAD_EXCLAMATION_MARK            0xCF
#define KEY_KEYPAD_MEMORY_STORE                0xD0
#define KEY_KEYPAD_MEMORY_RECALL               0xD1
#define KEY_KEYPAD_MEMORY_CLEAR                0xD2
#define KEY_KEYPAD_MEMORY_ADD                  0xD3
#define KEY_KEYPAD_MEMORY_SUBTRACT             0xD4
#define KEY_KEYPAD_MEMORY_MULTIPLY             0xD5
#define KEY_KEYPAD_MEMORY_DIVIDE               0xD6
#define KEY_KEYPAD_PLUSMINUS                   0xD7
#define KEY_KEYPAD_CLEAR                       0xD8
#define KEY_KEYPAD_CLEAR_ENTRY                 0xD9
#define KEY_KEYPAD_BINARY                      0xDA
#define KEY_KEYPAD_OCTAL                       0xDB
#define KEY_KEYPAD_DECIMAL                     0xDC
#define KEY_KEYPAD_HEXADECIMAL                 0xDD
#define KEY_LEFTCONTROL                        0xE0
#define KEY_LEFTSHIFT                          0xE1
#define KEY_LEFTALT                            0xE2
#define KEY_LEFT_GUI                           0xE3
#define KEY_RIGHTCONTROL                       0xE4
#define KEY_RIGHTSHIFT                         0xE5
#define KEY_RIGHTALT                           0xE6
#define KEY_RIGHT_GUI                          0xE7

Ref.: usbh_hid_keybd.h

Yes, for the external HUBs support we have couple of tickets, this is the last one: #12554 (comment)

Ok, thanks!

Is there anything else I can help with or we can close this issue?

No, that's all, thanks for your attention!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Resolution: Won't Do This will not be worked on Status: Done Issue is done internally Type: Feature Request Feature request for IDF
Projects
None yet
Development

No branches or pull requests

3 participants