Skip to content

Commit

Permalink
Merge pull request #63 from asterics/gamepad2022
Browse files Browse the repository at this point in the history
Gamepad implementation
  • Loading branch information
Benjamin Aigner authored Feb 15, 2023
2 parents af3e8e8 + 33210c2 commit 3cebe19
Show file tree
Hide file tree
Showing 11 changed files with 433 additions and 207 deletions.
16 changes: 12 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -50,7 +52,7 @@ This firmware is used on 2 different devices in context of our assistive devices
__Note:__ Please select the correct type of board in `idf.py menuconfig`!

__Note:__ If you want to use this firmware on a custom board, you can select the external UART interface settings in menuconfig; for our boards the pinning, baudrate and UART config is pre-defined.

# Usage via Console or second UART

## Control via stdin (make monitor)
Expand Down Expand Up @@ -114,7 +116,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
Expand All @@ -138,7 +147,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.

3 changes: 2 additions & 1 deletion main/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
8 changes: 4 additions & 4 deletions main/Kconfig.projbuild
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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.

Expand Down
152 changes: 124 additions & 28 deletions main/ble_hidd_demo_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -422,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);
Expand All @@ -431,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)
Expand Down Expand Up @@ -556,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 <key> get the value of the given key from NVS. Note: no spaces in <key>! max. key length: 15
// $SV <key> <value> set the value of the given key & store to NVS. Note: no spaces in <key>!
// $CV clear all key/value pairs set with $SV
Expand All @@ -570,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)
Expand Down Expand Up @@ -999,9 +1027,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++;
Expand All @@ -1011,25 +1039,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; i<CONFIG_BT_ACL_CONNECTIONS; i++)
{
if(active_hid_conn_ids[i] != -1) esp_hidd_send_keyboard_value(active_hid_conn_ids[i],cmdBuffer->buf[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; i<CONFIG_BT_ACL_CONNECTIONS; i++)
{
if(active_hid_conn_ids[i] != -1) esp_hidd_send_keyboard_value(active_hid_conn_ids[i],cmdBuffer->buf[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]);
//uint8_t joy[HID_JOYSTICK_IN_RPT_LEN];
//memcpy(joy,&cmdBuffer->buf[2],HID_JOYSTICK_IN_RPT_LEN);
///@todo esp_hidd_send_joystick_value...
} else if (cmdBuffer->buf[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; i<CONFIG_BT_ACL_CONNECTIONS; i++)
{
if(active_hid_conn_ids[i] != -1) esp_hidd_send_joy_report(active_hid_conn_ids[i],joy);
}
#else
ESP_LOGE(EXT_UART_TAG,"built without joystick support, cannot fix that!");
#endif
} else if (cmdBuffer->buf[1] == 0x03) { // mouse report
if(hid_conn_id == -1)
{
for(uint8_t i = 0; i<CONFIG_BT_ACL_CONNECTIONS; i++)
Expand Down Expand Up @@ -1118,8 +1156,9 @@ void uart_external_task(void *pvParameters)
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_DEFAULT
.source_clk = UART_SCLK_DEFAULT,
};

if(onArduinoRP2040) uart_config.baud_rate = 115200;

//update UART config
Expand Down Expand Up @@ -1196,6 +1235,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);
Expand Down Expand Up @@ -1241,6 +1283,51 @@ void uart_console_task(void *pvParameters)
}
ESP_LOGI(CONSOLE_UART_TAG,"consumer: mute");
break;
#if CONFIG_MODULE_USEJOYSTICK
case '1':
joy[8] = 0x01;
for(uint8_t i = 0; i<CONFIG_BT_ACL_CONNECTIONS; i++)
{
if(active_hid_conn_ids[i] != -1)
{
esp_hidd_send_joy_report(active_hid_conn_ids[i],joy);
}
}
ESP_LOGI(CONSOLE_UART_TAG,"joystick button 1: press");
break;
case '2':
for(uint8_t i = 0; i<CONFIG_BT_ACL_CONNECTIONS; i++)
{
if(active_hid_conn_ids[i] != -1)
{
esp_hidd_send_joy_report(active_hid_conn_ids[i],joy);
}
}
ESP_LOGI(CONSOLE_UART_TAG,"joystick release");
break;
case '3':
joy[0] = 127;
for(uint8_t i = 0; i<CONFIG_BT_ACL_CONNECTIONS; i++)
{
if(active_hid_conn_ids[i] != -1)
{
esp_hidd_send_joy_report(active_hid_conn_ids[i],joy);
}
}
ESP_LOGI(CONSOLE_UART_TAG,"joystick axis1: 127");
break;
case '4':
joy[0] = 0xFF;
for(uint8_t i = 0; i<CONFIG_BT_ACL_CONNECTIONS; i++)
{
if(active_hid_conn_ids[i] != -1)
{
esp_hidd_send_joy_report(active_hid_conn_ids[i],joy);
}
}
ESP_LOGI(CONSOLE_UART_TAG,"joystick axis1: -127");
break;
#endif
case 'p':
for(uint8_t i = 0; i<CONFIG_BT_ACL_CONNECTIONS; i++)
{
Expand Down Expand Up @@ -1441,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");
Expand Down Expand Up @@ -1469,9 +1565,9 @@ void app_main(void)
///clear the HID connection IDs&MACs
for(uint8_t i = 0; i<CONFIG_BT_ACL_CONNECTIONS;i++)
{
active_hid_conn_ids[i] = -1;
memset(active_connections[i],0,sizeof(esp_bd_addr_t));
}
active_hid_conn_ids[i] = -1;
memset(active_connections[i],0,sizeof(esp_bd_addr_t));
}
///register the callback function to the gap module
esp_ble_gap_register_callback(gap_event_handler);
esp_hidd_register_callbacks(hidd_event_callback);
Expand Down
2 changes: 1 addition & 1 deletion main/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit 3cebe19

Please sign in to comment.