From d36a58ffd4fc2eb454d6f74cff6129f86ade5bc5 Mon Sep 17 00:00:00 2001 From: beni Date: Mon, 5 Sep 2022 15:31:22 +0200 Subject: [PATCH 01/15] Added joystick to HID report map; removed SUPPORT_VENDOR --- main/Kconfig.projbuild | 8 ++-- main/ble_hidd_demo_main.c | 5 +-- main/hid_device_le_prf.c | 86 +++++++++++++++++++-------------------- main/hidd_le_prf_int.h | 7 ---- 4 files changed, 48 insertions(+), 58 deletions(-) diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 41b5a05..621b1e9 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -21,14 +21,14 @@ menu "esp32_mouse_keyboard - FLipMouse & FABI config" range 1 2 config MODULE_USEKEYBOARD - bool "Enable BLE-HID keyboard (UNUSED)" + bool "Enable BLE-HID keyboard (UNUSED, mouse is always enabled)" default y help Enable the Keyboard interface for Bluetooth. config MODULE_USEMOUSE depends on MODULE_USEKEYBOARD - bool "Enable BLE-HID mouse (UNUSED)" + bool "Enable BLE-HID mouse (UNUSED, kbd is always enabled)" default y help Enable the Mouse interface for Bluetooth. @@ -44,8 +44,8 @@ menu "esp32_mouse_keyboard - FLipMouse & FABI config" config MODULE_USEJOYSTICK depends on MODULE_USEMOUSE - bool "Enable BLE-HID joystick (UNUSED)" - default n + bool "Enable BLE-HID joystick" + default y help Enable the Joystick interface for Bluetooth. diff --git a/main/ble_hidd_demo_main.c b/main/ble_hidd_demo_main.c index 88146d4..e6d6816 100644 --- a/main/ble_hidd_demo_main.c +++ b/main/ble_hidd_demo_main.c @@ -73,10 +73,9 @@ /** * Note: - * 1. Win10 does not support vendor report , So SUPPORT_REPORT_VENDOR is always set to FALSE, it defines in hidd_le_prf_int.h - * 2. Update connection parameters are not allowed during iPhone HID encryption, slave turns + * 1. Update connection parameters are not allowed during iPhone HID encryption, slave turns * off the ability to automatically update connection parameters during encryption. - * 3. After our HID device is connected, the iPhones write 1 to the Report Characteristic Configuration Descriptor, + * 2. After our HID device is connected, the iPhones write 1 to the Report Characteristic Configuration Descriptor, * even if the HID encryption is not completed. This should actually be written 1 after the HID encryption is completed. * we modify the permissions of the Report Characteristic Configuration Descriptor to `ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE_ENCRYPTED`. * if you got `GATT_INSUF_ENCRYPTION` error, please ignore. diff --git a/main/hid_device_le_prf.c b/main/hid_device_le_prf.c index 1495b94..e21489f 100644 --- a/main/hid_device_le_prf.c +++ b/main/hid_device_le_prf.c @@ -139,7 +139,7 @@ static const uint8_t hidReportMap[] = { 0x81, 0x00, // Input (Data, Ary, Abs) 0xC0, // End Collection 0x81, 0x03, // Input (Const, Var, Abs) - 0xC0, // End Collectionq + 0xC0, // End Collection 0x05, 0x01, // Usage Page (Generic Desktop) @@ -171,18 +171,47 @@ static const uint8_t hidReportMap[] = { 0xC0, // End Collection 0xC0, // End Collection -#if (SUPPORT_REPORT_VENDOR == true) - 0x06, 0xFF, 0xFF, // Usage Page(Vendor defined) - 0x09, 0xA5, // Usage(Vendor Defined) - 0xA1, 0x01, // Collection(Application) - 0x85, 0x04, // Report Id (4) - 0x09, 0xA6, // Usage(Vendor defined) - 0x09, 0xA9, // Usage(Vendor defined) - 0x75, 0x08, // Report Size - 0x95, 0x7F, // Report Count = 127 Btyes - 0x91, 0x02, // Output(Data, Variable, Absolute) - 0xC0, // End Collection -#endif + #if CONFIG_MODULE_USEJOYSTICK + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x05, // Usage (Gamepad) + 0xA1, 0x01, // Collection (Application) + 0x85, 0x04, // Report Id (4) + /* 8 bit X, Y, Z, Rz, Rx, Ry (min -127, max 127 ) */ + /* implemented like Gamepad from tinyUSB */ + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x30, // Usage (desktop X) + 0x09, 0x31, // Usage (desktop Y) + 0x09, 0x32, // Usage (desktop Z) + 0x09, 0x35, // Usage (desktop RZ) + 0x09, 0x33, // Usage (desktop RX) + 0x09, 0x34, // Usage (desktop RY) + 0x15, 0x81, // Logical Minimum (-127) + 0x25, 0x7F, // Logical Maximum (127) + 0x95, 0x06, // Report Count (6) + 0x75, 0x08, // Report Size (8) + 0x81, 0x02, // Input: (Data, Variable, Absolute) + /* 8 bit DPad/Hat Button Map */ + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x39, // Usage (hat switch) + 0x15, 0x01, // Logical Min (1) + 0x25, 0x08, // Logical Max (8) + + 0x35, 0x00, // Physical minimum (0) + 0x46, 0x00, // Physical maximum (315, size 2) + 0x95, 0x06, // Report Count (1) + 0x75, 0x08, // Report Size (8) + 0x81, 0x02, // Input: (Data, Variable, Absolute) + /* 16 bit Button Map */ + 0x05, 0x09, // Usage Page (button) + 0x19, 0x01, // Usage Minimum (01) - Button 1 + 0x29, 0x20, // Usage Maximum (32) - Button 2 + 0x15, 0x00, // Logical Min (0) + 0x25, 0x01, // Logical Max (1) + 0x95, 0x20, // Report Count (32) + 0x75, 0x01, // Report Size (1) + 0x81, 0x02, // Input: (Data, Variable, Absolute) + 0xC0, // End Collection + #endif }; @@ -244,12 +273,6 @@ static uint8_t hidReportRefKeyIn[HID_REPORT_REF_LEN] = static uint8_t hidReportRefLedOut[HID_REPORT_REF_LEN] = { HID_RPT_ID_LED_OUT, HID_REPORT_TYPE_OUTPUT }; -#if (SUPPORT_REPORT_VENDOR == true) - -static uint8_t hidReportRefVendorOut[HID_REPORT_REF_LEN] = - {HID_RPT_ID_VENDOR_OUT, HID_REPORT_TYPE_OUTPUT}; -#endif - // HID Report Reference characteristic descriptor, Feature static uint8_t hidReportRefFeature[HID_REPORT_REF_LEN] = { HID_RPT_ID_FEATURE, HID_REPORT_TYPE_FEATURE }; @@ -446,21 +469,6 @@ static esp_gatts_attr_db_t hidd_le_gatt_db[HIDD_LE_IDX_NB] = ESP_GATT_PERM_READ, sizeof(hidReportRefMouseIn), sizeof(hidReportRefMouseIn), hidReportRefMouseIn}}, -#if (SUPPORT_REPORT_VENDOR == true) - // Report Characteristic Declaration - [HIDD_LE_IDX_REPORT_VENDOR_OUT_CHAR] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, - ESP_GATT_PERM_READ, - CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, - (uint8_t *)&char_prop_read_write_notify}}, - [HIDD_LE_IDX_REPORT_VENDOR_OUT_VAL] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&hid_report_uuid, - ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE, - HIDD_LE_REPORT_MAX_LEN, 0, - NULL}}, - [HIDD_LE_IDX_REPORT_VENDOR_OUT_REP_REF] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&hid_report_ref_descr_uuid, - ESP_GATT_PERM_READ, - sizeof(hidReportRefVendorOut), sizeof(hidReportRefVendorOut), - hidReportRefVendorOut}}, -#endif // Report Characteristic Declaration [HIDD_LE_IDX_REPORT_CC_IN_CHAR] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ, @@ -607,16 +615,6 @@ void esp_hidd_prf_cb_hdl(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, cb_param.vendor_write.data = param->write.value; (hidd_le_env.hidd_cb)(ESP_HIDD_EVENT_BLE_LED_OUT_WRITE_EVT, &cb_param); } -#if (SUPPORT_REPORT_VENDOR == true) - if (param->write.handle == hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_REPORT_VENDOR_OUT_VAL] && - hidd_le_env.hidd_cb != NULL) {; - cb_param.vendor_write.conn_id = param->write.conn_id; - cb_param.vendor_write.report_id = HID_RPT_ID_VENDOR_OUT; - cb_param.vendor_write.length = param->write.len; - cb_param.vendor_write.data = param->write.value; - (hidd_le_env.hidd_cb)(ESP_HIDD_EVENT_BLE_VENDOR_REPORT_WRITE_EVT, &cb_param); - } -#endif break; } case ESP_GATTS_CREAT_ATTR_TAB_EVT: { diff --git a/main/hidd_le_prf_int.h b/main/hidd_le_prf_int.h index fbfa1f6..5176f30 100644 --- a/main/hidd_le_prf_int.h +++ b/main/hidd_le_prf_int.h @@ -23,7 +23,6 @@ #include "esp_gap_ble_api.h" #include "hid_dev.h" -#define SUPPORT_REPORT_VENDOR false //HID BLE profile log tag #define HID_LE_PRF_TAG "HID_LE_PRF" @@ -140,12 +139,6 @@ enum { HIDD_LE_IDX_REPORT_LED_OUT_VAL, HIDD_LE_IDX_REPORT_LED_OUT_REP_REF, -#if (SUPPORT_REPORT_VENDOR == true) - /// Report Vendor - HIDD_LE_IDX_REPORT_VENDOR_OUT_CHAR, - HIDD_LE_IDX_REPORT_VENDOR_OUT_VAL, - HIDD_LE_IDX_REPORT_VENDOR_OUT_REP_REF, -#endif HIDD_LE_IDX_REPORT_CC_IN_CHAR, HIDD_LE_IDX_REPORT_CC_IN_VAL, HIDD_LE_IDX_REPORT_CC_IN_CCC, From 68c72b83034e761fd2b55a496c39f835153f9d49 Mon Sep 17 00:00:00 2001 From: beni Date: Wed, 7 Sep 2022 12:37:05 +0200 Subject: [PATCH 02/15] Added high level functions to send the joystick report; added comments in hidd api --- main/esp_hidd_prf_api.c | 49 +++++++++++++++++++++++++++++++++++++ main/esp_hidd_prf_api.h | 54 +++++++++++++++++++++++++++++++++++++++++ main/hidd_le_prf_int.h | 4 +-- 3 files changed, 105 insertions(+), 2 deletions(-) diff --git a/main/esp_hidd_prf_api.c b/main/esp_hidd_prf_api.c index 4fa5ed2..0d91b50 100644 --- a/main/esp_hidd_prf_api.c +++ b/main/esp_hidd_prf_api.c @@ -28,6 +28,9 @@ // HID mouse input report length #define HID_MOUSE_IN_RPT_LEN 5 +// HID joystick input report length +#define HID_JOYSTICK_IN_RPT_LEN 11 + // HID consumer control input report length #define HID_CC_IN_RPT_LEN 2 @@ -152,5 +155,51 @@ void esp_hidd_send_mouse_value(uint16_t conn_id, uint8_t mouse_button, int8_t mi return; } +#if CONFIG_MODULE_USEJOYSTICK +/** + * + * @brief Send a Joystick report, set individual axis + * + * @param conn_id HID over GATT connection ID to be used. + * @param x,y,z,rz,rx,ry Individual gamepad axis + * @param hat Hat switch status. Send 0 for rest/middleposition; 1-8 to for a direction. + * @param buttons Button bitmap, button 0 is bit 0 and so on. + */ +void esp_hidd_send_joy_value(uint16_t conn_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) +{ + uint8_t data[HID_JOYSTICK_IN_RPT_LEN] = {0}; + + //build axis into array + data[0] = x; + data[1] = y; + data[2] = z; + data[3] = rz; + data[4] = rx; + data[5] = ry; + + //add hat & buttons + data[6] = hat; + data[7] = (uint8_t)(buttons & 0xFF); + data[8] = (uint8_t)((buttons>>8) & 0xFF); + data[9] = (uint8_t)((buttons>>16) & 0xFF); + data[10] = (uint8_t)((buttons>>24) & 0xFF); + + //use other joystick function to send data + esp_hidd_send_joy_report(conn_id, data); +} +/** + * + * @brief Send a Joystick report, use a byte array + * + * @param conn_id HID over GATT connection ID to be used. + * @param report Pointer to a 11 Byte sized array which contains the full joystick/gamepad report + * @warning This function reads 11 Bytes and sends them without checks. + */ +void esp_hidd_send_joy_report(uint16_t conn_id, uint8_t *report) +{ + hid_dev_send_report(hidd_le_env.gatt_if, conn_id, + HID_RPT_ID_JOY_IN, HID_REPORT_TYPE_INPUT, HID_JOYSTICK_IN_RPT_LEN, report); +} +#endif diff --git a/main/esp_hidd_prf_api.h b/main/esp_hidd_prf_api.h index d40e01f..4144a84 100644 --- a/main/esp_hidd_prf_api.h +++ b/main/esp_hidd_prf_api.h @@ -165,12 +165,66 @@ esp_err_t esp_hidd_profile_deinit(void); */ uint16_t esp_hidd_get_version(void); +/** + * + * @brief Send consumer keys. + * + * @param conn_id HID over GATT connection ID to be used. + * @param key_cmd Type of consumer key, use defines like HID_CONSUMER_xx (e.g. HID_CONSUMER_MUTE) + * @param key_pressed True / False if key should be pressed or not. + * + */ void esp_hidd_send_consumer_value(uint16_t conn_id, uint8_t key_cmd, bool key_pressed); +/** + * + * @brief Send a keyboard report. + * + * @param conn_id HID over GATT connection ID to be used. + * @param special_key_mask All special keys (Alt / Shift / CTRL) in one byte + * @param keyboard_cmd Array of keycodes to be sent + * @param num_key Count of keycodes in keyboard_cmd which should be sent. + * + */ void esp_hidd_send_keyboard_value(uint16_t conn_id, key_mask_t special_key_mask, uint8_t *keyboard_cmd, uint8_t num_key); +/** + * + * @brief Send a Mouse report. + * + * @param conn_id HID over GATT connection ID to be used. + * @param mouse_button Mouse button values, 1 is pressed, 0 is released. bit 0: left, bit 1: right, bit 2: middle button + * @param mickeys_x relative X axis movement + * @param mickeys_y relative Y axis movement + * @param wheel relative mouse wheel movement + */ void esp_hidd_send_mouse_value(uint16_t conn_id, uint8_t mouse_button, int8_t mickeys_x, int8_t mickeys_y, int8_t wheel); + +#if CONFIG_MODULE_USEJOYSTICK +/** + * + * @brief Send a Joystick report, set individual axis + * + * @param conn_id HID over GATT connection ID to be used. + * @param x,y,z,rz,rx,ry Individual gamepad axis + * @param hat Hat switch status. Send 0 for rest/middleposition; 1-8 to for a direction. + * @param buttons Button bitmap, button 0 is bit 0 and so on. + */ +void esp_hidd_send_joy_value(uint16_t conn_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons); + +/** + * + * @brief Send a Joystick report, use a byte array + * + * @param conn_id HID over GATT connection ID to be used. + * @param report Pointer to a 11 Byte sized array which contains the full joystick/gamepad report + * @warning This function reads 11 Bytes and sends them without checks. + */ +void esp_hidd_send_joy_report(uint16_t conn_id, uint8_t *report); + +#endif + #ifdef __cplusplus } #endif diff --git a/main/hidd_le_prf_int.h b/main/hidd_le_prf_int.h index 5176f30..d15f5a6 100644 --- a/main/hidd_le_prf_int.h +++ b/main/hidd_le_prf_int.h @@ -46,9 +46,9 @@ // HID Report IDs for the service #define HID_RPT_ID_KEY_IN 1 // Keyboard input report ID -#define HID_RPT_ID_CC_IN 2 //Consumer Control input report ID +#define HID_RPT_ID_CC_IN 2 // Consumer Control input report ID #define HID_RPT_ID_MOUSE_IN 3 // Mouse input report ID -#define HID_RPT_ID_VENDOR_OUT 4 // Vendor output report ID +#define HID_RPT_ID_JOY_IN 4 // Joystick input report ID #define HID_RPT_ID_LED_OUT 1 // LED output report ID #define HID_RPT_ID_FEATURE 0 // Feature report ID From 4e6a9573947c897d203d89cedd7acef38f71af9d Mon Sep 17 00:00:00 2001 From: beni Date: Wed, 7 Sep 2022 12:53:08 +0200 Subject: [PATCH 03/15] Added joystick functions in main code; added API in README --- README.md | 14 ++++++++++---- main/ble_hidd_demo_main.c | 16 ++++++++++------ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 212eece..e30fda8 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ With `idf.py -p (PORT) flash` or `make flash` you can upload this build to an ES With `idf.py -p (PORT) monitor` or `make monitor` you can see the debug output (please use this output if you open an issue) or trigger basic test commands (mouse movement or a keyboard key press) on a connected target. - + # Usage via Console or second UART ## Control via stdin (make monitor) @@ -104,7 +104,14 @@ _Note:_ currently we only support the US keyboard layout. |Byte 0|Byte 1|Byte 2|Byte 3|Byte 4|Byte 5|Byte 6|Byte 7|Byte 8| |------|------|------|------|------|------|------|------|------| -| 0xFD | modifier mask | don't care | keycode 1 | keycode 2 | keycode 3 | keycode 4 | keycode 5 | keycode 6 | +| 0xFD | modifier mask | 0x00 | keycode 1 | keycode 2 | keycode 3 | keycode 4 | keycode 5 | keycode 6 | + +__Joystick:__ + + +|Byte 0|Byte 1|Byte 2|Byte 3-8|Byte 9|Byte 10|Byte 11|Byte 12|Byte 13| +|------|------|------|------|------|------|------|------|------| +| 0xFD | don't care | 0x01 | X,Y,Z,Rz,Rx,Ry axis (each _int8_t_) | hat switch (0 is rest position; 1-8 are directions) | buttons 0-7 | buttons 8-15 | buttons 16-23 | buttons 24-31 | ## RAW HID input from sourcecode @@ -128,7 +135,6 @@ Please use the functions provided by `esp_hidd_prf_api.c`. - Paul Stoffregen for the implementation of the keyboard layouts for his Teensyduino project: www.pjrc.com - Neil Kolban for his great contributions to the ESP32 SW (in particular the Bluetooth support): https://github.com/nkolban - Chegewara for help and support - -and to Espressif for providing the HID implementation within the esp-idf. +and to Espressif for providing the HID implementation within the esp-idf. diff --git a/main/ble_hidd_demo_main.c b/main/ble_hidd_demo_main.c index e6d6816..8af2b0c 100644 --- a/main/ble_hidd_demo_main.c +++ b/main/ble_hidd_demo_main.c @@ -935,9 +935,9 @@ void uart_parse_command (uint8_t character, struct cmdBuf * cmdBuffer) case CMDSTATE_GET_RAW: cmdBuffer->buf[cmdBuffer->bufferLength]=character; - if ((cmdBuffer->bufferLength == 1) && (character==0x01)) { // we have a joystick report: increase by 4 bytes - cmdBuffer->expectedBytes += 6; - //ESP_LOGI(EXT_UART_TAG,"expecting 4 more bytes for joystick"); + if ((cmdBuffer->bufferLength == 1) && (character==0x01)) { // we have a joystick report: increase by 5 bytes + cmdBuffer->expectedBytes += 5; + //ESP_LOGI(EXT_UART_TAG,"expecting 5 more bytes for joystick"); } cmdBuffer->bufferLength++; @@ -962,9 +962,13 @@ void uart_parse_command (uint8_t character, struct cmdBuf * cmdBuffer) timestampLastSent = esp_timer_get_time(); } else if (cmdBuffer->buf[1] == 0x01) { // joystick report //ESP_LOGI(EXT_UART_TAG,"joystick: buttons: 0x%X:0x%X:0x%X:0x%X",cmdBuffer->buf[2],cmdBuffer->buf[3],cmdBuffer->buf[4],cmdBuffer->buf[5]); - //uint8_t joy[HID_JOYSTICK_IN_RPT_LEN]; - //memcpy(joy,&cmdBuffer->buf[2],HID_JOYSTICK_IN_RPT_LEN); - ///@todo esp_hidd_send_joystick_value... + uint8_t joy[HID_JOYSTICK_IN_RPT_LEN]; + memcpy(joy,&cmdBuffer->buf[2],HID_JOYSTICK_IN_RPT_LEN); + //send joystick report + for(uint8_t i = 0; ibuf[1] == 0x03) { // mouse report if(hid_conn_id == -1) { From 346ab7ffa49ce6397660cbd14018f285c3b50bfb Mon Sep 17 00:00:00 2001 From: beni Date: Mon, 5 Sep 2022 15:31:22 +0200 Subject: [PATCH 04/15] Added joystick to HID report map; removed SUPPORT_VENDOR --- main/Kconfig.projbuild | 8 ++-- main/ble_hidd_demo_main.c | 5 +-- main/hid_device_le_prf.c | 86 +++++++++++++++++++-------------------- main/hidd_le_prf_int.h | 7 ---- 4 files changed, 48 insertions(+), 58 deletions(-) diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 34e84f0..8f66758 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -31,14 +31,14 @@ menu "esp32_mouse_keyboard / FLipMouse & FABI config" range 1 2 endmenu config MODULE_USEKEYBOARD - bool "Enable BLE-HID keyboard (UNUSED)" + bool "Enable BLE-HID keyboard (UNUSED, mouse is always enabled)" default y help Enable the Keyboard interface for Bluetooth. config MODULE_USEMOUSE depends on MODULE_USEKEYBOARD - bool "Enable BLE-HID mouse (UNUSED)" + bool "Enable BLE-HID mouse (UNUSED, kbd is always enabled)" default y help Enable the Mouse interface for Bluetooth. @@ -54,8 +54,8 @@ menu "esp32_mouse_keyboard / FLipMouse & FABI config" config MODULE_USEJOYSTICK depends on MODULE_USEMOUSE - bool "Enable BLE-HID joystick (UNUSED)" - default n + bool "Enable BLE-HID joystick" + default y help Enable the Joystick interface for Bluetooth. diff --git a/main/ble_hidd_demo_main.c b/main/ble_hidd_demo_main.c index f35c9ef..0f6b571 100644 --- a/main/ble_hidd_demo_main.c +++ b/main/ble_hidd_demo_main.c @@ -76,10 +76,9 @@ /** * Note: - * 1. Win10 does not support vendor report , So SUPPORT_REPORT_VENDOR is always set to FALSE, it defines in hidd_le_prf_int.h - * 2. Update connection parameters are not allowed during iPhone HID encryption, slave turns + * 1. Update connection parameters are not allowed during iPhone HID encryption, slave turns * off the ability to automatically update connection parameters during encryption. - * 3. After our HID device is connected, the iPhones write 1 to the Report Characteristic Configuration Descriptor, + * 2. After our HID device is connected, the iPhones write 1 to the Report Characteristic Configuration Descriptor, * even if the HID encryption is not completed. This should actually be written 1 after the HID encryption is completed. * we modify the permissions of the Report Characteristic Configuration Descriptor to `ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE_ENCRYPTED`. * if you got `GATT_INSUF_ENCRYPTION` error, please ignore. diff --git a/main/hid_device_le_prf.c b/main/hid_device_le_prf.c index 1495b94..e21489f 100644 --- a/main/hid_device_le_prf.c +++ b/main/hid_device_le_prf.c @@ -139,7 +139,7 @@ static const uint8_t hidReportMap[] = { 0x81, 0x00, // Input (Data, Ary, Abs) 0xC0, // End Collection 0x81, 0x03, // Input (Const, Var, Abs) - 0xC0, // End Collectionq + 0xC0, // End Collection 0x05, 0x01, // Usage Page (Generic Desktop) @@ -171,18 +171,47 @@ static const uint8_t hidReportMap[] = { 0xC0, // End Collection 0xC0, // End Collection -#if (SUPPORT_REPORT_VENDOR == true) - 0x06, 0xFF, 0xFF, // Usage Page(Vendor defined) - 0x09, 0xA5, // Usage(Vendor Defined) - 0xA1, 0x01, // Collection(Application) - 0x85, 0x04, // Report Id (4) - 0x09, 0xA6, // Usage(Vendor defined) - 0x09, 0xA9, // Usage(Vendor defined) - 0x75, 0x08, // Report Size - 0x95, 0x7F, // Report Count = 127 Btyes - 0x91, 0x02, // Output(Data, Variable, Absolute) - 0xC0, // End Collection -#endif + #if CONFIG_MODULE_USEJOYSTICK + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x05, // Usage (Gamepad) + 0xA1, 0x01, // Collection (Application) + 0x85, 0x04, // Report Id (4) + /* 8 bit X, Y, Z, Rz, Rx, Ry (min -127, max 127 ) */ + /* implemented like Gamepad from tinyUSB */ + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x30, // Usage (desktop X) + 0x09, 0x31, // Usage (desktop Y) + 0x09, 0x32, // Usage (desktop Z) + 0x09, 0x35, // Usage (desktop RZ) + 0x09, 0x33, // Usage (desktop RX) + 0x09, 0x34, // Usage (desktop RY) + 0x15, 0x81, // Logical Minimum (-127) + 0x25, 0x7F, // Logical Maximum (127) + 0x95, 0x06, // Report Count (6) + 0x75, 0x08, // Report Size (8) + 0x81, 0x02, // Input: (Data, Variable, Absolute) + /* 8 bit DPad/Hat Button Map */ + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x39, // Usage (hat switch) + 0x15, 0x01, // Logical Min (1) + 0x25, 0x08, // Logical Max (8) + + 0x35, 0x00, // Physical minimum (0) + 0x46, 0x00, // Physical maximum (315, size 2) + 0x95, 0x06, // Report Count (1) + 0x75, 0x08, // Report Size (8) + 0x81, 0x02, // Input: (Data, Variable, Absolute) + /* 16 bit Button Map */ + 0x05, 0x09, // Usage Page (button) + 0x19, 0x01, // Usage Minimum (01) - Button 1 + 0x29, 0x20, // Usage Maximum (32) - Button 2 + 0x15, 0x00, // Logical Min (0) + 0x25, 0x01, // Logical Max (1) + 0x95, 0x20, // Report Count (32) + 0x75, 0x01, // Report Size (1) + 0x81, 0x02, // Input: (Data, Variable, Absolute) + 0xC0, // End Collection + #endif }; @@ -244,12 +273,6 @@ static uint8_t hidReportRefKeyIn[HID_REPORT_REF_LEN] = static uint8_t hidReportRefLedOut[HID_REPORT_REF_LEN] = { HID_RPT_ID_LED_OUT, HID_REPORT_TYPE_OUTPUT }; -#if (SUPPORT_REPORT_VENDOR == true) - -static uint8_t hidReportRefVendorOut[HID_REPORT_REF_LEN] = - {HID_RPT_ID_VENDOR_OUT, HID_REPORT_TYPE_OUTPUT}; -#endif - // HID Report Reference characteristic descriptor, Feature static uint8_t hidReportRefFeature[HID_REPORT_REF_LEN] = { HID_RPT_ID_FEATURE, HID_REPORT_TYPE_FEATURE }; @@ -446,21 +469,6 @@ static esp_gatts_attr_db_t hidd_le_gatt_db[HIDD_LE_IDX_NB] = ESP_GATT_PERM_READ, sizeof(hidReportRefMouseIn), sizeof(hidReportRefMouseIn), hidReportRefMouseIn}}, -#if (SUPPORT_REPORT_VENDOR == true) - // Report Characteristic Declaration - [HIDD_LE_IDX_REPORT_VENDOR_OUT_CHAR] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, - ESP_GATT_PERM_READ, - CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, - (uint8_t *)&char_prop_read_write_notify}}, - [HIDD_LE_IDX_REPORT_VENDOR_OUT_VAL] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&hid_report_uuid, - ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE, - HIDD_LE_REPORT_MAX_LEN, 0, - NULL}}, - [HIDD_LE_IDX_REPORT_VENDOR_OUT_REP_REF] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&hid_report_ref_descr_uuid, - ESP_GATT_PERM_READ, - sizeof(hidReportRefVendorOut), sizeof(hidReportRefVendorOut), - hidReportRefVendorOut}}, -#endif // Report Characteristic Declaration [HIDD_LE_IDX_REPORT_CC_IN_CHAR] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ, @@ -607,16 +615,6 @@ void esp_hidd_prf_cb_hdl(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, cb_param.vendor_write.data = param->write.value; (hidd_le_env.hidd_cb)(ESP_HIDD_EVENT_BLE_LED_OUT_WRITE_EVT, &cb_param); } -#if (SUPPORT_REPORT_VENDOR == true) - if (param->write.handle == hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_REPORT_VENDOR_OUT_VAL] && - hidd_le_env.hidd_cb != NULL) {; - cb_param.vendor_write.conn_id = param->write.conn_id; - cb_param.vendor_write.report_id = HID_RPT_ID_VENDOR_OUT; - cb_param.vendor_write.length = param->write.len; - cb_param.vendor_write.data = param->write.value; - (hidd_le_env.hidd_cb)(ESP_HIDD_EVENT_BLE_VENDOR_REPORT_WRITE_EVT, &cb_param); - } -#endif break; } case ESP_GATTS_CREAT_ATTR_TAB_EVT: { diff --git a/main/hidd_le_prf_int.h b/main/hidd_le_prf_int.h index fbfa1f6..5176f30 100644 --- a/main/hidd_le_prf_int.h +++ b/main/hidd_le_prf_int.h @@ -23,7 +23,6 @@ #include "esp_gap_ble_api.h" #include "hid_dev.h" -#define SUPPORT_REPORT_VENDOR false //HID BLE profile log tag #define HID_LE_PRF_TAG "HID_LE_PRF" @@ -140,12 +139,6 @@ enum { HIDD_LE_IDX_REPORT_LED_OUT_VAL, HIDD_LE_IDX_REPORT_LED_OUT_REP_REF, -#if (SUPPORT_REPORT_VENDOR == true) - /// Report Vendor - HIDD_LE_IDX_REPORT_VENDOR_OUT_CHAR, - HIDD_LE_IDX_REPORT_VENDOR_OUT_VAL, - HIDD_LE_IDX_REPORT_VENDOR_OUT_REP_REF, -#endif HIDD_LE_IDX_REPORT_CC_IN_CHAR, HIDD_LE_IDX_REPORT_CC_IN_VAL, HIDD_LE_IDX_REPORT_CC_IN_CCC, From e2819fc8b0cf41394b1a7632e6ba8d70edcf0d40 Mon Sep 17 00:00:00 2001 From: beni Date: Wed, 7 Sep 2022 12:37:05 +0200 Subject: [PATCH 05/15] Added high level functions to send the joystick report; added comments in hidd api --- main/esp_hidd_prf_api.c | 49 +++++++++++++++++++++++++++++++++++++ main/esp_hidd_prf_api.h | 54 +++++++++++++++++++++++++++++++++++++++++ main/hidd_le_prf_int.h | 4 +-- 3 files changed, 105 insertions(+), 2 deletions(-) diff --git a/main/esp_hidd_prf_api.c b/main/esp_hidd_prf_api.c index 4fa5ed2..0d91b50 100644 --- a/main/esp_hidd_prf_api.c +++ b/main/esp_hidd_prf_api.c @@ -28,6 +28,9 @@ // HID mouse input report length #define HID_MOUSE_IN_RPT_LEN 5 +// HID joystick input report length +#define HID_JOYSTICK_IN_RPT_LEN 11 + // HID consumer control input report length #define HID_CC_IN_RPT_LEN 2 @@ -152,5 +155,51 @@ void esp_hidd_send_mouse_value(uint16_t conn_id, uint8_t mouse_button, int8_t mi return; } +#if CONFIG_MODULE_USEJOYSTICK +/** + * + * @brief Send a Joystick report, set individual axis + * + * @param conn_id HID over GATT connection ID to be used. + * @param x,y,z,rz,rx,ry Individual gamepad axis + * @param hat Hat switch status. Send 0 for rest/middleposition; 1-8 to for a direction. + * @param buttons Button bitmap, button 0 is bit 0 and so on. + */ +void esp_hidd_send_joy_value(uint16_t conn_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) +{ + uint8_t data[HID_JOYSTICK_IN_RPT_LEN] = {0}; + + //build axis into array + data[0] = x; + data[1] = y; + data[2] = z; + data[3] = rz; + data[4] = rx; + data[5] = ry; + + //add hat & buttons + data[6] = hat; + data[7] = (uint8_t)(buttons & 0xFF); + data[8] = (uint8_t)((buttons>>8) & 0xFF); + data[9] = (uint8_t)((buttons>>16) & 0xFF); + data[10] = (uint8_t)((buttons>>24) & 0xFF); + + //use other joystick function to send data + esp_hidd_send_joy_report(conn_id, data); +} +/** + * + * @brief Send a Joystick report, use a byte array + * + * @param conn_id HID over GATT connection ID to be used. + * @param report Pointer to a 11 Byte sized array which contains the full joystick/gamepad report + * @warning This function reads 11 Bytes and sends them without checks. + */ +void esp_hidd_send_joy_report(uint16_t conn_id, uint8_t *report) +{ + hid_dev_send_report(hidd_le_env.gatt_if, conn_id, + HID_RPT_ID_JOY_IN, HID_REPORT_TYPE_INPUT, HID_JOYSTICK_IN_RPT_LEN, report); +} +#endif diff --git a/main/esp_hidd_prf_api.h b/main/esp_hidd_prf_api.h index d40e01f..4144a84 100644 --- a/main/esp_hidd_prf_api.h +++ b/main/esp_hidd_prf_api.h @@ -165,12 +165,66 @@ esp_err_t esp_hidd_profile_deinit(void); */ uint16_t esp_hidd_get_version(void); +/** + * + * @brief Send consumer keys. + * + * @param conn_id HID over GATT connection ID to be used. + * @param key_cmd Type of consumer key, use defines like HID_CONSUMER_xx (e.g. HID_CONSUMER_MUTE) + * @param key_pressed True / False if key should be pressed or not. + * + */ void esp_hidd_send_consumer_value(uint16_t conn_id, uint8_t key_cmd, bool key_pressed); +/** + * + * @brief Send a keyboard report. + * + * @param conn_id HID over GATT connection ID to be used. + * @param special_key_mask All special keys (Alt / Shift / CTRL) in one byte + * @param keyboard_cmd Array of keycodes to be sent + * @param num_key Count of keycodes in keyboard_cmd which should be sent. + * + */ void esp_hidd_send_keyboard_value(uint16_t conn_id, key_mask_t special_key_mask, uint8_t *keyboard_cmd, uint8_t num_key); +/** + * + * @brief Send a Mouse report. + * + * @param conn_id HID over GATT connection ID to be used. + * @param mouse_button Mouse button values, 1 is pressed, 0 is released. bit 0: left, bit 1: right, bit 2: middle button + * @param mickeys_x relative X axis movement + * @param mickeys_y relative Y axis movement + * @param wheel relative mouse wheel movement + */ void esp_hidd_send_mouse_value(uint16_t conn_id, uint8_t mouse_button, int8_t mickeys_x, int8_t mickeys_y, int8_t wheel); + +#if CONFIG_MODULE_USEJOYSTICK +/** + * + * @brief Send a Joystick report, set individual axis + * + * @param conn_id HID over GATT connection ID to be used. + * @param x,y,z,rz,rx,ry Individual gamepad axis + * @param hat Hat switch status. Send 0 for rest/middleposition; 1-8 to for a direction. + * @param buttons Button bitmap, button 0 is bit 0 and so on. + */ +void esp_hidd_send_joy_value(uint16_t conn_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons); + +/** + * + * @brief Send a Joystick report, use a byte array + * + * @param conn_id HID over GATT connection ID to be used. + * @param report Pointer to a 11 Byte sized array which contains the full joystick/gamepad report + * @warning This function reads 11 Bytes and sends them without checks. + */ +void esp_hidd_send_joy_report(uint16_t conn_id, uint8_t *report); + +#endif + #ifdef __cplusplus } #endif diff --git a/main/hidd_le_prf_int.h b/main/hidd_le_prf_int.h index 5176f30..d15f5a6 100644 --- a/main/hidd_le_prf_int.h +++ b/main/hidd_le_prf_int.h @@ -46,9 +46,9 @@ // HID Report IDs for the service #define HID_RPT_ID_KEY_IN 1 // Keyboard input report ID -#define HID_RPT_ID_CC_IN 2 //Consumer Control input report ID +#define HID_RPT_ID_CC_IN 2 // Consumer Control input report ID #define HID_RPT_ID_MOUSE_IN 3 // Mouse input report ID -#define HID_RPT_ID_VENDOR_OUT 4 // Vendor output report ID +#define HID_RPT_ID_JOY_IN 4 // Joystick input report ID #define HID_RPT_ID_LED_OUT 1 // LED output report ID #define HID_RPT_ID_FEATURE 0 // Feature report ID From bb40781b5f267ba57171ef58ac0ffcd559b7a1ba Mon Sep 17 00:00:00 2001 From: beni Date: Wed, 7 Sep 2022 12:53:08 +0200 Subject: [PATCH 06/15] Added joystick functions in main code; added API in README --- README.md | 12 +++++++++--- main/ble_hidd_demo_main.c | 16 ++++++++++------ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 678aaf8..f4891a8 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,14 @@ _Note:_ currently we only support the US keyboard layout. |Byte 0|Byte 1|Byte 2|Byte 3|Byte 4|Byte 5|Byte 6|Byte 7|Byte 8| |------|------|------|------|------|------|------|------|------| -| 0xFD | modifier mask | don't care | keycode 1 | keycode 2 | keycode 3 | keycode 4 | keycode 5 | keycode 6 | +| 0xFD | modifier mask | 0x00 | keycode 1 | keycode 2 | keycode 3 | keycode 4 | keycode 5 | keycode 6 | + +__Joystick:__ + + +|Byte 0|Byte 1|Byte 2|Byte 3-8|Byte 9|Byte 10|Byte 11|Byte 12|Byte 13| +|------|------|------|------|------|------|------|------|------| +| 0xFD | don't care | 0x01 | X,Y,Z,Rz,Rx,Ry axis (each _int8_t_) | hat switch (0 is rest position; 1-8 are directions) | buttons 0-7 | buttons 8-15 | buttons 16-23 | buttons 24-31 | ## RAW HID input from sourcecode @@ -138,7 +145,6 @@ Please use the functions provided by `esp_hidd_prf_api.c`. - Paul Stoffregen for the implementation of the keyboard layouts for his Teensyduino project: www.pjrc.com - Neil Kolban for his great contributions to the ESP32 SW (in particular the Bluetooth support): https://github.com/nkolban - Chegewara for help and support - -and to Espressif for providing the HID implementation within the esp-idf. +and to Espressif for providing the HID implementation within the esp-idf. diff --git a/main/ble_hidd_demo_main.c b/main/ble_hidd_demo_main.c index 0f6b571..792a7c3 100644 --- a/main/ble_hidd_demo_main.c +++ b/main/ble_hidd_demo_main.c @@ -998,9 +998,9 @@ void uart_parse_command (uint8_t character, struct cmdBuf * cmdBuffer) case CMDSTATE_GET_RAW: cmdBuffer->buf[cmdBuffer->bufferLength]=character; - if ((cmdBuffer->bufferLength == 1) && (character==0x01)) { // we have a joystick report: increase by 4 bytes - cmdBuffer->expectedBytes += 6; - //ESP_LOGI(EXT_UART_TAG,"expecting 4 more bytes for joystick"); + if ((cmdBuffer->bufferLength == 1) && (character==0x01)) { // we have a joystick report: increase by 5 bytes + cmdBuffer->expectedBytes += 5; + //ESP_LOGI(EXT_UART_TAG,"expecting 5 more bytes for joystick"); } cmdBuffer->bufferLength++; @@ -1025,9 +1025,13 @@ void uart_parse_command (uint8_t character, struct cmdBuf * cmdBuffer) timestampLastSent = esp_timer_get_time(); } else if (cmdBuffer->buf[1] == 0x01) { // joystick report //ESP_LOGI(EXT_UART_TAG,"joystick: buttons: 0x%X:0x%X:0x%X:0x%X",cmdBuffer->buf[2],cmdBuffer->buf[3],cmdBuffer->buf[4],cmdBuffer->buf[5]); - //uint8_t joy[HID_JOYSTICK_IN_RPT_LEN]; - //memcpy(joy,&cmdBuffer->buf[2],HID_JOYSTICK_IN_RPT_LEN); - ///@todo esp_hidd_send_joystick_value... + uint8_t joy[HID_JOYSTICK_IN_RPT_LEN]; + memcpy(joy,&cmdBuffer->buf[2],HID_JOYSTICK_IN_RPT_LEN); + //send joystick report + for(uint8_t i = 0; ibuf[1] == 0x03) { // mouse report if(hid_conn_id == -1) { From daf9a4ad66fc7271ed7d93bbb766422ca55c123b Mon Sep 17 00:00:00 2001 From: Benjamin Aigner Date: Fri, 10 Feb 2023 09:37:48 +0100 Subject: [PATCH 07/15] Fixed compile error with joystick data array; enabled joystick in sdkconfig.defaults --- main/ble_hidd_demo_main.c | 5 +++-- sdkconfig.defaults | 6 ++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/main/ble_hidd_demo_main.c b/main/ble_hidd_demo_main.c index 792a7c3..92f6884 100644 --- a/main/ble_hidd_demo_main.c +++ b/main/ble_hidd_demo_main.c @@ -1025,8 +1025,9 @@ void uart_parse_command (uint8_t character, struct cmdBuf * cmdBuffer) timestampLastSent = esp_timer_get_time(); } else if (cmdBuffer->buf[1] == 0x01) { // joystick report //ESP_LOGI(EXT_UART_TAG,"joystick: buttons: 0x%X:0x%X:0x%X:0x%X",cmdBuffer->buf[2],cmdBuffer->buf[3],cmdBuffer->buf[4],cmdBuffer->buf[5]); - uint8_t joy[HID_JOYSTICK_IN_RPT_LEN]; - memcpy(joy,&cmdBuffer->buf[2],HID_JOYSTICK_IN_RPT_LEN); + //@todo should be HID_JOYSTICK_IN_RPT_LEN, but not available here. + uint8_t joy[11]; + memcpy(joy,&cmdBuffer->buf[2],11); //send joystick report for(uint8_t i = 0; i Date: Fri, 10 Feb 2023 13:31:35 +0100 Subject: [PATCH 08/15] Working bluetooth joystick & cleanup: -) added joystick axis & button to simple tests (keys 1,2,3,4) -) fixed log output of joystick report -) changed hid_add_id_tbl table creation, use variable as index -) fixe HIDD_LE_IDX_REPORT_JOY_IN_CHAR (and similar) enum, consumer control was on the wrong position --- main/ble_hidd_demo_main.c | 100 ++++++++++++++++++++++------- main/hid_dev.h | 4 -- main/hid_device_le_prf.c | 132 +++++++++++++++++++++++++------------- main/hidd_le_prf_int.h | 84 ++++++------------------ 4 files changed, 185 insertions(+), 135 deletions(-) diff --git a/main/ble_hidd_demo_main.c b/main/ble_hidd_demo_main.c index 92f6884..72a6327 100644 --- a/main/ble_hidd_demo_main.c +++ b/main/ble_hidd_demo_main.c @@ -1010,30 +1010,35 @@ void uart_parse_command (uint8_t character, struct cmdBuf * cmdBuffer) ESP_LOGI(EXT_UART_TAG,"not connected, cannot send report"); } else { if (cmdBuffer->buf[1] == 0x00) { // keyboard report - //if hid_conn_id is set (!= -1) we send to one device only. Send to all otherwise - if(hid_conn_id == -1) - { - for(uint8_t i = 0; ibuf[0],&cmdBuffer->buf[2],6); - } - } else { - esp_hidd_send_keyboard_value(hid_conn_id,cmdBuffer->buf[0],&cmdBuffer->buf[2],6); - } + //if hid_conn_id is set (!= -1) we send to one device only. Send to all otherwise + if(hid_conn_id == -1) + { + for(uint8_t i = 0; ibuf[0],&cmdBuffer->buf[2],6); + } + } else { + esp_hidd_send_keyboard_value(hid_conn_id,cmdBuffer->buf[0],&cmdBuffer->buf[2],6); + } - //update timestamp - timestampLastSent = esp_timer_get_time(); - } else if (cmdBuffer->buf[1] == 0x01) { // joystick report - //ESP_LOGI(EXT_UART_TAG,"joystick: buttons: 0x%X:0x%X:0x%X:0x%X",cmdBuffer->buf[2],cmdBuffer->buf[3],cmdBuffer->buf[4],cmdBuffer->buf[5]); - //@todo should be HID_JOYSTICK_IN_RPT_LEN, but not available here. - uint8_t joy[11]; - memcpy(joy,&cmdBuffer->buf[2],11); - //send joystick report - for(uint8_t i = 0; ibuf[1] == 0x03) { // mouse report + //update timestamp + timestampLastSent = esp_timer_get_time(); + } else if (cmdBuffer->buf[1] == 0x01) { // joystick report + ESP_LOGI(EXT_UART_TAG,"joystick: axis: 0x%X:0x%X:0x%X:0x%X, hat: %d",cmdBuffer->buf[2],cmdBuffer->buf[3],cmdBuffer->buf[4],cmdBuffer->buf[5],cmdBuffer->buf[8]); + ESP_LOGI(EXT_UART_TAG,"joystick: buttons: 0x%X:0x%X:0x%X:0x%X",cmdBuffer->buf[9],cmdBuffer->buf[10],cmdBuffer->buf[11],cmdBuffer->buf[12]); + //@todo should be HID_JOYSTICK_IN_RPT_LEN, but not available here. + uint8_t joy[11]; + memcpy(joy,&cmdBuffer->buf[2],11); + //send joystick report + #if CONFIG_MODULE_USEJOYSTICK + for(uint8_t i = 0; ibuf[1] == 0x03) { // mouse report if(hid_conn_id == -1) { for(uint8_t i = 0; i Date: Fri, 10 Feb 2023 15:30:39 +0100 Subject: [PATCH 09/15] Fixed joystick buttons --- main/hid_device_le_prf.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/main/hid_device_le_prf.c b/main/hid_device_le_prf.c index f2c75de..6c92f3b 100644 --- a/main/hid_device_le_prf.c +++ b/main/hid_device_le_prf.c @@ -197,14 +197,15 @@ static const uint8_t hidReportMap[] = { 0x25, 0x08, // Logical Max (8) 0x35, 0x00, // Physical minimum (0) - 0x46, 0x00, // Physical maximum (315, size 2) - 0x95, 0x06, // Report Count (1) + 0x46, 0x3B, 0x01, // Physical maximum (315, size 2) + //0x46, 0x00, // Physical maximum (315, size 2) + 0x95, 0x01, // Report Count (1) 0x75, 0x08, // Report Size (8) 0x81, 0x02, // Input: (Data, Variable, Absolute) /* 16 bit Button Map */ 0x05, 0x09, // Usage Page (button) 0x19, 0x01, // Usage Minimum (01) - Button 1 - 0x29, 0x20, // Usage Maximum (32) - Button 2 + 0x29, 0x20, // Usage Maximum (32) - Button 32 0x15, 0x00, // Logical Min (0) 0x25, 0x01, // Logical Max (1) 0x95, 0x20, // Report Count (32) From 42a6bb1a262cbf2cac24dcac386402211fbb00bb Mon Sep 17 00:00:00 2001 From: Benjamin Aigner Date: Fri, 10 Feb 2023 15:32:40 +0100 Subject: [PATCH 10/15] Changed version string --- main/config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/config.h b/main/config.h index 98f98d4..1940cc6 100644 --- a/main/config.h +++ b/main/config.h @@ -2,7 +2,7 @@ #ifndef _CONFIG_H_ #define _CONFIG_H_ -#define MODULE_ID "ESP32miniBT_v0.3.4" +#define MODULE_ID "ESP32miniBT_v0.3.5" #if CONFIG_USE_AS_FLIPMOUSE_FABI //this will be overwritten by FABI/FLipMouse/FLipPad firmware to correct From 03c5b2419a86f1467be54601670536553b8629a3 Mon Sep 17 00:00:00 2001 From: Benjamin Aigner Date: Wed, 15 Feb 2023 09:37:07 +0100 Subject: [PATCH 11/15] Stripped down HID report map; still no luck with win10 --- main/ble_hidd_demo_main.c | 44 ++++++++++++++++++++++++++++++++++++--- main/esp_hidd_prf_api.c | 16 +++++++++----- main/esp_hidd_prf_api.h | 2 -- main/hid_device_le_prf.c | 22 ++++++++++++++++---- main/hidd_le_prf_int.h | 3 ++- 5 files changed, 72 insertions(+), 15 deletions(-) diff --git a/main/ble_hidd_demo_main.c b/main/ble_hidd_demo_main.c index 72a6327..5f191da 100644 --- a/main/ble_hidd_demo_main.c +++ b/main/ble_hidd_demo_main.c @@ -421,6 +421,7 @@ static void hidd_event_callback(esp_hidd_cb_event_t event, esp_hidd_cb_param_t * xEventGroupSetBits(eventgroup_system,SYSTEM_CURRENTLY_ADVERTISING); break; } + /** case ESP_HIDD_EVENT_BLE_VENDOR_REPORT_WRITE_EVT: { ESP_LOGI(HID_DEMO_TAG, "%s, ESP_HIDD_EVENT_BLE_VENDOR_REPORT_WRITE_EVT", __func__); ESP_LOG_BUFFER_HEX(HID_DEMO_TAG, param->vendor_write.data, param->vendor_write.length); @@ -430,6 +431,7 @@ static void hidd_event_callback(esp_hidd_cb_event_t event, esp_hidd_cb_param_t * ESP_LOGI(HID_DEMO_TAG, "%s, ESP_HIDD_EVENT_BLE_LED_OUT_WRITE_EVT, keyboard LED value: %d", __func__, param->vendor_write.data[0]); break; } + */ case ESP_HIDD_EVENT_BLE_CONGEST: { if(param->congest.congested) @@ -555,6 +557,7 @@ void processCommand(struct cmdBuf *cmdBuffer) // $SW aabbccddeeff (select a BT addr to send the HID commands to) // $GC get connected devices // $NAME set name of bluetooth device + // $APx (0-4) Set the appearance value for advertising (0x03C0 - 0x03C4). See https://specificationrefs.bluetooth.com/assigned-values/Appearance%20Values.pdf page 8 // $GV get the value of the given key from NVS. Note: no spaces in ! max. key length: 15 // $SV set the value of the given key & store to NVS. Note: no spaces in ! // $CV clear all key/value pairs set with $SV @@ -569,6 +572,32 @@ void processCommand(struct cmdBuf *cmdBuffer) esp_ble_bond_dev_t * btdevlist; int counter; esp_err_t ret; + + /**++++ set BLE appearance ++++*/ + if(strncmp(input,"AP ", 2) == 0) + { + uint8_t appv = input[2] - '0'; + if(appv <= 4) + { + ESP_LOGI(EXT_UART_TAG,"setting appearance to NVS, will show on next reboot"); + nvs_set_u8(nvs_storage_h,"BLEAPPEAR",appv); + nvs_commit(nvs_storage_h); + if(cmdBuffer->sendToUART != 0) + { + uart_write_bytes(ext_uart_num, "AP:",strlen("AP:")); + uart_write_bytes(ext_uart_num, &input[2],1); + uart_write_bytes(ext_uart_num,nl,sizeof(nl)); //newline + } + } else { + ESP_LOGE(EXT_UART_TAG,"Cannot set appearance, value not correct. Use AP0 - AP4"); + if(cmdBuffer->sendToUART != 0) + { + uart_write_bytes(ext_uart_num, "AP:invalid number, AP0-AP4",strlen("AP:invalid number, AP0-AP4")); + uart_write_bytes(ext_uart_num,nl,sizeof(nl)); //newline + } + } + return; + } /**++++en-/disable logging++++*/ if(strcmp(input,"LG0") == 0) @@ -1499,6 +1528,15 @@ void app_main(void) ret = nvs_open("kvstorage", NVS_READWRITE, &nvs_storage_h); if(ret != ESP_OK) ESP_LOGE("MAIN","error opening NVS for key/value storage"); + //read the appearance value for advertising + uint8_t advapp; + ret = nvs_get_u8(nvs_storage_h,"BLEAPPEAR",&advapp); + if(ret == ESP_OK) + { + ESP_LOGI("MAIN","Setting appearance to 0x03C%d",advapp); + hidd_adv_data.appearance = 0x03C0 + advapp; + } + // Read config nvs_handle my_handle; ESP_LOGI("MAIN","loading configuration from NVS"); @@ -1527,9 +1565,9 @@ void app_main(void) ///clear the HID connection IDs&MACs for(uint8_t i = 0; i HID_KEYBOARD_IN_RPT_LEN - 2) { + //if (num_key > HID_KEYBOARD_IN_RPT_LEN - 2) { + ///@note Here without padding byte as well. + if (num_key > HID_KEYBOARD_IN_RPT_LEN - 1) { ESP_LOGE(HID_LE_PRF_TAG, "%s(), the number key should not be more than %d", __func__, HID_KEYBOARD_IN_RPT_LEN); return; } @@ -131,10 +134,13 @@ void esp_hidd_send_keyboard_value(uint16_t conn_id, key_mask_t special_key_mask, buffer[0] = special_key_mask; for (int i = 0; i < num_key; i++) { - buffer[i+2] = keyboard_cmd[i]; + ///@note start @1 instead of @2 with padding byte. + buffer[i+1] = keyboard_cmd[i]; } - ESP_LOGD(HID_LE_PRF_TAG, "the key vaule = %d,%d,%d, %d, %d, %d,%d, %d", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7]); + //ESP_LOGD(HID_LE_PRF_TAG, "the key value = %d,%d,%d, %d, %d, %d,%d, %d", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7]); + ///@note here is the padding byte removed as well. + ESP_LOGD(HID_LE_PRF_TAG, "the key value = %d,%d,%d, %d, %d, %d,%d", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6]); hid_dev_send_report(hidd_le_env.gatt_if, conn_id, HID_RPT_ID_KEY_IN, HID_REPORT_TYPE_INPUT, HID_KEYBOARD_IN_RPT_LEN, buffer); return; diff --git a/main/esp_hidd_prf_api.h b/main/esp_hidd_prf_api.h index 4144a84..afbd2b3 100644 --- a/main/esp_hidd_prf_api.h +++ b/main/esp_hidd_prf_api.h @@ -30,8 +30,6 @@ typedef enum { ESP_HIDD_EVENT_DEINIT_FINISH, ESP_HIDD_EVENT_BLE_CONNECT, ESP_HIDD_EVENT_BLE_DISCONNECT, - ESP_HIDD_EVENT_BLE_VENDOR_REPORT_WRITE_EVT, - ESP_HIDD_EVENT_BLE_LED_OUT_WRITE_EVT, ESP_HIDD_EVENT_BLE_CONGEST, } esp_hidd_cb_event_t; diff --git a/main/hid_device_le_prf.c b/main/hid_device_le_prf.c index 6c92f3b..043820b 100644 --- a/main/hid_device_le_prf.c +++ b/main/hid_device_le_prf.c @@ -54,9 +54,14 @@ static const uint8_t hidReportMap[] = { 0x81, 0x02, // Input: (Data, Variable, Absolute) // // Reserved byte + ///@todo do we need this reserved byte when removing the LED output? (if removed, the report must be adjusted as well!!!) + ///@note Will try, because 4 Bytes are necessary to save... + /** 0x95, 0x01, // Report Count (1) 0x75, 0x08, // Report Size (8) 0x81, 0x01, // Input: (Constant) + */ + /** // // LED report 0x95, 0x05, // Report Count (5) @@ -70,6 +75,7 @@ static const uint8_t hidReportMap[] = { 0x95, 0x01, // Report Count (1) 0x75, 0x03, // Report Size (3) 0x91, 0x01, // Output: (Constant) + **/ // // Key arrays (6 bytes) 0x95, 0x06, // Report Count (6) @@ -87,6 +93,7 @@ static const uint8_t hidReportMap[] = { 0x09, 0x01, // Usage (Consumer Control) 0xA1, 0x01, // Collection (Application) 0x85, 0x02, // Report Id (2) + /** 0x09, 0x02, // Usage (Numeric Key Pad) 0xA1, 0x02, // Collection (Logical) 0x05, 0x09, // Usage Pg (Button) @@ -98,6 +105,7 @@ static const uint8_t hidReportMap[] = { 0x95, 0x01, // Report Count (1) 0x81, 0x00, // Input (Data, Ary, Abs) 0xC0, // End Collection + **/ 0x05, 0x0C, // Usage Pg (Consumer Devices) 0x09, 0x86, // Usage (Channel) 0x15, 0xFF, // Logical Min (-1) @@ -244,7 +252,7 @@ struct gatts_profile_inst { hidd_le_env_t hidd_le_env; // HID report map length -uint16_t hidReportMapLen = sizeof(hidReportMap); +uint8_t hidReportMapLen = sizeof(hidReportMap); uint8_t hidProtocolMode = HID_PROTOCOL_MODE_REPORT; // HID report mapping table @@ -271,6 +279,7 @@ static uint8_t hidReportRefJoyIn[HID_REPORT_REF_LEN] = { HID_RPT_ID_JOY_IN, HID_REPORT_TYPE_INPUT }; #endif + // HID Report Reference characteristic descriptor, key input static uint8_t hidReportRefKeyIn[HID_REPORT_REF_LEN] = { HID_RPT_ID_KEY_IN, HID_REPORT_TYPE_INPUT }; @@ -440,13 +449,14 @@ static esp_gatts_attr_db_t hidd_le_gatt_db[HIDD_LE_IDX_NB] = ESP_GATT_PERM_READ, sizeof(hidReportRefKeyIn), sizeof(hidReportRefKeyIn), hidReportRefKeyIn}}, - +/** // Report Characteristic Declaration [HIDD_LE_IDX_REPORT_LED_OUT_CHAR] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ, CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_read_write_write_nr}}, + [HIDD_LE_IDX_REPORT_LED_OUT_VAL] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&hid_report_uuid, ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE, HIDD_LE_REPORT_MAX_LEN, 0, @@ -455,6 +465,7 @@ static esp_gatts_attr_db_t hidd_le_gatt_db[HIDD_LE_IDX_NB] = ESP_GATT_PERM_READ, sizeof(hidReportRefLedOut), sizeof(hidReportRefLedOut), hidReportRefLedOut}}, +**/ [HIDD_LE_IDX_REPORT_MOUSE_IN_CHAR] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ, @@ -634,7 +645,7 @@ void esp_hidd_prf_cb_hdl(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, case ESP_GATTS_CLOSE_EVT: break; case ESP_GATTS_WRITE_EVT: { - esp_hidd_cb_param_t cb_param = {0}; + /**esp_hidd_cb_param_t cb_param = {0}; if (param->write.handle == hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_REPORT_LED_OUT_VAL] && hidd_le_env.hidd_cb != NULL) { cb_param.vendor_write.conn_id = param->write.conn_id; @@ -642,7 +653,8 @@ void esp_hidd_prf_cb_hdl(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, cb_param.vendor_write.length = param->write.len; cb_param.vendor_write.data = param->write.value; (hidd_le_env.hidd_cb)(ESP_HIDD_EVENT_BLE_LED_OUT_WRITE_EVT, &cb_param); - } + }**/ + ESP_LOGE(HID_LE_PRF_TAG,"%s(), write evt, but no out report",__func__); break; } case ESP_GATTS_CREAT_ATTR_TAB_EVT: { @@ -821,12 +833,14 @@ static void hid_add_id_tbl(void) index++; // LED output report + /** hid_rpt_map[index].id = hidReportRefLedOut[0]; hid_rpt_map[index].type = hidReportRefLedOut[1]; hid_rpt_map[index].handle = hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_REPORT_LED_OUT_VAL]; hid_rpt_map[index].cccdHandle = 0; hid_rpt_map[index].mode = HID_PROTOCOL_MODE_REPORT; index++; + **/ // Mouse input report hid_rpt_map[index].id = hidReportRefMouseIn[0]; diff --git a/main/hidd_le_prf_int.h b/main/hidd_le_prf_int.h index 9da16ce..c2d0418 100644 --- a/main/hidd_le_prf_int.h +++ b/main/hidd_le_prf_int.h @@ -139,10 +139,11 @@ enum { HIDD_LE_IDX_REPORT_KEY_IN_CCC, HIDD_LE_IDX_REPORT_KEY_IN_REP_REF, ///Report Led output + /** HIDD_LE_IDX_REPORT_LED_OUT_CHAR, HIDD_LE_IDX_REPORT_LED_OUT_VAL, HIDD_LE_IDX_REPORT_LED_OUT_REP_REF, - + **/ // Report mouse input HIDD_LE_IDX_REPORT_MOUSE_IN_CHAR, HIDD_LE_IDX_REPORT_MOUSE_IN_VAL, From 1f3de22dd521af09f137e7bd397913338a5d65c1 Mon Sep 17 00:00:00 2001 From: Benjamin Aigner Date: Wed, 15 Feb 2023 14:36:04 +0100 Subject: [PATCH 12/15] Fixed for esp-idf v4. Warning: this code does not work with idf v5 + windows, no idea why... --- main/ble_hidd_demo_main.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/main/ble_hidd_demo_main.c b/main/ble_hidd_demo_main.c index 72a6327..a26e44a 100644 --- a/main/ble_hidd_demo_main.c +++ b/main/ble_hidd_demo_main.c @@ -1126,9 +1126,13 @@ void uart_external_task(void *pvParameters) .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, - .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, - .source_clk = UART_SCLK_DEFAULT + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, }; + + #ifdef UART_SCLK_DEFAULT + #error "You are using esp-idf v5. This won't work with Windows. Use v4.x instead, or delete this line." + #endif + if(onArduinoRP2040) uart_config.baud_rate = 115200; //update UART config @@ -1205,6 +1209,9 @@ void uart_console_task(void *pvParameters) struct cmdBuf commands; commands.sendToUART = 0; commands.state=CMDSTATE_IDLE; + #if CONFIG_MODULE_USEJOYSTICK + uint8_t joy[11] = {0}; + #endif //Install UART driver, and get the queue. uart_driver_install(CONSOLE_UART_NUM, UART_FIFO_LEN * 2, UART_FIFO_LEN * 2, 0, NULL, 0); @@ -1252,48 +1259,44 @@ void uart_console_task(void *pvParameters) break; #if CONFIG_MODULE_USEJOYSTICK case '1': - uint8_t joy1[11] = {0}; - joy1[8] = 0x01; + joy[8] = 0x01; for(uint8_t i = 0; i Date: Wed, 15 Feb 2023 16:04:57 +0100 Subject: [PATCH 13/15] Fixed UART clock rate for esp-idf v5 --- main/CMakeLists.txt | 3 ++- main/ble_hidd_demo_main.c | 7 ++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 31d5ae7..87a4793 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -3,6 +3,7 @@ idf_component_register(SRCS "ble_hidd_demo_main.c" "hid_dev.c" "hid_device_le_prf.c" INCLUDE_DIRS "." - REQUIRES esp_hid PRIV_REQUIRES esp_wifi esp_https_server esp_eth nvs_flash lwip fatfs esp_https_ota esp_hid app_update) + REQUIRES esp_hid + PRIV_REQUIRES esp_wifi esp_https_server esp_eth nvs_flash spi_flash lwip fatfs esp_https_ota esp_hid app_update) target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-unused-const-variable) diff --git a/main/ble_hidd_demo_main.c b/main/ble_hidd_demo_main.c index a26e44a..142b7dc 100644 --- a/main/ble_hidd_demo_main.c +++ b/main/ble_hidd_demo_main.c @@ -1126,13 +1126,10 @@ void uart_external_task(void *pvParameters) .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, - .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_DEFAULT, }; - #ifdef UART_SCLK_DEFAULT - #error "You are using esp-idf v5. This won't work with Windows. Use v4.x instead, or delete this line." - #endif - if(onArduinoRP2040) uart_config.baud_rate = 115200; //update UART config From ac4492c2d2fa16c97290bd6ec3352872901f35c1 Mon Sep 17 00:00:00 2001 From: Benjamin Aigner Date: Wed, 15 Feb 2023 16:26:24 +0100 Subject: [PATCH 14/15] Added note on supported IDF --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 841a36f..883f31e 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,8 @@ With `idf.py -p (PORT) flash` or `make flash` you can upload this build to an ES With `idf.py -p (PORT) monitor` or `make monitor` you can see the debug output (please use this output if you open an issue) or trigger basic test commands (mouse movement or a keyboard key press) on a connected target. +__Note: Currently tested IDF version: release/v5.0 (other ones won't be supported!)__ + ### esp32miniBT vs. Arduino Nano Connect This firmware is used on 2 different devices in context of our assistive devices: From 33210c2b4c6aa85c6c4333bb360695b6db8f4ddb Mon Sep 17 00:00:00 2001 From: Benjamin Aigner Date: Wed, 15 Feb 2023 16:54:09 +0100 Subject: [PATCH 15/15] Changed HID report map; windows is VERY picky (works on Android & Linux, but driver error in Win10) --- main/hid_device_le_prf.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/main/hid_device_le_prf.c b/main/hid_device_le_prf.c index 043820b..5db103b 100644 --- a/main/hid_device_le_prf.c +++ b/main/hid_device_le_prf.c @@ -136,6 +136,8 @@ static const uint8_t hidReportMap[] = { 0x75, 0x04, // Report Size (4) 0x95, 0x01, // Report Count (1) 0x81, 0x00, // Input (Data, Ary, Abs) + /** @note no idea what this is used for, but it destroys the byte alignment. + 0x09, 0x80, // Usage (Selection) 0xA1, 0x02, // Collection (Logical) 0x05, 0x09, // Usage Pg (Button) @@ -146,7 +148,10 @@ static const uint8_t hidReportMap[] = { 0x75, 0x02, // Report Size (2) 0x81, 0x00, // Input (Data, Ary, Abs) 0xC0, // End Collection + 0x81, 0x03, // Input (Const, Var, Abs) + * + * */ 0xC0, // End Collection