mirror of
https://github.com/espressif/esp-idf.git
synced 2026-05-28 16:46:31 +03:00
Merge branch 'bugfix/nimble_hid_fixes' into 'master'
fix(nimble): Always read initial BAS level and forward HID report/control/protocol writes as HIDD events Closes BLERP-2806 See merge request espressif/esp-idf!48598
This commit is contained in:
Submodule components/bt/host/nimble/nimble updated: 5045cb5eb8...61a88ab53b
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2017-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -302,6 +302,21 @@ static void attach_report_listeners(esp_gatt_if_t gattc_if, esp_hidh_dev_t *dev)
|
||||
|
||||
//subscribe to battery notifications
|
||||
if (dev->ble.battery_handle) {
|
||||
uint8_t *rdata = NULL;
|
||||
uint16_t rlen = 0;
|
||||
|
||||
if (event_loop_handle &&
|
||||
read_char(gattc_if, dev->ble.conn_id, dev->ble.battery_handle,
|
||||
ESP_GATT_AUTH_REQ_NO_MITM, &rdata, &rlen) == ESP_GATT_OK &&
|
||||
rlen >= 1 && rdata != NULL) {
|
||||
esp_hidh_event_data_t p = {0};
|
||||
p.battery.dev = dev;
|
||||
p.battery.level = rdata[0];
|
||||
esp_event_post_to(event_loop_handle, ESP_HIDH_EVENTS, ESP_HIDH_BATTERY_EVENT,
|
||||
&p, sizeof(esp_hidh_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
free(rdata);
|
||||
|
||||
register_for_notify(gattc_if, dev->addr.bda, dev->ble.battery_handle);
|
||||
if (dev->ble.battery_ccc_handle) {
|
||||
//Write CCC descr to enable notifications
|
||||
|
||||
@@ -43,6 +43,9 @@ static void (*s_prev_sync_cb)(void) = NULL;
|
||||
static struct ble_gap_event_listener nimble_gap_event_listener;
|
||||
static void nimble_host_synced(void);
|
||||
void nimble_host_reset(int reason);
|
||||
static void nimble_report_write_cb(uint16_t attr_handle, uint8_t report_type, uint8_t report_id,
|
||||
const uint8_t *data, uint16_t len);
|
||||
static void nimble_char_write_cb(uint16_t attr_handle, uint16_t char_uuid16, uint8_t value);
|
||||
|
||||
static inline void lock_hidd(void)
|
||||
{
|
||||
@@ -349,6 +352,8 @@ static int nimble_hidd_dev_deinit(void *devp)
|
||||
ble_hs_cfg.sync_cb = s_prev_sync_cb;
|
||||
}
|
||||
ble_hs_cfg.gatts_register_cb = NULL;
|
||||
ble_svc_hid_register_report_write_cb(NULL);
|
||||
ble_svc_hid_register_char_write_cb(NULL);
|
||||
unlock_hidd();
|
||||
|
||||
/* STOP_EVENT may be discarded because ble_hid_free_config() deletes the event
|
||||
@@ -423,6 +428,129 @@ static hidd_le_report_item_t* find_report_by_usage_and_type(uint8_t dev_index, u
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void nimble_report_write_cb(uint16_t attr_handle, uint8_t report_type, uint8_t report_id,
|
||||
const uint8_t *data, uint16_t len)
|
||||
{
|
||||
lock_hidd();
|
||||
if (s_dev == NULL || s_dev->event_loop_handle == NULL || data == NULL) {
|
||||
unlock_hidd();
|
||||
return;
|
||||
}
|
||||
|
||||
hidd_le_report_item_t *match = NULL;
|
||||
uint8_t map_index = 0;
|
||||
for (uint8_t d = 0; d < s_dev->devices_len && match == NULL; d++) {
|
||||
for (uint8_t r = 0; r < s_dev->devices[d].reports_len; r++) {
|
||||
hidd_le_report_item_t *item = &s_dev->devices[d].reports[r];
|
||||
if (item->handle == attr_handle) {
|
||||
match = item;
|
||||
map_index = d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (match == NULL) {
|
||||
unlock_hidd();
|
||||
return;
|
||||
}
|
||||
|
||||
if (report_type != ESP_HID_REPORT_TYPE_OUTPUT &&
|
||||
report_type != ESP_HID_REPORT_TYPE_FEATURE) {
|
||||
ESP_LOGD(TAG, "Ignoring host write for unsupported report type=%u, id=%u, handle=%u",
|
||||
report_type, report_id, attr_handle);
|
||||
unlock_hidd();
|
||||
return;
|
||||
}
|
||||
|
||||
size_t event_data_size = sizeof(esp_hidd_event_data_t);
|
||||
if (len > 0) {
|
||||
event_data_size += len;
|
||||
}
|
||||
esp_hidd_event_data_t *p_cb_param = (esp_hidd_event_data_t *)calloc(1, event_data_size);
|
||||
if (p_cb_param == NULL) {
|
||||
ESP_LOGE(TAG, "%s malloc event data failed!", __func__);
|
||||
unlock_hidd();
|
||||
return;
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
memcpy(((uint8_t *)p_cb_param) + sizeof(esp_hidd_event_data_t), data, len);
|
||||
}
|
||||
|
||||
if (report_type == ESP_HID_REPORT_TYPE_OUTPUT) {
|
||||
p_cb_param->output.dev = s_dev->dev;
|
||||
p_cb_param->output.usage = match->usage;
|
||||
p_cb_param->output.report_id = report_id;
|
||||
p_cb_param->output.length = len;
|
||||
p_cb_param->output.data = (len > 0) ? (uint8_t *)data : NULL; /* fixed by esp_hidd_process_event_data_handler */
|
||||
p_cb_param->output.map_index = map_index;
|
||||
esp_event_post_to(s_dev->event_loop_handle, ESP_HIDD_EVENTS, ESP_HIDD_OUTPUT_EVENT,
|
||||
p_cb_param, event_data_size, portMAX_DELAY);
|
||||
} else if (report_type == ESP_HID_REPORT_TYPE_FEATURE) {
|
||||
p_cb_param->feature.dev = s_dev->dev;
|
||||
p_cb_param->feature.usage = match->usage;
|
||||
p_cb_param->feature.report_id = report_id;
|
||||
p_cb_param->feature.length = len;
|
||||
p_cb_param->feature.data = (len > 0) ? (uint8_t *)data : NULL; /* fixed by esp_hidd_process_event_data_handler */
|
||||
p_cb_param->feature.map_index = map_index;
|
||||
esp_event_post_to(s_dev->event_loop_handle, ESP_HIDD_EVENTS, ESP_HIDD_FEATURE_EVENT,
|
||||
p_cb_param, event_data_size, portMAX_DELAY);
|
||||
}
|
||||
free(p_cb_param);
|
||||
unlock_hidd();
|
||||
}
|
||||
|
||||
static void nimble_char_write_cb(uint16_t attr_handle, uint16_t char_uuid16, uint8_t value)
|
||||
{
|
||||
lock_hidd();
|
||||
if (s_dev == NULL || s_dev->event_loop_handle == NULL) {
|
||||
unlock_hidd();
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t map_index = 0;
|
||||
bool found = false;
|
||||
|
||||
for (uint8_t d = 0; d < s_dev->devices_len; d++) {
|
||||
if (char_uuid16 == BLE_SVC_HID_CHR_UUID16_PROTOCOL_MODE &&
|
||||
s_dev->devices[d].hid_protocol_handle == attr_handle) {
|
||||
found = true;
|
||||
map_index = d;
|
||||
break;
|
||||
}
|
||||
if (char_uuid16 == BLE_SVC_HID_CHR_UUID16_HID_CTRL_PT &&
|
||||
s_dev->devices[d].hid_control_handle == attr_handle) {
|
||||
found = true;
|
||||
map_index = d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
unlock_hidd();
|
||||
return;
|
||||
}
|
||||
|
||||
esp_hidd_event_data_t cb_param = {0};
|
||||
if (char_uuid16 == BLE_SVC_HID_CHR_UUID16_PROTOCOL_MODE) {
|
||||
s_dev->protocol = value;
|
||||
cb_param.protocol_mode.dev = s_dev->dev;
|
||||
cb_param.protocol_mode.protocol_mode = value;
|
||||
cb_param.protocol_mode.map_index = map_index;
|
||||
esp_event_post_to(s_dev->event_loop_handle, ESP_HIDD_EVENTS, ESP_HIDD_PROTOCOL_MODE_EVENT,
|
||||
&cb_param, sizeof(esp_hidd_event_data_t), portMAX_DELAY);
|
||||
} else if (char_uuid16 == BLE_SVC_HID_CHR_UUID16_HID_CTRL_PT) {
|
||||
s_dev->control = value;
|
||||
cb_param.control.dev = s_dev->dev;
|
||||
cb_param.control.control = value;
|
||||
cb_param.control.map_index = map_index;
|
||||
esp_event_post_to(s_dev->event_loop_handle, ESP_HIDD_EVENTS, ESP_HIDD_CONTROL_EVENT,
|
||||
&cb_param, sizeof(esp_hidd_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
unlock_hidd();
|
||||
}
|
||||
|
||||
static int nimble_hidd_dev_input_set(void *devp, size_t index, size_t id, uint8_t *data, size_t length)
|
||||
{
|
||||
hidd_le_report_item_t *p_rpt;
|
||||
@@ -840,6 +968,8 @@ esp_err_t esp_ble_hidd_dev_init(esp_hidd_dev_t *dev_p, const esp_hid_device_conf
|
||||
ble_hs_cfg.reset_cb = nimble_host_reset;
|
||||
ble_hs_cfg.sync_cb = nimble_host_synced;
|
||||
ble_hs_cfg.gatts_register_cb = nimble_gatt_svr_register_cb;
|
||||
ble_svc_hid_register_report_write_cb(nimble_report_write_cb);
|
||||
ble_svc_hid_register_char_write_cb(nimble_char_write_cb);
|
||||
rc = nimble_hid_start_gatts();
|
||||
if (rc != ESP_OK) {
|
||||
if (ble_hs_cfg.reset_cb == nimble_host_reset) {
|
||||
@@ -849,6 +979,8 @@ esp_err_t esp_ble_hidd_dev_init(esp_hidd_dev_t *dev_p, const esp_hid_device_conf
|
||||
ble_hs_cfg.sync_cb = s_prev_sync_cb;
|
||||
}
|
||||
ble_hs_cfg.gatts_register_cb = NULL;
|
||||
ble_svc_hid_register_report_write_cb(NULL);
|
||||
ble_svc_hid_register_char_write_cb(NULL);
|
||||
ble_hidd_dev_free();
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -70,14 +70,14 @@ static inline void SEND_CB(void)
|
||||
static inline void LOCK_OPS(void)
|
||||
{
|
||||
if (s_ble_hidh_op_mutex) {
|
||||
xSemaphoreTake(s_ble_hidh_op_mutex, portMAX_DELAY);
|
||||
xSemaphoreTakeRecursive(s_ble_hidh_op_mutex, portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void UNLOCK_OPS(void)
|
||||
{
|
||||
if (s_ble_hidh_op_mutex) {
|
||||
xSemaphoreGive(s_ble_hidh_op_mutex);
|
||||
xSemaphoreGiveRecursive(s_ble_hidh_op_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -789,6 +789,20 @@ static void attach_report_listeners(esp_hidh_dev_t *dev)
|
||||
report = dev->reports;
|
||||
|
||||
if (dev->ble.battery_handle) {
|
||||
uint8_t *rdata = NULL;
|
||||
uint16_t rlen = 0;
|
||||
|
||||
if (event_loop_handle &&
|
||||
read_char(dev->ble.conn_id, dev->ble.battery_handle, &rdata, &rlen) == 0 &&
|
||||
rlen >= 1 && rdata != NULL) {
|
||||
esp_hidh_event_data_t p = {0};
|
||||
p.battery.dev = dev;
|
||||
p.battery.level = rdata[0];
|
||||
esp_event_post_to(event_loop_handle, ESP_HIDH_EVENTS, ESP_HIDH_BATTERY_EVENT,
|
||||
&p, sizeof(esp_hidh_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
free(rdata);
|
||||
|
||||
register_for_notify(dev->ble.conn_id, dev->ble.battery_handle);
|
||||
if (dev->ble.battery_ccc_handle && dev->ble.conn_id >= 0 && dev->connected) {
|
||||
write_char_descr(dev, dev->ble.battery_ccc_handle, 2, (uint8_t *)&ccc_data);
|
||||
@@ -1174,7 +1188,7 @@ esp_err_t esp_ble_hidh_init(const esp_hidh_config_t *config)
|
||||
s_ble_hidh_cb_semaphore = xSemaphoreCreateBinary();
|
||||
ESP_RETURN_ON_FALSE(s_ble_hidh_cb_semaphore,
|
||||
ESP_ERR_NO_MEM, TAG, "Allocation failed");
|
||||
s_ble_hidh_op_mutex = xSemaphoreCreateMutex();
|
||||
s_ble_hidh_op_mutex = xSemaphoreCreateRecursiveMutex();
|
||||
if (s_ble_hidh_op_mutex == NULL) {
|
||||
vSemaphoreDelete(s_ble_hidh_cb_semaphore);
|
||||
s_ble_hidh_cb_semaphore = NULL;
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "esp_hid_gap.h"
|
||||
|
||||
static const char *TAG = "HID_DEV_DEMO";
|
||||
#define HID_BATTERY_LEVEL 60
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -941,6 +942,7 @@ void app_main(void)
|
||||
ESP_LOGI(TAG, "setting ble device");
|
||||
ESP_ERROR_CHECK(
|
||||
esp_hidd_dev_init(&ble_hid_config, ESP_HID_TRANSPORT_BLE, ble_hidd_event_callback, &s_ble_hid_param.hid_dev));
|
||||
ESP_ERROR_CHECK(esp_hidd_dev_battery_set(s_ble_hid_param.hid_dev, HID_BATTERY_LEVEL));
|
||||
#endif
|
||||
|
||||
#if CONFIG_BT_HID_DEVICE_ENABLED
|
||||
|
||||
Reference in New Issue
Block a user