mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 11:10:54 +03:00
fix(nimble): Address review comments for hidd / hidh code
This commit is contained in:
committed by
Shreeyash Bhakare
parent
02b57e7e77
commit
541065755d
@@ -93,9 +93,9 @@ void btc_blufi_report_error(esp_blufi_error_state_t state)
|
|||||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL, NULL);
|
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FALSE POSITIVE: blufi_env is a single-connection global by design.
|
/* blufi_env is a global shared state but only one BLE connection is active at
|
||||||
* The GAP layer rejects new connections while is_connected==true,
|
* a time — the GAP layer rejects new connections while is_connected==true,
|
||||||
* so concurrent multi-connection access to this state never occurs. */
|
* so there is no concurrent access to this structure. */
|
||||||
void btc_blufi_recv_handler(uint8_t *data, int len)
|
void btc_blufi_recv_handler(uint8_t *data, int len)
|
||||||
{
|
{
|
||||||
if (len < sizeof(struct blufi_hdr)) {
|
if (len < sizeof(struct blufi_hdr)) {
|
||||||
@@ -239,9 +239,10 @@ void btc_blufi_recv_handler(uint8_t *data, int len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Known limitation: this function runs in the BTC task (app-initiated sends)
|
|
||||||
* AND in the NimBLE task (via recv_handler), racing on send_seq/frag_size.
|
/* This function is called from both the BTC task and the NimBLE task, so
|
||||||
* portENTER_CRITICAL cannot protect here; */
|
* send_seq/frag_size may race. portENTER_CRITICAL does not help across
|
||||||
|
* different FreeRTOS tasks; a mutex would be needed for full protection. */
|
||||||
void btc_blufi_send_encap(uint8_t type, uint8_t *data, int total_data_len)
|
void btc_blufi_send_encap(uint8_t type, uint8_t *data, int total_data_len)
|
||||||
{
|
{
|
||||||
struct blufi_hdr *hdr = NULL;
|
struct blufi_hdr *hdr = NULL;
|
||||||
|
|||||||
@@ -53,9 +53,9 @@ static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
|
|||||||
.uuid = BLE_UUID16_DECLARE(BLUFI_SERVICE_UUID),
|
.uuid = BLE_UUID16_DECLARE(BLUFI_SERVICE_UUID),
|
||||||
.characteristics = (struct ble_gatt_chr_def[])
|
.characteristics = (struct ble_gatt_chr_def[])
|
||||||
{ {
|
{ {
|
||||||
/* FALSE POSITIVE: No BLE_GATT_CHR_F_WRITE_ENC/READ_ENC by design.
|
/* BLE_GATT_CHR_F_WRITE_ENC/READ_ENC are not set because BLUFI uses its
|
||||||
* BLUFI uses its own app-layer security (DH key exchange + AES + CRC).
|
* own application-layer security (DH key exchange + AES-128 + CRC).
|
||||||
* BLE link-layer pairing is impossible before provisioning credentials exist. */
|
* BLE pairing cannot occur before Wi-Fi credentials are provisioned. */
|
||||||
/*** Characteristic: P2E */
|
/*** Characteristic: P2E */
|
||||||
.uuid = BLE_UUID16_DECLARE(BLUFI_CHAR_P2E_UUID),
|
.uuid = BLE_UUID16_DECLARE(BLUFI_CHAR_P2E_UUID),
|
||||||
.access_cb = gatt_svr_access_cb,
|
.access_cb = gatt_svr_access_cb,
|
||||||
|
|||||||
@@ -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
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -40,6 +40,34 @@ static inline void unlock_devices(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Atomically checks whether a device is still in the global list and acquires
|
||||||
|
* its mutex before releasing the list lock. This avoids TOCTOU between
|
||||||
|
* `esp_hidh_dev_exists()` and `esp_hidh_dev_lock()` for call sites that need
|
||||||
|
* a stable pointer.
|
||||||
|
*/
|
||||||
|
static bool lock_known_device(esp_hidh_dev_t *dev)
|
||||||
|
{
|
||||||
|
if (dev == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
esp_hidh_dev_t *d = NULL;
|
||||||
|
lock_devices();
|
||||||
|
TAILQ_FOREACH(d, &s_esp_hidh_devices, devices) {
|
||||||
|
if (d == dev) {
|
||||||
|
found = true;
|
||||||
|
if (dev->mutex != NULL) {
|
||||||
|
xSemaphoreTake(dev->mutex, portMAX_DELAY);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unlock_devices();
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Public Functions
|
* Public Functions
|
||||||
* */
|
* */
|
||||||
@@ -207,8 +235,7 @@ esp_hidh_dev_t *esp_hidh_dev_open(uint8_t *bda, esp_hid_transport_t transport, u
|
|||||||
esp_err_t esp_hidh_dev_close(esp_hidh_dev_t *dev)
|
esp_err_t esp_hidh_dev_close(esp_hidh_dev_t *dev)
|
||||||
{
|
{
|
||||||
esp_err_t ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
if (esp_hidh_dev_exists(dev)) {
|
if (lock_known_device(dev)) {
|
||||||
esp_hidh_dev_lock(dev);
|
|
||||||
ret = dev->close(dev);
|
ret = dev->close(dev);
|
||||||
esp_hidh_dev_unlock(dev);
|
esp_hidh_dev_unlock(dev);
|
||||||
} else {
|
} else {
|
||||||
@@ -219,8 +246,7 @@ esp_err_t esp_hidh_dev_close(esp_hidh_dev_t *dev)
|
|||||||
|
|
||||||
void esp_hidh_dev_dump(esp_hidh_dev_t *dev, FILE *fp)
|
void esp_hidh_dev_dump(esp_hidh_dev_t *dev, FILE *fp)
|
||||||
{
|
{
|
||||||
if (esp_hidh_dev_exists(dev)) {
|
if (lock_known_device(dev)) {
|
||||||
esp_hidh_dev_lock(dev);
|
|
||||||
dev->dump(dev, fp);
|
dev->dump(dev, fp);
|
||||||
esp_hidh_dev_unlock(dev);
|
esp_hidh_dev_unlock(dev);
|
||||||
}
|
}
|
||||||
@@ -229,8 +255,7 @@ void esp_hidh_dev_dump(esp_hidh_dev_t *dev, FILE *fp)
|
|||||||
esp_err_t esp_hidh_dev_output_set(esp_hidh_dev_t *dev, size_t map_index, size_t report_id, uint8_t *value, size_t value_len)
|
esp_err_t esp_hidh_dev_output_set(esp_hidh_dev_t *dev, size_t map_index, size_t report_id, uint8_t *value, size_t value_len)
|
||||||
{
|
{
|
||||||
esp_err_t ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
if (esp_hidh_dev_exists(dev)) {
|
if (lock_known_device(dev)) {
|
||||||
esp_hidh_dev_lock(dev);
|
|
||||||
ret = dev->report_write(dev, map_index, report_id, ESP_HID_REPORT_TYPE_OUTPUT, value, value_len);
|
ret = dev->report_write(dev, map_index, report_id, ESP_HID_REPORT_TYPE_OUTPUT, value, value_len);
|
||||||
esp_hidh_dev_unlock(dev);
|
esp_hidh_dev_unlock(dev);
|
||||||
} else {
|
} else {
|
||||||
@@ -242,8 +267,7 @@ esp_err_t esp_hidh_dev_output_set(esp_hidh_dev_t *dev, size_t map_index, size_t
|
|||||||
esp_err_t esp_hidh_dev_feature_set(esp_hidh_dev_t *dev, size_t map_index, size_t report_id, uint8_t *value, size_t value_len)
|
esp_err_t esp_hidh_dev_feature_set(esp_hidh_dev_t *dev, size_t map_index, size_t report_id, uint8_t *value, size_t value_len)
|
||||||
{
|
{
|
||||||
esp_err_t ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
if (esp_hidh_dev_exists(dev)) {
|
if (lock_known_device(dev)) {
|
||||||
esp_hidh_dev_lock(dev);
|
|
||||||
ret = dev->report_write(dev, map_index, report_id, ESP_HID_REPORT_TYPE_FEATURE, value, value_len);
|
ret = dev->report_write(dev, map_index, report_id, ESP_HID_REPORT_TYPE_FEATURE, value, value_len);
|
||||||
esp_hidh_dev_unlock(dev);
|
esp_hidh_dev_unlock(dev);
|
||||||
} else {
|
} else {
|
||||||
@@ -255,8 +279,7 @@ esp_err_t esp_hidh_dev_feature_set(esp_hidh_dev_t *dev, size_t map_index, size_t
|
|||||||
esp_err_t esp_hidh_dev_feature_get(esp_hidh_dev_t *dev, size_t map_index, size_t report_id, size_t max_length, uint8_t *value, size_t *value_len)
|
esp_err_t esp_hidh_dev_feature_get(esp_hidh_dev_t *dev, size_t map_index, size_t report_id, size_t max_length, uint8_t *value, size_t *value_len)
|
||||||
{
|
{
|
||||||
esp_err_t ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
if (esp_hidh_dev_exists(dev)) {
|
if (lock_known_device(dev)) {
|
||||||
esp_hidh_dev_lock(dev);
|
|
||||||
ret = dev->report_read(dev, map_index, report_id, ESP_HID_REPORT_TYPE_FEATURE, max_length, value, value_len);
|
ret = dev->report_read(dev, map_index, report_id, ESP_HID_REPORT_TYPE_FEATURE, max_length, value, value_len);
|
||||||
esp_hidh_dev_unlock(dev);
|
esp_hidh_dev_unlock(dev);
|
||||||
} else {
|
} else {
|
||||||
@@ -268,8 +291,7 @@ esp_err_t esp_hidh_dev_feature_get(esp_hidh_dev_t *dev, size_t map_index, size_t
|
|||||||
esp_err_t esp_hidh_dev_set_report(esp_hidh_dev_t *dev, size_t map_index, size_t report_id, int report_type, uint8_t *data, size_t length)
|
esp_err_t esp_hidh_dev_set_report(esp_hidh_dev_t *dev, size_t map_index, size_t report_id, int report_type, uint8_t *data, size_t length)
|
||||||
{
|
{
|
||||||
esp_err_t ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
if (esp_hidh_dev_exists(dev)) {
|
if (lock_known_device(dev)) {
|
||||||
esp_hidh_dev_lock(dev);
|
|
||||||
if (dev->set_report) {
|
if (dev->set_report) {
|
||||||
ret = dev->set_report(dev, map_index, report_id, report_type, data, length);
|
ret = dev->set_report(dev, map_index, report_id, report_type, data, length);
|
||||||
} else {
|
} else {
|
||||||
@@ -286,8 +308,7 @@ esp_err_t esp_hidh_dev_get_report(esp_hidh_dev_t *dev, size_t map_index, size_t
|
|||||||
size_t max_len)
|
size_t max_len)
|
||||||
{
|
{
|
||||||
esp_err_t ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
if (esp_hidh_dev_exists(dev)) {
|
if (lock_known_device(dev)) {
|
||||||
esp_hidh_dev_lock(dev);
|
|
||||||
ret = dev->report_read(dev, map_index, report_id, report_type, max_len, NULL, NULL);
|
ret = dev->report_read(dev, map_index, report_id, report_type, max_len, NULL, NULL);
|
||||||
esp_hidh_dev_unlock(dev);
|
esp_hidh_dev_unlock(dev);
|
||||||
} else {
|
} else {
|
||||||
@@ -299,8 +320,7 @@ esp_err_t esp_hidh_dev_get_report(esp_hidh_dev_t *dev, size_t map_index, size_t
|
|||||||
esp_err_t esp_hidh_dev_get_idle(esp_hidh_dev_t *dev)
|
esp_err_t esp_hidh_dev_get_idle(esp_hidh_dev_t *dev)
|
||||||
{
|
{
|
||||||
esp_err_t ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
if (esp_hidh_dev_exists(dev)) {
|
if (lock_known_device(dev)) {
|
||||||
esp_hidh_dev_lock(dev);
|
|
||||||
if (dev->get_idle) {
|
if (dev->get_idle) {
|
||||||
ret = dev->get_idle(dev);
|
ret = dev->get_idle(dev);
|
||||||
} else {
|
} else {
|
||||||
@@ -316,8 +336,7 @@ esp_err_t esp_hidh_dev_get_idle(esp_hidh_dev_t *dev)
|
|||||||
esp_err_t esp_hidh_dev_set_idle(esp_hidh_dev_t *dev, uint8_t idle_time)
|
esp_err_t esp_hidh_dev_set_idle(esp_hidh_dev_t *dev, uint8_t idle_time)
|
||||||
{
|
{
|
||||||
esp_err_t ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
if (esp_hidh_dev_exists(dev)) {
|
if (lock_known_device(dev)) {
|
||||||
esp_hidh_dev_lock(dev);
|
|
||||||
if (dev->set_idle) {
|
if (dev->set_idle) {
|
||||||
ret = dev->set_idle(dev, idle_time);
|
ret = dev->set_idle(dev, idle_time);
|
||||||
} else {
|
} else {
|
||||||
@@ -333,8 +352,7 @@ esp_err_t esp_hidh_dev_set_idle(esp_hidh_dev_t *dev, uint8_t idle_time)
|
|||||||
esp_err_t esp_hidh_dev_get_protocol(esp_hidh_dev_t *dev)
|
esp_err_t esp_hidh_dev_get_protocol(esp_hidh_dev_t *dev)
|
||||||
{
|
{
|
||||||
esp_err_t ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
if (esp_hidh_dev_exists(dev)) {
|
if (lock_known_device(dev)) {
|
||||||
esp_hidh_dev_lock(dev);
|
|
||||||
if (dev->get_protocol) {
|
if (dev->get_protocol) {
|
||||||
ret = dev->get_protocol(dev);
|
ret = dev->get_protocol(dev);
|
||||||
} else {
|
} else {
|
||||||
@@ -350,8 +368,7 @@ esp_err_t esp_hidh_dev_get_protocol(esp_hidh_dev_t *dev)
|
|||||||
esp_err_t esp_hidh_dev_set_protocol(esp_hidh_dev_t *dev, uint8_t protocol_mode)
|
esp_err_t esp_hidh_dev_set_protocol(esp_hidh_dev_t *dev, uint8_t protocol_mode)
|
||||||
{
|
{
|
||||||
esp_err_t ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
if (esp_hidh_dev_exists(dev)) {
|
if (lock_known_device(dev)) {
|
||||||
esp_hidh_dev_lock(dev);
|
|
||||||
if (dev->set_protocol) {
|
if (dev->set_protocol) {
|
||||||
ret = dev->set_protocol(dev, protocol_mode);
|
ret = dev->set_protocol(dev, protocol_mode);
|
||||||
} else {
|
} else {
|
||||||
@@ -368,8 +385,7 @@ const uint8_t *esp_hidh_dev_bda_get(esp_hidh_dev_t *dev)
|
|||||||
{
|
{
|
||||||
uint8_t *ret = NULL;
|
uint8_t *ret = NULL;
|
||||||
#if CONFIG_BLUEDROID_ENABLED || CONFIG_BT_NIMBLE_ENABLED
|
#if CONFIG_BLUEDROID_ENABLED || CONFIG_BT_NIMBLE_ENABLED
|
||||||
if (esp_hidh_dev_exists(dev)) {
|
if (lock_known_device(dev)) {
|
||||||
esp_hidh_dev_lock(dev);
|
|
||||||
ret = dev->addr.bda;
|
ret = dev->addr.bda;
|
||||||
esp_hidh_dev_unlock(dev);
|
esp_hidh_dev_unlock(dev);
|
||||||
}
|
}
|
||||||
@@ -380,8 +396,7 @@ const uint8_t *esp_hidh_dev_bda_get(esp_hidh_dev_t *dev)
|
|||||||
esp_hid_transport_t esp_hidh_dev_transport_get(esp_hidh_dev_t *dev)
|
esp_hid_transport_t esp_hidh_dev_transport_get(esp_hidh_dev_t *dev)
|
||||||
{
|
{
|
||||||
esp_hid_transport_t ret = ESP_HID_TRANSPORT_MAX;
|
esp_hid_transport_t ret = ESP_HID_TRANSPORT_MAX;
|
||||||
if (esp_hidh_dev_exists(dev)) {
|
if (lock_known_device(dev)) {
|
||||||
esp_hidh_dev_lock(dev);
|
|
||||||
ret = dev->transport;
|
ret = dev->transport;
|
||||||
esp_hidh_dev_unlock(dev);
|
esp_hidh_dev_unlock(dev);
|
||||||
}
|
}
|
||||||
@@ -391,8 +406,7 @@ esp_hid_transport_t esp_hidh_dev_transport_get(esp_hidh_dev_t *dev)
|
|||||||
const esp_hid_device_config_t *esp_hidh_dev_config_get(esp_hidh_dev_t *dev)
|
const esp_hid_device_config_t *esp_hidh_dev_config_get(esp_hidh_dev_t *dev)
|
||||||
{
|
{
|
||||||
esp_hid_device_config_t *ret = NULL;
|
esp_hid_device_config_t *ret = NULL;
|
||||||
if (esp_hidh_dev_exists(dev)) {
|
if (lock_known_device(dev)) {
|
||||||
esp_hidh_dev_lock(dev);
|
|
||||||
ret = &dev->config;
|
ret = &dev->config;
|
||||||
esp_hidh_dev_unlock(dev);
|
esp_hidh_dev_unlock(dev);
|
||||||
}
|
}
|
||||||
@@ -402,8 +416,7 @@ const esp_hid_device_config_t *esp_hidh_dev_config_get(esp_hidh_dev_t *dev)
|
|||||||
const char *esp_hidh_dev_name_get(esp_hidh_dev_t *dev)
|
const char *esp_hidh_dev_name_get(esp_hidh_dev_t *dev)
|
||||||
{
|
{
|
||||||
const char * ret = NULL;
|
const char * ret = NULL;
|
||||||
if (esp_hidh_dev_exists(dev)) {
|
if (lock_known_device(dev)) {
|
||||||
esp_hidh_dev_lock(dev);
|
|
||||||
ret = dev->config.device_name ? dev->config.device_name : "";
|
ret = dev->config.device_name ? dev->config.device_name : "";
|
||||||
esp_hidh_dev_unlock(dev);
|
esp_hidh_dev_unlock(dev);
|
||||||
}
|
}
|
||||||
@@ -413,8 +426,7 @@ const char *esp_hidh_dev_name_get(esp_hidh_dev_t *dev)
|
|||||||
const char *esp_hidh_dev_manufacturer_get(esp_hidh_dev_t *dev)
|
const char *esp_hidh_dev_manufacturer_get(esp_hidh_dev_t *dev)
|
||||||
{
|
{
|
||||||
const char *ret = NULL;
|
const char *ret = NULL;
|
||||||
if (esp_hidh_dev_exists(dev)) {
|
if (lock_known_device(dev)) {
|
||||||
esp_hidh_dev_lock(dev);
|
|
||||||
ret = dev->config.manufacturer_name ? dev->config.manufacturer_name : "";
|
ret = dev->config.manufacturer_name ? dev->config.manufacturer_name : "";
|
||||||
esp_hidh_dev_unlock(dev);
|
esp_hidh_dev_unlock(dev);
|
||||||
}
|
}
|
||||||
@@ -424,8 +436,7 @@ const char *esp_hidh_dev_manufacturer_get(esp_hidh_dev_t *dev)
|
|||||||
const char *esp_hidh_dev_serial_get(esp_hidh_dev_t *dev)
|
const char *esp_hidh_dev_serial_get(esp_hidh_dev_t *dev)
|
||||||
{
|
{
|
||||||
const char *ret = NULL;
|
const char *ret = NULL;
|
||||||
if (esp_hidh_dev_exists(dev)) {
|
if (lock_known_device(dev)) {
|
||||||
esp_hidh_dev_lock(dev);
|
|
||||||
ret = dev->config.serial_number ? dev->config.serial_number : "";
|
ret = dev->config.serial_number ? dev->config.serial_number : "";
|
||||||
esp_hidh_dev_unlock(dev);
|
esp_hidh_dev_unlock(dev);
|
||||||
}
|
}
|
||||||
@@ -435,8 +446,7 @@ const char *esp_hidh_dev_serial_get(esp_hidh_dev_t *dev)
|
|||||||
uint16_t esp_hidh_dev_vendor_id_get(esp_hidh_dev_t *dev)
|
uint16_t esp_hidh_dev_vendor_id_get(esp_hidh_dev_t *dev)
|
||||||
{
|
{
|
||||||
uint16_t ret = 0;
|
uint16_t ret = 0;
|
||||||
if (esp_hidh_dev_exists(dev)) {
|
if (lock_known_device(dev)) {
|
||||||
esp_hidh_dev_lock(dev);
|
|
||||||
ret = dev->config.vendor_id;
|
ret = dev->config.vendor_id;
|
||||||
esp_hidh_dev_unlock(dev);
|
esp_hidh_dev_unlock(dev);
|
||||||
}
|
}
|
||||||
@@ -446,8 +456,7 @@ uint16_t esp_hidh_dev_vendor_id_get(esp_hidh_dev_t *dev)
|
|||||||
uint16_t esp_hidh_dev_product_id_get(esp_hidh_dev_t *dev)
|
uint16_t esp_hidh_dev_product_id_get(esp_hidh_dev_t *dev)
|
||||||
{
|
{
|
||||||
uint16_t ret = 0;
|
uint16_t ret = 0;
|
||||||
if (esp_hidh_dev_exists(dev)) {
|
if (lock_known_device(dev)) {
|
||||||
esp_hidh_dev_lock(dev);
|
|
||||||
ret = dev->config.product_id;
|
ret = dev->config.product_id;
|
||||||
esp_hidh_dev_unlock(dev);
|
esp_hidh_dev_unlock(dev);
|
||||||
}
|
}
|
||||||
@@ -457,8 +466,7 @@ uint16_t esp_hidh_dev_product_id_get(esp_hidh_dev_t *dev)
|
|||||||
uint16_t esp_hidh_dev_version_get(esp_hidh_dev_t *dev)
|
uint16_t esp_hidh_dev_version_get(esp_hidh_dev_t *dev)
|
||||||
{
|
{
|
||||||
uint16_t ret = 0;
|
uint16_t ret = 0;
|
||||||
if (!esp_hidh_dev_exists(dev)) {
|
if (lock_known_device(dev)) {
|
||||||
esp_hidh_dev_lock(dev);
|
|
||||||
ret = dev->config.version;
|
ret = dev->config.version;
|
||||||
esp_hidh_dev_unlock(dev);
|
esp_hidh_dev_unlock(dev);
|
||||||
}
|
}
|
||||||
@@ -468,8 +476,7 @@ uint16_t esp_hidh_dev_version_get(esp_hidh_dev_t *dev)
|
|||||||
esp_hid_usage_t esp_hidh_dev_usage_get(esp_hidh_dev_t *dev)
|
esp_hid_usage_t esp_hidh_dev_usage_get(esp_hidh_dev_t *dev)
|
||||||
{
|
{
|
||||||
esp_hid_usage_t ret = ESP_HID_USAGE_GENERIC;
|
esp_hid_usage_t ret = ESP_HID_USAGE_GENERIC;
|
||||||
if (esp_hidh_dev_exists(dev)) {
|
if (lock_known_device(dev)) {
|
||||||
esp_hidh_dev_lock(dev);
|
|
||||||
ret = dev->usage;
|
ret = dev->usage;
|
||||||
esp_hidh_dev_unlock(dev);
|
esp_hidh_dev_unlock(dev);
|
||||||
}
|
}
|
||||||
@@ -481,11 +488,9 @@ esp_err_t esp_hidh_dev_reports_get(esp_hidh_dev_t *dev, size_t *num_reports, esp
|
|||||||
esp_err_t ret = 0;
|
esp_err_t ret = 0;
|
||||||
esp_hid_report_item_t *r = NULL;
|
esp_hid_report_item_t *r = NULL;
|
||||||
|
|
||||||
if (!esp_hidh_dev_exists(dev)) {
|
if (!lock_known_device(dev)) {
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_hidh_dev_lock(dev);
|
|
||||||
do {
|
do {
|
||||||
r = (esp_hid_report_item_t *)malloc(sizeof(esp_hid_report_item_t) * dev->reports_len);
|
r = (esp_hid_report_item_t *)malloc(sizeof(esp_hid_report_item_t) * dev->reports_len);
|
||||||
if (r == NULL) {
|
if (r == NULL) {
|
||||||
@@ -521,10 +526,9 @@ error_:;
|
|||||||
|
|
||||||
esp_err_t esp_hidh_dev_report_maps_get(esp_hidh_dev_t *dev, size_t *num_maps, esp_hid_raw_report_map_t **maps)
|
esp_err_t esp_hidh_dev_report_maps_get(esp_hidh_dev_t *dev, size_t *num_maps, esp_hid_raw_report_map_t **maps)
|
||||||
{
|
{
|
||||||
if (!esp_hidh_dev_exists(dev)) {
|
if (!lock_known_device(dev)) {
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
esp_hidh_dev_lock(dev);
|
|
||||||
*num_maps = dev->config.report_maps_len;
|
*num_maps = dev->config.report_maps_len;
|
||||||
*maps = dev->config.report_maps;
|
*maps = dev->config.report_maps;
|
||||||
esp_hidh_dev_unlock(dev);
|
esp_hidh_dev_unlock(dev);
|
||||||
@@ -692,6 +696,9 @@ static void esp_hidh_dev_resources_free(esp_hidh_dev_t *dev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
free((void *)dev->config.report_maps);
|
free((void *)dev->config.report_maps);
|
||||||
|
#if CONFIG_BT_NIMBLE_ENABLED
|
||||||
|
free((void *)dev->protocol_mode);
|
||||||
|
#endif
|
||||||
esp_hidh_dev_report_t *r;
|
esp_hidh_dev_report_t *r;
|
||||||
while (dev->reports) {
|
while (dev->reports) {
|
||||||
r = dev->reports;
|
r = dev->reports;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2017-2026 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "ble_hidd.h"
|
#include "ble_hidd.h"
|
||||||
#include "esp_private/esp_hidd_private.h"
|
#include "esp_private/esp_hidd_private.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
#include "freertos/semphr.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -35,6 +36,27 @@ static const char *TAG = "NIMBLE_HIDD";
|
|||||||
typedef struct esp_ble_hidd_dev_s esp_ble_hidd_dev_t;
|
typedef struct esp_ble_hidd_dev_s esp_ble_hidd_dev_t;
|
||||||
// there can be only one BLE HID device
|
// there can be only one BLE HID device
|
||||||
static esp_ble_hidd_dev_t *s_dev = NULL;
|
static esp_ble_hidd_dev_t *s_dev = NULL;
|
||||||
|
static SemaphoreHandle_t s_hidd_mutex = NULL;
|
||||||
|
static bool s_gap_listener_registered = false;
|
||||||
|
static void (*s_prev_reset_cb)(int reason) = NULL;
|
||||||
|
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 inline void lock_hidd(void)
|
||||||
|
{
|
||||||
|
if (s_hidd_mutex) {
|
||||||
|
xSemaphoreTake(s_hidd_mutex, portMAX_DELAY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void unlock_hidd(void)
|
||||||
|
{
|
||||||
|
if (s_hidd_mutex) {
|
||||||
|
xSemaphoreGive(s_hidd_mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
/** service index is used to identify the hid service instance
|
/** service index is used to identify the hid service instance
|
||||||
of the registered characteristic.
|
of the registered characteristic.
|
||||||
Assuming the first instance of the hid service is registered first.
|
Assuming the first instance of the hid service is registered first.
|
||||||
@@ -90,7 +112,10 @@ static int create_hid_db(int device_index)
|
|||||||
/* fill hid info */
|
/* fill hid info */
|
||||||
memcpy(&hparams.hid_info, hidInfo, sizeof hparams.hid_info);
|
memcpy(&hparams.hid_info, hidInfo, sizeof hparams.hid_info);
|
||||||
|
|
||||||
/* fill report map */
|
if (s_dev->devices[device_index].reports_map.len > REPORT_MAP_SIZE) {
|
||||||
|
ESP_LOGE(TAG, "Report map too large (%d > %d); aborting", s_dev->devices[device_index].reports_map.len, REPORT_MAP_SIZE);
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
memcpy(&hparams.report_map, (uint8_t *)s_dev->devices[device_index].reports_map.data, s_dev->devices[device_index].reports_map.len);
|
memcpy(&hparams.report_map, (uint8_t *)s_dev->devices[device_index].reports_map.data, s_dev->devices[device_index].reports_map.len);
|
||||||
hparams.report_map_len = s_dev->devices[device_index].reports_map.len;
|
hparams.report_map_len = s_dev->devices[device_index].reports_map.len;
|
||||||
hparams.external_rpt_ref = BLE_SVC_BAS_UUID16;
|
hparams.external_rpt_ref = BLE_SVC_BAS_UUID16;
|
||||||
@@ -102,6 +127,10 @@ static int create_hid_db(int device_index)
|
|||||||
for (uint8_t i = 0; i < s_dev->devices[device_index].reports_len; i++) {
|
for (uint8_t i = 0; i < s_dev->devices[device_index].reports_len; i++) {
|
||||||
hidd_le_report_item_t *report = &s_dev->devices[device_index].reports[i];
|
hidd_le_report_item_t *report = &s_dev->devices[device_index].reports[i];
|
||||||
if (report->protocol_mode == ESP_HID_PROTOCOL_MODE_REPORT) {
|
if (report->protocol_mode == ESP_HID_PROTOCOL_MODE_REPORT) {
|
||||||
|
if (report_mode_rpts >= MAX_REPORTS) {
|
||||||
|
ESP_LOGE(TAG, "Too many report-mode reports (%d >= MAX_REPORTS); truncating", report_mode_rpts);
|
||||||
|
break;
|
||||||
|
}
|
||||||
/* only consider report mode reports, all boot mode reports will be registered by default */
|
/* only consider report mode reports, all boot mode reports will be registered by default */
|
||||||
if (report->report_type == ESP_HID_REPORT_TYPE_INPUT) {
|
if (report->report_type == ESP_HID_REPORT_TYPE_INPUT) {
|
||||||
/* Input Report */
|
/* Input Report */
|
||||||
@@ -186,6 +215,15 @@ static int nimble_hid_stop_gatts(esp_ble_hidd_dev_t *dev)
|
|||||||
{
|
{
|
||||||
int rc = ESP_OK;
|
int rc = ESP_OK;
|
||||||
|
|
||||||
|
if (s_gap_listener_registered) {
|
||||||
|
ble_gap_event_listener_unregister(&nimble_gap_event_listener);
|
||||||
|
s_gap_listener_registered = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev && dev->connected) {
|
||||||
|
ble_gap_terminate(dev->conn_id, BLE_ERR_REM_USER_CONN_TERM);
|
||||||
|
}
|
||||||
|
|
||||||
/* stop gatt database */
|
/* stop gatt database */
|
||||||
ble_gatts_stop();
|
ble_gatts_stop();
|
||||||
|
|
||||||
@@ -249,6 +287,7 @@ static int ble_hid_init_config(esp_ble_hidd_dev_t *dev, const esp_hid_device_con
|
|||||||
dev->devices[d].reports = (hidd_le_report_item_t *)malloc(rmap->reports_len * sizeof(hidd_le_report_item_t));
|
dev->devices[d].reports = (hidd_le_report_item_t *)malloc(rmap->reports_len * sizeof(hidd_le_report_item_t));
|
||||||
if (dev->devices[d].reports == NULL) {
|
if (dev->devices[d].reports == NULL) {
|
||||||
ESP_LOGE(TAG, "reports malloc(%d) failed", rmap->reports_len * sizeof(hidd_le_report_item_t));
|
ESP_LOGE(TAG, "reports malloc(%d) failed", rmap->reports_len * sizeof(hidd_le_report_item_t));
|
||||||
|
free(rmap->reports);
|
||||||
free(rmap);
|
free(rmap);
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
@@ -287,22 +326,40 @@ static int ble_hid_free_config(esp_ble_hidd_dev_t *dev)
|
|||||||
static int nimble_hidd_dev_deinit(void *devp)
|
static int nimble_hidd_dev_deinit(void *devp)
|
||||||
{
|
{
|
||||||
esp_ble_hidd_dev_t *dev = (esp_ble_hidd_dev_t *)devp;
|
esp_ble_hidd_dev_t *dev = (esp_ble_hidd_dev_t *)devp;
|
||||||
|
lock_hidd();
|
||||||
if (!s_dev) {
|
if (!s_dev) {
|
||||||
ESP_LOGE(TAG, "HID device profile already uninitialized");
|
ESP_LOGE(TAG, "HID device profile already uninitialized");
|
||||||
|
unlock_hidd();
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s_dev != dev) {
|
if (s_dev != dev) {
|
||||||
ESP_LOGE(TAG, "Wrong HID device provided");
|
ESP_LOGE(TAG, "Wrong HID device provided");
|
||||||
|
unlock_hidd();
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
s_dev = NULL;
|
|
||||||
service_index = -1; // resetting the value
|
|
||||||
|
|
||||||
nimble_hid_stop_gatts(dev);
|
nimble_hid_stop_gatts(dev);
|
||||||
|
s_dev = NULL;
|
||||||
|
service_index = -1;
|
||||||
|
|
||||||
|
if (ble_hs_cfg.reset_cb == nimble_host_reset) {
|
||||||
|
ble_hs_cfg.reset_cb = s_prev_reset_cb;
|
||||||
|
}
|
||||||
|
if (ble_hs_cfg.sync_cb == nimble_host_synced) {
|
||||||
|
ble_hs_cfg.sync_cb = s_prev_sync_cb;
|
||||||
|
}
|
||||||
|
ble_hs_cfg.gatts_register_cb = NULL;
|
||||||
|
unlock_hidd();
|
||||||
|
|
||||||
|
/* STOP_EVENT may be discarded because ble_hid_free_config() deletes the event
|
||||||
|
* loop right after this call. This does not cause a crash or data corruption. */
|
||||||
esp_event_post_to(dev->event_loop_handle, ESP_HIDD_EVENTS, ESP_HIDD_STOP_EVENT, NULL, 0, portMAX_DELAY);
|
esp_event_post_to(dev->event_loop_handle, ESP_HIDD_EVENTS, ESP_HIDD_STOP_EVENT, NULL, 0, portMAX_DELAY);
|
||||||
ble_hid_free_config(dev);
|
ble_hid_free_config(dev);
|
||||||
free(dev);
|
free(dev);
|
||||||
|
if (s_hidd_mutex) {
|
||||||
|
vSemaphoreDelete(s_hidd_mutex);
|
||||||
|
s_hidd_mutex = NULL;
|
||||||
|
}
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,20 +373,19 @@ static int nimble_hidd_dev_battery_set(void *devp, uint8_t level)
|
|||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
esp_ble_hidd_dev_t *dev = (esp_ble_hidd_dev_t *)devp;
|
esp_ble_hidd_dev_t *dev = (esp_ble_hidd_dev_t *)devp;
|
||||||
|
lock_hidd();
|
||||||
if (!dev || s_dev != dev) {
|
if (!dev || s_dev != dev) {
|
||||||
|
unlock_hidd();
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dev->connected) {
|
|
||||||
/* Return success if not yet connected */
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = ble_svc_bas_battery_level_set(level);
|
rc = ble_svc_bas_battery_level_set(level);
|
||||||
if (rc) {
|
if (rc != 0 && dev->connected) {
|
||||||
ESP_LOGE(TAG, "esp_ble_gatts_send_notify failed: %d", rc);
|
ESP_LOGE(TAG, "ble_svc_bas_battery_level_set failed: %d", rc);
|
||||||
|
unlock_hidd();
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
unlock_hidd();
|
||||||
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
@@ -338,6 +394,9 @@ static int nimble_hidd_dev_battery_set(void *devp, uint8_t level)
|
|||||||
static hidd_le_report_item_t* find_report(uint8_t id, uint8_t type, uint8_t *mode)
|
static hidd_le_report_item_t* find_report(uint8_t id, uint8_t type, uint8_t *mode)
|
||||||
{
|
{
|
||||||
hidd_le_report_item_t *rpt;
|
hidd_le_report_item_t *rpt;
|
||||||
|
if (!s_dev) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
for (uint8_t d = 0; d < s_dev->devices_len; d++) {
|
for (uint8_t d = 0; d < s_dev->devices_len; d++) {
|
||||||
for (uint8_t i = 0; i < s_dev->devices[d].reports_len; i++) {
|
for (uint8_t i = 0; i < s_dev->devices[d].reports_len; i++) {
|
||||||
rpt = &s_dev->devices[d].reports[i];
|
rpt = &s_dev->devices[d].reports[i];
|
||||||
@@ -348,15 +407,17 @@ static hidd_le_report_item_t* find_report(uint8_t id, uint8_t type, uint8_t *mod
|
|||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
static hidd_le_report_item_t* find_report_by_usage_and_type(uint8_t usage, uint8_t type, uint8_t *mode)
|
|
||||||
|
static hidd_le_report_item_t* find_report_by_usage_and_type(uint8_t dev_index, uint8_t usage, uint8_t type, uint8_t *mode)
|
||||||
{
|
{
|
||||||
hidd_le_report_item_t *rpt;
|
hidd_le_report_item_t *rpt;
|
||||||
for (uint8_t d = 0; d < s_dev->devices_len; d++) {
|
if (!s_dev || dev_index >= s_dev->devices_len) {
|
||||||
for (uint8_t i = 0; i < s_dev->devices[d].reports_len; i++) {
|
return NULL;
|
||||||
rpt = &s_dev->devices[d].reports[i];
|
}
|
||||||
if (rpt->usage == usage && rpt->report_type == type && (!mode || (mode && *mode == rpt->protocol_mode))) {
|
for (uint8_t i = 0; i < s_dev->devices[dev_index].reports_len; i++) {
|
||||||
return rpt;
|
rpt = &s_dev->devices[dev_index].reports[i];
|
||||||
}
|
if (rpt->usage == usage && rpt->report_type == type && (!mode || (mode && *mode == rpt->protocol_mode))) {
|
||||||
|
return rpt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -372,6 +433,11 @@ static int nimble_hidd_dev_input_set(void *devp, size_t index, size_t id, uint8_
|
|||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (index >= s_dev->devices_len) {
|
||||||
|
ESP_LOGE(TAG, "%s invalid device index %zu (devices_len=%u)", __func__, index, s_dev->devices_len);
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
if (!dev->connected) {
|
if (!dev->connected) {
|
||||||
ESP_LOGE(TAG, "%s Device Not Connected", __func__);
|
ESP_LOGE(TAG, "%s Device Not Connected", __func__);
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
@@ -418,6 +484,11 @@ static int nimble_hidd_dev_feature_set(void *devp, size_t index, size_t id, uint
|
|||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (index >= s_dev->devices_len) {
|
||||||
|
ESP_LOGE(TAG, "%s invalid device index %zu (devices_len=%u)", __func__, index, s_dev->devices_len);
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
if (!dev->connected) {
|
if (!dev->connected) {
|
||||||
ESP_LOGE(TAG, "%s Device Not Connected", __func__);
|
ESP_LOGE(TAG, "%s Device Not Connected", __func__);
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
@@ -476,63 +547,87 @@ static void ble_hidd_dev_free(void)
|
|||||||
free(s_dev);
|
free(s_dev);
|
||||||
s_dev = NULL;
|
s_dev = NULL;
|
||||||
}
|
}
|
||||||
|
if (s_hidd_mutex) {
|
||||||
|
vSemaphoreDelete(s_hidd_mutex);
|
||||||
|
s_hidd_mutex = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nimble_hid_gap_event(struct ble_gap_event *event, void *arg)
|
static int nimble_hid_gap_event(struct ble_gap_event *event, void *arg)
|
||||||
{
|
{
|
||||||
struct ble_gap_conn_desc desc;
|
struct ble_gap_conn_desc desc;
|
||||||
struct os_mbuf *om;
|
|
||||||
uint8_t data;
|
uint8_t data;
|
||||||
int rc;
|
int rc;
|
||||||
|
esp_ble_hidd_dev_t *dev;
|
||||||
|
|
||||||
|
lock_hidd();
|
||||||
|
dev = s_dev;
|
||||||
|
if (dev == NULL) {
|
||||||
|
unlock_hidd();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HOGP encryption is not enforced at the GATT level in this component.
|
||||||
|
* Applications must configure encryption themselves, either by setting
|
||||||
|
* BLE_GATT_CHR_F_READ_ENC/WRITE_ENC in ble_svc_hid.c or by configuring
|
||||||
|
* ble_hs_cfg.sm_* security parameters. */
|
||||||
switch (event->type) {
|
switch (event->type) {
|
||||||
case BLE_GAP_EVENT_CONNECT:
|
case BLE_GAP_EVENT_CONNECT:
|
||||||
/* A new connection was established or a connection attempt failed. */
|
/* A new connection was established or a connection attempt failed. */
|
||||||
ESP_LOGD(TAG, "connection %s; status=%d",
|
ESP_LOGD(TAG, "connection %s; status=%d",
|
||||||
event->connect.status == 0 ? "established" : "failed",
|
event->connect.status == 0 ? "established" : "failed",
|
||||||
event->connect.status);
|
event->connect.status);
|
||||||
|
if (event->connect.status != 0) {
|
||||||
|
unlock_hidd();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
|
rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
|
||||||
assert(rc == 0);
|
assert(rc == 0);
|
||||||
|
|
||||||
/* save connection handle */
|
/* save connection handle */
|
||||||
s_dev->connected = true;
|
dev->connected = true;
|
||||||
s_dev->conn_id = event->connect.conn_handle;
|
dev->conn_id = event->connect.conn_handle;
|
||||||
esp_hidd_event_data_t cb_param = {
|
esp_hidd_event_data_t cb_param = {
|
||||||
.connect.dev = s_dev->dev,
|
.connect.dev = dev->dev,
|
||||||
.connect.status = event->connect.status
|
.connect.status = event->connect.status
|
||||||
};
|
};
|
||||||
|
|
||||||
/* reset the protocol mode value */
|
/* reset the protocol mode value */
|
||||||
data = ESP_HID_PROTOCOL_MODE_REPORT;
|
data = ESP_HID_PROTOCOL_MODE_REPORT;
|
||||||
om = ble_hs_mbuf_from_flat(&data, 1);
|
for (int i = 0; i < dev->devices_len; i++) {
|
||||||
if (om == NULL) {
|
struct os_mbuf *om = ble_hs_mbuf_from_flat(&data, 1);
|
||||||
ESP_LOGD(TAG, "No memory to allocate mbuf");
|
if (om == NULL) {
|
||||||
}
|
ESP_LOGD(TAG, "No memory to allocate mbuf");
|
||||||
/* NOTE : om is freed by stack */
|
break;
|
||||||
for (int i = 0; i < s_dev->devices_len; i++) {
|
}
|
||||||
rc = ble_att_svr_write_local(s_dev->devices[i].hid_protocol_handle, om);
|
rc = ble_att_svr_write_local(dev->devices[i].hid_protocol_handle, om);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
ESP_LOGE(TAG, "Write on Protocol Mode Failed: %d", rc);
|
ESP_LOGE(TAG, "Write on Protocol Mode Failed: %d", rc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
unlock_hidd();
|
||||||
|
|
||||||
esp_event_post_to(s_dev->event_loop_handle, ESP_HIDD_EVENTS, ESP_HIDD_CONNECT_EVENT,
|
esp_event_post_to(dev->event_loop_handle, ESP_HIDD_EVENTS, ESP_HIDD_CONNECT_EVENT,
|
||||||
&cb_param, sizeof(esp_hidd_event_data_t), portMAX_DELAY);
|
&cb_param, sizeof(esp_hidd_event_data_t), portMAX_DELAY);
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
case BLE_GAP_EVENT_DISCONNECT:
|
case BLE_GAP_EVENT_DISCONNECT:
|
||||||
ESP_LOGD(TAG, "disconnect; reason=%d", event->disconnect.reason);
|
ESP_LOGD(TAG, "disconnect; reason=%d", event->disconnect.reason);
|
||||||
|
|
||||||
if (s_dev->connected) {
|
if (dev->connected) {
|
||||||
s_dev->connected = false;
|
dev->connected = false;
|
||||||
esp_hidd_event_data_t cb_param = {0};
|
esp_hidd_event_data_t cb_param = {0};
|
||||||
cb_param.disconnect.dev = s_dev->dev;
|
cb_param.disconnect.dev = dev->dev;
|
||||||
cb_param.disconnect.reason = event->disconnect.reason;
|
cb_param.disconnect.reason = event->disconnect.reason;
|
||||||
esp_event_post_to(s_dev->event_loop_handle, ESP_HIDD_EVENTS, ESP_HIDD_DISCONNECT_EVENT,
|
unlock_hidd();
|
||||||
|
esp_event_post_to(dev->event_loop_handle, ESP_HIDD_EVENTS, ESP_HIDD_DISCONNECT_EVENT,
|
||||||
&cb_param, sizeof(esp_hidd_event_data_t), portMAX_DELAY);
|
&cb_param, sizeof(esp_hidd_event_data_t), portMAX_DELAY);
|
||||||
|
} else {
|
||||||
|
unlock_hidd();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
unlock_hidd();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -554,8 +649,13 @@ static void nimble_gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, voi
|
|||||||
ctxt->svc.handle);
|
ctxt->svc.handle);
|
||||||
uuid16 = ble_uuid_u16(ctxt->svc.svc_def->uuid);
|
uuid16 = ble_uuid_u16(ctxt->svc.svc_def->uuid);
|
||||||
if (uuid16 == BLE_SVC_HID_UUID16) {
|
if (uuid16 == BLE_SVC_HID_UUID16) {
|
||||||
++service_index;
|
if (service_index + 1 >= (int)s_dev->devices_len) {
|
||||||
s_dev->devices[service_index].hid_svc = ctxt->svc.handle;
|
ESP_LOGE(TAG, "Too many HID services registered (%d >= devices_len %d); ignoring",
|
||||||
|
service_index + 1, s_dev->devices_len);
|
||||||
|
} else {
|
||||||
|
++service_index;
|
||||||
|
s_dev->devices[service_index].hid_svc = ctxt->svc.handle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -566,6 +666,10 @@ static void nimble_gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, voi
|
|||||||
ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf),
|
ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf),
|
||||||
ctxt->chr.def_handle,
|
ctxt->chr.def_handle,
|
||||||
ctxt->chr.val_handle);
|
ctxt->chr.val_handle);
|
||||||
|
|
||||||
|
if (service_index < 0 || (uint8_t)service_index >= s_dev->devices_len) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
uuid16 = ble_uuid_u16(ctxt->chr.chr_def->uuid);
|
uuid16 = ble_uuid_u16(ctxt->chr.chr_def->uuid);
|
||||||
if (uuid16 == BLE_SVC_HID_CHR_UUID16_HID_CTRL_PT) {
|
if (uuid16 == BLE_SVC_HID_CHR_UUID16_HID_CTRL_PT) {
|
||||||
/* assuming this characteristic is from the last registered hid service */
|
/* assuming this characteristic is from the last registered hid service */
|
||||||
@@ -577,7 +681,7 @@ static void nimble_gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, voi
|
|||||||
}
|
}
|
||||||
if (uuid16 == BLE_SVC_HID_CHR_UUID16_BOOT_KBD_INP) {
|
if (uuid16 == BLE_SVC_HID_CHR_UUID16_BOOT_KBD_INP) {
|
||||||
protocol_mode = ESP_HID_PROTOCOL_MODE_BOOT;
|
protocol_mode = ESP_HID_PROTOCOL_MODE_BOOT;
|
||||||
rpt = find_report_by_usage_and_type(ESP_HID_USAGE_KEYBOARD, ESP_HID_REPORT_TYPE_INPUT, &protocol_mode);
|
rpt = find_report_by_usage_and_type(service_index, ESP_HID_USAGE_KEYBOARD, ESP_HID_REPORT_TYPE_INPUT, &protocol_mode);
|
||||||
if (rpt == NULL) {
|
if (rpt == NULL) {
|
||||||
ESP_LOGE(TAG, "Unknown boot kbd input report registration");
|
ESP_LOGE(TAG, "Unknown boot kbd input report registration");
|
||||||
return;
|
return;
|
||||||
@@ -586,7 +690,7 @@ static void nimble_gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, voi
|
|||||||
}
|
}
|
||||||
if (uuid16 == BLE_SVC_HID_CHR_UUID16_BOOT_KBD_OUT) {
|
if (uuid16 == BLE_SVC_HID_CHR_UUID16_BOOT_KBD_OUT) {
|
||||||
protocol_mode = ESP_HID_PROTOCOL_MODE_BOOT;
|
protocol_mode = ESP_HID_PROTOCOL_MODE_BOOT;
|
||||||
rpt = find_report_by_usage_and_type(ESP_HID_USAGE_KEYBOARD, ESP_HID_REPORT_TYPE_OUTPUT, &protocol_mode);
|
rpt = find_report_by_usage_and_type(service_index, ESP_HID_USAGE_KEYBOARD, ESP_HID_REPORT_TYPE_OUTPUT, &protocol_mode);
|
||||||
if (rpt == NULL) {
|
if (rpt == NULL) {
|
||||||
ESP_LOGE(TAG, "Unknown boot kbd output report registration");
|
ESP_LOGE(TAG, "Unknown boot kbd output report registration");
|
||||||
return;
|
return;
|
||||||
@@ -595,7 +699,7 @@ static void nimble_gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, voi
|
|||||||
}
|
}
|
||||||
if (uuid16 == BLE_SVC_HID_CHR_UUID16_BOOT_MOUSE_INP) {
|
if (uuid16 == BLE_SVC_HID_CHR_UUID16_BOOT_MOUSE_INP) {
|
||||||
protocol_mode = ESP_HID_PROTOCOL_MODE_BOOT;
|
protocol_mode = ESP_HID_PROTOCOL_MODE_BOOT;
|
||||||
rpt = find_report_by_usage_and_type(ESP_HID_USAGE_MOUSE, ESP_HID_REPORT_TYPE_INPUT, &protocol_mode);
|
rpt = find_report_by_usage_and_type(service_index, ESP_HID_USAGE_MOUSE, ESP_HID_REPORT_TYPE_INPUT, &protocol_mode);
|
||||||
if (rpt == NULL) {
|
if (rpt == NULL) {
|
||||||
ESP_LOGE(TAG, "Unknown boot mouse input report registration");
|
ESP_LOGE(TAG, "Unknown boot mouse input report registration");
|
||||||
return;
|
return;
|
||||||
@@ -616,6 +720,11 @@ static void nimble_gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, voi
|
|||||||
ble_hs_mbuf_to_flat(om, &report_info, sizeof report_info, NULL);
|
ble_hs_mbuf_to_flat(om, &report_info, sizeof report_info, NULL);
|
||||||
report_type = (uint8_t)((report_info & 0xFF00) >> 8);
|
report_type = (uint8_t)((report_info & 0xFF00) >> 8);
|
||||||
report_id = report_info & 0x00FF;
|
report_id = report_info & 0x00FF;
|
||||||
|
if (ctxt->dsc.dsc_def->arg == NULL) {
|
||||||
|
ESP_LOGE(TAG, "Report Reference descriptor has NULL arg; skipping handle assignment");
|
||||||
|
os_mbuf_free_chain(om);
|
||||||
|
break;
|
||||||
|
}
|
||||||
report_handle = (*(uint16_t*)(ctxt->dsc.dsc_def->arg));
|
report_handle = (*(uint16_t*)(ctxt->dsc.dsc_def->arg));
|
||||||
protocol_mode = ESP_HID_PROTOCOL_MODE_REPORT;
|
protocol_mode = ESP_HID_PROTOCOL_MODE_REPORT;
|
||||||
rpt = find_report(report_id, report_type, &protocol_mode);
|
rpt = find_report(report_id, report_type, &protocol_mode);
|
||||||
@@ -635,15 +744,24 @@ static void nimble_gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, voi
|
|||||||
|
|
||||||
static void nimble_host_synced(void)
|
static void nimble_host_synced(void)
|
||||||
{
|
{
|
||||||
esp_event_post_to(s_dev->event_loop_handle, ESP_HIDD_EVENTS, ESP_HIDD_START_EVENT, NULL, 0, portMAX_DELAY);
|
lock_hidd();
|
||||||
|
if (s_prev_sync_cb && s_prev_sync_cb != nimble_host_synced) {
|
||||||
|
s_prev_sync_cb();
|
||||||
|
}
|
||||||
|
if (s_dev && s_dev->event_loop_handle != NULL) {
|
||||||
|
esp_event_post_to(s_dev->event_loop_handle, ESP_HIDD_EVENTS, ESP_HIDD_START_EVENT, NULL, 0, portMAX_DELAY);
|
||||||
|
}
|
||||||
|
unlock_hidd();
|
||||||
}
|
}
|
||||||
|
|
||||||
void nimble_host_reset(int reason)
|
void nimble_host_reset(int reason)
|
||||||
{
|
{
|
||||||
|
if (s_prev_reset_cb && s_prev_reset_cb != nimble_host_reset) {
|
||||||
|
s_prev_reset_cb(reason);
|
||||||
|
}
|
||||||
MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason);
|
MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ble_gap_event_listener nimble_gap_event_listener;
|
|
||||||
esp_err_t esp_ble_hidd_dev_init(esp_hidd_dev_t *dev_p, const esp_hid_device_config_t *config, esp_event_handler_t callback)
|
esp_err_t esp_ble_hidd_dev_init(esp_hidd_dev_t *dev_p, const esp_hid_device_config_t *config, esp_event_handler_t callback)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
@@ -658,6 +776,15 @@ esp_err_t esp_ble_hidd_dev_init(esp_hidd_dev_t *dev_p, const esp_hid_device_conf
|
|||||||
ESP_LOGE(TAG, "HID device could not be allocated");
|
ESP_LOGE(TAG, "HID device could not be allocated");
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
if (s_hidd_mutex == NULL) {
|
||||||
|
s_hidd_mutex = xSemaphoreCreateMutex();
|
||||||
|
if (s_hidd_mutex == NULL) {
|
||||||
|
free(s_dev);
|
||||||
|
s_dev = NULL;
|
||||||
|
ESP_LOGE(TAG, "HID device mutex allocation failed");
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Reset the hid device target environment
|
// Reset the hid device target environment
|
||||||
s_dev->control = ESP_HID_CONTROL_EXIT_SUSPEND;
|
s_dev->control = ESP_HID_CONTROL_EXIT_SUSPEND;
|
||||||
@@ -708,15 +835,26 @@ esp_err_t esp_ble_hidd_dev_init(esp_hidd_dev_t *dev_p, const esp_hid_device_conf
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s_prev_reset_cb = ble_hs_cfg.reset_cb;
|
||||||
|
s_prev_sync_cb = ble_hs_cfg.sync_cb;
|
||||||
ble_hs_cfg.reset_cb = nimble_host_reset;
|
ble_hs_cfg.reset_cb = nimble_host_reset;
|
||||||
ble_hs_cfg.sync_cb = nimble_host_synced;
|
ble_hs_cfg.sync_cb = nimble_host_synced;
|
||||||
ble_hs_cfg.gatts_register_cb = nimble_gatt_svr_register_cb;
|
ble_hs_cfg.gatts_register_cb = nimble_gatt_svr_register_cb;
|
||||||
rc = nimble_hid_start_gatts();
|
rc = nimble_hid_start_gatts();
|
||||||
if (rc != ESP_OK) {
|
if (rc != ESP_OK) {
|
||||||
|
if (ble_hs_cfg.reset_cb == nimble_host_reset) {
|
||||||
|
ble_hs_cfg.reset_cb = s_prev_reset_cb;
|
||||||
|
}
|
||||||
|
if (ble_hs_cfg.sync_cb == nimble_host_synced) {
|
||||||
|
ble_hs_cfg.sync_cb = s_prev_sync_cb;
|
||||||
|
}
|
||||||
|
ble_hs_cfg.gatts_register_cb = NULL;
|
||||||
|
ble_hidd_dev_free();
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
ble_gap_event_listener_register(&nimble_gap_event_listener,
|
ble_gap_event_listener_register(&nimble_gap_event_listener,
|
||||||
nimble_hid_gap_event, NULL);
|
nimble_hid_gap_event, NULL);
|
||||||
|
s_gap_listener_registered = true;
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -233,9 +233,9 @@ esp_err_t esp_blufi_host_init(void)
|
|||||||
ble_hs_cfg.gatts_register_cb = esp_blufi_gatt_svr_register_cb;
|
ble_hs_cfg.gatts_register_cb = esp_blufi_gatt_svr_register_cb;
|
||||||
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
|
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
|
||||||
|
|
||||||
/* FALSE POSITIVE: BLUFI uses its own app-layer security (DH + AES), not BLE SM.
|
/* BLUFI uses its own application-layer security (DH + AES), not BLE Security
|
||||||
* sm_mitm/sm_sc/sm_bonding are opt-in via Kconfig to let the example show
|
* Manager. sm_mitm/sm_sc/sm_bonding are opt-in via Kconfig; Just Works
|
||||||
* multiple configurations; Just Works is acceptable for BLUFI provisioning. */
|
* pairing is acceptable because the DH key exchange provides the security. */
|
||||||
ble_hs_cfg.sm_io_cap = 4;
|
ble_hs_cfg.sm_io_cap = 4;
|
||||||
#ifdef CONFIG_EXAMPLE_BONDING
|
#ifdef CONFIG_EXAMPLE_BONDING
|
||||||
ble_hs_cfg.sm_bonding = 1;
|
ble_hs_cfg.sm_bonding = 1;
|
||||||
|
|||||||
@@ -90,6 +90,82 @@ I (50557) HID_DEV_DEMO: Send the volume
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## NimBLE Logging Scheme
|
||||||
|
|
||||||
|
The following are verbatim NimBLE log excerpts from `logs.txt` for each device role.
|
||||||
|
|
||||||
|
### Media Mode
|
||||||
|
|
||||||
|
```text
|
||||||
|
I (496) HID_DEV_DEMO: setting ble device
|
||||||
|
I (496) HID_DEV_DEMO: BLE Host Task Started
|
||||||
|
I (506) HID_DEV_BLE: START
|
||||||
|
I (506) NimBLE: GAP procedure initiated: advertise;
|
||||||
|
I (35886) ESP_HID_GAP: connection established; status=0
|
||||||
|
I (35896) HID_DEV_BLE: CONNECT
|
||||||
|
I (35946) ESP_HID_GAP: mtu update event; conn_handle=0 cid=4 mtu=256
|
||||||
|
I (36476) ESP_HID_GAP: PASSKEY_ACTION_EVENT started
|
||||||
|
I (36476) ESP_HID_GAP: Enter passkey 123456on the peer side
|
||||||
|
I (37896) ESP_HID_GAP: subscribe event; conn_handle=0 attr_handle=37 reason=1 prevn=0 curn=1 previ=0 curi=0
|
||||||
|
I (40936) NimBLE: encryption change event; status=0
|
||||||
|
I (40946) HID_DEV_DEMO: Send the volume
|
||||||
|
I (40946) NimBLE: GATT procedure initiated: notify;
|
||||||
|
I (40946) NimBLE: att_handle=37
|
||||||
|
I (40946) NimBLE: notify_tx event; conn_handle=0 attr_handle=37 status=0 is_indication=0
|
||||||
|
```
|
||||||
|
|
||||||
|
### Keyboard Mode
|
||||||
|
|
||||||
|
```text
|
||||||
|
I (436) HID_DEV_DEMO: setting ble device
|
||||||
|
I (436) HID_DEV_DEMO: BLE Host Task Started
|
||||||
|
I (436) HID_DEV_BLE: START
|
||||||
|
I (446) NimBLE: GAP procedure initiated: advertise;
|
||||||
|
I (11526) ESP_HID_GAP: connection established; status=0
|
||||||
|
I (11526) HID_DEV_BLE: CONNECT
|
||||||
|
I (11576) ESP_HID_GAP: mtu update event; conn_handle=0 cid=4 mtu=256
|
||||||
|
I (12116) ESP_HID_GAP: PASSKEY_ACTION_EVENT started
|
||||||
|
I (12116) ESP_HID_GAP: Enter passkey 123456on the peer side
|
||||||
|
I (13826) ESP_HID_GAP: subscribe event; conn_handle=0 attr_handle=37 reason=1 prevn=0 curn=1 previ=0 curi=0
|
||||||
|
I (16576) NimBLE: encryption change event; status=0
|
||||||
|
########################################################################
|
||||||
|
BT hid keyboard demo usage:
|
||||||
|
########################################################################
|
||||||
|
I (22306) NimBLE: GATT procedure initiated: notify;
|
||||||
|
I (22306) NimBLE: att_handle=37
|
||||||
|
I (22306) NimBLE: notify_tx event; conn_handle=0 attr_handle=37 status=0 is_indication=0
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mouse Mode
|
||||||
|
|
||||||
|
```text
|
||||||
|
I (446) HID_DEV_DEMO: setting ble device
|
||||||
|
I (446) HID_DEV_DEMO: BLE Host Task Started
|
||||||
|
I (456) HID_DEV_BLE: START
|
||||||
|
I (456) NimBLE: GAP procedure initiated: advertise;
|
||||||
|
I (10556) ESP_HID_GAP: connection established; status=0
|
||||||
|
I (10556) HID_DEV_BLE: CONNECT
|
||||||
|
I (10606) ESP_HID_GAP: mtu update event; conn_handle=0 cid=4 mtu=256
|
||||||
|
I (11136) ESP_HID_GAP: PASSKEY_ACTION_EVENT started
|
||||||
|
I (11136) ESP_HID_GAP: Enter passkey 123456on the peer side
|
||||||
|
I (12656) ESP_HID_GAP: subscribe event; conn_handle=0 attr_handle=37 reason=1 prevn=0 curn=1 previ=0 curi=0
|
||||||
|
I (15606) NimBLE: encryption change event; status=0
|
||||||
|
########################################################################
|
||||||
|
BT hid mouse demo usage:
|
||||||
|
You can input these value to simulate mouse: 'q', 'w', 'e', 'a', 's', 'd', 'h'
|
||||||
|
q -- click the left key
|
||||||
|
w -- move up
|
||||||
|
e -- click the right key
|
||||||
|
a -- move left
|
||||||
|
s -- move down
|
||||||
|
d -- move right
|
||||||
|
h -- show the help
|
||||||
|
########################################################################
|
||||||
|
I (18166) NimBLE: GATT procedure initiated: notify;
|
||||||
|
I (18166) NimBLE: att_handle=37
|
||||||
|
I (18166) NimBLE: notify_tx event; conn_handle=0 attr_handle=37 status=0 is_indication=0
|
||||||
|
```
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
1. When using NimBLE stack, some iOS devices do not show the volume pop up. To fix this, please set CONFIG_BT_NIMBLE_SM_LVL to value 2. iOS needs Authenticated Pairing with Encryption to show up the pop ups.
|
1. When using NimBLE stack, some iOS devices do not show the volume pop up. To fix this, please set CONFIG_BT_NIMBLE_SM_LVL to value 2. iOS needs Authenticated Pairing with Encryption to show up the pop ups.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||||
*/
|
*/
|
||||||
@@ -856,9 +856,13 @@ nimble_hid_gap_event(struct ble_gap_event *event, void *arg)
|
|||||||
/* Encryption has been enabled or disabled for this connection. */
|
/* Encryption has been enabled or disabled for this connection. */
|
||||||
MODLOG_DFLT(INFO, "encryption change event; status=%d ",
|
MODLOG_DFLT(INFO, "encryption change event; status=%d ",
|
||||||
event->enc_change.status);
|
event->enc_change.status);
|
||||||
rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc);
|
if (event->enc_change.status == 0) {
|
||||||
assert(rc == 0);
|
rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc);
|
||||||
ble_hid_task_start_up();
|
assert(rc == 0);
|
||||||
|
ble_hid_task_start_up();
|
||||||
|
} else {
|
||||||
|
ESP_LOGW(TAG, "encryption failed; waiting for disconnect/retry");
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case BLE_GAP_EVENT_NOTIFY_TX:
|
case BLE_GAP_EVENT_NOTIFY_TX:
|
||||||
@@ -889,7 +893,7 @@ nimble_hid_gap_event(struct ble_gap_event *event, void *arg)
|
|||||||
case BLE_GAP_EVENT_PASSKEY_ACTION:
|
case BLE_GAP_EVENT_PASSKEY_ACTION:
|
||||||
ESP_LOGI(TAG, "PASSKEY_ACTION_EVENT started");
|
ESP_LOGI(TAG, "PASSKEY_ACTION_EVENT started");
|
||||||
struct ble_sm_io pkey = {0};
|
struct ble_sm_io pkey = {0};
|
||||||
int key = 0;
|
int key = 1;
|
||||||
|
|
||||||
if (event->passkey.params.action == BLE_SM_IOACT_DISP) {
|
if (event->passkey.params.action == BLE_SM_IOACT_DISP) {
|
||||||
pkey.action = event->passkey.params.action;
|
pkey.action = event->passkey.params.action;
|
||||||
|
|||||||
@@ -94,6 +94,73 @@ I (18212) ESP_HIDH_DEMO: 00 00
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## NimBLE Logging Scheme
|
||||||
|
|
||||||
|
The following are verbatim NimBLE log excerpts from `logs.txt` for each device role.
|
||||||
|
|
||||||
|
### Media Mode (CCONTROL)
|
||||||
|
|
||||||
|
```text
|
||||||
|
I (2446) ESP_HIDH_DEMO: SCAN...
|
||||||
|
I (2446) NimBLE: GAP procedure initiated: discovery;
|
||||||
|
I (7456) NimBLE: discovery complete; reason=0
|
||||||
|
I (7466) NimBLE: GAP procedure initiated: connect;
|
||||||
|
I (7666) NimBLE: Connection established
|
||||||
|
I (7676) NimBLE: GATT procedure initiated: exchange mtu
|
||||||
|
I (7726) NimBLE: mtu update event; conn_handle=0 cid=4 mtu=256
|
||||||
|
I (8446) NIMBLE_HIDH: PASSKEY INPUT injected rc=0
|
||||||
|
I (9636) ESP_HIDH_DEMO: 02:50:f7:f9:55:60 OPEN: nimble
|
||||||
|
Report Maps: 1
|
||||||
|
Report Map Length: 111
|
||||||
|
CCONTROL INPUT REPORT, ID: 3, Length: 2, Permissions: 0x1a, Handle: 37, CCC Handle: 38
|
||||||
|
I (12776) NIMBLE_HIDH: ENC_CHANGE status=0 encrypted=1 authenticated=1 bonded=1
|
||||||
|
I (12826) ESP_HIDH_DEMO: 02:50:f7:f9:55:60 INPUT: CCONTROL, MAP: 0, ID: 3, Len: 2, Data:
|
||||||
|
I (12826) ESP_HIDH_DEMO: 80 00
|
||||||
|
I (12876) ESP_HIDH_DEMO: 02:50:f7:f9:55:60 INPUT: CCONTROL, MAP: 0, ID: 3, Len: 2, Data:
|
||||||
|
I (12876) ESP_HIDH_DEMO: 00 00
|
||||||
|
I (14876) ESP_HIDH_DEMO: 02:50:f7:f9:55:60 INPUT: CCONTROL, MAP: 0, ID: 3, Len: 2, Data:
|
||||||
|
I (14876) ESP_HIDH_DEMO: 40 00
|
||||||
|
```
|
||||||
|
|
||||||
|
### Keyboard Mode
|
||||||
|
|
||||||
|
```text
|
||||||
|
I (7426) ESP_HIDH_DEMO: SCAN: 2 results
|
||||||
|
BLE: 68:2e:f7:f9:55:60, RSSI: -57, USAGE: GENERIC, APPEARANCE: 0x03c0, ADDR_TYPE: '0', NAME: ESP Mouse
|
||||||
|
BLE: 02:50:f7:f9:55:60, RSSI: -30, USAGE: GENERIC, APPEARANCE: 0x03c0, ADDR_TYPE: '0', NAME: ESP Keyboard
|
||||||
|
I (7446) NimBLE: GAP procedure initiated: connect;
|
||||||
|
I (7836) NimBLE: Connection established
|
||||||
|
I (8606) NIMBLE_HIDH: PASSKEY INPUT injected rc=0
|
||||||
|
I (10086) ESP_HIDH_DEMO: 02:50:f7:f9:55:60 OPEN: nimble
|
||||||
|
Report Maps: 1
|
||||||
|
Report Map Length: 65
|
||||||
|
KEYBOARD INPUT REPORT, ID: 1, Length: 7, Permissions: 0x1a, Handle: 37, CCC Handle: 38
|
||||||
|
I (12936) NIMBLE_HIDH: ENC_CHANGE status=0 encrypted=1 authenticated=1 bonded=1
|
||||||
|
I (18636) ESP_HIDH_DEMO: 02:50:f7:f9:55:60 INPUT: KEYBOARD, MAP: 0, ID: 1, Len: 8, Data:
|
||||||
|
I (18636) ESP_HIDH_DEMO: 00 00 04 00 00 00 00 00
|
||||||
|
I (18686) ESP_HIDH_DEMO: 02:50:f7:f9:55:60 INPUT: KEYBOARD, MAP: 0, ID: 1, Len: 8, Data:
|
||||||
|
I (18686) ESP_HIDH_DEMO: 00 00 00 00 00 00 00 00
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mouse Mode
|
||||||
|
|
||||||
|
```text
|
||||||
|
I (7426) ESP_HIDH_DEMO: SCAN: 1 results
|
||||||
|
BLE: 02:50:f7:f9:55:60, RSSI: -29, USAGE: GENERIC, APPEARANCE: 0x03c0, ADDR_TYPE: '0', NAME: ESP Mouse
|
||||||
|
I (7436) NimBLE: GAP procedure initiated: connect;
|
||||||
|
I (7666) NimBLE: Connection established
|
||||||
|
I (8436) NIMBLE_HIDH: PASSKEY INPUT injected rc=0
|
||||||
|
I (9716) ESP_HIDH_DEMO: 02:50:f7:f9:55:60 OPEN: nimble
|
||||||
|
Report Maps: 1
|
||||||
|
Report Map Length: 52
|
||||||
|
MOUSE INPUT REPORT, ID: 0, Length: 4, Permissions: 0x1a, Handle: 37, CCC Handle: 38
|
||||||
|
I (12766) NIMBLE_HIDH: ENC_CHANGE status=0 encrypted=1 authenticated=1 bonded=1
|
||||||
|
I (15316) ESP_HIDH_DEMO: 02:50:f7:f9:55:60 INPUT: MOUSE, MAP: 0, ID: 0, Len: 4, Data:
|
||||||
|
I (15316) ESP_HIDH_DEMO: 00 f6 00 00
|
||||||
|
I (15816) ESP_HIDH_DEMO: 02:50:f7:f9:55:60 INPUT: MOUSE, MAP: 0, ID: 0, Len: 4, Data:
|
||||||
|
I (15816) ESP_HIDH_DEMO: 00 00 0a 00
|
||||||
|
```
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.
|
For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.
|
||||||
|
|||||||
Reference in New Issue
Block a user