diff --git a/examples/bluetooth/bluedroid/classic_bt/bt_hid_mouse_device/main/main.c b/examples/bluetooth/bluedroid/classic_bt/bt_hid_mouse_device/main/main.c index b92bee049d..0e97be38b6 100644 --- a/examples/bluetooth/bluedroid/classic_bt/bt_hid_mouse_device/main/main.c +++ b/examples/bluetooth/bluedroid/classic_bt/bt_hid_mouse_device/main/main.c @@ -14,103 +14,24 @@ #include "freertos/task.h" #include "freertos/semphr.h" -#define BOOT_PROTO_MOUSE_RPT_ID 0x02 -typedef struct -{ +#define REPORT_PROTOCOL_MOUSE_REPORT_SIZE (4) +#define REPORT_BUFFER_SIZE REPORT_PROTOCOL_MOUSE_REPORT_SIZE + +typedef struct { esp_hidd_app_param_t app_param; esp_hidd_qos_param_t both_qos; uint8_t protocol_mode; SemaphoreHandle_t mouse_mutex; - xTaskHandle mouse_task_hdl; - uint8_t buffer[4]; + TaskHandle_t mouse_task_hdl; + uint8_t buffer[REPORT_BUFFER_SIZE]; int8_t x_dir; } local_param_t; static local_param_t s_local_param = {0}; -bool check_report_id_type(uint8_t report_id, uint8_t report_type) -{ - bool ret = false; - xSemaphoreTake(s_local_param.mouse_mutex, portMAX_DELAY); - do { - if (report_type != ESP_HIDD_REPORT_TYPE_INPUT) { - break; - } - if (s_local_param.protocol_mode == ESP_HIDD_BOOT_MODE) { - if (report_id == BOOT_PROTO_MOUSE_RPT_ID) { - ret = true; - break; - } - } else { - if (report_id == 0) { - ret = true; - break; - } - } - } while (0); - - if (!ret) { - if (s_local_param.protocol_mode == ESP_HIDD_BOOT_MODE) { - esp_bt_hid_device_report_error(ESP_HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID); - } else { - esp_bt_hid_device_report_error(ESP_HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID); - } - } - xSemaphoreGive(s_local_param.mouse_mutex); - return ret; -} - -// send the buttons, change in x, and change in y -void send_mouse(uint8_t buttons, char dx, char dy, char wheel) -{ - xSemaphoreTake(s_local_param.mouse_mutex, portMAX_DELAY); - if (s_local_param.protocol_mode == ESP_HIDD_REPORT_MODE) { - s_local_param.buffer[0] = buttons; - s_local_param.buffer[1] = dx; - s_local_param.buffer[2] = dy; - s_local_param.buffer[3] = wheel; - esp_bt_hid_device_send_report(ESP_HIDD_REPORT_TYPE_INTRDATA, 0x00, 4, s_local_param.buffer); - } else if (s_local_param.protocol_mode == ESP_HIDD_BOOT_MODE) { - s_local_param.buffer[0] = buttons; - s_local_param.buffer[1] = dx; - s_local_param.buffer[2] = dy; - esp_bt_hid_device_send_report(ESP_HIDD_REPORT_TYPE_INTRDATA, BOOT_PROTO_MOUSE_RPT_ID, 3, s_local_param.buffer); - } - xSemaphoreGive(s_local_param.mouse_mutex); -} - -// move the mouse left and right -void mouse_move_task(void* pvParameters) { - const char* TAG = "mouse_move_task"; - - ESP_LOGI(TAG, "starting"); - for(;;) { - s_local_param.x_dir = 1; - int8_t step = 10; - for (int i = 0; i < 2; i++) { - xSemaphoreTake(s_local_param.mouse_mutex, portMAX_DELAY); - s_local_param.x_dir *= -1; - xSemaphoreGive(s_local_param.mouse_mutex); - for (int j = 0; j < 100; j++) { - send_mouse(0, s_local_param.x_dir * step, 0, 0); - vTaskDelay(50 / portTICK_PERIOD_MS); - } - } - vTaskDelay(1000 / portTICK_PERIOD_MS); - } -} - -static void print_bt_address(void) { - const char* TAG = "bt_address"; - const uint8_t* bd_addr; - - bd_addr = esp_bt_dev_get_address(); - ESP_LOGI(TAG, "my bluetooth address is %02X:%02X:%02X:%02X:%02X:%02X", - bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]); -} - -// a generic mouse descriptor -uint8_t hid_descriptor_mouse_boot_mode[] = { +// HID report descriptor for a generic mouse. The contents of the report are: +// 3 buttons, moving information for X and Y cursors, information for a wheel. +uint8_t hid_mouse_descriptor[] = { 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x02, // USAGE (Mouse) 0xa1, 0x01, // COLLECTION (Application) @@ -143,13 +64,109 @@ uint8_t hid_descriptor_mouse_boot_mode[] = { 0xc0, // END_COLLECTION 0xc0 // END_COLLECTION }; -int hid_descriptor_mouse_boot_mode_len = sizeof(hid_descriptor_mouse_boot_mode); + +const int hid_mouse_descriptor_len = sizeof(hid_mouse_descriptor); + +/** + * @brief Integrity check of the report ID and report type for GET_REPORT request from HID host. + * Boot Protocol Mode requires report ID. For Report Protocol Mode, when the report descriptor + * does not declare report ID Global ITEMS, the report ID does not exist in the GET_REPORT request, + * and a value of 0 for report_id will occur in ESP_HIDD_GET_REPORT_EVT callback parameter. + */ +bool check_report_id_type(uint8_t report_id, uint8_t report_type) +{ + bool ret = false; + xSemaphoreTake(s_local_param.mouse_mutex, portMAX_DELAY); + do { + if (report_type != ESP_HIDD_REPORT_TYPE_INPUT) { + break; + } + if (s_local_param.protocol_mode == ESP_HIDD_BOOT_MODE) { + if (report_id == ESP_HIDD_BOOT_REPORT_ID_MOUSE) { + ret = true; + break; + } + } else { + if (report_id == 0) { + ret = true; + break; + } + } + } while (0); + + if (!ret) { + if (s_local_param.protocol_mode == ESP_HIDD_BOOT_MODE) { + esp_bt_hid_device_report_error(ESP_HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID); + } else { + esp_bt_hid_device_report_error(ESP_HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID); + } + } + xSemaphoreGive(s_local_param.mouse_mutex); + return ret; +} + +// send the buttons, change in x, and change in y +void send_mouse_report(uint8_t buttons, char dx, char dy, char wheel) +{ + uint8_t report_id; + uint16_t report_size; + xSemaphoreTake(s_local_param.mouse_mutex, portMAX_DELAY); + if (s_local_param.protocol_mode == ESP_HIDD_REPORT_MODE) { + report_id = 0; + report_size = REPORT_PROTOCOL_MOUSE_REPORT_SIZE; + s_local_param.buffer[0] = buttons; + s_local_param.buffer[1] = dx; + s_local_param.buffer[2] = dy; + s_local_param.buffer[3] = wheel; + } else { + // Boot Mode + report_id = ESP_HIDD_BOOT_REPORT_ID_MOUSE; + report_size = ESP_HIDD_BOOT_REPORT_SIZE_MOUSE - 1; + s_local_param.buffer[0] = buttons; + s_local_param.buffer[1] = dx; + s_local_param.buffer[2] = dy; + } + esp_bt_hid_device_send_report(ESP_HIDD_REPORT_TYPE_INTRDATA, report_id, report_size, s_local_param.buffer); + xSemaphoreGive(s_local_param.mouse_mutex); +} + +// move the mouse left and right +void mouse_move_task(void *pvParameters) +{ + const char *TAG = "mouse_move_task"; + + ESP_LOGI(TAG, "starting"); + for (;;) { + s_local_param.x_dir = 1; + int8_t step = 10; + for (int i = 0; i < 2; i++) { + xSemaphoreTake(s_local_param.mouse_mutex, portMAX_DELAY); + s_local_param.x_dir *= -1; + xSemaphoreGive(s_local_param.mouse_mutex); + for (int j = 0; j < 100; j++) { + send_mouse_report(0, s_local_param.x_dir * step, 0, 0); + vTaskDelay(50 / portTICK_PERIOD_MS); + } + } + vTaskDelay(1000 / portTICK_PERIOD_MS); + } +} + +static void print_bt_address(void) +{ + const char *TAG = "bt_address"; + const uint8_t *bd_addr; + + bd_addr = esp_bt_dev_get_address(); + ESP_LOGI(TAG, "my bluetooth address is %02X:%02X:%02X:%02X:%02X:%02X", + bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]); +} void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param) { - const char* TAG = "esp_bt_gap_cb"; + const char *TAG = "esp_bt_gap_cb"; switch (event) { - case ESP_BT_GAP_AUTH_CMPL_EVT:{ + case ESP_BT_GAP_AUTH_CMPL_EVT: { if (param->auth_cmpl.stat == ESP_BT_STATUS_SUCCESS) { ESP_LOGI(TAG, "authentication success: %s", param->auth_cmpl.device_name); esp_log_buffer_hex(TAG, param->auth_cmpl.bda, ESP_BD_ADDR_LEN); @@ -158,7 +175,7 @@ void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param) } break; } - case ESP_BT_GAP_PIN_REQ_EVT:{ + case ESP_BT_GAP_PIN_REQ_EVT: { ESP_LOGI(TAG, "ESP_BT_GAP_PIN_REQ_EVT min_16_digit:%d", param->pin_req.min_16_digit); if (param->pin_req.min_16_digit) { ESP_LOGI(TAG, "Input pin code: 0000 0000 0000 0000"); @@ -201,7 +218,7 @@ void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param) void bt_app_task_start_up(void) { s_local_param.mouse_mutex = xSemaphoreCreateMutex(); - memset(s_local_param.buffer, 0, 4); + memset(s_local_param.buffer, 0, REPORT_BUFFER_SIZE); xTaskCreate(mouse_move_task, "mouse_move_task", 2 * 1024, NULL, configMAX_PRIORITIES - 3, &s_local_param.mouse_task_hdl); return; } @@ -222,7 +239,7 @@ void bt_app_task_shut_down(void) void esp_bt_hidd_cb(esp_hidd_cb_event_t event, esp_hidd_cb_param_t *param) { - static const char* TAG = "esp_bt_hidd_cb"; + static const char *TAG = "esp_bt_hidd_cb"; switch (event) { case ESP_HIDD_INIT_EVT: if (param->init.status == ESP_HIDD_SUCCESS) { @@ -306,12 +323,18 @@ void esp_bt_hidd_cb(esp_hidd_cb_event_t event, esp_hidd_cb_param_t *param) ESP_LOGI(TAG, "ESP_HIDD_GET_REPORT_EVT id:0x%02x, type:%d, size:%d", param->get_report.report_id, param->get_report.report_type, param->get_report.buffer_size); if (check_report_id_type(param->get_report.report_id, param->get_report.report_type)) { - xSemaphoreTake(s_local_param.mouse_mutex, portMAX_DELAY); + uint8_t report_id; + uint16_t report_len; if (s_local_param.protocol_mode == ESP_HIDD_REPORT_MODE) { - esp_bt_hid_device_send_report(param->get_report.report_type, 0x00, 4, s_local_param.buffer); - } else if (s_local_param.protocol_mode == ESP_HIDD_BOOT_MODE) { - esp_bt_hid_device_send_report(param->get_report.report_type, 0x02, 3, s_local_param.buffer); + report_id = 0; + report_len = REPORT_PROTOCOL_MOUSE_REPORT_SIZE; + } else { + // Boot Mode + report_id = ESP_HIDD_BOOT_REPORT_ID_MOUSE; + report_len = ESP_HIDD_BOOT_REPORT_SIZE_MOUSE - 1; } + xSemaphoreTake(s_local_param.mouse_mutex, portMAX_DELAY); + esp_bt_hid_device_send_report(param->get_report.report_type, report_id, report_len, s_local_param.buffer); xSemaphoreGive(s_local_param.mouse_mutex); } else { ESP_LOGE(TAG, "check_report_id failed!"); @@ -357,46 +380,38 @@ void esp_bt_hidd_cb(esp_hidd_cb_event_t event, esp_hidd_cb_param_t *param) } } -void app_main(void) { - const char* TAG = "app_main"; - esp_err_t ret; +void app_main(void) +{ + const char *TAG = "app_main"; + esp_err_t ret; - s_local_param.app_param.name = "Mouse"; - s_local_param.app_param.description = "Mouse Example"; - s_local_param.app_param.provider = "ESP32"; - s_local_param.app_param.subclass = ESP_HID_CLASS_MIC; - s_local_param.app_param.desc_list = hid_descriptor_mouse_boot_mode; - s_local_param.app_param.desc_list_len = hid_descriptor_mouse_boot_mode_len; - memset(&s_local_param.both_qos, 0, sizeof(esp_hidd_qos_param_t)); // don't set the qos parameters - s_local_param.protocol_mode = ESP_HIDD_REPORT_MODE; - - ret = nvs_flash_init(); + ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_ERROR_CHECK(nvs_flash_erase()); ret = nvs_flash_init(); } ESP_ERROR_CHECK( ret ); - ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BLE)); + ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BLE)); - esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); + esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); if ((ret = esp_bt_controller_init(&bt_cfg)) != ESP_OK) { - ESP_LOGE(TAG, "initialize controller failed: %s\n", esp_err_to_name(ret)); + ESP_LOGE(TAG, "initialize controller failed: %s\n", esp_err_to_name(ret)); return; } if ((ret = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT)) != ESP_OK) { - ESP_LOGE(TAG, "enable controller failed: %s\n", esp_err_to_name(ret)); + ESP_LOGE(TAG, "enable controller failed: %s\n", esp_err_to_name(ret)); return; } if ((ret = esp_bluedroid_init()) != ESP_OK) { - ESP_LOGE(TAG, "initialize bluedroid failed: %s\n", esp_err_to_name(ret)); + ESP_LOGE(TAG, "initialize bluedroid failed: %s\n", esp_err_to_name(ret)); return; } if ((ret = esp_bluedroid_enable()) != ESP_OK) { - ESP_LOGE(TAG, "enable bluedroid failed: %s\n", esp_err_to_name(ret)); + ESP_LOGE(TAG, "enable bluedroid failed: %s\n", esp_err_to_name(ret)); return; } @@ -405,22 +420,37 @@ void app_main(void) { return; } - ESP_LOGI(TAG, "setting device name"); esp_bt_dev_set_device_name("HID Mouse Example"); ESP_LOGI(TAG, "setting cod major, peripheral"); esp_bt_cod_t cod; cod.major = ESP_BT_COD_MAJOR_DEV_PERIPHERAL; - esp_bt_gap_set_cod(cod ,ESP_BT_SET_COD_MAJOR_MINOR); + esp_bt_gap_set_cod(cod, ESP_BT_SET_COD_MAJOR_MINOR); vTaskDelay(2000 / portTICK_PERIOD_MS); + // Initialize HID SDP information and L2CAP parameters. + // to be used in the call of `esp_bt_hid_device_register_app` after profile initialization finishes + do { + s_local_param.app_param.name = "Mouse"; + s_local_param.app_param.description = "Mouse Example"; + s_local_param.app_param.provider = "ESP32"; + s_local_param.app_param.subclass = ESP_HID_CLASS_MIC; + s_local_param.app_param.desc_list = hid_mouse_descriptor; + s_local_param.app_param.desc_list_len = hid_mouse_descriptor_len; + + memset(&s_local_param.both_qos, 0, sizeof(esp_hidd_qos_param_t)); // don't set the qos parameters + } while (0); + + // Report Protocol Mode is the default mode, according to Bluetooth HID specification + s_local_param.protocol_mode = ESP_HIDD_REPORT_MODE; + ESP_LOGI(TAG, "register hid device callback"); esp_bt_hid_device_register_callback(esp_bt_hidd_cb); ESP_LOGI(TAG, "starting hid device"); - esp_bt_hid_device_init(); + esp_bt_hid_device_init(); #if (CONFIG_BT_SSP_ENABLED == true) /* Set default parameters for Secure Simple Pairing */ @@ -438,5 +468,5 @@ void app_main(void) { esp_bt_gap_set_pin(pin_type, 0, pin_code); print_bt_address(); - ESP_LOGI(TAG, "exiting"); + ESP_LOGI(TAG, "exiting"); }