From efb747d16774879e114b1ec8680398227e008540 Mon Sep 17 00:00:00 2001 From: Yulong Date: Fri, 9 Mar 2018 03:25:23 -0500 Subject: [PATCH] example/hid: Added the BLE hid device profile. demo/hid: Change the license validity period & some unreasonable LOG print. example/hid: Added the Vendor Report output support. --- .../bluetooth/ble_hid_device_demo/Makefile | 11 + .../main/ble_hidd_demo_main.c | 317 ++++++++ .../ble_hid_device_demo/main/component.mk | 10 + .../main/esp_hidd_prf_api.c | 146 ++++ .../main/esp_hidd_prf_api.h | 167 ++++ .../ble_hid_device_demo/main/hid_dev.c | 143 ++++ .../ble_hid_device_demo/main/hid_dev.h | 257 ++++++ .../main/hid_device_le_prf.c | 762 ++++++++++++++++++ .../main/hidd_le_prf_int.h | 339 ++++++++ .../ble_hid_device_demo/sdkconfig.defaults | 3 + 10 files changed, 2155 insertions(+) create mode 100644 examples/bluetooth/ble_hid_device_demo/Makefile create mode 100644 examples/bluetooth/ble_hid_device_demo/main/ble_hidd_demo_main.c create mode 100644 examples/bluetooth/ble_hid_device_demo/main/component.mk create mode 100644 examples/bluetooth/ble_hid_device_demo/main/esp_hidd_prf_api.c create mode 100644 examples/bluetooth/ble_hid_device_demo/main/esp_hidd_prf_api.h create mode 100644 examples/bluetooth/ble_hid_device_demo/main/hid_dev.c create mode 100644 examples/bluetooth/ble_hid_device_demo/main/hid_dev.h create mode 100644 examples/bluetooth/ble_hid_device_demo/main/hid_device_le_prf.c create mode 100644 examples/bluetooth/ble_hid_device_demo/main/hidd_le_prf_int.h create mode 100644 examples/bluetooth/ble_hid_device_demo/sdkconfig.defaults diff --git a/examples/bluetooth/ble_hid_device_demo/Makefile b/examples/bluetooth/ble_hid_device_demo/Makefile new file mode 100644 index 0000000000..8604de3327 --- /dev/null +++ b/examples/bluetooth/ble_hid_device_demo/Makefile @@ -0,0 +1,11 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := hidd_demos + +COMPONENT_ADD_INCLUDEDIRS := components/include \ + + +include $(IDF_PATH)/make/project.mk diff --git a/examples/bluetooth/ble_hid_device_demo/main/ble_hidd_demo_main.c b/examples/bluetooth/ble_hid_device_demo/main/ble_hidd_demo_main.c new file mode 100644 index 0000000000..626d69ce10 --- /dev/null +++ b/examples/bluetooth/ble_hid_device_demo/main/ble_hidd_demo_main.c @@ -0,0 +1,317 @@ +/* This example code is in the Public Domain (or CC0 licensed, at your option.) + Unless required by applicable law or agreed to in writing, this software is + distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "esp_system.h" +#include "esp_wifi.h" +#include "esp_event_loop.h" +#include "esp_log.h" +#include "nvs_flash.h" +#include "esp_bt.h" + +#include "esp_hidd_prf_api.h" +#include "esp_bt_defs.h" +#include "esp_gap_ble_api.h" +#include "esp_gatts_api.h" +#include "esp_gatt_defs.h" +#include "esp_bt_main.h" +#include "esp_bt_device.h" +#include "bt_trace.h" +#include "driver/gpio.h" +#include "hid_dev.h" + +/** + * Brief: + * This test code shows how to configure gpio and how to use gpio interrupt. + * + * GPIO status: + * GPIO18: output + * GPIO19: output + * GPIO4: input, pulled up, interrupt from rising edge and falling edge + * GPIO5: input, pulled up, interrupt from rising edge. + * + * Test: + * Connect GPIO18 with GPIO4 + * Connect GPIO19 with GPIO5 + * Generate pulses on GPIO18/19, that triggers interrupt on GPIO4/5 + * + */ + +#define GATTS_TAG "HID_DEMO" + + +#define GPIO_OUTPUT_IO_0 18 +#define GPIO_OUTPUT_IO_1 19 +#define GPIO_OUTPUT_PIN_SEL ((1< MSB */ + //first uuid, 16bit, [12],[13] is the value + 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x12, 0x18, 0x00, 0x00, +}; + +static esp_ble_adv_data_t hidd_adv_data = { + .set_scan_rsp = false, + .include_name = true, + .include_txpower = true, + .min_interval = 0x20, + .max_interval = 0x30, + .appearance = 0x03c0, //HID Generic, + .manufacturer_len = 0, + .p_manufacturer_data = NULL, + .service_data_len = 0, + .p_service_data = NULL, + .service_uuid_len = sizeof(hidd_service_uuid128), + .p_service_uuid = hidd_service_uuid128, + .flag = 0x6, +}; + +static esp_ble_adv_params_t hidd_adv_params = { + .adv_int_min = 0x20, + .adv_int_max = 0x30, + .adv_type = ADV_TYPE_IND, + .own_addr_type = BLE_ADDR_TYPE_PUBLIC, + //.peer_addr = + //.peer_addr_type = + .channel_map = ADV_CHNL_ALL, + .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, +}; + +void IRAM_ATTR gpio_isr_handler(void* arg) +{ + uint32_t gpio_num = (uint32_t) arg; + xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL); +} + +void gpio_task_example(void* arg) +{ + static uint8_t i = 0; + uint32_t io_num; + for(;;) { + if(xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) { + ESP_LOGI(GATTS_TAG, "GPIO[%d] intr, val: %d\n", io_num, gpio_get_level(io_num)); + if(i == 0) { + ++i; + } + } + } +} + +static void gpio_demo_init(void) +{ + gpio_config_t io_conf; + //disable interrupt + io_conf.intr_type = GPIO_PIN_INTR_DISABLE; + //set as output mode + io_conf.mode = GPIO_MODE_OUTPUT; + //bit mask of the pins that you want to set,e.g.GPIO18/19 + io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL; + //disable pull-down mode + io_conf.pull_down_en = 0; + //disable pull-up mode + io_conf.pull_up_en = 0; + //configure GPIO with the given settings + gpio_config(&io_conf); + + //interrupt of rising edge + io_conf.intr_type = GPIO_PIN_INTR_POSEDGE; + //bit mask of the pins, use GPIO4/5 here + io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL; + //set as input mode + io_conf.mode = GPIO_MODE_INPUT; + //enable pull-up mode + io_conf.pull_up_en = 1; + gpio_config(&io_conf); + + //change gpio intrrupt type for one pin + gpio_set_intr_type(GPIO_INPUT_IO_0, GPIO_INTR_ANYEDGE); + + //create a queue to handle gpio event from isr + gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t)); + //start gpio task + xTaskCreate(gpio_task_example, "gpio_task_example", 2048, NULL, 10, NULL); + + //install gpio isr service + gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT); + //hook isr handler for specific gpio pin + gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0); + //hook isr handler for specific gpio pin + gpio_isr_handler_add(GPIO_INPUT_IO_1, gpio_isr_handler, (void*) GPIO_INPUT_IO_1); + + //remove isr handler for gpio number. + gpio_isr_handler_remove(GPIO_INPUT_IO_0); + //hook isr handler for specific gpio pin again + gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0); + +} + + + +static void hidd_event_callback(esp_hidd_cb_event_t event, esp_hidd_cb_param_t *param) +{ + switch(event) { + case ESP_HIDD_EVENT_REG_FINISH: { + if (param->init_finish.state == ESP_HIDD_INIT_OK) { + //esp_bd_addr_t rand_addr = {0x04,0x11,0x11,0x11,0x11,0x05}; + esp_ble_gap_set_device_name(HIDD_DEVICE_NAME); + esp_ble_gap_config_adv_data(&hidd_adv_data); + + } + break; + } + case ESP_BAT_EVENT_REG: { + break; + } + case ESP_HIDD_EVENT_DEINIT_FINISH: + break; + case ESP_HIDD_EVENT_BLE_CONNECT: { + hid_conn_id = param->connect.conn_id; + break; + } + case ESP_HIDD_EVENT_BLE_DISCONNECT: { + sec_conn = false; + LOG_ERROR("%s(), ESP_HIDD_EVENT_BLE_DISCONNECT", __func__); + esp_ble_gap_start_advertising(&hidd_adv_params); + break; + } + case ESP_HIDD_EVENT_BLE_VENDOR_REPORT_WRITE_EVT: { + LOG_ERROR("%s, ESP_HIDD_EVENT_BLE_VENDOR_REPORT_WRITE_EVT", __func__); + ESP_LOG_BUFFER_HEX(GATTS_TAG, param->vendor_write.data, param->vendor_write.length); + } + default: + break; + } + return; +} + +static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) +{ + switch (event) { + case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: + esp_ble_gap_start_advertising(&hidd_adv_params); + break; + case ESP_GAP_BLE_SEC_REQ_EVT: + for(int i = 0; i < ESP_BD_ADDR_LEN; i++) { + LOG_DEBUG("%x:",param->ble_security.ble_req.bd_addr[i]); + } + esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true); + break; + case ESP_GAP_BLE_AUTH_CMPL_EVT: + sec_conn = true; + LOG_ERROR("staus =%s, ESP_GAP_BLE_AUTH_CMPL_EVT",param->ble_security.auth_cmpl.success ? "success" : "fail"); + break; + default: + break; + } +} + +void hid_demo_task(void *pvParameters) +{ + vTaskDelay(1000 / portTICK_PERIOD_MS); + while(1) { + vTaskDelay(2000 / portTICK_PERIOD_MS); + if (sec_conn) { + LOG_ERROR("Send the volume"); + //send_volum_up = true; + uint8_t key_vaule = {HID_KEY_A}; + esp_hidd_send_keyboard_value(hid_conn_id, 0, &key_vaule, 1); + //esp_hidd_send_consumer_value(hid_conn_id, HID_CONSUMER_VOLUME_UP, true); + vTaskDelay(3000 / portTICK_PERIOD_MS); + if (send_volum_up) { + send_volum_up = false; + //esp_hidd_send_consumer_value(hid_conn_id, HID_CONSUMER_VOLUME_UP, false); + esp_hidd_send_consumer_value(hid_conn_id, HID_CONSUMER_VOLUME_DOWN, true); + } + } + } +} + + +void app_main() +{ + esp_err_t ret; + + // Initialize NVS. + ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK( ret ); + + esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); + ret = esp_bt_controller_init(&bt_cfg); + if (ret) { + ESP_LOGE(GATTS_TAG, "%s initialize controller failed\n", __func__); + return; + } + + ret = esp_bt_controller_enable(ESP_BT_MODE_BTDM); + if (ret) { + ESP_LOGE(GATTS_TAG, "%s enable controller failed\n", __func__); + return; + } + + ret = esp_bluedroid_init(); + if (ret) { + LOG_ERROR("%s init bluedroid failed\n", __func__); + return; + } + + ret = esp_bluedroid_enable(); + if (ret) { + LOG_ERROR("%s init bluedroid failed\n", __func__); + return; + } + + if((ret = esp_hidd_profile_init()) != ESP_OK) { + LOG_ERROR("%s init bluedroid failed\n", __func__); + } + + ///register the callback function to the gap module + esp_ble_gap_register_callback(gap_event_handler); + esp_hidd_register_callbacks(hidd_event_callback); + + /* set the security iocap & auth_req & key size & init key response key parameters to the stack*/ + esp_ble_auth_req_t auth_req = ESP_LE_AUTH_BOND; //bonding with peer device after authentication + esp_ble_io_cap_t iocap = ESP_IO_CAP_NONE; //set the IO capability to No output No input + uint8_t key_size = 16; //the key size should be 7~16 bytes + uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK; + uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK; + esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &auth_req, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &key_size, sizeof(uint8_t)); + /* If your BLE device act as a Slave, the init_key means you hope which types of key of the master should distribut to you, + and the response key means which key you can distribut to the Master; + If your BLE device act as a master, the response key means you hope which types of key of the slave should distribut to you, + and the init key means which key you can distribut to the slave. */ + esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &init_key, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &rsp_key, sizeof(uint8_t)); + + //init the gpio pin + gpio_demo_init(); + xTaskCreate(&hid_demo_task, "hid_task", 2048, NULL, 5, NULL); + +} + diff --git a/examples/bluetooth/ble_hid_device_demo/main/component.mk b/examples/bluetooth/ble_hid_device_demo/main/component.mk new file mode 100644 index 0000000000..48adb595ca --- /dev/null +++ b/examples/bluetooth/ble_hid_device_demo/main/component.mk @@ -0,0 +1,10 @@ +# +# Main Makefile. This is basically the same as a component makefile. +# +# This Makefile should, at the very least, just include $(SDK_PATH)/make/component_common.mk. By default, +# this will take the sources in the src/ directory, compile them and link them into +# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable, +# please read the ESP-IDF documents if you need to do this. +# + +# include $(IDF_PATH)/make/component_common.mk diff --git a/examples/bluetooth/ble_hid_device_demo/main/esp_hidd_prf_api.c b/examples/bluetooth/ble_hid_device_demo/main/esp_hidd_prf_api.c new file mode 100644 index 0000000000..b3ee517f93 --- /dev/null +++ b/examples/bluetooth/ble_hid_device_demo/main/esp_hidd_prf_api.c @@ -0,0 +1,146 @@ +// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "esp_hidd_prf_api.h" +#include "hidd_le_prf_int.h" +#include "hid_dev.h" +#include +#include +#include "bt_trace.h" + +// HID keyboard input report length +#define HID_KEYBOARD_IN_RPT_LEN 8 + +// HID LED output report length +#define HID_LED_OUT_RPT_LEN 1 + +// HID mouse input report length +#define HID_MOUSE_IN_RPT_LEN 5 + +// HID consumer control input report length +#define HID_CC_IN_RPT_LEN 2 + + +esp_err_t esp_hidd_register_callbacks(esp_hidd_event_cb_t callbacks) +{ + esp_err_t hidd_status; + + if(callbacks != NULL) { + hidd_le_env.hidd_cb = callbacks; + } else { + return ESP_FAIL; + } + + if((hidd_status = hidd_register_cb()) != ESP_OK) { + return hidd_status; + } + + esp_ble_gatts_app_register(BATTRAY_APP_ID); + + if((hidd_status = esp_ble_gatts_app_register(HIDD_APP_ID)) != ESP_OK) { + return hidd_status; + } + + return hidd_status; +} + +esp_err_t esp_hidd_profile_init(void) +{ + if (hidd_le_env.enabled) { + LOG_ERROR("HID device profile already initialized"); + return ESP_FAIL; + } + // Reset the hid device target environment + memset(&hidd_le_env, 0, sizeof(hidd_le_env_t)); + hidd_le_env.enabled = true; + return ESP_OK; +} + +esp_err_t esp_hidd_profile_deinit(void) +{ + uint16_t hidd_svc_hdl = hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_SVC]; + if (!hidd_le_env.enabled) { + LOG_ERROR("HID device profile already initialized"); + return ESP_OK; + } + + if(hidd_svc_hdl != 0) { + esp_ble_gatts_stop_service(hidd_svc_hdl); + esp_ble_gatts_delete_service(hidd_svc_hdl); + } else { + return ESP_FAIL; + } + + /* register the HID device profile to the BTA_GATTS module*/ + esp_ble_gatts_app_unregister(hidd_le_env.gatt_if); + + return ESP_OK; +} + +uint16_t esp_hidd_get_version(void) +{ + return HIDD_VERSION; +} + +void esp_hidd_send_consumer_value(uint16_t conn_id, uint8_t key_cmd, bool key_pressed) +{ + uint8_t buffer[HID_CC_IN_RPT_LEN] = {0, 0}; + if (key_pressed) { + LOG_DEBUG("hid_consumer_build_report"); + hid_consumer_build_report(buffer, key_cmd); + } + LOG_DEBUG("buffer[0] = %x, buffer[1] = %x", buffer[0], buffer[1]); + hid_dev_send_report(hidd_le_env.gatt_if, conn_id, + HID_RPT_ID_CC_IN, HID_REPORT_TYPE_INPUT, HID_CC_IN_RPT_LEN, buffer); + return; +} + +void esp_hidd_send_keyboard_value(uint16_t conn_id, key_mask_t special_key_mask, uint8_t *keyboard_cmd, uint8_t num_key) +{ + if (num_key > HID_KEYBOARD_IN_RPT_LEN - 2) { + LOG_ERROR("%s(), the number key should not be more than %d", __func__, HID_KEYBOARD_IN_RPT_LEN); + return; + } + + uint8_t buffer[HID_KEYBOARD_IN_RPT_LEN] = {0}; + + buffer[0] = special_key_mask; + + for (int i = 0; i < num_key; i++) { + buffer[i+2] = keyboard_cmd[i]; + } + + LOG_DEBUG("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]); + 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; +} + +void esp_hidd_send_mouse_value(uint16_t conn_id, uint8_t mouse_button, int8_t mickeys_x, int8_t mickeys_y) +{ + uint8_t buffer[HID_MOUSE_IN_RPT_LEN]; + + buffer[0] = mouse_button; // Buttons + buffer[1] = mickeys_x; // X + buffer[2] = mickeys_y; // Y + buffer[3] = 0; // Wheel + buffer[4] = 0; // AC Pan + + hid_dev_send_report(hidd_le_env.gatt_if, conn_id, + HID_RPT_ID_MOUSE_IN, HID_REPORT_TYPE_INPUT, HID_MOUSE_IN_RPT_LEN, buffer); + return; +} + + + diff --git a/examples/bluetooth/ble_hid_device_demo/main/esp_hidd_prf_api.h b/examples/bluetooth/ble_hid_device_demo/main/esp_hidd_prf_api.h new file mode 100644 index 0000000000..32c8c6c0ce --- /dev/null +++ b/examples/bluetooth/ble_hid_device_demo/main/esp_hidd_prf_api.h @@ -0,0 +1,167 @@ +// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef __ESP_HIDD_API_H__ +#define __ESP_HIDD_API_H__ + +#include "esp_bt_defs.h" +#include "esp_gatt_defs.h" +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + ESP_HIDD_EVENT_REG_FINISH = 0, + ESP_BAT_EVENT_REG, + 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_cb_event_t; + +/// HID config status +typedef enum { + ESP_HIDD_STA_CONN_SUCCESS = 0x00, + ESP_HIDD_STA_CONN_FAIL = 0x01, +} esp_hidd_sta_conn_state_t; + +/// HID init status +typedef enum { + ESP_HIDD_INIT_OK = 0, + ESP_HIDD_INIT_FAILED = 1, +} esp_hidd_init_state_t; + +/// HID deinit status +typedef enum { + ESP_HIDD_DEINIT_OK = 0, + ESP_HIDD_DEINIT_FAILED = 0, +} esp_hidd_deinit_state_t; + +#define LEFT_CONTROL_KEY_MASK (1 >> 0) +#define LEFT_SHIFT_KEY_MASK (1 >> 1) +#define LEFT_ALT_KEY_MASK (1 >> 2) +#define LEFT_GUI_KEY_MASK (1 >> 3) +#define RIGHT_CONTROL_KEY_MASK (1 >> 4) +#define RIGHT_SHIFT_KEY_MASK (1 >> 5) +#define RIGHT_ALT_KEY_MASK (1 >> 6) +#define RIGHT_GUI_KEY_MASK (1 >> 7) +typedef uint8_t key_mask_t; +/** + * @brief HIDD callback parameters union + */ +typedef union { + /** + * @brief ESP_HIDD_EVENT_INIT_FINISH + */ + struct hidd_init_finish_evt_param { + esp_hidd_init_state_t state; /*!< Initial status */ + esp_gatt_if_t gatts_if; + } init_finish; /*!< HID callback param of ESP_HIDD_EVENT_INIT_FINISH */ + + /** + * @brief ESP_HIDD_EVENT_DEINIT_FINISH + */ + struct hidd_deinit_finish_evt_param { + esp_hidd_deinit_state_t state; /*!< De-initial status */ + } deinit_finish; /*!< HID callback param of ESP_HIDD_EVENT_DEINIT_FINISH */ + + /** + * @brief ESP_HIDD_EVENT_CONNECT + */ + struct hidd_connect_evt_param { + uint16_t conn_id; + esp_bd_addr_t remote_bda; /*!< HID Remote bluetooth connection index */ + } connect; /*!< HID callback param of ESP_HIDD_EVENT_CONNECT */ + + /** + * @brief ESP_HIDD_EVENT_DISCONNECT + */ + struct hidd_disconnect_evt_param { + esp_bd_addr_t remote_bda; /*!< HID Remote bluetooth device address */ + } disconnect; /*!< HID callback param of ESP_HIDD_EVENT_DISCONNECT */ + + /** + * @brief ESP_HIDD_EVENT_BLE_VENDOR_REPORT_WRITE_EVT + */ + struct hidd_vendor_write_evt_param { + uint16_t conn_id; /*!< HID connection index */ + uint16_t report_id; /*!< HID report index */ + uint16_t length; /*!< data length */ + uint8_t *data; /*!< The pointer to the data */ + } vendor_write; /*!< HID callback param of ESP_HIDD_EVENT_BLE_VENDOR_REPORT_WRITE_EVT */ + +} esp_hidd_cb_param_t; + + +/** + * @brief HID device event callback function type + * @param event : Event type + * @param param : Point to callback parameter, currently is union type + */ +typedef void (*esp_hidd_event_cb_t) (esp_hidd_cb_event_t event, esp_hidd_cb_param_t *param); + + + +/** + * + * @brief This function is called to receive hid device callback event + * + * @param[in] callbacks: callback functions + * + * @return ESP_OK - success, other - failed + * + */ +esp_err_t esp_hidd_register_callbacks(esp_hidd_event_cb_t callbacks); + +/** + * + * @brief This function is called to initialize hid device profile + * + * @return ESP_OK - success, other - failed + * + */ +esp_err_t esp_hidd_profile_init(void); + +/** + * + * @brief This function is called to de-initialize hid device profile + * + * @return ESP_OK - success, other - failed + * + */ +esp_err_t esp_hidd_profile_deinit(void); + +/** + * + * @brief Get hidd profile version + * + * @return Most 8bit significant is Great version, Least 8bit is Sub version + * + */ +uint16_t esp_hidd_get_version(void); + +void esp_hidd_send_consumer_value(uint16_t conn_id, uint8_t key_cmd, bool key_pressed); + +void esp_hidd_send_keyboard_value(uint16_t conn_id, key_mask_t special_key_mask, uint8_t *keyboard_cmd, uint8_t num_key); + +void esp_hidd_send_mouse_value(uint16_t conn_id, uint8_t mouse_button, int8_t mickeys_x, int8_t mickeys_y); + +#ifdef __cplusplus +} +#endif + +#endif /* __ESP_HIDD_API_H__ */ + diff --git a/examples/bluetooth/ble_hid_device_demo/main/hid_dev.c b/examples/bluetooth/ble_hid_device_demo/main/hid_dev.c new file mode 100644 index 0000000000..aba5724105 --- /dev/null +++ b/examples/bluetooth/ble_hid_device_demo/main/hid_dev.c @@ -0,0 +1,143 @@ +// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "hid_dev.h" +#include "bt_trace.h" +#include +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +static hid_report_map_t *hid_dev_rpt_tbl; +static uint8_t hid_dev_rpt_tbl_Len; + +static hid_report_map_t *hid_dev_rpt_by_id(uint8_t id, uint8_t type) +{ + hid_report_map_t *rpt = hid_dev_rpt_tbl; + + for (uint8_t i = hid_dev_rpt_tbl_Len; i > 0; i--, rpt++) { + if (rpt->id == id && rpt->type == type && rpt->mode == hidProtocolMode) { + return rpt; + } + } + + return NULL; +} + +void hid_dev_register_reports(uint8_t num_reports, hid_report_map_t *p_report) +{ + hid_dev_rpt_tbl = p_report; + hid_dev_rpt_tbl_Len = num_reports; + return; +} + +void hid_dev_send_report(esp_gatt_if_t gatts_if, uint16_t conn_id, + uint8_t id, uint8_t type, uint8_t length, uint8_t *data) +{ + hid_report_map_t *p_rpt; + + // get att handle for report + if ((p_rpt = hid_dev_rpt_by_id(id, type)) != NULL) { + // if notifications are enabled + LOG_DEBUG("%s(), send the report, handle = %d", __func__, p_rpt->handle); + esp_ble_gatts_send_indicate(gatts_if, conn_id, p_rpt->handle, length, data, false); + } + + return; +} + +void hid_consumer_build_report(uint8_t *buffer, consumer_cmd_t cmd) +{ + if (!buffer) { + LOG_ERROR("%s(), the buffer is NULL, hid build report failed.", __func__); + return; + } + + switch (cmd) { + case HID_CONSUMER_CHANNEL_UP: + HID_CC_RPT_SET_CHANNEL(buffer, HID_CC_RPT_CHANNEL_UP); + break; + + case HID_CONSUMER_CHANNEL_DOWN: + HID_CC_RPT_SET_CHANNEL(buffer, HID_CC_RPT_CHANNEL_DOWN); + break; + + case HID_CONSUMER_VOLUME_UP: + HID_CC_RPT_SET_VOLUME_UP(buffer); + break; + + case HID_CONSUMER_VOLUME_DOWN: + HID_CC_RPT_SET_VOLUME_DOWN(buffer); + break; + + case HID_CONSUMER_MUTE: + HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_MUTE); + break; + + case HID_CONSUMER_POWER: + HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_POWER); + break; + + case HID_CONSUMER_RECALL_LAST: + HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_LAST); + break; + + case HID_CONSUMER_ASSIGN_SEL: + HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_ASSIGN_SEL); + break; + + case HID_CONSUMER_PLAY: + HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_PLAY); + break; + + case HID_CONSUMER_PAUSE: + HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_PAUSE); + break; + + case HID_CONSUMER_RECORD: + HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_RECORD); + break; + + case HID_CONSUMER_FAST_FORWARD: + HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_FAST_FWD); + break; + + case HID_CONSUMER_REWIND: + HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_REWIND); + break; + + case HID_CONSUMER_SCAN_NEXT_TRK: + HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_SCAN_NEXT_TRK); + break; + + case HID_CONSUMER_SCAN_PREV_TRK: + HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_SCAN_PREV_TRK); + break; + + case HID_CONSUMER_STOP: + HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_STOP); + break; + + default: + break; + } + + return; +} + diff --git a/examples/bluetooth/ble_hid_device_demo/main/hid_dev.h b/examples/bluetooth/ble_hid_device_demo/main/hid_dev.h new file mode 100644 index 0000000000..17b406b797 --- /dev/null +++ b/examples/bluetooth/ble_hid_device_demo/main/hid_dev.h @@ -0,0 +1,257 @@ +// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef HID_DEV_H__ +#define HID_DEV_H__ + +#include "hidd_le_prf_int.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* HID Report type */ +#define HID_TYPE_INPUT 1 +#define HID_TYPE_OUTPUT 2 +#define HID_TYPE_FEATURE 3 + +// HID Keyboard/Keypad Usage IDs (subset of the codes available in the USB HID Usage Tables spec) +#define HID_KEY_RESERVED 0 // No event inidicated +#define HID_KEY_A 4 // Keyboard a and A +#define HID_KEY_B 5 // Keyboard b and B +#define HID_KEY_C 6 // Keyboard c and C +#define HID_KEY_D 7 // Keyboard d and D +#define HID_KEY_E 8 // Keyboard e and E +#define HID_KEY_F 9 // Keyboard f and F +#define HID_KEY_G 10 // Keyboard g and G +#define HID_KEY_H 11 // Keyboard h and H +#define HID_KEY_I 12 // Keyboard i and I +#define HID_KEY_J 13 // Keyboard j and J +#define HID_KEY_K 14 // Keyboard k and K +#define HID_KEY_L 15 // Keyboard l and L +#define HID_KEY_M 16 // Keyboard m and M +#define HID_KEY_N 17 // Keyboard n and N +#define HID_KEY_O 18 // Keyboard o and O +#define HID_KEY_P 19 // Keyboard p and p +#define HID_KEY_Q 20 // Keyboard q and Q +#define HID_KEY_R 21 // Keyboard r and R +#define HID_KEY_S 22 // Keyboard s and S +#define HID_KEY_T 23 // Keyboard t and T +#define HID_KEY_U 24 // Keyboard u and U +#define HID_KEY_V 25 // Keyboard v and V +#define HID_KEY_W 26 // Keyboard w and W +#define HID_KEY_X 27 // Keyboard x and X +#define HID_KEY_Y 28 // Keyboard y and Y +#define HID_KEY_Z 29 // Keyboard z and Z +#define HID_KEY_1 30 // Keyboard 1 and ! +#define HID_KEY_2 31 // Keyboard 2 and @ +#define HID_KEY_3 32 // Keyboard 3 and # +#define HID_KEY_4 33 // Keyboard 4 and % +#define HID_KEY_5 34 // Keyboard 5 and % +#define HID_KEY_6 35 // Keyboard 6 and ^ +#define HID_KEY_7 36 // Keyboard 7 and & +#define HID_KEY_8 37 // Keyboard 8 and * +#define HID_KEY_9 38 // Keyboard 9 and ( +#define HID_KEY_0 39 // Keyboard 0 and ) +#define HID_KEY_RETURN 40 // Keyboard Return (ENTER) +#define HID_KEY_ESCAPE 41 // Keyboard ESCAPE +#define HID_KEY_DELETE 42 // Keyboard DELETE (Backspace) +#define HID_KEY_TAB 43 // Keyboard Tab +#define HID_KEY_SPACEBAR 44 // Keyboard Spacebar +#define HID_KEY_MINUS 45 // Keyboard - and (underscore) +#define HID_KEY_EQUAL 46 // Keyboard = and + +#define HID_KEY_LEFT_BRKT 47 // Keyboard [ and { +#define HID_KEY_RIGHT_BRKT 48 // Keyboard ] and } +#define HID_KEY_BACK_SLASH 49 // Keyboard \ and | +#define HID_KEY_SEMI_COLON 51 // Keyboard ; and : +#define HID_KEY_SGL_QUOTE 52 // Keyboard ' and " +#define HID_KEY_GRV_ACCENT 53 // Keyboard Grave Accent and Tilde +#define HID_KEY_COMMA 54 // Keyboard , and < +#define HID_KEY_DOT 55 // Keyboard . and > +#define HID_KEY_FWD_SLASH 56 // Keyboard / and ? +#define HID_KEY_CAPS_LOCK 57 // Keyboard Caps Lock +#define HID_KEY_F1 58 // Keyboard F1 +#define HID_KEY_F2 59 // Keyboard F2 +#define HID_KEY_F3 60 // Keyboard F3 +#define HID_KEY_F4 61 // Keyboard F4 +#define HID_KEY_F5 62 // Keyboard F5 +#define HID_KEY_F6 63 // Keyboard F6 +#define HID_KEY_F7 64 // Keyboard F7 +#define HID_KEY_F8 65 // Keyboard F8 +#define HID_KEY_F9 66 // Keyboard F9 +#define HID_KEY_F10 67 // Keyboard F10 +#define HID_KEY_F11 68 // Keyboard F11 +#define HID_KEY_F12 69 // Keyboard F12 +#define HID_KEY_PRNT_SCREEN 70 // Keyboard Print Screen +#define HID_KEY_SCROLL_LOCK 71 // Keyboard Scroll Lock +#define HID_KEY_PAUSE 72 // Keyboard Pause +#define HID_KEY_INSERT 73 // Keyboard Insert +#define HID_KEY_HOME 74 // Keyboard Home +#define HID_KEY_PAGE_UP 75 // Keyboard PageUp +#define HID_KEY_DELETE_FWD 76 // Keyboard Delete Forward +#define HID_KEY_END 77 // Keyboard End +#define HID_KEY_PAGE_DOWN 78 // Keyboard PageDown +#define HID_KEY_RIGHT_ARROW 79 // Keyboard RightArrow +#define HID_KEY_LEFT_ARROW 80 // Keyboard LeftArrow +#define HID_KEY_DOWN_ARROW 81 // Keyboard DownArrow +#define HID_KEY_UP_ARROW 82 // Keyboard UpArrow +#define HID_KEY_NUM_LOCK 83 // Keypad Num Lock and Clear +#define HID_KEY_DIVIDE 84 // Keypad / +#define HID_KEY_MULTIPLY 85 // Keypad * +#define HID_KEY_SUBTRACT 86 // Keypad - +#define HID_KEY_ADD 87 // Keypad + +#define HID_KEY_ENTER 88 // Keypad ENTER +#define HID_KEYPAD_1 89 // Keypad 1 and End +#define HID_KEYPAD_2 90 // Keypad 2 and Down Arrow +#define HID_KEYPAD_3 91 // Keypad 3 and PageDn +#define HID_KEYPAD_4 92 // Keypad 4 and Lfet Arrow +#define HID_KEYPAD_5 93 // Keypad 5 +#define HID_KEYPAD_6 94 // Keypad 6 and Right Arrow +#define HID_KEYPAD_7 95 // Keypad 7 and Home +#define HID_KEYPAD_8 96 // Keypad 8 and Up Arrow +#define HID_KEYPAD_9 97 // Keypad 9 and PageUp +#define HID_KEYPAD_0 98 // Keypad 0 and Insert +#define HID_KEYPAD_DOT 99 // Keypad . and Delete +#define HID_KEY_MUTE 127 // Keyboard Mute +#define HID_KEY_VOLUME_UP 128 // Keyboard Volume up +#define HID_KEY_VOLUME_DOWN 129 // Keyboard Volume down +#define HID_KEY_LEFT_CTRL 224 // Keyboard LeftContorl +#define HID_KEY_LEFT_SHIFT 225 // Keyboard LeftShift +#define HID_KEY_LEFT_ALT 226 // Keyboard LeftAlt +#define HID_KEY_LEFT_GUI 227 // Keyboard LeftGUI +#define HID_KEY_RIGHT_CTRL 228 // Keyboard LeftContorl +#define HID_KEY_RIGHT_SHIFT 229 // Keyboard LeftShift +#define HID_KEY_RIGHT_ALT 230 // Keyboard LeftAlt +#define HID_KEY_RIGHT_GUI 231 // Keyboard RightGUI +typedef uint8_t keyboard_cmd_t; + +#define HID_MOUSE_LEFT 253 +#define HID_MOUSE_MIDDLE 254 +#define HID_MOUSE_RIGHT 255 +typedef uint8_t mouse_cmd_t; + +// HID Consumer Usage IDs (subset of the codes available in the USB HID Usage Tables spec) +#define HID_CONSUMER_POWER 48 // Power +#define HID_CONSUMER_RESET 49 // Reset +#define HID_CONSUMER_SLEEP 50 // Sleep + +#define HID_CONSUMER_MENU 64 // Menu +#define HID_CONSUMER_SELECTION 128 // Selection +#define HID_CONSUMER_ASSIGN_SEL 129 // Assign Selection +#define HID_CONSUMER_MODE_STEP 130 // Mode Step +#define HID_CONSUMER_RECALL_LAST 131 // Recall Last +#define HID_CONSUMER_QUIT 148 // Quit +#define HID_CONSUMER_HELP 149 // Help +#define HID_CONSUMER_CHANNEL_UP 156 // Channel Increment +#define HID_CONSUMER_CHANNEL_DOWN 157 // Channel Decrement + +#define HID_CONSUMER_PLAY 176 // Play +#define HID_CONSUMER_PAUSE 177 // Pause +#define HID_CONSUMER_RECORD 178 // Record +#define HID_CONSUMER_FAST_FORWARD 179 // Fast Forward +#define HID_CONSUMER_REWIND 180 // Rewind +#define HID_CONSUMER_SCAN_NEXT_TRK 181 // Scan Next Track +#define HID_CONSUMER_SCAN_PREV_TRK 182 // Scan Previous Track +#define HID_CONSUMER_STOP 183 // Stop +#define HID_CONSUMER_EJECT 184 // Eject +#define HID_CONSUMER_RANDOM_PLAY 185 // Random Play +#define HID_CONSUMER_SELECT_DISC 186 // Select Disk +#define HID_CONSUMER_ENTER_DISC 187 // Enter Disc +#define HID_CONSUMER_REPEAT 188 // Repeat +#define HID_CONSUMER_STOP_EJECT 204 // Stop/Eject +#define HID_CONSUMER_PLAY_PAUSE 205 // Play/Pause +#define HID_CONSUMER_PLAY_SKIP 206 // Play/Skip + +#define HID_CONSUMER_VOLUME 224 // Volume +#define HID_CONSUMER_BALANCE 225 // Balance +#define HID_CONSUMER_MUTE 226 // Mute +#define HID_CONSUMER_BASS 227 // Bass +#define HID_CONSUMER_VOLUME_UP 233 // Volume Increment +#define HID_CONSUMER_VOLUME_DOWN 234 // Volume Decrement +typedef uint8_t consumer_cmd_t; + +#define HID_CC_RPT_MUTE 1 +#define HID_CC_RPT_POWER 2 +#define HID_CC_RPT_LAST 3 +#define HID_CC_RPT_ASSIGN_SEL 4 +#define HID_CC_RPT_PLAY 5 +#define HID_CC_RPT_PAUSE 6 +#define HID_CC_RPT_RECORD 7 +#define HID_CC_RPT_FAST_FWD 8 +#define HID_CC_RPT_REWIND 9 +#define HID_CC_RPT_SCAN_NEXT_TRK 10 +#define HID_CC_RPT_SCAN_PREV_TRK 11 +#define HID_CC_RPT_STOP 12 + +#define HID_CC_RPT_CHANNEL_UP 0x01 +#define HID_CC_RPT_CHANNEL_DOWN 0x03 +#define HID_CC_RPT_VOLUME_UP 0x40 +#define HID_CC_RPT_VOLUME_DOWN 0x80 + +// HID Consumer Control report bitmasks +#define HID_CC_RPT_NUMERIC_BITS 0xF0 +#define HID_CC_RPT_CHANNEL_BITS 0xCF +#define HID_CC_RPT_VOLUME_BITS 0x3F +#define HID_CC_RPT_BUTTON_BITS 0xF0 +#define HID_CC_RPT_SELECTION_BITS 0xCF + + +// Macros for the HID Consumer Control 2-byte report +#define HID_CC_RPT_SET_NUMERIC(s, x) (s)[0] &= HID_CC_RPT_NUMERIC_BITS; \ + (s)[0] = (x) +#define HID_CC_RPT_SET_CHANNEL(s, x) (s)[0] &= HID_CC_RPT_CHANNEL_BITS; \ + (s)[0] |= ((x) & 0x03) << 4 +#define HID_CC_RPT_SET_VOLUME_UP(s) (s)[0] &= HID_CC_RPT_VOLUME_BITS; \ + (s)[0] |= 0x40 +#define HID_CC_RPT_SET_VOLUME_DOWN(s) (s)[0] &= HID_CC_RPT_VOLUME_BITS; \ + (s)[0] |= 0x80 +#define HID_CC_RPT_SET_BUTTON(s, x) (s)[1] &= HID_CC_RPT_BUTTON_BITS; \ + (s)[1] |= (x) +#define HID_CC_RPT_SET_SELECTION(s, x) (s)[1] &= HID_CC_RPT_SELECTION_BITS; \ + (s)[1] |= ((x) & 0x03) << 4 + + +// HID report mapping table +typedef struct +{ + uint16_t handle; // Handle of report characteristic + uint16_t cccdHandle; // Handle of CCCD for report characteristic + uint8_t id; // Report ID + uint8_t type; // Report type + uint8_t mode; // Protocol mode (report or boot) +} hid_report_map_t; + +// HID dev configuration structure +typedef struct +{ + uint32_t idleTimeout; // Idle timeout in milliseconds + uint8_t hidFlags; // HID feature flags + +} hid_dev_cfg_t; + +void hid_dev_register_reports(uint8_t num_reports, hid_report_map_t *p_report); + +void hid_dev_send_report(esp_gatt_if_t gatts_if, uint16_t conn_id, + uint8_t id, uint8_t type, uint8_t length, uint8_t *data); + +void hid_consumer_build_report(uint8_t *buffer, consumer_cmd_t cmd); + +void hid_keyboard_build_report(uint8_t *buffer, keyboard_cmd_t cmd); + +void hid_mouse_build_report(uint8_t *buffer, mouse_cmd_t cmd); + +#endif /* HID_DEV_H__ */ + diff --git a/examples/bluetooth/ble_hid_device_demo/main/hid_device_le_prf.c b/examples/bluetooth/ble_hid_device_demo/main/hid_device_le_prf.c new file mode 100644 index 0000000000..b938c50488 --- /dev/null +++ b/examples/bluetooth/ble_hid_device_demo/main/hid_device_le_prf.c @@ -0,0 +1,762 @@ +// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "hidd_le_prf_int.h" +#include +#include "bt_types.h" +#include "bt_trace.h" +//#include "esp_gap_ble_api.h" + + +/// characteristic presentation information +struct prf_char_pres_fmt +{ + /// Unit (The Unit is a UUID) + uint16_t unit; + /// Description + uint16_t description; + /// Format + uint8_t format; + /// Exponent + uint8_t exponent; + /// Name space + uint8_t name_space; +}; + +// HID report mapping table +static hid_report_map_t hid_rpt_map[HID_NUM_REPORTS]; + +// HID Report Map characteristic value +// Keyboard report descriptor (using format for Boot interface descriptor) +static const uint8_t hidReportMap[] = { + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x02, // Usage (Mouse) + 0xA1, 0x01, // Collection (Application) + 0x85, 0x01, // Report Id (1) + 0x09, 0x01, // Usage (Pointer) + 0xA1, 0x00, // Collection (Physical) + 0x05, 0x09, // Usage Page (Buttons) + 0x19, 0x01, // Usage Minimum (01) - Button 1 + 0x29, 0x03, // Usage Maximum (03) - Button 3 + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x03, // Report Count (3) + 0x81, 0x02, // Input (Data, Variable, Absolute) - Button states + 0x75, 0x05, // Report Size (5) + 0x95, 0x01, // Report Count (1) + 0x81, 0x01, // Input (Constant) - Padding or Reserved bits + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x38, // Usage (Wheel) + 0x15, 0x81, // Logical Minimum (-127) + 0x25, 0x7F, // Logical Maximum (127) + 0x75, 0x08, // Report Size (8) + 0x95, 0x03, // Report Count (3) + 0x81, 0x06, // Input (Data, Variable, Relative) - X & Y coordinate + 0xC0, // End Collection + 0xC0, // End Collection + + 0x05, 0x01, // Usage Pg (Generic Desktop) + 0x09, 0x06, // Usage (Keyboard) + 0xA1, 0x01, // Collection: (Application) + 0x85, 0x02, // Report Id (2) + // + 0x05, 0x07, // Usage Pg (Key Codes) + 0x19, 0xE0, // Usage Min (224) + 0x29, 0xE7, // Usage Max (231) + 0x15, 0x00, // Log Min (0) + 0x25, 0x01, // Log Max (1) + // + // Modifier byte + 0x75, 0x01, // Report Size (1) + 0x95, 0x08, // Report Count (8) + 0x81, 0x02, // Input: (Data, Variable, Absolute) + // + // Reserved byte + 0x95, 0x01, // Report Count (1) + 0x75, 0x08, // Report Size (8) + 0x81, 0x01, // Input: (Constant) + // + // LED report + 0x95, 0x05, // Report Count (5) + 0x75, 0x01, // Report Size (1) + 0x05, 0x08, // Usage Pg (LEDs) + 0x19, 0x01, // Usage Min (1) + 0x29, 0x05, // Usage Max (5) + 0x91, 0x02, // Output: (Data, Variable, Absolute) + // + // LED report padding + 0x95, 0x01, // Report Count (1) + 0x75, 0x03, // Report Size (3) + 0x91, 0x01, // Output: (Constant) + // + // Key arrays (6 bytes) + 0x95, 0x06, // Report Count (6) + 0x75, 0x08, // Report Size (8) + 0x15, 0x00, // Log Min (0) + 0x25, 0x65, // Log Max (101) + 0x05, 0x07, // Usage Pg (Key Codes) + 0x19, 0x00, // Usage Min (0) + 0x29, 0x65, // Usage Max (101) + 0x81, 0x00, // Input: (Data, Array) + // + 0xC0, // End Collection + // + 0x05, 0x0C, // Usage Pg (Consumer Devices) + 0x09, 0x01, // Usage (Consumer Control) + 0xA1, 0x01, // Collection (Application) + 0x85, 0x03, // Report Id (3) + 0x09, 0x02, // Usage (Numeric Key Pad) + 0xA1, 0x02, // Collection (Logical) + 0x05, 0x09, // Usage Pg (Button) + 0x19, 0x01, // Usage Min (Button 1) + 0x29, 0x0A, // Usage Max (Button 10) + 0x15, 0x01, // Logical Min (1) + 0x25, 0x0A, // Logical Max (10) + 0x75, 0x04, // Report Size (4) + 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) + 0x25, 0x01, // Logical Max (1) + 0x75, 0x02, // Report Size (2) + 0x95, 0x01, // Report Count (1) + 0x81, 0x46, // Input (Data, Var, Rel, Null) + 0x09, 0xE9, // Usage (Volume Up) + 0x09, 0xEA, // Usage (Volume Down) + 0x15, 0x00, // Logical Min (0) + 0x75, 0x01, // Report Size (1) + 0x95, 0x02, // Report Count (2) + 0x81, 0x02, // Input (Data, Var, Abs) + 0x09, 0xE2, // Usage (Mute) + 0x09, 0x30, // Usage (Power) + 0x09, 0x83, // Usage (Recall Last) + 0x09, 0x81, // Usage (Assign Selection) + 0x09, 0xB0, // Usage (Play) + 0x09, 0xB1, // Usage (Pause) + 0x09, 0xB2, // Usage (Record) + 0x09, 0xB3, // Usage (Fast Forward) + 0x09, 0xB4, // Usage (Rewind) + 0x09, 0xB5, // Usage (Scan Next) + 0x09, 0xB6, // Usage (Scan Prev) + 0x09, 0xB7, // Usage (Stop) + 0x15, 0x01, // Logical Min (1) + 0x25, 0x0C, // Logical Max (12) + 0x75, 0x04, // Report Size (4) + 0x95, 0x01, // Report Count (1) + 0x81, 0x00, // Input (Data, Ary, Abs) + 0x09, 0x80, // Usage (Selection) + 0xA1, 0x02, // Collection (Logical) + 0x05, 0x09, // Usage Pg (Button) + 0x19, 0x01, // Usage Min (Button 1) + 0x29, 0x03, // Usage Max (Button 3) + 0x15, 0x01, // Logical Min (1) + 0x25, 0x03, // Logical Max (3) + 0x75, 0x02, // Report Size (2) + 0x81, 0x00, // Input (Data, Ary, Abs) + 0xC0, // End Collection + 0x81, 0x03, // Input (Const, Var, Abs) + 0xC0, // End Collection + 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 +}; + +/// Battery Service Attributes Indexes +enum +{ + BAS_IDX_SVC, + + BAS_IDX_BATT_LVL_CHAR, + BAS_IDX_BATT_LVL_VAL, + BAS_IDX_BATT_LVL_NTF_CFG, + BAS_IDX_BATT_LVL_PRES_FMT, + + BAS_IDX_NB, +}; + +#define HI_UINT16(a) (((a) >> 8) & 0xFF) +#define LO_UINT16(a) ((a) & 0xFF) + +hidd_le_env_t hidd_le_env; + +// HID report map length +uint8_t hidReportMapLen = sizeof(hidReportMap); +uint8_t hidProtocolMode = HID_PROTOCOL_MODE_REPORT; + +// HID report mapping table +//static hidRptMap_t hidRptMap[HID_NUM_REPORTS]; + +// HID Information characteristic value +static const uint8_t hidInfo[HID_INFORMATION_LEN] = { + LO_UINT16(0x0111), HI_UINT16(0x0111), // bcdHID (USB HID version) + 0x00, // bCountryCode + HID_KBD_FLAGS // Flags +}; + + +// HID External Report Reference Descriptor +static uint16_t hidExtReportRefDesc = ESP_GATT_UUID_BATTERY_LEVEL; + +// HID Report Reference characteristic descriptor, mouse input +static uint8_t hidReportRefMouseIn[HID_REPORT_REF_LEN] = + { HID_RPT_ID_MOUSE_IN, HID_REPORT_TYPE_INPUT }; + + +// HID Report Reference characteristic descriptor, key input +static uint8_t hidReportRefKeyIn[HID_REPORT_REF_LEN] = + { HID_RPT_ID_KEY_IN, HID_REPORT_TYPE_INPUT }; + +// HID Report Reference characteristic descriptor, LED output +static uint8_t hidReportRefLedOut[HID_REPORT_REF_LEN] = + { HID_RPT_ID_LED_OUT, HID_REPORT_TYPE_OUTPUT }; + +static uint8_t hidReportRefVendorOut[HID_REPORT_REF_LEN] = + {HID_RPT_ID_VENDOR_OUT, HID_REPORT_TYPE_OUTPUT}; + +// HID Report Reference characteristic descriptor, Feature +static uint8_t hidReportRefFeature[HID_REPORT_REF_LEN] = + { HID_RPT_ID_FEATURE, HID_REPORT_TYPE_FEATURE }; + +// HID Report Reference characteristic descriptor, consumer control input +static uint8_t hidReportRefCCIn[HID_REPORT_REF_LEN] = + { HID_RPT_ID_CC_IN, HID_REPORT_TYPE_INPUT }; + + +/* + * Heart Rate PROFILE ATTRIBUTES + **************************************************************************************** + */ + +/// hid Service uuid +static uint16_t hid_le_svc = ATT_SVC_HID; +uint16_t hid_count = 0; +esp_gatts_incl_svc_desc_t incl_svc = {0}; + +#define CHAR_DECLARATION_SIZE (sizeof(uint8_t)) +///the uuid definition +static const uint16_t primary_service_uuid = ESP_GATT_UUID_PRI_SERVICE; +static const uint16_t include_service_uuid = ESP_GATT_UUID_INCLUDE_SERVICE; +static const uint16_t character_declaration_uuid = ESP_GATT_UUID_CHAR_DECLARE; +static const uint16_t character_client_config_uuid = ESP_GATT_UUID_CHAR_CLIENT_CONFIG; +static const uint16_t hid_info_char_uuid = ESP_GATT_UUID_HID_INFORMATION; +static const uint16_t hid_report_map_uuid = ESP_GATT_UUID_HID_REPORT_MAP; +static const uint16_t hid_control_point_uuid = ESP_GATT_UUID_HID_CONTROL_POINT; +static const uint16_t hid_report_uuid = ESP_GATT_UUID_HID_REPORT; +static const uint16_t hid_proto_mode_uuid = ESP_GATT_UUID_HID_PROTO_MODE; +static const uint16_t hid_kb_input_uuid = ESP_GATT_UUID_HID_BT_KB_INPUT; +static const uint16_t hid_kb_output_uuid = ESP_GATT_UUID_HID_BT_KB_OUTPUT; +static const uint16_t hid_mouse_input_uuid = ESP_GATT_UUID_HID_BT_MOUSE_INPUT; +static const uint16_t hid_repot_map_ext_desc_uuid = ESP_GATT_UUID_EXT_RPT_REF_DESCR; +static const uint16_t hid_report_ref_descr_uuid = ESP_GATT_UUID_RPT_REF_DESCR; +///the propoty definition +static const uint8_t char_prop_notify = ESP_GATT_CHAR_PROP_BIT_NOTIFY; +static const uint8_t char_prop_read = ESP_GATT_CHAR_PROP_BIT_READ; +static const uint8_t char_prop_write = ESP_GATT_CHAR_PROP_BIT_WRITE; +static const uint8_t char_prop_read_write = ESP_GATT_CHAR_PROP_BIT_WRITE|ESP_GATT_CHAR_PROP_BIT_READ; +static const uint8_t char_prop_read_notify = ESP_GATT_CHAR_PROP_BIT_READ|ESP_GATT_CHAR_PROP_BIT_NOTIFY; +static const uint8_t char_prop_read_write_notify = ESP_GATT_CHAR_PROP_BIT_READ|ESP_GATT_CHAR_PROP_BIT_WRITE|ESP_GATT_CHAR_PROP_BIT_NOTIFY; + +/// battary Service +static const uint16_t battary_svc = ESP_GATT_UUID_BATTERY_SERVICE_SVC; + +static const uint16_t bat_lev_uuid = ESP_GATT_UUID_BATTERY_LEVEL; +static const uint8_t bat_lev_ccc[2] ={ 0x00, 0x00}; +static const uint16_t char_format_uuid = ESP_GATT_UUID_CHAR_PRESENT_FORMAT; + +static uint8_t battary_lev = 50; +/// Full HRS Database Description - Used to add attributes into the database +static const esp_gatts_attr_db_t bas_att_db[BAS_IDX_NB] = +{ + // Battary Service Declaration + [BAS_IDX_SVC] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&primary_service_uuid, ESP_GATT_PERM_READ, + sizeof(uint16_t), sizeof(battary_svc), (uint8_t *)&battary_svc}}, + + // Battary level Characteristic Declaration + [BAS_IDX_BATT_LVL_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_notify}}, + + // Battary level Characteristic Value + [BAS_IDX_BATT_LVL_VAL] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&bat_lev_uuid, ESP_GATT_PERM_READ, + sizeof(uint8_t),sizeof(uint8_t), &battary_lev}}, + + // Battary level Characteristic - Client Characteristic Configuration Descriptor + [BAS_IDX_BATT_LVL_NTF_CFG] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_client_config_uuid, ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE, + sizeof(uint16_t),sizeof(bat_lev_ccc), (uint8_t *)bat_lev_ccc}}, + + // Battary level report Characteristic Declaration + [BAS_IDX_BATT_LVL_PRES_FMT] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&char_format_uuid, ESP_GATT_PERM_READ, + sizeof(struct prf_char_pres_fmt), 0, NULL}}, +}; + + +/// Full Hid device Database Description - Used to add attributes into the database +static esp_gatts_attr_db_t hidd_le_gatt_db[HIDD_LE_IDX_NB] = +{ + // HID Service Declaration + [HIDD_LE_IDX_SVC] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&primary_service_uuid, + ESP_GATT_PERM_READ_ENCRYPTED, sizeof(uint16_t), sizeof(hid_le_svc), + (uint8_t *)&hid_le_svc}}, + + // HID Service Declaration + [HIDD_LE_IDX_INCL_SVC] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&include_service_uuid, + ESP_GATT_PERM_READ, + sizeof(esp_gatts_incl_svc_desc_t), sizeof(esp_gatts_incl_svc_desc_t), + (uint8_t *)&incl_svc}}, + + // HID Information Characteristic Declaration + [HIDD_LE_IDX_HID_INFO_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}}, + // HID Information Characteristic Value + [HIDD_LE_IDX_HID_INFO_VAL] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&hid_info_char_uuid, + ESP_GATT_PERM_READ, + sizeof(hids_hid_info_t), sizeof(hidInfo), + (uint8_t *)&hidInfo}}, + + // HID Control Point Characteristic Declaration + [HIDD_LE_IDX_HID_CTNL_PT_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_write}}, + // HID Control Point Characteristic Value + [HIDD_LE_IDX_HID_CTNL_PT_VAL] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&hid_control_point_uuid, + ESP_GATT_PERM_WRITE, + sizeof(uint8_t), 0, + NULL}}, + + // Report Map Characteristic Declaration + [HIDD_LE_IDX_REPORT_MAP_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}}, + // Report Map Characteristic Value + [HIDD_LE_IDX_REPORT_MAP_VAL] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&hid_report_map_uuid, + ESP_GATT_PERM_READ, + HIDD_LE_REPORT_MAP_MAX_LEN, sizeof(hidReportMap), + (uint8_t *)&hidReportMap}}, + + // Report Map Characteristic - External Report Reference Descriptor + [HIDD_LE_IDX_REPORT_MAP_EXT_REP_REF] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&hid_repot_map_ext_desc_uuid, + ESP_GATT_PERM_READ, + sizeof(uint16_t), sizeof(uint16_t), + (uint8_t *)&hidExtReportRefDesc}}, + + // Protocol Mode Characteristic Declaration + [HIDD_LE_IDX_PROTO_MODE_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}}, + // Protocol Mode Characteristic Value + [HIDD_LE_IDX_PROTO_MODE_VAL] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&hid_proto_mode_uuid, + (ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE), + sizeof(uint8_t), sizeof(hidProtocolMode), + (uint8_t *)&hidProtocolMode}}, + + [HIDD_LE_IDX_REPORT_MOUSE_IN_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_notify}}, + + [HIDD_LE_IDX_REPORT_MOUSE_IN_VAL] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&hid_report_uuid, + ESP_GATT_PERM_READ, + HIDD_LE_REPORT_MAX_LEN, 0, + NULL}}, + + [HIDD_LE_IDX_REPORT_MOUSE_IN_CCC] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_client_config_uuid, + (ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE), + sizeof(uint16_t), 0, + NULL}}, + + [HIDD_LE_IDX_REPORT_MOUSE_REP_REF] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&hid_report_ref_descr_uuid, + ESP_GATT_PERM_READ, + sizeof(hidReportRefMouseIn), sizeof(hidReportRefMouseIn), + hidReportRefMouseIn}}, + // Report Characteristic Declaration + [HIDD_LE_IDX_REPORT_KEY_IN_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_notify}}, + // Report Characteristic Value + [HIDD_LE_IDX_REPORT_KEY_IN_VAL] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&hid_report_uuid, + ESP_GATT_PERM_READ, + HIDD_LE_REPORT_MAX_LEN, 0, + NULL}}, + // Report KEY INPUT Characteristic - Client Characteristic Configuration Descriptor + [HIDD_LE_IDX_REPORT_KEY_IN_CCC] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_client_config_uuid, + (ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE), + sizeof(uint16_t), 0, + NULL}}, + // Report Characteristic - Report Reference Descriptor + [HIDD_LE_IDX_REPORT_KEY_IN_REP_REF] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&hid_report_ref_descr_uuid, + 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}}, + + [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, + NULL}}, + [HIDD_LE_IDX_REPORT_LED_OUT_REP_REF] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&hid_report_ref_descr_uuid, + ESP_GATT_PERM_READ, + sizeof(hidReportRefLedOut), sizeof(hidReportRefLedOut), + hidReportRefLedOut}}, + // 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}}, + + // 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, + CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, + (uint8_t *)&char_prop_read_notify}}, + // Report Characteristic Value + [HIDD_LE_IDX_REPORT_CC_IN_VAL] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&hid_report_uuid, + ESP_GATT_PERM_READ, + HIDD_LE_REPORT_MAX_LEN, 0, + NULL}}, + // Report KEY INPUT Characteristic - Client Characteristic Configuration Descriptor + [HIDD_LE_IDX_REPORT_CC_IN_CCC] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_client_config_uuid, + (ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE), + sizeof(uint16_t), 0, + NULL}}, + // Report Characteristic - Report Reference Descriptor + [HIDD_LE_IDX_REPORT_CC_IN_REP_REF] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&hid_report_ref_descr_uuid, + ESP_GATT_PERM_READ, + sizeof(hidReportRefCCIn), sizeof(hidReportRefCCIn), + hidReportRefCCIn}}, + + // Boot Keyboard Input Report Characteristic Declaration + [HIDD_LE_IDX_BOOT_KB_IN_REPORT_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_notify}}, + // Boot Keyboard Input Report Characteristic Value + [HIDD_LE_IDX_BOOT_KB_IN_REPORT_VAL] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&hid_kb_input_uuid, + ESP_GATT_PERM_READ, + HIDD_LE_BOOT_REPORT_MAX_LEN, 0, + NULL}}, + // Boot Keyboard Input Report Characteristic - Client Characteristic Configuration Descriptor + [HIDD_LE_IDX_BOOT_KB_IN_REPORT_NTF_CFG] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_client_config_uuid, + (ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE), + sizeof(uint16_t), 0, + NULL}}, + + // Boot Keyboard Output Report Characteristic Declaration + [HIDD_LE_IDX_BOOT_KB_OUT_REPORT_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}}, + // Boot Keyboard Output Report Characteristic Value + [HIDD_LE_IDX_BOOT_KB_OUT_REPORT_VAL] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&hid_kb_output_uuid, + (ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE), + HIDD_LE_BOOT_REPORT_MAX_LEN, 0, + NULL}}, + + // Boot Mouse Input Report Characteristic Declaration + [HIDD_LE_IDX_BOOT_MOUSE_IN_REPORT_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_notify}}, + // Boot Mouse Input Report Characteristic Value + [HIDD_LE_IDX_BOOT_MOUSE_IN_REPORT_VAL] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&hid_mouse_input_uuid, + ESP_GATT_PERM_READ, + HIDD_LE_BOOT_REPORT_MAX_LEN, 0, + NULL}}, + // Boot Mouse Input Report Characteristic - Client Characteristic Configuration Descriptor + [HIDD_LE_IDX_BOOT_MOUSE_IN_REPORT_NTF_CFG] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_client_config_uuid, + (ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE), + sizeof(uint16_t), 0, + NULL}}, + + // Report Characteristic Declaration + [HIDD_LE_IDX_REPORT_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}}, + // Report Characteristic Value + [HIDD_LE_IDX_REPORT_VAL] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&hid_report_uuid, + ESP_GATT_PERM_READ, + HIDD_LE_REPORT_MAX_LEN, 0, + NULL}}, + // Report Characteristic - Report Reference Descriptor + [HIDD_LE_IDX_REPORT_REP_REF] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&hid_report_ref_descr_uuid, + ESP_GATT_PERM_READ, + sizeof(hidReportRefFeature), sizeof(hidReportRefFeature), + hidReportRefFeature}}, +}; + +static void hid_add_id_tbl(void); + +void esp_hidd_prf_cb_hdl(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t *param) +{ + switch(event) { + case ESP_GATTS_REG_EVT: { + esp_hidd_cb_param_t hidd_param; + hidd_param.init_finish.state = param->reg.status; + if(param->reg.app_id == HIDD_APP_ID) { + hidd_le_env.gatt_if = gatts_if; + if(hidd_le_env.hidd_cb != NULL) { + (hidd_le_env.hidd_cb)(ESP_HIDD_EVENT_REG_FINISH, &hidd_param); + hidd_le_create_service(hidd_le_env.gatt_if); + } + } + if(param->reg.app_id == BATTRAY_APP_ID) { + hidd_param.init_finish.gatts_if = gatts_if; + if(hidd_le_env.hidd_cb != NULL) { + (hidd_le_env.hidd_cb)(ESP_BAT_EVENT_REG, &hidd_param); + } + + } + + break; + } + case ESP_GATTS_CONF_EVT: { + break; + } + case ESP_GATTS_CREATE_EVT: + break; + case ESP_GATTS_CONNECT_EVT: { + esp_hidd_cb_param_t cb_param = {0}; + LOG_ERROR("the connection establish, conn_id = %x",param->connect.conn_id); + memcpy(cb_param.connect.remote_bda, param->connect.remote_bda, sizeof(esp_bd_addr_t)); + cb_param.connect.conn_id = param->connect.conn_id; + hidd_clcb_alloc(param->connect.conn_id, param->connect.remote_bda); + //esp_ble_set_encryption(param->connect.remote_bda, ESP_BLE_SEC_ENCRYPT_NO_MITM); + if(hidd_le_env.hidd_cb != NULL) { + (hidd_le_env.hidd_cb)(ESP_HIDD_EVENT_BLE_CONNECT, &cb_param); + } + break; + } + case ESP_GATTS_DISCONNECT_EVT: { + if(hidd_le_env.hidd_cb != NULL) { + (hidd_le_env.hidd_cb)(ESP_HIDD_EVENT_BLE_DISCONNECT, NULL); + } + hidd_clcb_dealloc(param->disconnect.conn_id); + break; + } + case ESP_GATTS_CLOSE_EVT: + break; + case ESP_GATTS_WRITE_EVT: { + esp_hidd_cb_param_t cb_param = {0}; + 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); + } + break; + } + case ESP_GATTS_CREAT_ATTR_TAB_EVT: { + if (param->add_attr_tab.num_handle == BAS_IDX_NB && + param->add_attr_tab.svc_uuid.uuid.uuid16 == ESP_GATT_UUID_BATTERY_SERVICE_SVC && + param->add_attr_tab.status == ESP_GATT_OK) { + incl_svc.start_hdl = param->add_attr_tab.handles[BAS_IDX_SVC]; + incl_svc.end_hdl = incl_svc.start_hdl + BAS_IDX_NB -1; + LOG_ERROR("%s(), start added the hid service to the stack database. incl_handle = %d", + __func__, incl_svc.start_hdl); + esp_ble_gatts_create_attr_tab(hidd_le_gatt_db, gatts_if, HIDD_LE_IDX_NB, 0); + } + if (param->add_attr_tab.num_handle == HIDD_LE_IDX_NB && + param->add_attr_tab.status == ESP_GATT_OK) { + memcpy(hidd_le_env.hidd_inst.att_tbl, param->add_attr_tab.handles, + HIDD_LE_IDX_NB*sizeof(uint16_t)); + LOG_ERROR("hid svc handle = %x",hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_SVC]); + hid_add_id_tbl(); + esp_ble_gatts_start_service(hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_SVC]); + } else { + esp_ble_gatts_start_service(param->add_attr_tab.handles[0]); + } + break; + } + + default: + break; + } +} + +void hidd_le_create_service(esp_gatt_if_t gatts_if) +{ + /* Here should added the battery service first, because the hid service should include the battery service. + After finish to added the battery service then can added the hid service. */ + esp_ble_gatts_create_attr_tab(bas_att_db, gatts_if, BAS_IDX_NB, 0); + +} + +void hidd_le_init(void) +{ + + // Reset the hid device target environment + memset(&hidd_le_env, 0, sizeof(hidd_le_env_t)); +} + +void hidd_clcb_alloc (uint16_t conn_id, esp_bd_addr_t bda) +{ + uint8_t i_clcb = 0; + hidd_clcb_t *p_clcb = NULL; + + for (i_clcb = 0, p_clcb= hidd_le_env.hidd_clcb; i_clcb < HID_MAX_APPS; i_clcb++, p_clcb++) { + if (!p_clcb->in_use) { + p_clcb->in_use = TRUE; + p_clcb->conn_id = conn_id; + p_clcb->connected = TRUE; + memcpy (p_clcb->remote_bda, bda, ESP_BD_ADDR_LEN); + break; + } + } + return; +} + +bool hidd_clcb_dealloc (uint16_t conn_id) +{ + uint8_t i_clcb = 0; + hidd_clcb_t *p_clcb = NULL; + + for (i_clcb = 0, p_clcb= hidd_le_env.hidd_clcb; i_clcb < HID_MAX_APPS; i_clcb++, p_clcb++) { + memset(p_clcb, 0, sizeof(hidd_clcb_t)); + return TRUE; + } + + return FALSE; +} + +esp_err_t hidd_register_cb(void) +{ + esp_err_t status; + status = esp_ble_gatts_register_callback(esp_hidd_prf_cb_hdl); + return status; +} + +void hidd_set_attr_value(uint16_t handle, uint16_t val_len, const uint8_t *value) +{ + hidd_inst_t *hidd_inst = &hidd_le_env.hidd_inst; + if(hidd_inst->att_tbl[HIDD_LE_IDX_HID_INFO_VAL] <= handle && + hidd_inst->att_tbl[HIDD_LE_IDX_REPORT_REP_REF] >= handle) { + esp_ble_gatts_set_attr_value(handle, val_len, value); + } else { + LOG_ERROR("%s error:Invalid handle value.",__func__); + } + return; +} + +void hidd_get_attr_value(uint16_t handle, uint16_t *length, uint8_t **value) +{ + hidd_inst_t *hidd_inst = &hidd_le_env.hidd_inst; + if(hidd_inst->att_tbl[HIDD_LE_IDX_HID_INFO_VAL] <= handle && + hidd_inst->att_tbl[HIDD_LE_IDX_REPORT_REP_REF] >= handle){ + esp_ble_gatts_get_attr_value(handle, length, (const uint8_t **)value); + } else { + LOG_ERROR("%s error:Invalid handle value.", __func__); + } + + return; +} + +static void hid_add_id_tbl(void) +{ + // Mouse input report + hid_rpt_map[0].id = hidReportRefMouseIn[0]; + hid_rpt_map[0].type = hidReportRefMouseIn[1]; + hid_rpt_map[0].handle = hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_REPORT_MOUSE_IN_VAL]; + hid_rpt_map[0].cccdHandle = hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_REPORT_MOUSE_IN_VAL]; + hid_rpt_map[0].mode = HID_PROTOCOL_MODE_REPORT; + + // Key input report + hid_rpt_map[1].id = hidReportRefKeyIn[0]; + hid_rpt_map[1].type = hidReportRefKeyIn[1]; + hid_rpt_map[1].handle = hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_REPORT_KEY_IN_VAL]; + hid_rpt_map[1].cccdHandle = hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_REPORT_KEY_IN_CCC]; + hid_rpt_map[1].mode = HID_PROTOCOL_MODE_REPORT; + + // Consumer Control input report + hid_rpt_map[2].id = hidReportRefCCIn[0]; + hid_rpt_map[2].type = hidReportRefCCIn[1]; + hid_rpt_map[2].handle = hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_REPORT_CC_IN_VAL]; + hid_rpt_map[2].cccdHandle = hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_REPORT_CC_IN_CCC]; + hid_rpt_map[2].mode = HID_PROTOCOL_MODE_REPORT; + + // LED output report + hid_rpt_map[3].id = hidReportRefLedOut[0]; + hid_rpt_map[3].type = hidReportRefLedOut[1]; + hid_rpt_map[3].handle = hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_REPORT_LED_OUT_VAL]; + hid_rpt_map[3].cccdHandle = 0; + hid_rpt_map[3].mode = HID_PROTOCOL_MODE_REPORT; + + // Boot keyboard input report + // Use same ID and type as key input report + hid_rpt_map[4].id = hidReportRefKeyIn[0]; + hid_rpt_map[4].type = hidReportRefKeyIn[1]; + hid_rpt_map[4].handle = hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_BOOT_KB_IN_REPORT_VAL]; + hid_rpt_map[4].cccdHandle = 0; + hid_rpt_map[4].mode = HID_PROTOCOL_MODE_BOOT; + + // Boot keyboard output report + // Use same ID and type as LED output report + hid_rpt_map[5].id = hidReportRefLedOut[0]; + hid_rpt_map[5].type = hidReportRefLedOut[1]; + hid_rpt_map[5].handle = hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_BOOT_KB_OUT_REPORT_VAL]; + hid_rpt_map[5].cccdHandle = 0; + hid_rpt_map[5].mode = HID_PROTOCOL_MODE_BOOT; + + // Boot mouse input report + // Use same ID and type as mouse input report + hid_rpt_map[6].id = hidReportRefMouseIn[0]; + hid_rpt_map[6].type = hidReportRefMouseIn[1]; + hid_rpt_map[6].handle = hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_BOOT_MOUSE_IN_REPORT_VAL]; + hid_rpt_map[6].cccdHandle = 0; + hid_rpt_map[6].mode = HID_PROTOCOL_MODE_BOOT; + + // Feature report + hid_rpt_map[7].id = hidReportRefFeature[0]; + hid_rpt_map[7].type = hidReportRefFeature[1]; + hid_rpt_map[7].handle = hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_REPORT_VAL]; + hid_rpt_map[7].cccdHandle = 0; + hid_rpt_map[7].mode = HID_PROTOCOL_MODE_REPORT; + + + // Setup report ID map + hid_dev_register_reports(HID_NUM_REPORTS, hid_rpt_map); +} + diff --git a/examples/bluetooth/ble_hid_device_demo/main/hidd_le_prf_int.h b/examples/bluetooth/ble_hid_device_demo/main/hidd_le_prf_int.h new file mode 100644 index 0000000000..311279af44 --- /dev/null +++ b/examples/bluetooth/ble_hid_device_demo/main/hidd_le_prf_int.h @@ -0,0 +1,339 @@ +// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + + +#ifndef __HID_DEVICE_LE_PRF__ +#define __HID_DEVICE_LE_PRF__ +#include "esp_gatts_api.h" +#include "esp_gatt_defs.h" +#include "esp_hidd_prf_api.h" +#include "esp_gap_ble_api.h" +#include "hid_dev.h" + + +/// Maximal number of HIDS that can be added in the DB +#ifndef USE_ONE_HIDS_INSTANCE +#define HIDD_LE_NB_HIDS_INST_MAX (2) +#else +#define HIDD_LE_NB_HIDS_INST_MAX (1) +#endif + +#define HIDD_GREAT_VER 0x01 //Version + Subversion +#define HIDD_SUB_VER 0x00 //Version + Subversion +#define HIDD_VERSION ((HIDD_GREAT_VER<<8)|HIDD_SUB_VER) //Version + Subversion + +#define HID_MAX_APPS 1 + +// Number of HID reports defined in the service +#define HID_NUM_REPORTS 9 + +// HID Report IDs for the service +#define HID_RPT_ID_MOUSE_IN 1 // Mouse input report ID +#define HID_RPT_ID_KEY_IN 2 // Keyboard input report ID +#define HID_RPT_ID_CC_IN 3 //Consumer Control input report ID +#define HID_RPT_ID_VENDOR_OUT 4 // Vendor output report ID +#define HID_RPT_ID_LED_OUT 0 // LED output report ID +#define HID_RPT_ID_FEATURE 0 // Feature report ID + +#define HIDD_APP_ID 0x1812//ATT_SVC_HID + +#define BATTRAY_APP_ID 0x180f + + +#define ATT_SVC_HID 0x1812 + +/// Maximal number of Report Char. that can be added in the DB for one HIDS - Up to 11 +#define HIDD_LE_NB_REPORT_INST_MAX (5) + +/// Maximal length of Report Char. Value +#define HIDD_LE_REPORT_MAX_LEN (255) +/// Maximal length of Report Map Char. Value +#define HIDD_LE_REPORT_MAP_MAX_LEN (512) + +/// Length of Boot Report Char. Value Maximal Length +#define HIDD_LE_BOOT_REPORT_MAX_LEN (8) + +/// Boot KB Input Report Notification Configuration Bit Mask +#define HIDD_LE_BOOT_KB_IN_NTF_CFG_MASK (0x40) +/// Boot KB Input Report Notification Configuration Bit Mask +#define HIDD_LE_BOOT_MOUSE_IN_NTF_CFG_MASK (0x80) +/// Boot Report Notification Configuration Bit Mask +#define HIDD_LE_REPORT_NTF_CFG_MASK (0x20) + + +/* HID information flags */ +#define HID_FLAGS_REMOTE_WAKE 0x01 // RemoteWake +#define HID_FLAGS_NORMALLY_CONNECTABLE 0x02 // NormallyConnectable + +/* Control point commands */ +#define HID_CMD_SUSPEND 0x00 // Suspend +#define HID_CMD_EXIT_SUSPEND 0x01 // Exit Suspend + +/* HID protocol mode values */ +#define HID_PROTOCOL_MODE_BOOT 0x00 // Boot Protocol Mode +#define HID_PROTOCOL_MODE_REPORT 0x01 // Report Protocol Mode + +/* Attribute value lengths */ +#define HID_PROTOCOL_MODE_LEN 1 // HID Protocol Mode +#define HID_INFORMATION_LEN 4 // HID Information +#define HID_REPORT_REF_LEN 2 // HID Report Reference Descriptor +#define HID_EXT_REPORT_REF_LEN 2 // External Report Reference Descriptor + +// HID feature flags +#define HID_KBD_FLAGS HID_FLAGS_REMOTE_WAKE + +/* HID Report type */ +#define HID_REPORT_TYPE_INPUT 1 +#define HID_REPORT_TYPE_OUTPUT 2 +#define HID_REPORT_TYPE_FEATURE 3 + + +/// HID Service Attributes Indexes +enum { + HIDD_LE_IDX_SVC, + + // Included Service + HIDD_LE_IDX_INCL_SVC, + + // HID Information + HIDD_LE_IDX_HID_INFO_CHAR, + HIDD_LE_IDX_HID_INFO_VAL, + + // HID Control Point + HIDD_LE_IDX_HID_CTNL_PT_CHAR, + HIDD_LE_IDX_HID_CTNL_PT_VAL, + + // Report Map + HIDD_LE_IDX_REPORT_MAP_CHAR, + HIDD_LE_IDX_REPORT_MAP_VAL, + HIDD_LE_IDX_REPORT_MAP_EXT_REP_REF, + + // Protocol Mode + HIDD_LE_IDX_PROTO_MODE_CHAR, + HIDD_LE_IDX_PROTO_MODE_VAL, + + // Report mouse input + HIDD_LE_IDX_REPORT_MOUSE_IN_CHAR, + HIDD_LE_IDX_REPORT_MOUSE_IN_VAL, + HIDD_LE_IDX_REPORT_MOUSE_IN_CCC, + HIDD_LE_IDX_REPORT_MOUSE_REP_REF, + //Report Key input + HIDD_LE_IDX_REPORT_KEY_IN_CHAR, + HIDD_LE_IDX_REPORT_KEY_IN_VAL, + 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 Vendor + HIDD_LE_IDX_REPORT_VENDOR_OUT_CHAR, + HIDD_LE_IDX_REPORT_VENDOR_OUT_VAL, + HIDD_LE_IDX_REPORT_VENDOR_OUT_REP_REF, + + HIDD_LE_IDX_REPORT_CC_IN_CHAR, + HIDD_LE_IDX_REPORT_CC_IN_VAL, + HIDD_LE_IDX_REPORT_CC_IN_CCC, + HIDD_LE_IDX_REPORT_CC_IN_REP_REF, + + // Boot Keyboard Input Report + HIDD_LE_IDX_BOOT_KB_IN_REPORT_CHAR, + HIDD_LE_IDX_BOOT_KB_IN_REPORT_VAL, + HIDD_LE_IDX_BOOT_KB_IN_REPORT_NTF_CFG, + + // Boot Keyboard Output Report + HIDD_LE_IDX_BOOT_KB_OUT_REPORT_CHAR, + HIDD_LE_IDX_BOOT_KB_OUT_REPORT_VAL, + + // Boot Mouse Input Report + HIDD_LE_IDX_BOOT_MOUSE_IN_REPORT_CHAR, + HIDD_LE_IDX_BOOT_MOUSE_IN_REPORT_VAL, + HIDD_LE_IDX_BOOT_MOUSE_IN_REPORT_NTF_CFG, + + // Report + HIDD_LE_IDX_REPORT_CHAR, + HIDD_LE_IDX_REPORT_VAL, + HIDD_LE_IDX_REPORT_REP_REF, + //HIDD_LE_IDX_REPORT_NTF_CFG, + + HIDD_LE_IDX_NB, +}; + + +/// Attribute Table Indexes +enum { + HIDD_LE_INFO_CHAR, + HIDD_LE_CTNL_PT_CHAR, + HIDD_LE_REPORT_MAP_CHAR, + HIDD_LE_REPORT_CHAR, + HIDD_LE_PROTO_MODE_CHAR, + HIDD_LE_BOOT_KB_IN_REPORT_CHAR, + HIDD_LE_BOOT_KB_OUT_REPORT_CHAR, + HIDD_LE_BOOT_MOUSE_IN_REPORT_CHAR, + HIDD_LE_CHAR_MAX //= HIDD_LE_REPORT_CHAR + HIDD_LE_NB_REPORT_INST_MAX, +}; + +///att read event table Indexs +enum { + HIDD_LE_READ_INFO_EVT, + HIDD_LE_READ_CTNL_PT_EVT, + HIDD_LE_READ_REPORT_MAP_EVT, + HIDD_LE_READ_REPORT_EVT, + HIDD_LE_READ_PROTO_MODE_EVT, + HIDD_LE_BOOT_KB_IN_REPORT_EVT, + HIDD_LE_BOOT_KB_OUT_REPORT_EVT, + HIDD_LE_BOOT_MOUSE_IN_REPORT_EVT, + + HID_LE_EVT_MAX +}; + +/// Client Characteristic Configuration Codes +enum { + HIDD_LE_DESC_MASK = 0x10, + + HIDD_LE_BOOT_KB_IN_REPORT_CFG = HIDD_LE_BOOT_KB_IN_REPORT_CHAR | HIDD_LE_DESC_MASK, + HIDD_LE_BOOT_MOUSE_IN_REPORT_CFG = HIDD_LE_BOOT_MOUSE_IN_REPORT_CHAR | HIDD_LE_DESC_MASK, + HIDD_LE_REPORT_CFG = HIDD_LE_REPORT_CHAR | HIDD_LE_DESC_MASK, +}; + +/// Features Flag Values +enum { + HIDD_LE_CFG_KEYBOARD = 0x01, + HIDD_LE_CFG_MOUSE = 0x02, + HIDD_LE_CFG_PROTO_MODE = 0x04, + HIDD_LE_CFG_MAP_EXT_REF = 0x08, + HIDD_LE_CFG_BOOT_KB_WR = 0x10, + HIDD_LE_CFG_BOOT_MOUSE_WR = 0x20, +}; + +/// Report Char. Configuration Flag Values +enum { + HIDD_LE_CFG_REPORT_IN = 0x01, + HIDD_LE_CFG_REPORT_OUT = 0x02, + //HOGPD_CFG_REPORT_FEAT can be used as a mask to check Report type + HIDD_LE_CFG_REPORT_FEAT = 0x03, + HIDD_LE_CFG_REPORT_WR = 0x10, +}; + +/// Pointer to the connection clean-up function +#define HIDD_LE_CLEANUP_FNCT (NULL) + +/* + * TYPE DEFINITIONS + **************************************************************************************** + */ + +/// HIDD Features structure +typedef struct { + /// Service Features + uint8_t svc_features; + /// Number of Report Char. instances to add in the database + uint8_t report_nb; + /// Report Char. Configuration + uint8_t report_char_cfg[HIDD_LE_NB_REPORT_INST_MAX]; +} hidd_feature_t; + + +typedef struct { + bool in_use; + bool congest; + uint16_t conn_id; + bool connected; + esp_bd_addr_t remote_bda; + uint32_t trans_id; + uint8_t cur_srvc_id; + +} hidd_clcb_t; + +// HID report mapping table +typedef struct { + uint16_t handle; // Handle of report characteristic + uint16_t cccdHandle; // Handle of CCCD for report characteristic + uint8_t id; // Report ID + uint8_t type; // Report type + uint8_t mode; // Protocol mode (report or boot) +} hidRptMap_t; + + +typedef struct { + /// hidd profile id + uint8_t app_id; + /// Notified handle + uint16_t ntf_handle; + ///Attribute handle Table + uint16_t att_tbl[HIDD_LE_IDX_NB]; + /// Supported Features + hidd_feature_t hidd_feature[HIDD_LE_NB_HIDS_INST_MAX]; + /// Current Protocol Mode + uint8_t proto_mode[HIDD_LE_NB_HIDS_INST_MAX]; + /// Number of HIDS added in the database + uint8_t hids_nb; + uint8_t pending_evt; + uint16_t pending_hal; +} hidd_inst_t; + +/// Report Reference structure +typedef struct +{ + ///Report ID + uint8_t report_id; + ///Report Type + uint8_t report_type; +}hids_report_ref_t; + +/// HID Information structure +typedef struct +{ + /// bcdHID + uint16_t bcdHID; + /// bCountryCode + uint8_t bCountryCode; + /// Flags + uint8_t flags; +}hids_hid_info_t; + + +/* service engine control block */ +typedef struct { + hidd_clcb_t hidd_clcb[HID_MAX_APPS]; /* connection link*/ + esp_gatt_if_t gatt_if; + bool enabled; + bool is_take; + bool is_primery; + hidd_inst_t hidd_inst; + esp_hidd_event_cb_t hidd_cb; + uint8_t inst_id; +} hidd_le_env_t; + +extern hidd_le_env_t hidd_le_env; +extern uint8_t hidProtocolMode; + + +void hidd_clcb_alloc (uint16_t conn_id, esp_bd_addr_t bda); + +bool hidd_clcb_dealloc (uint16_t conn_id); + +void hidd_le_create_service(esp_gatt_if_t gatts_if); + +void hidd_set_attr_value(uint16_t handle, uint16_t val_len, const uint8_t *value); + +void hidd_get_attr_value(uint16_t handle, uint16_t *length, uint8_t **value); + +esp_err_t hidd_register_cb(void); + + +#endif ///__HID_DEVICE_LE_PRF__ + diff --git a/examples/bluetooth/ble_hid_device_demo/sdkconfig.defaults b/examples/bluetooth/ble_hid_device_demo/sdkconfig.defaults new file mode 100644 index 0000000000..14f5546ffa --- /dev/null +++ b/examples/bluetooth/ble_hid_device_demo/sdkconfig.defaults @@ -0,0 +1,3 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y -- 2.40.0