diff --git a/examples/bluetooth/ble_get_started/nimble/NimBLE_Beacon/main/main.c b/examples/bluetooth/ble_get_started/nimble/NimBLE_Beacon/main/main.c index d4c871e9649..3640902be47 100644 --- a/examples/bluetooth/ble_get_started/nimble/NimBLE_Beacon/main/main.c +++ b/examples/bluetooth/ble_get_started/nimble/NimBLE_Beacon/main/main.c @@ -83,6 +83,7 @@ void app_main(void) { rc = gap_init(); if (rc != 0) { ESP_LOGE(TAG, "failed to initialize GAP service, error code: %d", rc); + nimble_port_deinit(); return; } #endif diff --git a/examples/bluetooth/ble_get_started/nimble/NimBLE_Beacon/main/src/gap.c b/examples/bluetooth/ble_get_started/nimble/NimBLE_Beacon/main/src/gap.c index 8243ecf3341..acb8bc50759 100644 --- a/examples/bluetooth/ble_get_started/nimble/NimBLE_Beacon/main/src/gap.c +++ b/examples/bluetooth/ble_get_started/nimble/NimBLE_Beacon/main/src/gap.c @@ -35,6 +35,9 @@ static void start_advertising(void) { /* Set device name */ name = ble_svc_gap_device_name(); + if (name == NULL) { + name = DEVICE_NAME; + } adv_fields.name = (uint8_t *)name; adv_fields.name_len = strlen(name); adv_fields.name_is_complete = 1; diff --git a/examples/bluetooth/ble_get_started/nimble/NimBLE_Connection/main/main.c b/examples/bluetooth/ble_get_started/nimble/NimBLE_Connection/main/main.c index 6fc6c414a01..971d09d489a 100644 --- a/examples/bluetooth/ble_get_started/nimble/NimBLE_Connection/main/main.c +++ b/examples/bluetooth/ble_get_started/nimble/NimBLE_Connection/main/main.c @@ -87,6 +87,7 @@ void app_main(void) { rc = gap_init(); if (rc != 0) { ESP_LOGE(TAG, "failed to initialize GAP service, error code: %d", rc); + nimble_port_deinit(); return; } #endif diff --git a/examples/bluetooth/ble_get_started/nimble/NimBLE_Connection/main/src/gap.c b/examples/bluetooth/ble_get_started/nimble/NimBLE_Connection/main/src/gap.c index d4d220d9fc1..1c591becf4e 100644 --- a/examples/bluetooth/ble_get_started/nimble/NimBLE_Connection/main/src/gap.c +++ b/examples/bluetooth/ble_get_started/nimble/NimBLE_Connection/main/src/gap.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -64,6 +64,9 @@ static void start_advertising(void) { /* Set device name */ name = ble_svc_gap_device_name(); + if (name == NULL) { + name = DEVICE_NAME; + } adv_fields.name = (uint8_t *)name; adv_fields.name_len = strlen(name); adv_fields.name_is_complete = 1; @@ -160,26 +163,29 @@ static int gap_event_handler(struct ble_gap_event *event, void *arg) { print_conn_desc(&desc); led_on(); - /* Try to update connection parameters */ + /* Try to update connection parameters. + * BT spec requires: supervision_timeout > (1+latency)*itvl/4 + * Ensure the timeout satisfies this constraint when latency=3. */ + uint16_t min_timeout = (uint16_t)(((1 + 3) * (uint32_t)desc.conn_itvl) / 4 + 1); + uint16_t supervision_timeout = (desc.supervision_timeout > min_timeout) + ? desc.supervision_timeout : min_timeout; struct ble_gap_upd_params params = {.itvl_min = desc.conn_itvl, .itvl_max = desc.conn_itvl, .latency = 3, - .supervision_timeout = - desc.supervision_timeout}; + .supervision_timeout = supervision_timeout}; rc = ble_gap_update_params(event->connect.conn_handle, ¶ms); if (rc != 0) { ESP_LOGE( TAG, "failed to update connection parameters, error code: %d", rc); - return rc; } } /* Connection failed, restart advertising */ else { start_advertising(); } - return rc; + return 0; /* Disconnect event */ case BLE_GAP_EVENT_DISCONNECT: diff --git a/examples/bluetooth/ble_get_started/nimble/NimBLE_GATT_Server/main/main.c b/examples/bluetooth/ble_get_started/nimble/NimBLE_GATT_Server/main/main.c index ee95a2dd84e..1bd3fb010c9 100644 --- a/examples/bluetooth/ble_get_started/nimble/NimBLE_GATT_Server/main/main.c +++ b/examples/bluetooth/ble_get_started/nimble/NimBLE_GATT_Server/main/main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -54,7 +54,7 @@ static void nimble_host_task(void *param) { nimble_port_run(); /* Clean up at exit */ - vTaskDelete(NULL); + nimble_port_freertos_deinit(); } static void heart_rate_task(void *param) { @@ -114,6 +114,7 @@ void app_main(void) { rc = gap_init(); if (rc != 0) { ESP_LOGE(TAG, "failed to initialize GAP service, error code: %d", rc); + nimble_port_deinit(); return; } #endif @@ -122,6 +123,7 @@ void app_main(void) { rc = gatt_svc_init(); if (rc != 0) { ESP_LOGE(TAG, "failed to initialize GATT server, error code: %d", rc); + nimble_port_deinit(); return; } @@ -129,12 +131,7 @@ void app_main(void) { nimble_host_config_init(); /* Start NimBLE host task thread and return */ - rc = xTaskCreate(nimble_host_task, "NimBLE Host", 4 * 1024, NULL, - 5, NULL); - if (rc != pdPASS) { - ESP_LOGE(TAG, "failed to create NimBLE host task"); - return; - } + nimble_port_freertos_init(nimble_host_task); rc = xTaskCreate(heart_rate_task, "Heart Rate", 4 * 1024, NULL, 5, NULL); if (rc != pdPASS) { diff --git a/examples/bluetooth/ble_get_started/nimble/NimBLE_GATT_Server/main/src/gap.c b/examples/bluetooth/ble_get_started/nimble/NimBLE_GATT_Server/main/src/gap.c index 20f3171a8e1..d707f881369 100644 --- a/examples/bluetooth/ble_get_started/nimble/NimBLE_GATT_Server/main/src/gap.c +++ b/examples/bluetooth/ble_get_started/nimble/NimBLE_GATT_Server/main/src/gap.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -64,6 +64,9 @@ static void start_advertising(void) { /* Set device name */ name = ble_svc_gap_device_name(); + if (name == NULL) { + name = DEVICE_NAME; + } adv_fields.name = (uint8_t *)name; adv_fields.name_len = strlen(name); adv_fields.name_is_complete = 1; @@ -159,26 +162,29 @@ static int gap_event_handler(struct ble_gap_event *event, void *arg) { /* Print connection descriptor */ print_conn_desc(&desc); - /* Try to update connection parameters */ + /* Try to update connection parameters. + * BT spec requires: supervision_timeout > (1+latency)*itvl/4 + * Ensure the timeout satisfies this constraint when latency=3. */ + uint16_t min_timeout = (uint16_t)(((1 + 3) * (uint32_t)desc.conn_itvl) / 4 + 1); + uint16_t supervision_timeout = (desc.supervision_timeout > min_timeout) + ? desc.supervision_timeout : min_timeout; struct ble_gap_upd_params params = {.itvl_min = desc.conn_itvl, .itvl_max = desc.conn_itvl, .latency = 3, - .supervision_timeout = - desc.supervision_timeout}; + .supervision_timeout = supervision_timeout}; rc = ble_gap_update_params(event->connect.conn_handle, ¶ms); if (rc != 0) { ESP_LOGE( TAG, "failed to update connection parameters, error code: %d", rc); - return rc; } } /* Connection failed, restart advertising */ else { start_advertising(); } - return rc; + return 0; /* Disconnect event */ case BLE_GAP_EVENT_DISCONNECT: diff --git a/examples/bluetooth/ble_get_started/nimble/NimBLE_GATT_Server/main/src/gatt_svc.c b/examples/bluetooth/ble_get_started/nimble/NimBLE_GATT_Server/main/src/gatt_svc.c index bf03d4023f4..5668eff43aa 100644 --- a/examples/bluetooth/ble_get_started/nimble/NimBLE_GATT_Server/main/src/gatt_svc.c +++ b/examples/bluetooth/ble_get_started/nimble/NimBLE_GATT_Server/main/src/gatt_svc.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -164,9 +164,11 @@ error: /* Public functions */ void send_heart_rate_indication(void) { if (heart_rate_ind_status && heart_rate_chr_conn_handle_inited) { - ble_gatts_indicate(heart_rate_chr_conn_handle, - heart_rate_chr_val_handle); - ESP_LOGI(TAG, "heart rate indication sent!"); + int rc = ble_gatts_indicate(heart_rate_chr_conn_handle, + heart_rate_chr_val_handle); + if (rc != 0) { + ESP_LOGE(TAG, "failed to send heart rate indication, error code: %d", rc); + } } } @@ -230,9 +232,13 @@ void gatt_svr_subscribe_cb(struct ble_gap_event *event) { /* Check attribute handle */ if (event->subscribe.attr_handle == heart_rate_chr_val_handle) { + if (event->subscribe.conn_handle == BLE_HS_CONN_HANDLE_NONE) { + return; + } + /* Update heart rate subscription status */ heart_rate_chr_conn_handle = event->subscribe.conn_handle; - heart_rate_chr_conn_handle_inited = true; + heart_rate_chr_conn_handle_inited = event->subscribe.cur_indicate; heart_rate_ind_status = event->subscribe.cur_indicate; } } diff --git a/examples/bluetooth/ble_get_started/nimble/NimBLE_Security/main/include/gatt_svc.h b/examples/bluetooth/ble_get_started/nimble/NimBLE_Security/main/include/gatt_svc.h index 4971525b558..3a765423e6c 100644 --- a/examples/bluetooth/ble_get_started/nimble/NimBLE_Security/main/include/gatt_svc.h +++ b/examples/bluetooth/ble_get_started/nimble/NimBLE_Security/main/include/gatt_svc.h @@ -15,6 +15,7 @@ #include "host/ble_gap.h" /* Public function declarations */ +void gatt_svr_reset_heart_rate_subscription(void); void send_heart_rate_indication(void); void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg); int gatt_svr_subscribe_cb(struct ble_gap_event *event); diff --git a/examples/bluetooth/ble_get_started/nimble/NimBLE_Security/main/main.c b/examples/bluetooth/ble_get_started/nimble/NimBLE_Security/main/main.c index dfe997eb080..7f4e84c8367 100644 --- a/examples/bluetooth/ble_get_started/nimble/NimBLE_Security/main/main.c +++ b/examples/bluetooth/ble_get_started/nimble/NimBLE_Security/main/main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -59,7 +59,7 @@ static void nimble_host_task(void *param) { nimble_port_run(); /* Clean up at exit */ - vTaskDelete(NULL); + nimble_port_freertos_deinit(); } static void heart_rate_task(void *param) { @@ -123,6 +123,7 @@ void app_main(void) { rc = gap_init(); if (rc != 0) { ESP_LOGE(TAG, "failed to initialize GAP service, error code: %d", rc); + nimble_port_deinit(); return; } #endif @@ -131,6 +132,7 @@ void app_main(void) { rc = gatt_svc_init(); if (rc != 0) { ESP_LOGE(TAG, "failed to initialize GATT server, error code: %d", rc); + nimble_port_deinit(); return; } @@ -138,7 +140,12 @@ void app_main(void) { nimble_host_config_init(); /* Start NimBLE host task thread and return */ - xTaskCreate(nimble_host_task, "NimBLE Host", 4*1024, NULL, 5, NULL); - xTaskCreate(heart_rate_task, "Heart Rate", 4*1024, NULL, 5, NULL); + nimble_port_freertos_init(nimble_host_task); + + rc = xTaskCreate(heart_rate_task, "Heart Rate", 4 * 1024, NULL, 5, NULL); + if (rc != pdPASS) { + ESP_LOGE(TAG, "failed to create heart rate task"); + return; + } return; } diff --git a/examples/bluetooth/ble_get_started/nimble/NimBLE_Security/main/src/gap.c b/examples/bluetooth/ble_get_started/nimble/NimBLE_Security/main/src/gap.c index 55c34487eb9..5a9f174c939 100644 --- a/examples/bluetooth/ble_get_started/nimble/NimBLE_Security/main/src/gap.c +++ b/examples/bluetooth/ble_get_started/nimble/NimBLE_Security/main/src/gap.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -12,7 +12,6 @@ inline static void format_addr(char *addr_str, uint8_t addr[]); static void print_conn_desc(struct ble_gap_conn_desc *desc); static void start_advertising(void); -static void set_random_addr(void); static int gap_event_handler(struct ble_gap_event *event, void *arg); /* Private variables */ @@ -52,20 +51,6 @@ static void print_conn_desc(struct ble_gap_conn_desc *desc) { desc->sec_state.bonded); } -static void set_random_addr(void) { - /* Local variables */ - int rc = 0; - ble_addr_t addr; - - /* Generate new non-resolvable private address */ - rc = ble_hs_id_gen_rnd(0, &addr); - assert(rc == 0); - - /* Set address */ - rc = ble_hs_id_set_rnd(addr.val); - assert(rc == 0); -} - static void start_advertising(void) { /* Local variables */ int rc = 0; @@ -79,6 +64,9 @@ static void start_advertising(void) { /* Set device name */ name = ble_svc_gap_device_name(); + if (name == NULL) { + name = DEVICE_NAME; + } adv_fields.name = (uint8_t *)name; adv_fields.name_len = strlen(name); adv_fields.name_is_complete = 1; @@ -201,6 +189,9 @@ static int gap_event_handler(struct ble_gap_event *event, void *arg) { ESP_LOGI(TAG, "disconnected from peer; reason=%d", event->disconnect.reason); + /* Reset heart rate subscription state */ + gatt_svr_reset_heart_rate_subscription(); + /* Restart advertising */ start_advertising(); return rc; @@ -324,8 +315,9 @@ void adv_init(void) { int rc = 0; char addr_str[18] = {0}; - /* Make sure we have proper BT identity address set */ - set_random_addr(); + /* Make sure we have proper BT identity address set. + * ble_hs_util_ensure_addr(1) safely generates a random address only if + * one is not already set, avoiding conflicts on re-sync events. */ rc = ble_hs_util_ensure_addr(1); if (rc != 0) { ESP_LOGE(TAG, "device does not have any available bt address!"); diff --git a/examples/bluetooth/ble_get_started/nimble/NimBLE_Security/main/src/gatt_svc.c b/examples/bluetooth/ble_get_started/nimble/NimBLE_Security/main/src/gatt_svc.c index 726a4f2bb60..b3c7e73a489 100644 --- a/examples/bluetooth/ble_get_started/nimble/NimBLE_Security/main/src/gatt_svc.c +++ b/examples/bluetooth/ble_get_started/nimble/NimBLE_Security/main/src/gatt_svc.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -24,7 +24,7 @@ static uint8_t heart_rate_chr_val[2] = {0}; static uint16_t heart_rate_chr_val_handle; static const ble_uuid16_t heart_rate_chr_uuid = BLE_UUID16_INIT(0x2A37); -static uint16_t heart_rate_chr_conn_handle = 0; +static uint16_t heart_rate_chr_conn_handle = BLE_HS_CONN_HANDLE_NONE; static bool heart_rate_chr_conn_handle_inited = false; static bool heart_rate_ind_status = false; @@ -165,6 +165,12 @@ error: } /* Public functions */ +void gatt_svr_reset_heart_rate_subscription(void) { + heart_rate_chr_conn_handle_inited = false; + heart_rate_ind_status = false; + heart_rate_chr_conn_handle = BLE_HS_CONN_HANDLE_NONE; +} + void send_heart_rate_indication(void) { /* Check if connection handle is initialized */ if (!heart_rate_chr_conn_handle_inited) { @@ -230,10 +236,19 @@ void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) { int gatt_svr_subscribe_cb(struct ble_gap_event *event) { /* Check attribute handle */ if (event->subscribe.attr_handle == heart_rate_chr_val_handle) { + if (event->subscribe.conn_handle == BLE_HS_CONN_HANDLE_NONE) { + return 0; + } + + if (!event->subscribe.cur_indicate) { + gatt_svr_reset_heart_rate_subscription(); + return 0; + } + /* Update heart rate subscription status */ heart_rate_chr_conn_handle = event->subscribe.conn_handle; heart_rate_chr_conn_handle_inited = true; - heart_rate_ind_status = event->subscribe.cur_indicate; + heart_rate_ind_status = true; /* Check security status */ if (!is_connection_encrypted(event->subscribe.conn_handle)) { diff --git a/examples/bluetooth/nimble/ble_ancs/main/ble_ancs.c b/examples/bluetooth/nimble/ble_ancs/main/ble_ancs.c index 820fad21c02..31255fca0c9 100644 --- a/examples/bluetooth/nimble/ble_ancs/main/ble_ancs.c +++ b/examples/bluetooth/nimble/ble_ancs/main/ble_ancs.c @@ -113,7 +113,7 @@ void ble_receive_apple_notification_source(uint8_t *message, uint16_t message_le uint8_t CategoryID = message[2]; char *Cidstr = CategoryID_to_String(CategoryID); uint8_t CategoryCount = message[3]; - uint32_t NotificationUID = (message[4]) | (message[5]<< 8) | (message[6]<< 16) | (message[7] << 24); + uint32_t NotificationUID = ((uint32_t)message[4]) | ((uint32_t)message[5] << 8) | ((uint32_t)message[6] << 16) | ((uint32_t)message[7] << 24); ESP_LOGI(NimBLE_ANCS_TAG, "EventID:%s EventFlags:0x%x CategoryID:%s CategoryCount:%d NotificationUID:%" PRIu32, EventIDS, EventFlags, Cidstr, CategoryCount, NotificationUID); } @@ -131,14 +131,18 @@ void ble_receive_apple_data_source(uint8_t *message, uint16_t message_len) message_len); return; } - uint32_t NotificationUID = (message[1]) | (message[2]<< 8) | (message[3]<< 16) | (message[4] << 24); + uint32_t NotificationUID = ((uint32_t)message[1]) | ((uint32_t)message[2] << 8) | ((uint32_t)message[3] << 16) | ((uint32_t)message[4] << 24); uint32_t remain_attr_len = message_len - 5; uint8_t *attrs = &message[5]; ESP_LOGI(NimBLE_ANCS_TAG, "recevice Notification Attributes response Command_id %d NotificationUID %" PRIu32, Command_id, NotificationUID); - while(remain_attr_len >= 3) { + while(remain_attr_len > 0) { + if (remain_attr_len < 3) { + ESP_LOGE(NimBLE_ANCS_TAG, "incomplete attribute header"); + break; + } uint8_t AttributeID = attrs[0]; uint16_t len = attrs[1] | (attrs[2] << 8); - if(len > remain_attr_len - 3) { + if(len > (remain_attr_len - 3)) { ESP_LOGE(NimBLE_ANCS_TAG, "data error"); break; } diff --git a/examples/bluetooth/nimble/ble_ancs/main/main.c b/examples/bluetooth/nimble/ble_ancs/main/main.c index b9daeaa073b..da0c70b3b91 100644 --- a/examples/bluetooth/nimble/ble_ancs/main/main.c +++ b/examples/bluetooth/nimble/ble_ancs/main/main.c @@ -344,7 +344,7 @@ ext_ble_ancs_advertise(void) params.connectable = 1; /* advertise using configured addr */ - params.own_addr_type = BLE_OWN_ADDR_PUBLIC; + params.own_addr_type = own_addr_type; params.primary_phy = BLE_HCI_LE_PHY_1M; params.secondary_phy = BLE_HCI_LE_PHY_2M; params.tx_power = 127; @@ -413,11 +413,15 @@ ble_ancs_advertise(void) fields.tx_pwr_lvl_is_present = 1; fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO; +#if CONFIG_BT_NIMBLE_GAP_SERVICE name = ble_svc_gap_device_name(); fields.name = (uint8_t *)name; fields.name_len = strlen(name); fields.name_is_complete = 1; +#endif + static const ble_uuid16_t adv_uuids16[] = { BLE_UUID16_INIT(0x1811) }; + fields.uuids16 = adv_uuids16; fields.num_uuids16 = 1; fields.uuids16_is_complete = 1; @@ -485,6 +489,7 @@ ble_ancs_gap_event(struct ble_gap_event *event, void *arg) #else ble_ancs_advertise(); #endif + return 0; } /** Initiate security - It will perform @@ -544,7 +549,11 @@ ble_ancs_gap_event(struct ble_gap_event *event, void *arg) assert(rc == 0); ble_ancs_print_conn_desc(&desc); MODLOG_DFLT(INFO, "\n"); - rc = ble_gattc_disc_svc_by_uuid(event->connect.conn_handle, &APPLE_NC_UUID.u, + if (event->enc_change.status != 0) { + MODLOG_DFLT(ERROR, "encryption failed; status=%d\n", event->enc_change.status); + return 0; + } + rc = ble_gattc_disc_svc_by_uuid(event->enc_change.conn_handle, &APPLE_NC_UUID.u, ancs_service_discovered_cb, NULL); if (rc != 0) { return rc; @@ -563,6 +572,10 @@ ble_ancs_gap_event(struct ble_gap_event *event, void *arg) case BLE_GAP_EVENT_NOTIFY_RX: /* Peer sent us a notification or indication. */ if (event->notify_rx.attr_handle == notification_source_handle) { + if (event->notify_rx.om == NULL || event->notify_rx.om->om_len < 8) { + MODLOG_DFLT(ERROR, "NOTIFY_RX: short or NULL notification source packet\n"); + return 0; + } ble_receive_apple_notification_source(event->notify_rx.om->om_data, event->notify_rx.om->om_len); uint8_t *notificationUID = &event->notify_rx.om->om_data[4]; if (event->notify_rx.om->om_data[0] == EventIDNotificationAdded && @@ -773,6 +786,13 @@ app_main(void) /* XXX Need to have template for store */ ble_store_config_init(); + ret = esp_timer_create(&periodic_timer_args, &periodic_timer); + if (ret != ESP_OK) { + ESP_LOGE(tag, "Failed to create periodic timer: %d", ret); + nimble_port_deinit(); + return; + } + nimble_port_freertos_init(ble_ancs_host_task); } diff --git a/examples/bluetooth/nimble/ble_chan_sound_initiator/main/main.c b/examples/bluetooth/nimble/ble_chan_sound_initiator/main/main.c index deaf7012b99..56a5cfddba9 100644 --- a/examples/bluetooth/nimble/ble_chan_sound_initiator/main/main.c +++ b/examples/bluetooth/nimble/ble_chan_sound_initiator/main/main.c @@ -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 */ @@ -79,6 +79,10 @@ int blecent_on_subscribe(uint16_t conn_handle, param.cb_arg=NULL; ble_cs_initiator_procedure_start(¶m); } + } else { + MODLOG_DFLT(ERROR, "Subscription failed; status=%d conn_handle=%d\n", + error->status, conn_handle); + ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM); } return 0; @@ -180,6 +184,7 @@ blecent_on_custom_read(uint16_t conn_handle, rc = ble_chan_ras_subsribe_by_uuid(BLE_UUID16_DECLARE(BLE_UUID_RAS_REALTIME_RD_VAL), peer, conn_handle); if (rc != 0) { MODLOG_DFLT(ERROR, "Error: Peer doesn't support the RAS on demand raging data or fail to subscribe \n"); + ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM); return -1; } else { MODLOG_DFLT(INFO, "Subscribed to the RAS Realtime Ranging Data characteristic\n"); @@ -189,6 +194,7 @@ blecent_on_custom_read(uint16_t conn_handle, rc = ble_chan_ras_subsribe_by_uuid(BLE_UUID16_DECLARE(BLE_UUID_RAS_ONDEMAND_RD_VAL), peer, conn_handle); if (rc != 0) { MODLOG_DFLT(ERROR, "Error: Peer doesn't support the RAS on demand ranging data or fail to subscribe \n"); + ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM); return -1; } else { MODLOG_DFLT(INFO, "Subscribed to the RAS On Demand Ranging Data characteristic\n"); @@ -197,7 +203,11 @@ blecent_on_custom_read(uint16_t conn_handle, ble_chan_ras_subscribe(peer, conn_handle); } else if (error->status == BLE_ATT_ERR_INSUFFICIENT_AUTHEN) { MODLOG_DFLT(INFO, "Error: Insufficient authentication to read the characteristic\n"); + ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM); return -1; + } else { + MODLOG_DFLT(ERROR, "Error: Failed to read RAS Features; status=%d\n", error->status); + ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM); } return 0; } @@ -279,6 +289,7 @@ blecent_on_disc_complete(const struct peer *peer, int status, void *arg) blecent_on_custom_read, (void *)peer); if (rc != 0) { MODLOG_DFLT(ERROR, "2 Error: Failed to read the custom subscribable characteristic; ""rc=%d\n", rc); + ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM); } } @@ -289,7 +300,7 @@ static void blecent_scan(void) { uint8_t own_addr_type; - struct ble_gap_disc_params disc_params; + struct ble_gap_disc_params disc_params = {0}; int rc; /* Figure out address to use while advertising (no privacy for now) */ @@ -351,15 +362,17 @@ blecent_connect_if_interesting(void *disc) adv_data_len = d->length_data; #endif - for (int i = 1; i < adv_data_len - 1; i++) { - if (adv_data[i-1] == 0x03 && adv_data[i] == 0x5b && adv_data[i+1] == 0x18) { - found = 1; - MODLOG_DFLT(DEBUG, "Found 0x5b18 at index %d\n", i); - break; + struct ble_hs_adv_fields adv_fields; + if (ble_hs_adv_parse_fields(&adv_fields, adv_data, adv_data_len) == 0) { + for (int i = 0; i < adv_fields.num_uuids16; i++) { + if (adv_fields.uuids16[i].value == BLE_UUID_RANGING_SERVICE_VAL) { + found = 1; + break; + } } } if (!found) { - MODLOG_DFLT(DEBUG, "0x5b18 not found in adv_data, skipping connect.\n"); + MODLOG_DFLT(DEBUG, "Ranging Service UUID not found in adv_data, skipping connect.\n"); return; } #if !(MYNEWT_VAL(BLE_HOST_ALLOW_CONNECT_WITH_SCAN)) @@ -374,12 +387,18 @@ blecent_connect_if_interesting(void *disc) rc = ble_hs_id_infer_auto(0, &own_addr_type); if (rc != 0) { MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc); +#if !(MYNEWT_VAL(BLE_HOST_ALLOW_CONNECT_WITH_SCAN)) + blecent_scan(); +#endif return; } rc = ble_gap_connect(own_addr_type, addr, 30000, NULL, blecent_gap_event, NULL); if (rc != 0) { MODLOG_DFLT(ERROR, "Connection failed.\n"); +#if !(MYNEWT_VAL(BLE_HOST_ALLOW_CONNECT_WITH_SCAN)) + blecent_scan(); +#endif return; } } @@ -577,18 +596,19 @@ blecent_gap_event(struct ble_gap_event *event, void *arg) rc = ble_gattc_write_no_rsp_flat(event->notify_rx.conn_handle, ble_svc_ras_cp_val_handle, &value, sizeof value); } else if( value[0] == RASCP_RSP_OPCODE_RSP_CODE) { MODLOG_DFLT(INFO, "Sucssefully completed the Ranging procedure\n"); - vTaskDelay(1000 / portTICK_PERIOD_MS); - } } else if(ble_svc_ras_rd_val_handle == event->notify_rx.attr_handle){ MODLOG_DFLT(INFO, "Received Ranging Data Ready Indication\n"); + if (OS_MBUF_PKTLEN(event->notify_rx.om) < sizeof(uint16_t)) { + MODLOG_DFLT(ERROR, "Error: Invalid Ranging Data Ready Indication length\n"); + return 0; + } uint16_t ranging_counter; os_mbuf_copydata(event->notify_rx.om, 0, sizeof(uint16_t), &ranging_counter); - most_recent_peer_ranging_counter=ranging_counter; - most_recent_local_ranging_counter= ranging_counter; + most_recent_peer_ranging_counter = ranging_counter; - if (most_recent_peer_ranging_counter!=most_recent_local_ranging_counter) { + if (most_recent_peer_ranging_counter != most_recent_local_ranging_counter) { MODLOG_DFLT(INFO, "Ranging counter mismatch : %" PRId32 " , %" PRId32, most_recent_peer_ranging_counter,most_recent_local_ranging_counter); return 0; diff --git a/examples/bluetooth/nimble/ble_chan_sound_reflector/main/main.c b/examples/bluetooth/nimble/ble_chan_sound_reflector/main/main.c index d367d3fbb66..a037201294b 100644 --- a/examples/bluetooth/nimble/ble_chan_sound_reflector/main/main.c +++ b/examples/bluetooth/nimble/ble_chan_sound_reflector/main/main.c @@ -71,13 +71,17 @@ void print_cs_event(const struct ble_cs_event *event) MODLOG_DFLT(INFO, "subev_result.num_antenna_paths = %u\n", event->subev_result.num_antenna_paths); MODLOG_DFLT(INFO, "subev_result.num_steps_reported = %u\n", event->subev_result.num_steps_reported); - for (int i = 0; i < event->subev_result.num_steps_reported; i++) { - const struct cs_steps_data *step = &event->subev_result.steps[i]; - MODLOG_DFLT(INFO, "steps[%d]: mode=%u, channel=%u, data_len=%u, data=", i, step->mode, step->channel, step->data_len); - for (int j = 0; j < step->data_len; j++) { - esp_rom_printf("%02x ", step->data[j]); + { + const uint8_t *p = (const uint8_t *)event->subev_result.steps; + for (int i = 0; i < event->subev_result.num_steps_reported; i++) { + const struct cs_steps_data *step = (const struct cs_steps_data *)p; + MODLOG_DFLT(INFO, "steps[%d]: mode=%u, channel=%u, data_len=%u, data=", i, step->mode, step->channel, step->data_len); + for (int j = 0; j < step->data_len; j++) { + esp_rom_printf("%02x ", step->data[j]); + } + esp_rom_printf("\n"); + p += sizeof(struct cs_steps_data) + step->data_len; } - esp_rom_printf("\n"); } break; case BLE_CS_EVENT_SUBEVET_RESULT_CONTINUE: @@ -89,13 +93,17 @@ void print_cs_event(const struct ble_cs_event *event) MODLOG_DFLT(INFO, "subev_result_continue.num_antenna_paths = %u\n", event->subev_result_continue.num_antenna_paths); MODLOG_DFLT(INFO, "subev_result_continue.num_steps_reported = %u\n", event->subev_result_continue.num_steps_reported); - for (int i = 0; i < event->subev_result_continue.num_steps_reported; i++) { - const struct cs_steps_data *step = &event->subev_result_continue.steps[i]; - MODLOG_DFLT(INFO, "steps[%d]: mode=%u, channel=%u, data_len=%u, data=", i, step->mode, step->channel, step->data_len); - for (int j = 0; j < step->data_len; j++) { - esp_rom_printf("%02x ", step->data[j]); + { + const uint8_t *p = (const uint8_t *)event->subev_result_continue.steps; + for (int i = 0; i < event->subev_result_continue.num_steps_reported; i++) { + const struct cs_steps_data *step = (const struct cs_steps_data *)p; + MODLOG_DFLT(INFO, "steps[%d]: mode=%u, channel=%u, data_len=%u, data=", i, step->mode, step->channel, step->data_len); + for (int j = 0; j < step->data_len; j++) { + esp_rom_printf("%02x ", step->data[j]); + } + esp_rom_printf("\n"); + p += sizeof(struct cs_steps_data) + step->data_len; } - esp_rom_printf("\n"); } break; @@ -124,6 +132,7 @@ static int blecs_gap_event(struct ble_cs_event *event, void *arg) if (idx==1) { most_recent_local_ranging_counter=event->subev_result.procedure_counter; } + ble_gatts_store_ranging_data(ranging_subevent); MODLOG_DFLT(INFO, "LE CS Subevent Result , status: Partial, procedure counter %d\n", event->subev_result.procedure_counter); } else { MODLOG_DFLT(INFO, "LE CS Subevent Result , status: Unknown\n"); @@ -135,16 +144,19 @@ static int blecs_gap_event(struct ble_cs_event *event, void *arg) MODLOG_DFLT(INFO, "LE CS Subevent Result Continue , status: Aborted\n"); } else if ( event->subev_result_continue.procedure_done_status == BLE_HCI_LE_CS_SUBEVENT_DONE_STATUS_COMPLETE) { MODLOG_DFLT(INFO, "LE CS Subevent Result Continue , status: Complete\n"); - ranging_subevent.type = BLE_CS_EVENT_SUBEVET_RESULT_CONTINUE; - ranging_subevent.subev_result_continue = event->subev_result_continue; /* To * Get total number of CS procedure from CS enable event and then accordigly indicate to most recent ranging counter Currently we are considering only one CS procedure */ ind ++; if (ind==1) { - ble_gatts_store_ranging_data(ranging_subevent); + struct ble_cs_event continue_event; + continue_event.type = BLE_CS_EVENT_SUBEVET_RESULT_CONTINUE; + continue_event.subev_result_continue = event->subev_result_continue; + ble_gatts_store_ranging_data(continue_event); ble_gatts_indicate_ranging_data_ready(most_recent_local_ranging_counter); + idx = 0; + ind = 0; } } @@ -226,6 +238,9 @@ ext_bleprph_advertise(void) /* start advertising */ rc = ble_gap_ext_adv_start(instance, 0, 0); + if (rc != 0) { + MODLOG_DFLT(ERROR, "error starting extended advertisement; rc=%d\n", rc); + } } #else /** @@ -266,9 +281,10 @@ bleprph_advertise(void) fields.name_len = strlen(name); fields.name_is_complete = 1; #endif - fields.uuids16 = (ble_uuid16_t[]) { + static const ble_uuid16_t uuids16[] = { BLE_UUID16_INIT(BLE_UUID_RANGING_SERVICE_VAL) }; + fields.uuids16 = uuids16; fields.num_uuids16 = 1; fields.uuids16_is_complete = 1; rc = ble_gap_adv_set_fields(&fields); @@ -335,6 +351,9 @@ bleprph_gap_event(struct ble_gap_event *event, void *arg) MODLOG_DFLT(INFO, "disconnect; reason=%d ", event->disconnect.reason); bleprph_print_conn_desc(&event->disconnect.conn); MODLOG_DFLT(INFO, "\n"); + idx = 0; + ind = 0; + most_recent_local_ranging_counter = -1; /* Connection terminated; resume advertising. */ #if CONFIG_EXAMPLE_EXTENDED_ADV ext_bleprph_advertise(); @@ -381,7 +400,6 @@ bleprph_gap_event(struct ble_gap_event *event, void *arg) event->notify_tx.indication); if (event->notify_tx.status == BLE_HS_EDONE) { - vTaskDelay(4000 / portTICK_PERIOD_MS); ble_gatts_indicate_control_point_response(event->notify_tx.attr_handle,most_recent_local_ranging_counter); } return 0; @@ -409,6 +427,9 @@ static void bleprph_on_reset(int reason) { MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason); + idx = 0; + ind = 0; + most_recent_local_ranging_counter = -1; } static void diff --git a/examples/bluetooth/nimble/ble_cte/ble_periodic_adv_with_cte/main/main.c b/examples/bluetooth/nimble/ble_cte/ble_periodic_adv_with_cte/main/main.c index ac8941cec61..85c02629467 100644 --- a/examples/bluetooth/nimble/ble_cte/ble_periodic_adv_with_cte/main/main.c +++ b/examples/bluetooth/nimble/ble_cte/ble_periodic_adv_with_cte/main/main.c @@ -54,10 +54,9 @@ static void start_periodic_adv_cte(uint8_t own_addr_type) assert(rc == 0); /* Configure advertising data */ - struct ble_hs_adv_fields adv_fields = { - .name = (const uint8_t *)"CTE_Periodic_Adv", - .name_len = strlen((char *)adv_fields.name) - }; + struct ble_hs_adv_fields adv_fields = {0}; + adv_fields.name = (const uint8_t *)"CTE_Periodic_Adv"; + adv_fields.name_len = strlen("CTE_Periodic_Adv"); struct os_mbuf *data = os_msys_get_pkthdr(BLE_HS_ADV_MAX_FIELD_SZ, 0); assert(data); @@ -198,7 +197,12 @@ void app_main(void) ESP_LOGI(TAG, "%s", direction_finding_logo); #if defined(CONFIG_EXAMPLE_ADV_DIRECTION_FINDING_AOD) ESP_LOGI(TAG, "DIRECTION_FINDING Example Periodic Adv AOD Mode"); - ble_direction_finding_antenna_init(antenna_use_gpio,CONFIG_EXAMPLE_ANT_GPIO_BIT_COUNT); + rc = ble_direction_finding_antenna_init(antenna_use_gpio, CONFIG_EXAMPLE_ANT_GPIO_BIT_COUNT); + if (rc != 0) { + ESP_LOGE(TAG, "Antenna init failed; rc=%d", rc); + nimble_port_deinit(); + return; + } #elif defined(CONFIG_EXAMPLE_ADV_DIRECTION_FINDING_AOA) ESP_LOGI(TAG, "DIRECTION_FINDING Example Periodic Adv AOA Mode"); #endif diff --git a/examples/bluetooth/nimble/ble_cte/ble_periodic_sync_with_cte/main/main.c b/examples/bluetooth/nimble/ble_cte/ble_periodic_sync_with_cte/main/main.c index 2117fdf7bae..7a9f008d91b 100644 --- a/examples/bluetooth/nimble/ble_cte/ble_periodic_sync_with_cte/main/main.c +++ b/examples/bluetooth/nimble/ble_cte/ble_periodic_sync_with_cte/main/main.c @@ -173,7 +173,7 @@ static int periodic_sync_gap_event(struct ble_gap_event *event, void *arg) memcpy(dev_name, &adv_data[index + 2], name_len); dev_name[name_len] = '\0'; - if (strcmp(dev_name, CONFIG_SYNC_TARGET_DEVNAME) == 0) { + if (strcmp(dev_name, CONFIG_EXAMPLE_SYNC_TARGET_DEVNAME) == 0) { should_sync = true; break; } @@ -184,7 +184,7 @@ static int periodic_sync_gap_event(struct ble_gap_event *event, void *arg) #else #error "Please select EXAMPLE_SYNC_BY_SID or EXAMPLE_SYNC_BY_NAME in menuconfig" #endif - if (should_sync) { + if (should_sync && disc->periodic_adv_itvl != 0) { ble_addr_t addr; memcpy(&addr, &disc->addr, sizeof(ble_addr_t)); @@ -249,6 +249,7 @@ static int periodic_sync_gap_event(struct ble_gap_event *event, void *arg) static void periodic_sync_on_reset(int reason) { ESP_LOGE(TAG, "Resetting state; reason=%d", reason); + is_synced = 0; } static void periodic_sync_on_sync(void) diff --git a/examples/bluetooth/nimble/ble_cts/cts_cent/main/main.c b/examples/bluetooth/nimble/ble_cts/cts_cent/main/main.c index 5a358a0c363..f2856d6f47d 100644 --- a/examples/bluetooth/nimble/ble_cts/cts_cent/main/main.c +++ b/examples/bluetooth/nimble/ble_cts/cts_cent/main/main.c @@ -206,16 +206,17 @@ ext_ble_cts_cent_should_connect(const struct ble_gap_ext_disc_desc *disc) { int offset = 0; int ad_struct_len = 0; - uint8_t test_addr[6]; - if (disc->legacy_event_type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND && - disc->legacy_event_type != BLE_HCI_ADV_RPT_EVTYPE_DIR_IND) { + uint8_t test_addr[6] = {0}; + if (!(disc->props & BLE_HCI_ADV_CONN_MASK)) { return 0; } if (strlen(CONFIG_EXAMPLE_PEER_ADDR) && (strncmp(CONFIG_EXAMPLE_PEER_ADDR, "ADDR_ANY", strlen("ADDR_ANY")) != 0)) { ESP_LOGI(tag, "Peer address from menuconfig: %s", CONFIG_EXAMPLE_PEER_ADDR); - /* Convert string to address */ - peer_addr_parse(CONFIG_EXAMPLE_PEER_ADDR, test_addr); + /* Convert string to address */ + if (peer_addr_parse(CONFIG_EXAMPLE_PEER_ADDR, test_addr) != 6) { + return 0; + } if (memcmp(test_addr, disc->addr.val, sizeof(disc->addr.val)) != 0) { return 0; } @@ -224,17 +225,24 @@ ext_ble_cts_cent_should_connect(const struct ble_gap_ext_disc_desc *disc) /* The device has to advertise support for the CTS * service (0x1805). */ - do { + while (offset < disc->length_data) { + if (offset + 1 >= disc->length_data) { + break; + } ad_struct_len = disc->data[offset]; if (!ad_struct_len) { break; } + if (offset + ad_struct_len >= disc->length_data) { + break; + } + /* Search if cts UUID is advertised */ if (disc->data[offset + 1] == 0x03) { int temp = 2; - while (temp < ad_struct_len) { + while (temp < ad_struct_len && (offset + temp + 1) < disc->length_data) { if(disc->data[offset + temp] == 0x05 && disc->data[offset + temp + 1] == 0x18) { return 1; @@ -243,7 +251,7 @@ ext_ble_cts_cent_should_connect(const struct ble_gap_ext_disc_desc *disc) } } offset += ad_struct_len + 1; - } while ( offset < disc->length_data ); + } return 0; } @@ -255,7 +263,7 @@ ble_cts_cent_should_connect(const struct ble_gap_disc_desc *disc) struct ble_hs_adv_fields fields; int rc; int i; - uint8_t test_addr[6]; + uint8_t test_addr[6] = {0}; /* The device has to be advertising connectability. */ if (disc->event_type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND && disc->event_type != BLE_HCI_ADV_RPT_EVTYPE_DIR_IND) { @@ -271,7 +279,9 @@ ble_cts_cent_should_connect(const struct ble_gap_disc_desc *disc) if (strlen(CONFIG_EXAMPLE_PEER_ADDR) && (strncmp(CONFIG_EXAMPLE_PEER_ADDR, "ADDR_ANY", strlen("ADDR_ANY")) != 0)) { ESP_LOGI(tag, "Peer address from menuconfig: %s", CONFIG_EXAMPLE_PEER_ADDR); /* Convert string to address */ - peer_addr_parse(CONFIG_EXAMPLE_PEER_ADDR, test_addr); + if (peer_addr_parse(CONFIG_EXAMPLE_PEER_ADDR, test_addr) != 6) { + return 0; + } if (memcmp(test_addr, disc->addr.val, sizeof(disc->addr.val)) != 0) { return 0; } @@ -326,6 +336,9 @@ ble_cts_cent_connect_if_interesting(void *disc) rc = ble_hs_id_infer_auto(0, &own_addr_type); if (rc != 0) { MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc); +#if !(MYNEWT_VAL(BLE_HOST_ALLOW_CONNECT_WITH_SCAN)) + ble_cts_cent_scan(); +#endif return; } @@ -343,6 +356,9 @@ ble_cts_cent_connect_if_interesting(void *disc) MODLOG_DFLT(ERROR, "Error: Failed to connect to device; addr_type=%d " "addr=%s; rc=%d\n", addr->type, addr_str(addr->val), rc); +#if !(MYNEWT_VAL(BLE_HOST_ALLOW_CONNECT_WITH_SCAN)) + ble_cts_cent_scan(); +#endif return; } } @@ -365,11 +381,13 @@ static int ble_cts_cent_gap_event(struct ble_gap_event *event, void *arg) { struct ble_gap_conn_desc desc; - struct ble_hs_adv_fields fields; int rc; switch (event->type) { case BLE_GAP_EVENT_DISC: +#if !CONFIG_EXAMPLE_EXTENDED_ADV + { + struct ble_hs_adv_fields fields; rc = ble_hs_adv_parse_fields(&fields, event->disc.data, event->disc.length_data); if (rc != 0) { @@ -381,6 +399,8 @@ ble_cts_cent_gap_event(struct ble_gap_event *event, void *arg) /* Try to connect to the advertiser if it looks interesting. */ ble_cts_cent_connect_if_interesting(&event->disc); + } +#endif return 0; case BLE_GAP_EVENT_CONNECT: @@ -597,11 +617,14 @@ app_main(void) /* Initialize data structures to track connected peers. */ #if MYNEWT_VAL(BLE_INCL_SVC_DISCOVERY) || MYNEWT_VAL(BLE_GATT_CACHING_INCLUDE_SERVICES) rc = peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64, 64); - assert(rc == 0); #else rc = peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64); - assert(rc == 0); #endif + if (rc != 0) { + ESP_LOGE(tag, "Failed to init peer tracking; rc=%d", rc); + nimble_port_deinit(); + return; + } #if CONFIG_BT_NIMBLE_GAP_SERVICE /* Set the default device name. */ diff --git a/examples/bluetooth/nimble/ble_cts/cts_prph/main/gatt_svr.c b/examples/bluetooth/nimble/ble_cts/cts_prph/main/gatt_svr.c index b11cef220a6..e38b30368b9 100644 --- a/examples/bluetooth/nimble/ble_cts/cts_prph/main/gatt_svr.c +++ b/examples/bluetooth/nimble/ble_cts/cts_prph/main/gatt_svr.c @@ -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 */ @@ -71,9 +71,8 @@ int fetch_current_time(struct ble_svc_cts_curr_time *ctime) { ctime->et_256.d_d_t.d_t.seconds = timeinfo.tm_sec; /* day of week */ - /* time gives day range of [0, 6], current_time_sevice - has day range of [1,7] */ - ctime->et_256.d_d_t.day_of_week = timeinfo.tm_wday + 1; + /* tm_wday: 0=Sunday..6=Saturday; CTS: 1=Monday..7=Sunday */ + ctime->et_256.d_d_t.day_of_week = (timeinfo.tm_wday == 0) ? 7 : timeinfo.tm_wday; /* fractions_256 */ ctime->et_256.fractions_256 = (((uint64_t)tv_now.tv_usec * 256L )/ 1000000L); @@ -108,7 +107,9 @@ int set_current_time(struct ble_svc_cts_curr_time ctime) { timeinfo.tm_hour = ctime.et_256.d_d_t.d_t.hours; timeinfo.tm_min = ctime.et_256.d_d_t.d_t.minutes; timeinfo.tm_sec = ctime.et_256.d_d_t.d_t.seconds; - timeinfo.tm_wday = ctime.et_256.d_d_t.day_of_week - 1; + /* CTS day_of_week: 1=Monday..7=Sunday; tm_wday: 0=Sunday..6=Saturday */ + timeinfo.tm_wday = (ctime.et_256.d_d_t.day_of_week == 7) ? 0 : ctime.et_256.d_d_t.day_of_week; + timeinfo.tm_isdst = -1; now = mktime(&timeinfo); if (now == (time_t)-1) { ESP_LOGE(TAG, "Failed to convert current time"); @@ -137,6 +138,7 @@ int set_local_time_info(struct ble_svc_cts_local_time_info info) { local_info.timezone = info.timezone; local_info.dst_offset = info.dst_offset; gettimeofday(&last_updated, NULL); + adjust_reason = (CHANGE_OF_DST_MASK | CHANGE_OF_TIME_ZONE_MASK); return 0; } int fetch_reference_time_info(struct ble_svc_cts_reference_time_info *info) { @@ -160,8 +162,6 @@ int fetch_reference_time_info(struct ble_svc_cts_reference_time_info *info) { hours_since_update = (tv_now.tv_sec % 86400L) / 3600; info->hours_since_update = hours_since_update; } - adjust_reason = (CHANGE_OF_DST_MASK | CHANGE_OF_TIME_ZONE_MASK); - return 0; } int diff --git a/examples/bluetooth/nimble/ble_cts/cts_prph/main/main.c b/examples/bluetooth/nimble/ble_cts/cts_prph/main/main.c index b054ef9ecb5..35968b02a6c 100644 --- a/examples/bluetooth/nimble/ble_cts/cts_prph/main/main.c +++ b/examples/bluetooth/nimble/ble_cts/cts_prph/main/main.c @@ -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 */ @@ -79,8 +79,8 @@ ext_ble_cts_prph_advertise(void) /* enable connectable advertising */ params.connectable = 1; - /* advertise using random addr */ - params.own_addr_type = BLE_OWN_ADDR_PUBLIC; + /* advertise using configured addr */ + params.own_addr_type = ble_cts_prph_addr_type; params.primary_phy = BLE_HCI_LE_PHY_1M; params.secondary_phy = BLE_HCI_LE_PHY_2M; @@ -148,9 +148,10 @@ ble_cts_prph_advertise(void) fields.name_len = strlen(device_name); fields.name_is_complete = 1; - fields.uuids16 = (ble_uuid16_t[]) { + static const ble_uuid16_t adv_uuids16[] = { BLE_UUID16_INIT(BLE_SVC_CTS_UUID16) }; + fields.uuids16 = adv_uuids16; fields.num_uuids16 = 1; fields.uuids16_is_complete = 1; diff --git a/examples/bluetooth/nimble/ble_dynamic_service/main/gatt_svr.c b/examples/bluetooth/nimble/ble_dynamic_service/main/gatt_svr.c index 4efb54ba8d7..010f6ddce63 100644 --- a/examples/bluetooth/nimble/ble_dynamic_service/main/gatt_svr.c +++ b/examples/bluetooth/nimble/ble_dynamic_service/main/gatt_svr.c @@ -141,9 +141,11 @@ gatt_svc_access(uint16_t conn_handle, uint16_t attr_handle, sizeof(gatt_svr_chr_val), sizeof(gatt_svr_chr_val), &gatt_svr_chr_val, NULL); - ble_gatts_chr_updated(attr_handle); - MODLOG_DFLT(INFO, "Notification/Indication scheduled for " - "all subscribed peers.\n"); + if (rc == 0) { + ble_gatts_chr_updated(attr_handle); + MODLOG_DFLT(INFO, "Notification/Indication scheduled for " + "all subscribed peers.\n"); + } return rc; } goto unknown; @@ -160,7 +162,7 @@ gatt_svc_access(uint16_t conn_handle, uint16_t attr_handle, if (ble_uuid_cmp(uuid, &gatt_svr_dsc_uuid.u) == 0) { rc = os_mbuf_append(ctxt->om, &gatt_svr_dsc_val, - sizeof(gatt_svr_chr_val)); + sizeof(gatt_svr_dsc_val)); return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; } goto unknown; diff --git a/examples/bluetooth/nimble/ble_dynamic_service/main/main.c b/examples/bluetooth/nimble/ble_dynamic_service/main/main.c index 02a7ed07271..aea975194b5 100644 --- a/examples/bluetooth/nimble/ble_dynamic_service/main/main.c +++ b/examples/bluetooth/nimble/ble_dynamic_service/main/main.c @@ -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 */ @@ -90,9 +90,11 @@ dynamic_service_advertise(void) fields.name_len = strlen(name); fields.name_is_complete = 1; - fields.uuids16 = (ble_uuid16_t[]) { - BLE_UUID16_INIT(GATT_SVR_SVC_ALERT_UUID) - }; + /* Must be static: ble_gap_adv_set_fields stores the pointer, not the data. + * A stack compound literal becomes dangling after this function returns, + * causing corruption when BLE_NIMBLE_ENABLE_CONN_REATTEMPT re-uses it. */ + static const ble_uuid16_t adv_uuids16[] = { BLE_UUID16_INIT(GATT_SVR_SVC_ALERT_UUID) }; + fields.uuids16 = adv_uuids16; fields.num_uuids16 = 1; fields.uuids16_is_complete = 1; @@ -143,8 +145,11 @@ dynamic_service_gap_event(struct ble_gap_event *event, void *arg) event->connect.status); if (event->connect.status == 0) { rc = ble_gap_conn_find(event->connect.conn_handle, &desc); - assert(rc == 0); - dynamic_service_print_conn_desc(&desc); + if (rc != 0) { + MODLOG_DFLT(ERROR, "Failed to find connection; rc=%d\n", rc); + } else { + dynamic_service_print_conn_desc(&desc); + } } MODLOG_DFLT(INFO, "\n"); @@ -282,11 +287,19 @@ app_main(void) #if MYNEWT_VAL(BLE_GATTS) rc = gatt_svr_init(); - assert(rc == 0); + if (rc != 0) { + MODLOG_DFLT(ERROR, "Failed to init GATT server; rc=%d\n", rc); + nimble_port_deinit(); + return; + } /* Set the default device name. */ rc = ble_svc_gap_device_name_set("ble-dynamic-service"); - assert(rc == 0); + if (rc != 0) { + MODLOG_DFLT(ERROR, "Failed to set device name; rc=%d\n", rc); + nimble_port_deinit(); + return; + } #endif nimble_port_freertos_init(dynamic_service_host_task); diff --git a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/main/main.c b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/main/main.c index 3d17bd4e76d..92bb03144ed 100644 --- a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/main/main.c +++ b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/main/main.c @@ -78,6 +78,7 @@ enc_adv_data_cent_on_read(uint16_t conn_handle, { int rc; struct ble_store_value_ead value_ead = {0}; + struct ble_gap_conn_desc desc; struct peer *p; MODLOG_DFLT(INFO, "Read complete; status=%d conn_handle=%d", error->status, @@ -119,6 +120,10 @@ enc_adv_data_cent_on_read(uint16_t conn_handle, print_bytes(value_ead.km.iv, BLE_EAD_IV_SIZE); memcpy(&value_ead.peer_addr.val, &p->peer_addr, PEER_ADDR_VAL_SIZE); + rc = ble_gap_conn_find(conn_handle, &desc); + if (rc == 0) { + value_ead.peer_addr.type = desc.peer_id_addr.type; + } rc = ble_store_write_ead(&value_ead); if (rc == 0) { @@ -184,6 +189,8 @@ enc_adv_data_cent_on_disc_complete(const struct peer *peer, int status, void *ar if (!enc_adv_data_check_km_exist(peer->peer_addr)) { /* Now perform GATT read procedures against the peer */ enc_adv_data_cent_read(peer); + } else { + ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM); } } #endif @@ -289,7 +296,17 @@ enc_adv_data_cent_decrypt(uint8_t length_data, const uint8_t *data, const uint8_ return 0; } + uint8_t actual_dec_len = enc_payload_len - (BLE_EAD_RANDOMIZER_SIZE + BLE_EAD_MIC_SIZE); + if (actual_dec_len == 0) { + free(enc_data); + return 0; + } dec_data_len = temp[0]; + if ((uint16_t)dec_data_len + 1 > actual_dec_len) { + MODLOG_DFLT(ERROR, "Decrypted length field exceeds payload"); + free(enc_data); + return 0; + } MODLOG_DFLT(INFO, "Data after decryption:"); for (int i = 0; i < dec_data_len + 1; i++) { @@ -318,34 +335,17 @@ enc_adv_data_cent_ext_should_connect(const struct ble_gap_ext_disc_desc *disc) { int offset = 0; int ad_struct_len = 0; -#if CONFIG_EXAMPLE_USE_CI_ADDRESS - uint32_t *addr_offset; -#endif // CONFIG_EXAMPLE_USE_CI_ADDRESS - uint8_t test_addr[6]; - if (disc->legacy_event_type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND && - disc->legacy_event_type != BLE_HCI_ADV_RPT_EVTYPE_DIR_IND) { + uint8_t test_addr[6] = {0}; + if (!(disc->props & BLE_HCI_ADV_CONN_MASK)) { return 0; } - if (strlen(CONFIG_EXAMPLE_PEER_ADDR) && (strncmp(CONFIG_EXAMPLE_PEER_ADDR, "ADDR_ANY", strlen ("ADDR_ANY")) != 0)) { -#if !CONFIG_EXAMPLE_USE_CI_ADDRESS + if (strlen(CONFIG_EXAMPLE_PEER_ADDR) && + (strncmp(CONFIG_EXAMPLE_PEER_ADDR, "ADDR_ANY", strlen("ADDR_ANY")) != 0)) { ESP_LOGI(tag, "Peer address from menuconfig: %s", CONFIG_EXAMPLE_PEER_ADDR); /* Convert string to address */ peer_addr_parse(CONFIG_EXAMPLE_PEER_ADDR, test_addr); -#endif - - /* Conversion */ - for(int i=0; i<6; i++) { - test_addr[i] = (uint8_t )peer_addr[i]; - } - -#if CONFIG_EXAMPLE_USE_CI_ADDRESS - addr_offset = (uint32_t *)&test_addr[1]; - *addr_offset = atoi(CONFIG_EXAMPLE_PEER_ADDR); - test_addr[5] = 0xC3; - test_addr[0] = CONFIG_IDF_FIRMWARE_CHIP_ID; -#endif - if (memcmp(test_addr, disc->addr.val, sizeof(disc->addr.val)) != 0) { - return 0; + if (memcmp(test_addr, disc->addr.val, sizeof(disc->addr.val)) != 0) { + return 0; } } @@ -372,6 +372,7 @@ enc_adv_data_cent_ext_should_connect(const struct ble_gap_ext_disc_desc *disc) MODLOG_DFLT(INFO, "Adding peer addr : %s", addr_str(&disc->addr.val)); memcpy(&kmp[counter].peer_addr, &disc->addr.val, PEER_ADDR_VAL_SIZE); + kmp[counter].key_material_exist = false; counter++; if (counter > CONFIG_BT_NIMBLE_MAX_CONNECTIONS) { @@ -399,7 +400,7 @@ enc_adv_data_cent_should_connect(const struct ble_gap_disc_desc *disc) struct ble_hs_adv_fields fields; int rc; int i; - uint8_t test_addr[6]; + uint8_t test_addr[6] = {0}; if (disc->event_type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND && disc->event_type != BLE_HCI_ADV_RPT_EVTYPE_DIR_IND) { return 0; @@ -410,7 +411,8 @@ enc_adv_data_cent_should_connect(const struct ble_gap_disc_desc *disc) return 0; } - if (strlen(CONFIG_EXAMPLE_PEER_ADDR) && (strncmp(CONFIG_EXAMPLE_PEER_ADDR, "ADDR_ANY", strlen ("ADDR_ANY")) != 0)) { + if (strlen(CONFIG_EXAMPLE_PEER_ADDR) && + (strncmp(CONFIG_EXAMPLE_PEER_ADDR, "ADDR_ANY", strlen("ADDR_ANY")) != 0)) { MODLOG_DFLT(INFO, "Peer address from menuconfig: %s", CONFIG_EXAMPLE_PEER_ADDR); /* Convert string to address */ peer_addr_parse(CONFIG_EXAMPLE_PEER_ADDR, test_addr); @@ -433,6 +435,7 @@ enc_adv_data_cent_should_connect(const struct ble_gap_disc_desc *disc) MODLOG_DFLT(INFO, "Adding peer addr : %s", addr_str(&disc->addr.val)); memcpy(&kmp[counter].peer_addr, &disc->addr.val, PEER_ADDR_VAL_SIZE); + kmp[counter].key_material_exist = false; counter++; if (counter > CONFIG_BT_NIMBLE_MAX_CONNECTIONS) { @@ -487,6 +490,9 @@ enc_adv_data_cent_connect_if_interesting(void *disc) rc = ble_hs_id_infer_auto(0, &own_addr_type); if (rc != 0) { MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc); +#if !(MYNEWT_VAL(BLE_HOST_ALLOW_CONNECT_WITH_SCAN)) + enc_adv_data_cent_scan(); +#endif return; } @@ -505,6 +511,9 @@ enc_adv_data_cent_connect_if_interesting(void *disc) MODLOG_DFLT(ERROR, "Error: Failed to connect to device; addr_type=%d " "addr=%s; rc=%d\n", addr->type, addr_str(addr->val), rc); +#if !(MYNEWT_VAL(BLE_HOST_ALLOW_CONNECT_WITH_SCAN)) + enc_adv_data_cent_scan(); +#endif return; } } @@ -572,12 +581,15 @@ enc_adv_data_cent_gap_event(struct ble_gap_event *event, void *arg) rc = peer_add(event->connect.conn_handle); if (rc != 0) { MODLOG_DFLT(ERROR, "Failed to add peer; rc=%d\n", rc); + ble_gap_terminate(event->connect.conn_handle, BLE_ERR_REM_USER_CONN_TERM); return 0; } rc = peer_set_addr(event->connect.conn_handle, desc.peer_id_addr.val); if (rc != 0) { MODLOG_DFLT(ERROR, "Failed to set peer addr; rc=%d\n", rc); + peer_delete(event->connect.conn_handle); + ble_gap_terminate(event->connect.conn_handle, BLE_ERR_REM_USER_CONN_TERM); return 0; } @@ -744,11 +756,14 @@ app_main(void) /* Initialize data structures to track connected peers. */ #if MYNEWT_VAL(BLE_INCL_SVC_DISCOVERY) || MYNEWT_VAL(BLE_GATT_CACHING_INCLUDE_SERVICES) rc = peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64, 64); - assert(rc == 0); #else rc = peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64); - assert(rc == 0); #endif + if (rc != 0) { + ESP_LOGE(tag, "Failed to init peer tracking; rc=%d", rc); + nimble_port_deinit(); + return; + } #if CONFIG_BT_NIMBLE_GAP_SERVICE /* Set the default device name. */ diff --git a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/gatt_svr.c b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/gatt_svr.c index 912597dc4cc..271df861233 100644 --- a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/gatt_svr.c +++ b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/gatt_svr.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -150,9 +150,11 @@ gatt_svc_access(uint16_t conn_handle, uint16_t attr_handle, sizeof(gatt_svr_chr_val), sizeof(gatt_svr_chr_val), &gatt_svr_chr_val, NULL); - ble_gatts_chr_updated(attr_handle); - MODLOG_DFLT(INFO, "Notification/Indication scheduled for " - "all subscribed peers.\n"); + if (rc == 0) { + ble_gatts_chr_updated(attr_handle); + MODLOG_DFLT(INFO, "Notification/Indication scheduled for " + "all subscribed peers.\n"); + } return rc; } goto unknown; @@ -169,7 +171,7 @@ gatt_svc_access(uint16_t conn_handle, uint16_t attr_handle, if (ble_uuid_cmp(uuid, &gatt_svr_dsc_uuid.u) == 0) { rc = os_mbuf_append(ctxt->om, &gatt_svr_dsc_val, - sizeof(gatt_svr_chr_val)); + sizeof(gatt_svr_dsc_val)); return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; } goto unknown; diff --git a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/main.c b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/main.c index e28495ee06a..10a1737cf56 100644 --- a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/main.c +++ b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/main.c @@ -140,8 +140,8 @@ enc_adv_data_prph_ext_advertise(void) /* enable connectable advertising */ params.connectable = 1; - /* advertise using random addr */ - params.own_addr_type = BLE_OWN_ADDR_PUBLIC; + /* advertise using configured addr */ + params.own_addr_type = own_addr_type; params.primary_phy = BLE_HCI_LE_PHY_1M; params.secondary_phy = BLE_HCI_LE_PHY_2M; @@ -163,6 +163,10 @@ enc_adv_data_prph_ext_advertise(void) /* get mbuf with adv data */ temp = malloc(sizeof(ext_adv_pattern) + 2 + encrypted_adv_data_len); + if (temp == NULL) { + MODLOG_DFLT(ERROR, "Failed to allocate temp buffer for ext adv data"); + return; + } memcpy(temp, ext_adv_pattern, sizeof(ext_adv_pattern)); temp[sizeof(ext_adv_pattern)] = 1 + encrypted_adv_data_len; temp[sizeof(ext_adv_pattern) + 1] = BLE_GAP_ENC_ADV_DATA; @@ -194,8 +198,11 @@ enc_adv_data_prph_advertise(void) struct ble_hs_adv_fields fields; int rc; - const unsigned encrypted_adv_data_len = BLE_EAD_ENCRYPTED_PAYLOAD_SIZE(sizeof(unencrypted_adv_pattern)); - uint8_t encrypted_adv_data[encrypted_adv_data_len]; + static const ble_uuid16_t adv_uuids16[] = { + BLE_UUID16_INIT(0x2C01) /** For the central to recognise this device */ + }; + static uint8_t encrypted_adv_data[BLE_EAD_ENCRYPTED_PAYLOAD_SIZE(sizeof(unencrypted_adv_pattern))]; + const unsigned encrypted_adv_data_len = sizeof(encrypted_adv_data); memset(encrypted_adv_data, 0, encrypted_adv_data_len); /* First check if any instance is already active */ @@ -207,8 +214,6 @@ enc_adv_data_prph_advertise(void) memset (¶ms, 0, sizeof(params)); memset (&fields, 0, sizeof(fields)); - own_addr_type = BLE_OWN_ADDR_PUBLIC; - /* enable connectable advertising */ params.conn_mode = BLE_GAP_CONN_MODE_UND; params.disc_mode = BLE_GAP_DISC_MODE_GEN; @@ -222,9 +227,7 @@ enc_adv_data_prph_advertise(void) fields.name_len = 3; fields.name_is_complete = 1; - fields.uuids16 = (ble_uuid16_t[]) { - BLE_UUID16_INIT(0x2C01) /** For the central to recognise this device */ - }; + fields.uuids16 = adv_uuids16; fields.num_uuids16 = 1; fields.uuids16_is_complete = 1; @@ -397,17 +400,22 @@ enc_adv_data_prph_on_reset(int reason) static void ble_app_set_addr(void) { - ble_addr_t addr; + ble_addr_t addr = {0}; int rc; /* generate new non-resolvable private address */ rc = ble_hs_id_gen_rnd(0, &addr); - assert(rc == 0); + if (rc != 0) { + MODLOG_DFLT(ERROR, "Failed to generate random address; rc=%d\n", rc); + return; + } /* set generated address */ rc = ble_hs_id_set_rnd(addr.val); - - assert(rc == 0); + if (rc != 0) { + MODLOG_DFLT(ERROR, "Failed to set random address; rc=%d\n", rc); + return; + } } #endif diff --git a/examples/bluetooth/nimble/ble_gattc_gatts_coex/main/main.c b/examples/bluetooth/nimble/ble_gattc_gatts_coex/main/main.c index 665b179d9e2..a69617bc2db 100644 --- a/examples/bluetooth/nimble/ble_gattc_gatts_coex/main/main.c +++ b/examples/bluetooth/nimble/ble_gattc_gatts_coex/main/main.c @@ -17,16 +17,16 @@ static uint8_t own_addr_type; static int blecoex_gap_event(struct ble_gap_event *event, void *arg); void ble_coex_advertise(void); void ble_coex_scan(void); -static bool client_connect = 0; +static uint8_t client_connect = 0; static int gatt_svr_access_cb(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { int rc = 0; if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { static uint8_t data[1] = {42}; // Example value - os_mbuf_append(ctxt->om, data, sizeof(data)); + rc = os_mbuf_append(ctxt->om, data, sizeof(data)); if (rc != 0) { - return rc; + return BLE_ATT_ERR_INSUFFICIENT_RES; } } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC) { static uint8_t dsc_data[1] = {0x01}; // Example descriptor value @@ -192,6 +192,10 @@ blecent_on_write(uint16_t conn_handle, uint8_t value[2]; int rc; const struct peer *peer = peer_find(conn_handle); + if (peer == NULL) { + MODLOG_DFLT(ERROR, "Peer not found for conn_handle=%d\n", conn_handle); + return ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM); + } dsc = peer_dsc_find_uuid(peer, BLE_UUID16_DECLARE(BLECOEX_SVC_ALERT_UUID), @@ -216,7 +220,7 @@ blecent_on_write(uint16_t conn_handle, return 0; err: /* Terminate the connection. */ - return ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM); + return ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM); } @@ -241,6 +245,10 @@ blecent_on_read(uint16_t conn_handle, uint8_t value[2]; int rc; const struct peer *peer = peer_find(conn_handle); + if (peer == NULL) { + MODLOG_DFLT(ERROR, "Peer not found for conn_handle=%d\n", conn_handle); + return ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM); + } chr = peer_chr_find_uuid(peer, BLE_UUID16_DECLARE(BLECOEX_SVC_ALERT_UUID), @@ -263,7 +271,7 @@ blecent_on_read(uint16_t conn_handle, return 0; err: /* Terminate the connection. */ - return ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM); + return ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM); } @@ -369,23 +377,40 @@ blecoex_gap_event(struct ble_gap_event *event, void *arg) MODLOG_DFLT(INFO, "%02x:%02x:%02x:%02x:%02x:%02x", u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]); - } + if (client_connect == 1) { + client_connect = 2; - if (client_connect == 1 ) { - client_connect = 2; + /* Remember peer. */ + rc = peer_add(event->connect.conn_handle); + if (rc != 0) { + MODLOG_DFLT(ERROR, "Failed to add peer; rc=%d\n", rc); + rc = ble_gap_terminate(event->connect.conn_handle, + BLE_ERR_REM_USER_CONN_TERM); + if (rc != 0) { + MODLOG_DFLT(ERROR, "Failed to terminate connection; rc=%d\n", rc); + restart_coex(); + } + return 0; + } - /* Remember peer. */ - rc = peer_add(event->connect.conn_handle); - if (rc != 0) { - MODLOG_DFLT(ERROR, "Failed to add peer; rc=%d\n", rc); - restart_coex(); + /* Perform service discovery */ + rc = peer_disc_all(event->connect.conn_handle, + blecent_on_disc_complete, NULL); + if(rc != 0) { + MODLOG_DFLT(ERROR, "Failed to discover services; rc=%d\n", rc); + peer_delete(event->connect.conn_handle); + rc = ble_gap_terminate(event->connect.conn_handle, + BLE_ERR_REM_USER_CONN_TERM); + if (rc != 0) { + MODLOG_DFLT(ERROR, "Failed to terminate connection; rc=%d\n", rc); + restart_coex(); + } + return 0; + } } - - /* Perform service discovery */ - rc = peer_disc_all(event->connect.conn_handle, - blecent_on_disc_complete, NULL); - if(rc != 0) { - MODLOG_DFLT(ERROR, "Failed to discover services; rc=%d\n", rc); + } else { + if (client_connect == 1) { + MODLOG_DFLT(ERROR, "Client connection failed; status=%d\n", event->connect.status); restart_coex(); } } @@ -393,6 +418,7 @@ blecoex_gap_event(struct ble_gap_event *event, void *arg) case BLE_GAP_EVENT_DISCONNECT: MODLOG_DFLT(INFO, "Disconnect \n"); + peer_delete(event->disconnect.conn.conn_handle); restart_coex(); return 0; @@ -497,9 +523,10 @@ ble_coex_advertise(void) fields.name_is_complete = 1; } - fields.uuids16 = (ble_uuid16_t[]) { + static const ble_uuid16_t adv_uuids16[] = { BLE_UUID16_INIT(BLECOEX_SVC_ALERT_UUID) }; + fields.uuids16 = adv_uuids16; fields.num_uuids16 = 1; fields.uuids16_is_complete = 1; @@ -569,11 +596,17 @@ void app_main(void) } ble_hs_cfg.sync_cb = on_sync; + int rc; #if MYNEWT_VAL(BLE_INCL_SVC_DISCOVERY) || MYNEWT_VAL(BLE_GATT_CACHING_INCLUDE_SERVICES) - peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64, 64); + rc = peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64, 64); #else - peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64); + rc = peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64); #endif + if (rc != 0) { + MODLOG_DFLT(ERROR, "Failed to init peer tracking; rc=%d\n", rc); + nimble_port_deinit(); + return; + } #if CONFIG_BT_NIMBLE_GAP_SERVICE ble_svc_gap_init(); @@ -585,8 +618,18 @@ void app_main(void) ble_svc_ans_init(); #endif - ble_gatts_count_cfg(gatt_svr_svcs); - ble_gatts_add_svcs(gatt_svr_svcs); + rc = ble_gatts_count_cfg(gatt_svr_svcs); + if (rc != 0) { + MODLOG_DFLT(ERROR, "ble_gatts_count_cfg failed; rc=%d\n", rc); + nimble_port_deinit(); + return; + } + rc = ble_gatts_add_svcs(gatt_svr_svcs); + if (rc != 0) { + MODLOG_DFLT(ERROR, "ble_gatts_add_svcs failed; rc=%d\n", rc); + nimble_port_deinit(); + return; + } nimble_port_freertos_init(ble_hs_task); } diff --git a/examples/bluetooth/nimble/ble_htp/htp_cent/main/main.c b/examples/bluetooth/nimble/ble_htp/htp_cent/main/main.c index ccc03dbecac..472643e5df1 100644 --- a/examples/bluetooth/nimble/ble_htp/htp_cent/main/main.c +++ b/examples/bluetooth/nimble/ble_htp/htp_cent/main/main.c @@ -63,6 +63,15 @@ ble_htp_cent_on_subscribe(uint16_t conn_handle, uint8_t value[2]; int rc; const struct peer *peer = peer_find(conn_handle); + if (peer == NULL) { + MODLOG_DFLT(ERROR, "Peer not found for conn_handle=%d\n", conn_handle); + return ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM); + } + + if (error->status != 0) { + MODLOG_DFLT(ERROR, "Subscribe to temp measurement failed; status=%d\n", error->status); + return ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM); + } dsc = peer_dsc_find_uuid(peer, BLE_UUID16_DECLARE(BLE_SVC_HTP_UUID16), @@ -86,9 +95,7 @@ ble_htp_cent_on_subscribe(uint16_t conn_handle, return 0; err: /* Terminate the connection. */ - return ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM); - - return 0; + return ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM); } /** @@ -113,6 +120,15 @@ ble_htp_cent_on_write(uint16_t conn_handle, uint8_t value[2]; int rc; const struct peer *peer = peer_find(conn_handle); + if (peer == NULL) { + MODLOG_DFLT(ERROR, "Peer not found for conn_handle=%d\n", conn_handle); + return ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM); + } + + if (error->status != 0) { + MODLOG_DFLT(ERROR, "Write to measurement interval failed; status=%d\n", error->status); + return ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM); + } dsc = peer_dsc_find_uuid(peer, BLE_UUID16_DECLARE(BLE_SVC_HTP_UUID16), @@ -137,7 +153,7 @@ ble_htp_cent_on_write(uint16_t conn_handle, return 0; err: /* Terminate the connection. */ - return ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM); + return ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM); } /** @@ -155,6 +171,9 @@ ble_htp_cent_on_read(uint16_t conn_handle, if (error->status == 0) { MODLOG_DFLT(INFO, " attr_handle=%d value=", attr->handle); print_mbuf(attr->om); + } else { + MODLOG_DFLT(ERROR, "Read temperature type failed; status=%d\n", error->status); + return ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM); } MODLOG_DFLT(INFO, "\n"); @@ -319,18 +338,15 @@ ext_ble_htp_cent_should_connect(const struct ble_gap_ext_disc_desc *disc) { int offset = 0; int ad_struct_len = 0; - uint8_t test_addr[6]; - uint8_t parsed_addr[6]; - if (disc->legacy_event_type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND && - disc->legacy_event_type != BLE_HCI_ADV_RPT_EVTYPE_DIR_IND) { + uint8_t test_addr[6] = {0}; + if (!(disc->props & BLE_HCI_ADV_CONN_MASK)) { return 0; } if (strlen(CONFIG_EXAMPLE_PEER_ADDR) && (strncmp(CONFIG_EXAMPLE_PEER_ADDR, "ADDR_ANY", strlen ("ADDR_ANY")) != 0)) { ESP_LOGI(tag, "Peer address from menuconfig: %s", CONFIG_EXAMPLE_PEER_ADDR); /* Convert string to address */ - peer_addr_parse(CONFIG_EXAMPLE_PEER_ADDR, parsed_addr); - for (int i = 0; i < 6; i++) { - test_addr[i] = parsed_addr[5 - i]; + if (peer_addr_parse(CONFIG_EXAMPLE_PEER_ADDR, test_addr) != 6) { + return 0; } if (memcmp(test_addr, disc->addr.val, sizeof(disc->addr.val)) != 0) { @@ -349,9 +365,9 @@ ext_ble_htp_cent_should_connect(const struct ble_gap_ext_disc_desc *disc) break; } - /* Search if HTP UUID is advertised */ + /* Search if HTP UUID is advertised (little-endian: 0x09 0x18 = 0x1809) */ if (disc->data[offset] == 0x03 && disc->data[offset + 1] == 0x03) { - if ( disc->data[offset + 2] == 0x18 && disc->data[offset + 3] == 0x09 ) { + if ( disc->data[offset + 2] == 0x09 && disc->data[offset + 3] == 0x18 ) { return 1; } } @@ -369,7 +385,7 @@ ble_htp_cent_should_connect(const struct ble_gap_disc_desc *disc) struct ble_hs_adv_fields fields; int rc; int i; - uint8_t test_addr[6]; + uint8_t test_addr[6] = {0}; /* The device has to be advertising connectability. */ if (disc->event_type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND && disc->event_type != BLE_HCI_ADV_RPT_EVTYPE_DIR_IND) { @@ -385,7 +401,9 @@ ble_htp_cent_should_connect(const struct ble_gap_disc_desc *disc) if (strlen(CONFIG_EXAMPLE_PEER_ADDR) && (strncmp(CONFIG_EXAMPLE_PEER_ADDR, "ADDR_ANY", strlen("ADDR_ANY")) != 0)) { ESP_LOGI(tag, "Peer address from menuconfig: %s", CONFIG_EXAMPLE_PEER_ADDR); /* Convert string to address */ - peer_addr_parse(CONFIG_EXAMPLE_PEER_ADDR, test_addr); + if (peer_addr_parse(CONFIG_EXAMPLE_PEER_ADDR, test_addr) != 6) { + return 0; + } if (memcmp(test_addr, disc->addr.val, sizeof(disc->addr.val)) != 0) { return 0; } @@ -440,6 +458,9 @@ ble_htp_cent_connect_if_interesting(void *disc) rc = ble_hs_id_infer_auto(0, &own_addr_type); if (rc != 0) { MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc); +#if !(MYNEWT_VAL(BLE_HOST_ALLOW_CONNECT_WITH_SCAN)) + ble_htp_cent_scan(); +#endif return; } @@ -457,6 +478,9 @@ ble_htp_cent_connect_if_interesting(void *disc) MODLOG_DFLT(ERROR, "Error: Failed to connect to device; addr_type=%d " "addr=%s; rc=%d\n", addr->type, addr_str(addr->val), rc); +#if !(MYNEWT_VAL(BLE_HOST_ALLOW_CONNECT_WITH_SCAN)) + ble_htp_cent_scan(); +#endif return; } } @@ -479,11 +503,13 @@ static int ble_htp_cent_gap_event(struct ble_gap_event *event, void *arg) { struct ble_gap_conn_desc desc; - struct ble_hs_adv_fields fields; int rc; switch (event->type) { case BLE_GAP_EVENT_DISC: +#if !CONFIG_EXAMPLE_EXTENDED_ADV + { + struct ble_hs_adv_fields fields; rc = ble_hs_adv_parse_fields(&fields, event->disc.data, event->disc.length_data); if (rc != 0) { @@ -495,6 +521,8 @@ ble_htp_cent_gap_event(struct ble_gap_event *event, void *arg) /* Try to connect to the advertiser if it looks interesting. */ ble_htp_cent_connect_if_interesting(&event->disc); + } +#endif return 0; case BLE_GAP_EVENT_CONNECT: @@ -727,11 +755,14 @@ app_main(void) /* Initialize data structures to track connected peers. */ #if MYNEWT_VAL(BLE_INCL_SVC_DISCOVERY) || MYNEWT_VAL(BLE_GATT_CACHING_INCLUDE_SERVICES) rc = peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64, 64); - assert(rc == 0); #else rc = peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64); - assert(rc == 0); #endif + if (rc != 0) { + ESP_LOGE(tag, "Failed to init peer tracking; rc=%d", rc); + nimble_port_deinit(); + return; + } #if CONFIG_BT_NIMBLE_GAP_SERVICE /* Set the default device name. */ rc = ble_svc_gap_device_name_set("nimble-htp-cent"); diff --git a/examples/bluetooth/nimble/ble_htp/htp_prph/main/gatt_svr.c b/examples/bluetooth/nimble/ble_htp/htp_prph/main/gatt_svr.c index aae6bd14d51..29d2e2cea57 100644 --- a/examples/bluetooth/nimble/ble_htp/htp_prph/main/gatt_svr.c +++ b/examples/bluetooth/nimble/ble_htp/htp_prph/main/gatt_svr.c @@ -15,7 +15,7 @@ static const char *manuf_name = "ESP32 devkitC"; static const char *model_num = "HTP Sensor demo"; -static const char *system_id = "HTP1"; +static const uint8_t system_id[8] = { 'H', 'T', 'P', '1' }; static int gatt_svr_chr_access_device_info(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg); @@ -72,7 +72,7 @@ gatt_svr_chr_access_device_info(uint16_t conn_handle, uint16_t attr_handle, } if (uuid == GATT_DIS_CHR_UUID16_SYS_ID) { - rc = os_mbuf_append(ctxt->om, system_id, strlen(system_id)); + rc = os_mbuf_append(ctxt->om, system_id, sizeof(system_id)); return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; } diff --git a/examples/bluetooth/nimble/ble_htp/htp_prph/main/main.c b/examples/bluetooth/nimble/ble_htp/htp_prph/main/main.c index e400a619c60..47abc4d490f 100644 --- a/examples/bluetooth/nimble/ble_htp/htp_prph/main/main.c +++ b/examples/bluetooth/nimble/ble_htp/htp_prph/main/main.c @@ -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 */ @@ -20,7 +20,7 @@ static uint8_t ext_adv_pattern_1[] = { 0x02, BLE_HS_ADV_TYPE_FLAGS, 0x06, 0x03, BLE_HS_ADV_TYPE_COMP_UUIDS16, 0xab, 0xcd, - 0x03, BLE_HS_ADV_TYPE_COMP_UUIDS16, 0x18, 0x09, + 0x03, BLE_HS_ADV_TYPE_COMP_UUIDS16, 0x09, 0x18, 0x12, BLE_HS_ADV_TYPE_COMP_NAME, 'n', 'i', 'm', 'b', 'l', 'e', '-', 'h', 't', 'p', '-', 'p', 'r', 'p', 'h', '-', 'e', }; #endif @@ -81,8 +81,8 @@ ext_ble_htp_prph_advertise(void) /* enable connectable advertising */ params.connectable = 1; - /* advertise using random addr */ - params.own_addr_type = BLE_OWN_ADDR_PUBLIC; + /* advertise using configured addr */ + params.own_addr_type = ble_htp_prph_addr_type; params.primary_phy = BLE_HCI_LE_PHY_1M; params.secondary_phy = BLE_HCI_LE_PHY_2M; @@ -150,9 +150,10 @@ ble_htp_prph_advertise(void) fields.name_len = strlen(device_name); fields.name_is_complete = 1; - fields.uuids16 = (ble_uuid16_t[]) { + static const ble_uuid16_t adv_uuids16[] = { BLE_UUID16_INIT(BLE_SVC_HTP_UUID16) }; + fields.uuids16 = adv_uuids16; fields.num_uuids16 = 1; fields.uuids16_is_complete = 1; @@ -178,23 +179,16 @@ ble_htp_prph_advertise(void) static void ble_htp_prph_tx_htp_stop(void) { - xTimerStop( ble_htp_prph_tx_timer, 1000 / portTICK_PERIOD_MS ); + xTimerStop( ble_htp_prph_tx_timer, 0 ); } /* Reset temperature measurement */ static void ble_htp_prph_tx_htp_reset(void) { - int rc; - - if (xTimerReset(ble_htp_prph_tx_timer, 1000 / portTICK_PERIOD_MS ) == pdPASS) { - rc = 0; - } else { - rc = 1; + if (xTimerReset(ble_htp_prph_tx_timer, 0) != pdPASS) { + MODLOG_DFLT(ERROR, "Failed to reset HTP timer\n"); } - - assert(rc == 0); - } /* This function notifies intermediate temperature to the client */ @@ -372,6 +366,11 @@ void app_main(void) /* name, period/time, auto reload, timer ID, callback */ ble_htp_prph_tx_timer = xTimerCreate("ble_htp_prph_tx_timer", pdMS_TO_TICKS(1000), pdTRUE, (void *)0, ble_htp_prph_tx); + if (ble_htp_prph_tx_timer == NULL) { + MODLOG_DFLT(ERROR, "Failed to create HTP TX timer\n"); + nimble_port_deinit(); + return; + } #if MYNEWT_VAL(BLE_GATTS) int rc; diff --git a/examples/bluetooth/nimble/ble_l2cap_coc/coc_blecent/main/main.c b/examples/bluetooth/nimble/ble_l2cap_coc/coc_blecent/main/main.c index 91a1691376f..d333a0da919 100644 --- a/examples/bluetooth/nimble/ble_l2cap_coc/coc_blecent/main/main.c +++ b/examples/bluetooth/nimble/ble_l2cap_coc/coc_blecent/main/main.c @@ -68,16 +68,9 @@ blecent_l2cap_coc_send_data(struct ble_l2cap_chan *chan) rc = ble_l2cap_send(chan, sdu_rx_data); - retry = 0; - while (rc == BLE_HS_ESTALLED && retry < max_retry) { - MODLOG_DFLT(INFO, "Send stalled, waiting for credits (retry=%d)", retry); - vTaskDelay(100 / portTICK_PERIOD_MS); - rc = ble_l2cap_send(chan, sdu_rx_data); - retry++; - } - if (rc == BLE_HS_ESTALLED) { - MODLOG_DFLT(INFO, "Send still stalled after %d retries, returning", retry); + /* Stack took ownership of sdu_rx_data; wait for BLE_L2CAP_EVENT_COC_TX_UNSTALLED */ + MODLOG_DFLT(INFO, "Send stalled, waiting for credits"); return; } @@ -115,7 +108,7 @@ blecent_l2cap_coc_on_disc_complete(const struct peer *peer, int status, void *ar rc = ble_l2cap_connect(conn_handle_coc, psm, MTU, sdu_rx, blecent_l2cap_coc_event_cb, NULL); if (rc != 0) { MODLOG_DFLT(ERROR, "L2CAP COC connect failed, rc=%d", rc); - os_mbuf_free_chain(sdu_rx); + /* sdu_rx is freed by the stack on all failure paths; do not free here */ } } @@ -163,6 +156,7 @@ blecent_l2cap_coc_event_cb(struct ble_l2cap_event *event, void *arg) case BLE_L2CAP_EVENT_COC_DISCONNECTED: console_printf("LE CoC disconnected, chan: %p\n", event->disconnect.chan); + coc_chan = NULL; return 0; default: @@ -266,8 +260,7 @@ ext_blecent_should_connect(const struct ble_gap_ext_disc_desc *disc) int offset = 0; int ad_struct_len = 0; uint8_t test_addr[6]; - if (disc->legacy_event_type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND && - disc->legacy_event_type != BLE_HCI_ADV_RPT_EVTYPE_DIR_IND) { + if (!(disc->props & BLE_HCI_ADV_CONN_MASK)) { return 0; } if (strlen(CONFIG_EXAMPLE_PEER_ADDR) && @@ -296,11 +289,11 @@ ext_blecent_should_connect(const struct ble_gap_ext_disc_desc *disc) break; } - /* AD Type (1) + UUID16 (2) requires at least 4 bytes total */ + /* AD Type (1) + UUID16 (2) requires at least 4 bytes total; UUID 0x1812 is LE [0x12, 0x18] */ if (ad_struct_len >= 3 && disc->data[offset + 1] == 0x03 && - disc->data[offset + 2] == 0x18 && - disc->data[offset + 3] == 0x12) { + disc->data[offset + 2] == 0x12 && + disc->data[offset + 3] == 0x18) { return 1; } @@ -386,6 +379,9 @@ blecent_connect_if_interesting(void *disc) rc = ble_hs_id_infer_auto(0, &own_addr_type); if (rc != 0) { MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc); +#if !(MYNEWT_VAL(BLE_HOST_ALLOW_CONNECT_WITH_SCAN)) + blecent_scan(); +#endif return; } @@ -404,6 +400,9 @@ blecent_connect_if_interesting(void *disc) MODLOG_DFLT(ERROR, "Error: Failed to connect to device; addr_type=%d " "addr=%s; rc=%d\n", addr->type, addr_str(addr->val), rc); +#if !(MYNEWT_VAL(BLE_HOST_ALLOW_CONNECT_WITH_SCAN)) + blecent_scan(); +#endif return; } } @@ -491,6 +490,10 @@ blecent_gap_event(struct ble_gap_event *event, void *arg) print_conn_desc(&event->disconnect.conn); MODLOG_DFLT(INFO, "\n"); +#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) >= 1 + coc_chan = NULL; +#endif + /* Forget about peer. */ peer_delete(event->disconnect.conn.conn_handle); @@ -536,6 +539,9 @@ static void blecent_on_reset(int reason) { MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason); +#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) >= 1 + coc_chan = NULL; +#endif } static void diff --git a/examples/bluetooth/nimble/ble_l2cap_coc/coc_bleprph/main/main.c b/examples/bluetooth/nimble/ble_l2cap_coc/coc_bleprph/main/main.c index 02734f1ff78..94198f6ffcc 100644 --- a/examples/bluetooth/nimble/ble_l2cap_coc/coc_bleprph/main/main.c +++ b/examples/bluetooth/nimble/ble_l2cap_coc/coc_bleprph/main/main.c @@ -18,7 +18,7 @@ static uint8_t ext_adv_pattern_1[] = { 0x02, BLE_HS_ADV_TYPE_FLAGS, 0x06, 0x03, BLE_HS_ADV_TYPE_COMP_UUIDS16, 0xab, 0xcd, - 0x03, BLE_HS_ADV_TYPE_COMP_UUIDS16, 0x18, 0x12, + 0x03, BLE_HS_ADV_TYPE_COMP_UUIDS16, 0x12, 0x18, /* UUID 0x1812 in little-endian */ 0x12, BLE_HS_ADV_TYPE_COMP_NAME, 'e', 'x', 't', '-', 'b', 'l', 'e', 'p', 'r', 'p', 'h', '-', 'l', '2', 'c', 'o', 'c', }; #endif @@ -164,9 +164,10 @@ bleprph_advertise(void) fields.name_len = strlen(name); fields.name_is_complete = 1; - fields.uuids16 = (ble_uuid16_t[]) { + static const ble_uuid16_t adv_uuids16[] = { BLE_UUID16_INIT(L2CAP_COC_UUID) }; + fields.uuids16 = adv_uuids16; fields.num_uuids16 = 1; fields.uuids16_is_complete = 1; @@ -259,7 +260,7 @@ bleprph_l2cap_coc_event_cb(struct ble_l2cap_event *event, void *arg) for (int i = 0; i < event->receive.sdu_rx->om_len; i++) { console_printf("%d ", event->receive.sdu_rx->om_data[i]); } - os_mbuf_free(event->receive.sdu_rx); + os_mbuf_free_chain(event->receive.sdu_rx); } fflush(stdout); bleprph_l2cap_coc_accept(event->receive.conn_handle, diff --git a/examples/bluetooth/nimble/ble_multi_adv/main/gatt_svr.c b/examples/bluetooth/nimble/ble_multi_adv/main/gatt_svr.c index bf5d27b4d99..82e46e9f3e3 100644 --- a/examples/bluetooth/nimble/ble_multi_adv/main/gatt_svr.c +++ b/examples/bluetooth/nimble/ble_multi_adv/main/gatt_svr.c @@ -109,6 +109,9 @@ gatt_svc_access(uint16_t conn_handle, uint16_t attr_handle, case BLE_GATT_ACCESS_OP_WRITE_CHR: MODLOG_DFLT(INFO, "Characteristic write; conn_handle=%d attr_handle=%d", conn_handle, attr_handle); + if (OS_MBUF_PKTLEN(ctxt->om) != sizeof(gatt_svr_chr_val)) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } rc = os_mbuf_copydata(ctxt->om, 0, sizeof(gatt_svr_chr_val), diff --git a/examples/bluetooth/nimble/ble_multi_adv/main/main.c b/examples/bluetooth/nimble/ble_multi_adv/main/main.c index b234034c54b..762fdffb7c3 100644 --- a/examples/bluetooth/nimble/ble_multi_adv/main/main.c +++ b/examples/bluetooth/nimble/ble_multi_adv/main/main.c @@ -374,7 +374,7 @@ ble_multi_adv_gap_event(struct ble_gap_event *event, void *arg) assert(rc == 0); ble_multi_adv_print_conn_desc(&desc); - ble_multi_perform_gatt_proc(desc.our_id_addr); + ble_multi_perform_gatt_proc(desc.our_ota_addr); } MODLOG_DFLT(INFO, "\n"); return 0; diff --git a/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_cent/main/main.c b/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_cent/main/main.c index d79daed6f84..bfec7d71033 100644 --- a/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_cent/main/main.c +++ b/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_cent/main/main.c @@ -102,18 +102,21 @@ ble_cent_client_gap_event(struct ble_gap_event *event, void *arg) case BLE_GAP_EVENT_CONNECT: if (event->connect.status == 0) { + s_ble_multi_conn_num++; ESP_LOGI(TAG, "Connection established. Handle:%d, Total:%d", event->connect.conn_handle, - ++s_ble_multi_conn_num); + s_ble_multi_conn_num); /* Remember peer. */ rc = peer_add(event->connect.conn_handle); if (rc != 0) { ESP_LOGE(TAG, "Failed to add peer; rc=%d\n", rc); + ble_gap_terminate(event->connect.conn_handle, BLE_ERR_REM_USER_CONN_TERM); } else { /* Perform service discovery */ rc = peer_disc_svc_by_uuid(event->connect.conn_handle, remote_svc_uuid, ble_cent_on_disc_complete, NULL); if(rc != 0) { ESP_LOGE(TAG, "Failed to discover services; rc=%d\n", rc); + ble_gap_terminate(event->connect.conn_handle, BLE_ERR_REM_USER_CONN_TERM); } } } else { @@ -130,9 +133,10 @@ ble_cent_client_gap_event(struct ble_gap_event *event, void *arg) /* Forget about peer. */ peer_delete(event->disconnect.conn.conn_handle); + s_ble_multi_conn_num--; ESP_LOGI(TAG, "Central disconnected; Handle:%d, Reason=%d, Total:%d", event->disconnect.conn.conn_handle, event->disconnect.reason, - --s_ble_multi_conn_num); + s_ble_multi_conn_num); /* Resume scanning. */ ble_cent_scan(); @@ -282,8 +286,8 @@ ble_cent_scan(void) return; } - struct ble_gap_ext_disc_params uncoded_disc_params; - struct ble_gap_ext_disc_params coded_disc_params; + struct ble_gap_ext_disc_params uncoded_disc_params = {0}; + struct ble_gap_ext_disc_params coded_disc_params = {0}; /* Perform a passive scan. I.e., don't send follow-up scan requests to * each advertiser. @@ -409,8 +413,10 @@ blecent_on_sync(void) * the `MINIMUM_CONN_INTERVAL` should be greater than ((261 * 8us) * 2 + 150us) * 10 = 43260us. * */ - rc = ble_gap_common_factor_set(true, (BLE_PREF_CONN_ITVL_MS * 1000) / 625); - assert(rc == 0); + if (BLE_PEER_MAX_NUM > 0) { + rc = ble_gap_common_factor_set(true, (BLE_PREF_CONN_ITVL_MS * 1000) / 625); + assert(rc == 0); + } /* Make sure we have proper identity address set (public preferred) */ rc = ble_hs_util_ensure_addr(0); diff --git a/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_prph/main/main.c b/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_prph/main/main.c index 2cf93be2d17..c9b18309047 100644 --- a/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_prph/main/main.c +++ b/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_prph/main/main.c @@ -24,7 +24,7 @@ static uint8_t ext_adv_pattern_1[] = { #endif static const char *TAG = "ESP_MULTI_CONN_PRPH"; -static uint8_t s_ble_prph_conn_num = 0; +static volatile uint8_t s_ble_prph_conn_num = 0; static SemaphoreHandle_t s_sem_restart_adv = NULL; static int ble_prph_gap_event(struct ble_gap_event *event, void *arg); @@ -194,8 +194,9 @@ ble_prph_gap_event(struct ble_gap_event *event, void *arg) case BLE_GAP_EVENT_CONNECT: if (event->connect.status == 0) { /* A new connection was established. */ + s_ble_prph_conn_num++; ESP_LOGI(TAG, "Connection established. Handle:%d. Total:%d", event->connect.conn_handle, - ++s_ble_prph_conn_num); + s_ble_prph_conn_num); #if CONFIG_EXAMPLE_RESTART_ADV_AFTER_CONNECTED ble_prph_restart_adv(); #endif //CONFIG_EXAMPLE_RESTART_ADV_AFTER_CONNECTED @@ -206,8 +207,9 @@ ble_prph_gap_event(struct ble_gap_event *event, void *arg) return 0; case BLE_GAP_EVENT_DISCONNECT: + s_ble_prph_conn_num--; ESP_LOGI(TAG, "Disconnect. Handle:%d. Reason=%d. Total:%d", - event->disconnect.conn.conn_handle, event->disconnect.reason, --s_ble_prph_conn_num); + event->disconnect.conn.conn_handle, event->disconnect.reason, s_ble_prph_conn_num); /* Connection terminated; resume advertising. */ ble_prph_restart_adv(); diff --git a/examples/bluetooth/nimble/ble_pawr_adv/ble_pawr_adv/main/main.c b/examples/bluetooth/nimble/ble_pawr_adv/ble_pawr_adv/main/main.c index a10b3d552ea..7bfbffe7172 100644 --- a/examples/bluetooth/nimble/ble_pawr_adv/ble_pawr_adv/main/main.c +++ b/examples/bluetooth/nimble/ble_pawr_adv/ble_pawr_adv/main/main.c @@ -42,11 +42,20 @@ gap_event_cb(struct ble_gap_event *event, void *arg) event->periodic_adv_subev_data_req.subevent_data_count); sent_num = event->periodic_adv_subev_data_req.subevent_data_count; + if (sent_num > BLE_PAWR_NUM_SUBEVTS) { + ESP_LOGE(TAG, "subevent_data_count %d exceeds max %d", sent_num, BLE_PAWR_NUM_SUBEVTS); + sent_num = BLE_PAWR_NUM_SUBEVTS; + } + uint8_t actual_sent = 0; for (uint8_t i = 0; i < sent_num; i++) { data = os_msys_get_pkthdr(BLE_PAWR_SUB_DATA_LEN, 0); if (!data) { ESP_LOGE(TAG, "No memory, %d", i); - break; + for (uint8_t j = 0; j < i; j++) { + os_mbuf_free_chain(sub_data_params[j].data); + sub_data_params[j].data = NULL; + } + return 0; } sub = (i + event->periodic_adv_subev_data_req.subevent_start) % BLE_PAWR_NUM_SUBEVTS; memset(&sub_data_pattern[1], sub, BLE_PAWR_SUB_DATA_LEN - 1); @@ -56,10 +65,11 @@ gap_event_cb(struct ble_gap_event *event, void *arg) sub_data_params[i].response_slot_count = BLE_PAWR_NUM_RSP_SLOTS; sub_data_params[i].data = data; sub_data_pattern[0]++; + actual_sent++; } rc = ble_gap_set_periodic_adv_subev_data(event->periodic_adv_subev_data_req.adv_handle, - sent_num, sub_data_params); + actual_sent, sub_data_params); if (rc) { ESP_LOGE(TAG, "Failed to set Subevent Data, rc = 0x%x", rc); } @@ -72,7 +82,9 @@ gap_event_cb(struct ble_gap_event *event, void *arg) event->periodic_adv_response.response_slot, event->periodic_adv_response.data_length); const uint8_t *data = event->periodic_adv_response.data; - ESP_LOGI(TAG, "data: 0x%0x, 0x%0x", data[0], data[1]); + if (data != NULL && event->periodic_adv_response.data_length >= 2) { + ESP_LOGI(TAG, "data: 0x%0x, 0x%0x", data[0], data[1]); + } } else { ESP_LOGE(TAG, "[Response] subevent:%d, response_slot:%d, rsp_data status:%d", event->periodic_adv_response.subevent, @@ -102,8 +114,7 @@ start_periodic_adv(uint8_t own_addr_type) #endif /* Get the local address. */ - uint8_t addr_type = own_addr_type == BLE_OWN_ADDR_RANDOM ? BLE_ADDR_RANDOM : BLE_ADDR_PUBLIC; - rc = ble_hs_id_copy_addr(addr_type, addr, NULL); + rc = ble_hs_id_copy_addr(own_addr_type, addr, NULL); assert (rc == 0); ESP_LOGI(TAG, "Device Address %02x:%02x:%02x:%02x:%02x:%02x", addr[5], addr[4], addr[3], diff --git a/examples/bluetooth/nimble/ble_pawr_adv/ble_pawr_sync/main/main.c b/examples/bluetooth/nimble/ble_pawr_adv/ble_pawr_sync/main/main.c index 1ae6f656004..1ef1b305550 100644 --- a/examples/bluetooth/nimble/ble_pawr_adv/ble_pawr_sync/main/main.c +++ b/examples/bluetooth/nimble/ble_pawr_adv/ble_pawr_sync/main/main.c @@ -47,7 +47,7 @@ gap_event_cb(struct ble_gap_event *event, void *arg) return 0; } - if (disc->periodic_adv_itvl && fields.name_len && !memcmp(fields.name, TARGET_NAME, strlen(TARGET_NAME))) { + if (disc->periodic_adv_itvl && fields.name_len == strlen(TARGET_NAME) && !memcmp(fields.name, TARGET_NAME, fields.name_len)) { create_periodic_sync(disc); } return 0; @@ -71,6 +71,10 @@ gap_event_cb(struct ble_gap_event *event, void *arg) return 0; } // create a special data for checking manually in ADV side + if (event->periodic_report.data == NULL || event->periodic_report.data_length == 0) { + os_mbuf_free_chain(data); + return 0; + } sub_data_pattern[0] = event->periodic_report.data[0]; memset(sub_data_pattern + 1, event->periodic_report.subevent, BLE_PAWR_RSP_DATA_LEN - 1); os_mbuf_append(data, sub_data_pattern, BLE_PAWR_RSP_DATA_LEN); @@ -190,6 +194,7 @@ static void on_reset(int reason) { ESP_LOGE(TAG, "Resetting state; reason=%d\n", reason); + synced = false; } static void diff --git a/examples/bluetooth/nimble/ble_pawr_adv_conn/ble_pawr_adv_conn/main/main.c b/examples/bluetooth/nimble/ble_pawr_adv_conn/ble_pawr_adv_conn/main/main.c index d5a6fe0fc8f..f5145169cc4 100644 --- a/examples/bluetooth/nimble/ble_pawr_adv_conn/ble_pawr_adv_conn/main/main.c +++ b/examples/bluetooth/nimble/ble_pawr_adv_conn/ble_pawr_adv_conn/main/main.c @@ -147,6 +147,10 @@ gap_event_cb(struct ble_gap_event *event, void *arg) event->periodic_adv_response.response_slot, event->periodic_adv_response.data_length); const uint8_t *data = event->periodic_adv_response.data; + if (data == NULL || event->periodic_adv_response.data_length < 10) { + ESP_LOGE(TAG, "Invalid response data: NULL or too short (%d)", event->periodic_adv_response.data_length); + return 0; + } ESP_LOGI(TAG, "data: 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x", data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9]); @@ -161,10 +165,10 @@ gap_event_cb(struct ble_gap_event *event, void *arg) rc = ble_gap_connect_with_synced(own_addr_type,adv_handle,subevent,&peer_addr,30000,phy_mask,NULL,NULL,NULL,gap_event_cb,NULL); if (rc != 0 ) { ESP_LOGI(TAG,"Error: Failed to connect to device , rc = %d\n",rc); - }else { + } else { ESP_LOGI(TAG,"Connection create sent, adv handle = %d, subevent = %d", adv_handle, subevent); + conn = 1; } - conn = 1; } } else { ESP_LOGE(TAG, "[Response] subevent:%d, response_slot:%d, rsp_data status:%d", @@ -265,6 +269,7 @@ static void on_reset(int reason) { ESP_LOGE(TAG, "Resetting state; reason=%d\n", reason); + conn = 0; } static void diff --git a/examples/bluetooth/nimble/ble_pawr_adv_conn/ble_pawr_sync_conn/main/main.c b/examples/bluetooth/nimble/ble_pawr_adv_conn/ble_pawr_sync_conn/main/main.c index d00c37fc320..3ab740b1dbc 100644 --- a/examples/bluetooth/nimble/ble_pawr_adv_conn/ble_pawr_sync_conn/main/main.c +++ b/examples/bluetooth/nimble/ble_pawr_adv_conn/ble_pawr_sync_conn/main/main.c @@ -100,7 +100,7 @@ gap_event_cb(struct ble_gap_event *event, void *arg) return 0; } - if (fields.name_len && !memcmp(fields.name, TARGET_NAME, strlen(TARGET_NAME))) { + if (fields.name_len == strlen(TARGET_NAME) && !memcmp(fields.name, TARGET_NAME, fields.name_len)) { create_periodic_sync(disc); } return 0; @@ -229,6 +229,11 @@ start_scan(void) int rc; struct ble_gap_ext_disc_params disc_params; + /* Cancel any active scan first to reset the duplicate filter. */ + if (ble_gap_disc_active()) { + ble_gap_disc_cancel(); + } + /* Perform a passive scan. I.e., don't send follow-up scan requests to * each advertiser. */ @@ -258,6 +263,7 @@ static void on_reset(int reason) { ESP_LOGE(TAG, "Resetting state; reason=%d\n", reason); + synced = false; } static void diff --git a/examples/bluetooth/nimble/ble_periodic_sync/main/main.c b/examples/bluetooth/nimble/ble_periodic_sync/main/main.c index 234e48d711e..74632c3f951 100644 --- a/examples/bluetooth/nimble/ble_periodic_sync/main/main.c +++ b/examples/bluetooth/nimble/ble_periodic_sync/main/main.c @@ -106,7 +106,6 @@ periodic_sync_gap_event(struct ble_gap_event *event, void *arg) if (disc->sid == 2 && synced == 0) { struct ble_gap_periodic_sync_params params = {0}; int rc; - synced++; params.skip = 10; params.sync_timeout = 1000; @@ -117,7 +116,11 @@ periodic_sync_gap_event(struct ble_gap_event *event, void *arg) params.filter_duplicates = 1; #endif rc = ble_gap_periodic_adv_sync_create(&disc->addr, disc->sid, ¶ms, periodic_sync_gap_event, NULL); - assert(rc == 0); + if (rc != 0) { + MODLOG_DFLT(ERROR, "Failed to create periodic sync; rc=%d\n", rc); + } else { + synced++; + } } return 0; } @@ -151,6 +154,7 @@ static void periodic_sync_on_reset(int reason) { MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason); + synced = 0; } static void diff --git a/examples/bluetooth/nimble/ble_phy/phy_cent/main/main.c b/examples/bluetooth/nimble/ble_phy/phy_cent/main/main.c index ccb57c124b9..219a4ba7531 100644 --- a/examples/bluetooth/nimble/ble_phy/phy_cent/main/main.c +++ b/examples/bluetooth/nimble/ble_phy/phy_cent/main/main.c @@ -66,17 +66,28 @@ blecent_on_read(uint16_t conn_handle, MODLOG_DFLT(INFO, " attr_handle=%d value=", attr->handle); print_mbuf(attr->om); } - MODLOG_DFLT(INFO, "\n"); + if (error->status != 0) { + MODLOG_DFLT(ERROR, "Read failed; terminating connection\n"); + ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM); + return 0; + } + /* Write 1000 bytes to the LE PHY characteristic.*/ const struct peer_chr *chr; - int len = 1000; - uint8_t value[len]; + const int len = 1000; + uint8_t *value; int rc; struct os_mbuf *txom; const struct peer *peer = peer_find(conn_handle); + if (peer == NULL) { + MODLOG_DFLT(ERROR, "Error: peer not found for conn_handle=%d\n", conn_handle); + ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM); + return 0; + } + chr = peer_chr_find_uuid(peer, BLE_UUID16_DECLARE(LE_PHY_UUID16), BLE_UUID16_DECLARE(LE_PHY_CHR_UUID16)); @@ -86,12 +97,19 @@ blecent_on_read(uint16_t conn_handle, goto err; } + value = malloc(len); + if (value == NULL) { + MODLOG_DFLT(ERROR, "Insufficient memory\n"); + goto err; + } + /* Fill the value array with data */ for (int i = 0; i < len; i++) { value[i] = i; } - txom = ble_hs_mbuf_from_flat(&value, len); + txom = ble_hs_mbuf_from_flat(value, len); + free(value); if (!txom) { MODLOG_DFLT(ERROR, "Insufficient memory"); goto err; @@ -108,7 +126,7 @@ blecent_on_read(uint16_t conn_handle, err: /* Terminate the connection. */ - return ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM); + return ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM); } static void @@ -234,18 +252,15 @@ ext_blecent_should_connect(const struct ble_gap_ext_disc_desc *disc) { int offset = 0; int ad_struct_len = 0; - uint8_t test_addr[6]; - if (disc->legacy_event_type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND && - disc->legacy_event_type != BLE_HCI_ADV_RPT_EVTYPE_DIR_IND) { + uint8_t test_addr[6] = {0}; + if (!(disc->props & BLE_HCI_ADV_CONN_MASK)) { return 0; } if (strlen(CONFIG_EXAMPLE_PEER_ADDR) && (strncmp(CONFIG_EXAMPLE_PEER_ADDR, "ADDR_ANY", strlen("ADDR_ANY")) != 0)) { ESP_LOGI(tag, "Peer address from menuconfig: %s", CONFIG_EXAMPLE_PEER_ADDR); /* Convert string to address */ - uint8_t parsed_addr[6]; - peer_addr_parse(CONFIG_EXAMPLE_PEER_ADDR, parsed_addr); - for (int i = 0; i < 6; i++) { - test_addr[5 - i] = parsed_addr[i]; + if (peer_addr_parse(CONFIG_EXAMPLE_PEER_ADDR, test_addr) != 6) { + return 0; } if (memcmp(test_addr, disc->addr.val, sizeof(disc->addr.val)) != 0) { @@ -255,19 +270,24 @@ ext_blecent_should_connect(const struct ble_gap_ext_disc_desc *disc) /* The device has to advertise support LE PHY UUID (0xABF2). */ - do { + while (offset < disc->length_data) { + if (offset + 1 >= disc->length_data) { + break; + } ad_struct_len = disc->data[offset]; if (!ad_struct_len || (offset + ad_struct_len + 1 > disc->length_data)) { break; } - /* Search if LE PHY UUID is advertised */ - if (disc->data[offset] == 0x03 && disc->data[offset + 1] == 0x03) { - if ( disc->data[offset + 2] == 0xAB && disc->data[offset + 3] == 0xF2 ) { - return 1; + /* Search if LE PHY UUID is advertised (UUID list, type 0x02 or 0x03) */ + if (ad_struct_len >= 3 && (disc->data[offset + 1] == 0x02 || disc->data[offset + 1] == 0x03)) { + for (int i = 2; i + 1 <= ad_struct_len; i += 2) { + if (disc->data[offset + i] == 0xF2 && disc->data[offset + i + 1] == 0xAB) { + return 1; + } } } offset += ad_struct_len + 1; - } while (offset < disc->length_data); + } return 0; } @@ -301,6 +321,9 @@ blecent_connect_if_interesting(void *disc) rc = ble_hs_id_infer_auto(0, &own_addr_type); if (rc != 0) { MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc); +#if !(MYNEWT_VAL(BLE_HOST_ALLOW_CONNECT_WITH_SCAN)) + blecent_scan(); +#endif return; } @@ -322,6 +345,9 @@ blecent_connect_if_interesting(void *disc) MODLOG_DFLT(ERROR, "Error: Failed to connect to device; addr_type=%d " "addr=%s; rc=%d\n", conn_addr.type, addr_str(conn_addr.val), rc); +#if !(MYNEWT_VAL(BLE_HOST_ALLOW_CONNECT_WITH_SCAN)) + blecent_scan(); +#endif return; } } @@ -344,6 +370,7 @@ static int blecent_gap_event(struct ble_gap_event *event, void *arg) { struct ble_gap_conn_desc desc; + uint8_t own_addr_type; int rc; switch (event->type) { @@ -419,20 +446,36 @@ blecent_gap_event(struct ble_gap_event *event, void *arg) case BLE_HCI_LE_PHY_CODED_PREF_MASK: return 0; + + default: + return 0; } vTaskDelay(200); + rc = ble_hs_id_infer_auto(0, &own_addr_type); + if (rc != 0) { + MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc); + return 0; + } + /* Attempt direct connection on 2M or Coded phy now */ if (s_current_phy == BLE_HCI_LE_PHY_CODED_PREF_MASK) { MODLOG_DFLT(INFO, " Attempting to initiate connection on Coded PHY \n"); - ble_gap_ext_connect(0, &conn_addr, 30000, BLE_HCI_LE_PHY_CODED_PREF_MASK, - NULL, NULL, NULL, blecent_gap_event, NULL); + rc = ble_gap_ext_connect(own_addr_type, &conn_addr, 30000, BLE_HCI_LE_PHY_CODED_PREF_MASK, + NULL, NULL, NULL, blecent_gap_event, NULL); + if (rc != 0) { + MODLOG_DFLT(ERROR, "Error: Failed to initiate ext connect; rc=%d\n", rc); + } } else if (s_current_phy == BLE_HCI_LE_PHY_2M_PREF_MASK) { MODLOG_DFLT(INFO, " Attempting to initiate connection on 2M PHY \n"); - ble_gap_ext_connect(0, &conn_addr, 30000, (BLE_HCI_LE_PHY_1M_PREF_MASK | BLE_HCI_LE_PHY_2M_PREF_MASK), - NULL, NULL, NULL, blecent_gap_event, NULL); + rc = ble_gap_ext_connect(own_addr_type, &conn_addr, 30000, + (BLE_HCI_LE_PHY_1M_PREF_MASK | BLE_HCI_LE_PHY_2M_PREF_MASK), + NULL, NULL, NULL, blecent_gap_event, NULL); + if (rc != 0) { + MODLOG_DFLT(ERROR, "Error: Failed to initiate ext connect; rc=%d\n", rc); + } } return 0; @@ -464,11 +507,18 @@ blecent_on_sync(void) { int ii, rc; uint8_t all_phy; + uint8_t own_addr_type; uint8_t test_addr[6]; /* Make sure we have proper identity address set (public preferred) */ rc = ble_hs_util_ensure_addr(0); assert(rc == 0); + rc = ble_hs_id_infer_auto(0, &own_addr_type); + if (rc != 0) { + MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc); + return; + } + all_phy = BLE_HCI_LE_PHY_1M_PREF_MASK | BLE_HCI_LE_PHY_2M_PREF_MASK | BLE_HCI_LE_PHY_CODED_PREF_MASK; set_default_le_phy(all_phy, all_phy); @@ -484,10 +534,14 @@ blecent_on_sync(void) vTaskDelay(300); - s_current_phy = BLE_HCI_LE_PHY_1M_PREF_MASK | BLE_HCI_LE_PHY_2M_PREF_MASK ; + s_current_phy = BLE_HCI_LE_PHY_2M_PREF_MASK; - ble_gap_ext_connect(0, &conn_addr, 30000, s_current_phy, - NULL, NULL, NULL, blecent_gap_event, NULL); + rc = ble_gap_ext_connect(own_addr_type, &conn_addr, 30000, + BLE_HCI_LE_PHY_1M_PREF_MASK | s_current_phy, + NULL, NULL, NULL, blecent_gap_event, NULL); + if (rc != 0) { + MODLOG_DFLT(ERROR, "Error: Failed to initiate ext connect; rc=%d\n", rc); + } } else { s_current_phy = BLE_HCI_LE_PHY_1M_PREF_MASK; @@ -531,11 +585,14 @@ app_main(void) /* Initialize data structures to track connected peers. */ #if MYNEWT_VAL(BLE_INCL_SVC_DISCOVERY) || MYNEWT_VAL(BLE_GATT_CACHING_INCLUDE_SERVICES) rc = peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64, 64); - assert(rc == 0); #else rc = peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64); - assert(rc == 0); #endif + if (rc != 0) { + MODLOG_DFLT(ERROR, "Failed to init peer; rc=%d\n", rc); + nimble_port_deinit(); + return; + } #if CONFIG_BT_NIMBLE_GAP_SERVICE /* Set the default device name. */ rc = ble_svc_gap_device_name_set("blecent-phy"); diff --git a/examples/bluetooth/nimble/ble_phy/phy_prph/main/gatt_svr.c b/examples/bluetooth/nimble/ble_phy/phy_prph/main/gatt_svr.c index e14647c31dc..cacc4472e22 100644 --- a/examples/bluetooth/nimble/ble_phy/phy_prph/main/gatt_svr.c +++ b/examples/bluetooth/nimble/ble_phy/phy_prph/main/gatt_svr.c @@ -31,8 +31,7 @@ static const struct ble_gatt_svc_def gatt_svr_svcs_le_phy[] = { .uuid = BLE_UUID16_DECLARE(LE_PHY_CHR_UUID16), .access_cb = gatt_svr_chr_access_le_phy, .val_handle = &gatt_svr_chr_val_handle, - .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE - | BLE_GATT_CHR_F_WRITE_ENC, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE, }, { 0, /* No more characteristics in this service. */ } diff --git a/examples/bluetooth/nimble/ble_phy/phy_prph/main/main.c b/examples/bluetooth/nimble/ble_phy/phy_prph/main/main.c index 4c54e8ff77c..44e9b30875c 100644 --- a/examples/bluetooth/nimble/ble_phy/phy_prph/main/main.c +++ b/examples/bluetooth/nimble/ble_phy/phy_prph/main/main.c @@ -17,22 +17,19 @@ static uint8_t ext_adv_pattern_1M[] = { 0x02, BLE_HS_ADV_TYPE_FLAGS, 0x06, - 0x03, BLE_HS_ADV_TYPE_COMP_UUIDS16, 0xab, 0xcd, - 0x03, BLE_HS_ADV_TYPE_COMP_UUIDS16, 0xAB, 0xF2, + 0x03, BLE_HS_ADV_TYPE_COMP_UUIDS16, 0xF2, 0xAB, 0x0e, BLE_HS_ADV_TYPE_COMP_NAME, 'b', 'l', 'e', 'p', 'r', 'p', 'h', '-', 'p', 'h', 'y', '-', '1', 'M', }; static uint8_t ext_adv_pattern_2M[] = { 0x02, BLE_HS_ADV_TYPE_FLAGS, 0x06, - 0x03, BLE_HS_ADV_TYPE_COMP_UUIDS16, 0xab, 0xcd, - 0x03, BLE_HS_ADV_TYPE_COMP_UUIDS16, 0xAB, 0xF2, + 0x03, BLE_HS_ADV_TYPE_COMP_UUIDS16, 0xF2, 0xAB, 0x0e, BLE_HS_ADV_TYPE_COMP_NAME, 'b', 'l', 'e', 'p', 'r', 'p', 'h', '-', 'p', 'h', 'y', '-', '2', 'M', }; static uint8_t ext_adv_pattern_coded[] = { 0x02, BLE_HS_ADV_TYPE_FLAGS, 0x06, - 0x03, BLE_HS_ADV_TYPE_COMP_UUIDS16, 0xab, 0xcd, - 0x03, BLE_HS_ADV_TYPE_COMP_UUIDS16, 0xAB, 0xF2, + 0x03, BLE_HS_ADV_TYPE_COMP_UUIDS16, 0xF2, 0xAB, 0x11, BLE_HS_ADV_TYPE_COMP_NAME, 'b', 'l', 'e', 'p', 'r', 'p', 'h', '-', 'p', 'h', 'y', '-', 'c', 'o', 'd', 'e', 'd', }; @@ -239,7 +236,10 @@ bleprph_gap_event(struct ble_gap_event *event, void *arg) MODLOG_DFLT(INFO, "connection updated; status=%d ", event->conn_update.status); rc = ble_gap_conn_find(event->conn_update.conn_handle, &desc); - assert(rc == 0); + if (rc != 0) { + MODLOG_DFLT(ERROR, "ble_gap_conn_find failed; rc=%d\n", rc); + return 0; + } bleprph_print_conn_desc(&desc); MODLOG_DFLT(INFO, "\n"); return 0; @@ -352,9 +352,11 @@ app_main(void) assert(rc == 0); #endif +#if CONFIG_BT_NIMBLE_GAP_SERVICE /* Set the default device name. */ rc = ble_svc_gap_device_name_set("bleprph-phy"); assert(rc == 0); +#endif /* XXX Need to have template for store */ ble_store_config_init(); diff --git a/examples/bluetooth/nimble/ble_phy/phy_prph/sdkconfig.defaults b/examples/bluetooth/nimble/ble_phy/phy_prph/sdkconfig.defaults index 7c4edca7294..45f4fd7f9ac 100644 --- a/examples/bluetooth/nimble/ble_phy/phy_prph/sdkconfig.defaults +++ b/examples/bluetooth/nimble/ble_phy/phy_prph/sdkconfig.defaults @@ -12,3 +12,4 @@ CONFIG_BT_BLUEDROID_ENABLED=n CONFIG_BT_NIMBLE_ENABLED=y CONFIG_BT_NIMBLE_EXT_ADV=y CONFIG_BT_NIMBLE_BLE_GATT_BLOB_TRANSFER=y +CONFIG_BT_NIMBLE_MSYS_1_BLOCK_COUNT=64 diff --git a/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_cent/main/main.c b/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_cent/main/main.c index 67a6e1ecc53..b5b584c1b98 100644 --- a/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_cent/main/main.c +++ b/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_cent/main/main.c @@ -19,7 +19,6 @@ #endif static const char *tag = "NimBLE_PROX_CENT"; -static uint8_t link_supervision_timeout; static int8_t tx_pwr_lvl; static struct ble_prox_cent_conn_peer conn_peer[MYNEWT_VAL(BLE_MAX_CONNECTIONS) + 1]; static struct ble_prox_cent_link_lost_peer disconn_peer[MYNEWT_VAL(BLE_MAX_CONNECTIONS) + 1]; @@ -41,7 +40,11 @@ ble_prox_cent_on_read(uint16_t conn_handle, if (error->status == 0) { MODLOG_DFLT(INFO, " attr_handle=%d value=", attr->handle); print_mbuf(attr->om); - os_mbuf_copydata(attr->om, 0, attr->om->om_len, &tx_pwr_lvl); + if (attr->om->om_len != sizeof(tx_pwr_lvl)) { + MODLOG_DFLT(ERROR, "Unexpected TX power level length: %d\n", attr->om->om_len); + return 0; + } + os_mbuf_copydata(attr->om, 0, sizeof(tx_pwr_lvl), &tx_pwr_lvl); conn_peer[conn_handle].calc_path_loss = true; } @@ -129,8 +132,10 @@ ble_prox_cent_read_write_subscribe(const struct peer *peer) goto err; } + /* Alert Level: 0=No Alert, 1=Mild Alert, 2=High Alert (BLE SIG LLS spec) */ + static const uint8_t alert_level = 1; rc = ble_gattc_write_flat(peer->conn_handle, chr->chr.val_handle, - &link_supervision_timeout, sizeof(link_supervision_timeout), + &alert_level, sizeof(alert_level), ble_prox_cent_on_write, NULL); if (rc != 0) { MODLOG_DFLT(ERROR, "Error: Failed to write characteristic; rc=%d\n", @@ -228,19 +233,13 @@ ext_ble_prox_cent_should_connect(const struct ble_gap_ext_disc_desc *disc) int offset = 0; int ad_struct_len = 0; uint8_t test_addr[6]; - if (disc->legacy_event_type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND && - disc->legacy_event_type != BLE_HCI_ADV_RPT_EVTYPE_DIR_IND) { + if (!(disc->props & BLE_HCI_ADV_CONN_MASK)) { return 0; } if (strlen(CONFIG_EXAMPLE_PEER_ADDR) && (strncmp(CONFIG_EXAMPLE_PEER_ADDR, "ADDR_ANY", strlen ("ADDR_ANY")) != 0)) { ESP_LOGI(tag, "Peer address from menuconfig: %s", CONFIG_EXAMPLE_PEER_ADDR); - /* Convert string to address */ - uint8_t parsed_addr[6]; - peer_addr_parse(CONFIG_EXAMPLE_PEER_ADDR, parsed_addr); - for (int i = 0; i < 6; i++) { - test_addr[5 - i] = parsed_addr[i]; - } - + /* Convert string to address; peer_addr_parse outputs little-endian matching disc->addr.val */ + peer_addr_parse(CONFIG_EXAMPLE_PEER_ADDR, test_addr); if (memcmp(test_addr, disc->addr.val, sizeof(disc->addr.val)) != 0) { return 0; } @@ -256,9 +255,9 @@ ext_ble_prox_cent_should_connect(const struct ble_gap_ext_disc_desc *disc) break; } - /* Search if Proximity Sensor (Link loss) UUID is advertised */ + /* Search if Proximity Sensor (Link loss) UUID 0x1803 is advertised (little-endian: [0x03, 0x18]) */ if (disc->data[offset] == 0x03 && disc->data[offset + 1] == 0x03) { - if ( disc->data[offset + 2] == 0x18 && disc->data[offset + 3] == 0x03 ) { + if ( disc->data[offset + 2] == 0x03 && disc->data[offset + 3] == 0x18 ) { return 1; } } @@ -347,6 +346,9 @@ ble_prox_cent_connect_if_interesting(void *disc) rc = ble_hs_id_infer_auto(0, &own_addr_type); if (rc != 0) { MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc); +#if !(MYNEWT_VAL(BLE_HOST_ALLOW_CONNECT_WITH_SCAN)) + ble_prox_cent_scan(); +#endif return; } @@ -364,6 +366,9 @@ ble_prox_cent_connect_if_interesting(void *disc) MODLOG_DFLT(ERROR, "Error: Failed to connect to device; addr_type=%d " "addr=%s; rc=%d\n", addr->type, addr_str(addr->val), rc); +#if !(MYNEWT_VAL(BLE_HOST_ALLOW_CONNECT_WITH_SCAN)) + ble_prox_cent_scan(); +#endif return; } } @@ -415,8 +420,6 @@ ble_prox_cent_gap_event(struct ble_gap_event *event, void *arg) print_conn_desc(&desc); MODLOG_DFLT(INFO, "\n"); - link_supervision_timeout = 8 * desc.conn_itvl; - /* Remember peer. */ rc = peer_add(event->connect.conn_handle); if (rc != 0) { @@ -427,7 +430,7 @@ ble_prox_cent_gap_event(struct ble_gap_event *event, void *arg) /* Check if this device is reconnected */ for (int i = 0; i <= MYNEWT_VAL(BLE_MAX_CONNECTIONS); i++) { if (disconn_peer[i].addr != NULL) { - if (memcmp(disconn_peer[i].addr, &desc.peer_id_addr.val, BLE_ADDR_LEN)) { + if (memcmp(disconn_peer[i].addr, &desc.peer_id_addr.val, BLE_ADDR_LEN) == 0) { /* Peer reconnected. Stop alert for this peer */ free(disconn_peer[i].addr); disconn_peer[i].addr = NULL; @@ -500,8 +503,10 @@ ble_prox_cent_gap_event(struct ble_gap_event *event, void *arg) } } /* Stop calculating path loss, restart once connection is established again */ - conn_peer[event->disconnect.conn.conn_handle].calc_path_loss = false; - conn_peer[event->disconnect.conn.conn_handle].val_handle = 0; + if (event->disconnect.conn.conn_handle <= MYNEWT_VAL(BLE_MAX_CONNECTIONS)) { + conn_peer[event->disconnect.conn.conn_handle].calc_path_loss = false; + conn_peer[event->disconnect.conn.conn_handle].val_handle = 0; + } /* Forget about peer. */ peer_delete(event->disconnect.conn.conn_handle); @@ -726,12 +731,12 @@ app_main(void) return; } - /* Initialize a task to keep checking path loss of the link */ - ble_prox_cent_init(); for (int i = 0; i <= MYNEWT_VAL(BLE_MAX_CONNECTIONS); i++) { disconn_peer[i].addr = NULL; - disconn_peer[i].link_lost = true; + disconn_peer[i].link_lost = false; } + /* Initialize tasks after disconn_peer array is ready */ + ble_prox_cent_init(); /* Configure the host. */ ble_hs_cfg.reset_cb = ble_prox_cent_on_reset; diff --git a/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_prph/main/main.c b/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_prph/main/main.c index 684758be33c..169e5f0fdfe 100644 --- a/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_prph/main/main.c +++ b/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_prph/main/main.c @@ -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 */ @@ -21,7 +21,7 @@ static uint8_t ext_adv_pattern_1[] = { 0x02, BLE_HS_ADV_TYPE_FLAGS, 0x06, 0x03, BLE_HS_ADV_TYPE_COMP_UUIDS16, 0xab, 0xcd, - 0x03, BLE_HS_ADV_TYPE_COMP_UUIDS16, 0x18, 0x03, + 0x03, BLE_HS_ADV_TYPE_COMP_UUIDS16, 0x03, 0x18, /* UUID 0x1803 in little-endian */ 0x13, BLE_HS_ADV_TYPE_COMP_NAME, 'n', 'i', 'm', 'b', 'l', 'e', '-', 'p', 'r', 'o', 'x', '-', 'p', 'r', 'p', 'h', '-', 'e', }; #endif @@ -80,8 +80,8 @@ ext_ble_prox_prph_advertise(void) /* enable connectable advertising */ params.connectable = 1; - /* advertise using random addr */ - params.own_addr_type = BLE_OWN_ADDR_PUBLIC; + /* advertise using the inferred address type */ + params.own_addr_type = ble_prox_prph_addr_type; params.primary_phy = BLE_HCI_LE_PHY_1M; params.secondary_phy = BLE_HCI_LE_PHY_2M; @@ -145,9 +145,11 @@ ble_prox_prph_advertise(void) fields.tx_pwr_lvl_is_present = 1; fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO; +#if CONFIG_BT_NIMBLE_GAP_SERVICE fields.name = (uint8_t *)device_name; fields.name_len = strlen(device_name); fields.name_is_complete = 1; +#endif fields.uuids16 = (ble_uuid16_t[]) { BLE_UUID16_INIT(BLE_SVC_LINK_LOSS_UUID16) @@ -301,13 +303,19 @@ void app_main(void) ble_hs_cfg.sm_sc = 1; ble_hs_cfg.sm_mitm = 1; +#if CONFIG_BT_NIMBLE_GAP_SERVICE ble_svc_gap_init(); +#endif +#if MYNEWT_VAL(BLE_GATTS) ble_svc_gatt_init(); +#endif +#if CONFIG_BT_NIMBLE_GAP_SERVICE int rc; /* Set the default device name */ rc = ble_svc_gap_device_name_set(device_name); assert(rc == 0); +#endif /* Start the task */ nimble_port_freertos_init(ble_prox_prph_host_task); diff --git a/examples/bluetooth/nimble/ble_spi_slave/main/main.c b/examples/bluetooth/nimble/ble_spi_slave/main/main.c index 0edb49ecd97..d93f23d427b 100644 --- a/examples/bluetooth/nimble/ble_spi_slave/main/main.c +++ b/examples/bluetooth/nimble/ble_spi_slave/main/main.c @@ -11,6 +11,7 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "esp_err.h" #include "esp_log.h" #include "driver/spi_slave.h" #include "driver/gpio.h" @@ -101,12 +102,17 @@ void app_main(void) t.length = 1024 * 8; t.tx_buffer = NULL; t.rx_buffer = recvbuf; + t.flags = SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO; /* This call enables the SPI slave interface to receive to the recvbuf. The transaction is * initialized by the SPI master, however, so it will not actually happen until the master starts a hardware transaction * by pulling CS low and pulsing the clock etc. */ ret = spi_slave_transmit(RCV_HOST, &t, portMAX_DELAY); + if (ret != ESP_OK) { + ESP_LOGE("SPI_SLAVE", "spi_slave_transmit failed: %s", esp_err_to_name(ret)); + continue; + } /* Get the actual number of bytes received */ int rcv_bytes = t.trans_len / 8; diff --git a/examples/bluetooth/nimble/ble_spp/spp_client/main/main.c b/examples/bluetooth/nimble/ble_spp/spp_client/main/main.c index 83478518fe4..1c3308129a7 100644 --- a/examples/bluetooth/nimble/ble_spp/spp_client/main/main.c +++ b/examples/bluetooth/nimble/ble_spp/spp_client/main/main.c @@ -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 */ @@ -69,8 +69,6 @@ static void ble_spp_client_set_handle(const struct peer *peer) { const struct peer_chr *chr; - const struct peer_dsc *dsc; - uint8_t value[2]; chr = peer_chr_find_uuid(peer, BLE_UUID16_DECLARE(GATT_SPP_SVC_UUID), BLE_UUID16_DECLARE(GATT_SPP_CHR_UUID)); @@ -79,6 +77,10 @@ ble_spp_client_set_handle(const struct peer *peer) MODLOG_DFLT(ERROR, "Error: Peer lacks SPP characteristic\n"); return; } + if (peer->conn_handle > CONFIG_BT_NIMBLE_MAX_CONNECTIONS) { + MODLOG_DFLT(ERROR, "Error: conn_handle %d out of range\n", peer->conn_handle); + return; + } if (g_attr_handle_mutex != NULL) { xSemaphoreTake(g_attr_handle_mutex, portMAX_DELAY); } @@ -88,19 +90,6 @@ ble_spp_client_set_handle(const struct peer *peer) xSemaphoreGive(g_attr_handle_mutex); } - dsc = peer_dsc_find_uuid(peer, - BLE_UUID16_DECLARE(GATT_SPP_SVC_UUID), - BLE_UUID16_DECLARE(GATT_SPP_CHR_UUID), - BLE_UUID16_DECLARE(BLE_GATT_DSC_CLT_CFG_UUID16)); - if (dsc == NULL) { - MODLOG_DFLT(ERROR, "Error: Peer lacks a CCCD for the subscribable characteristic\n"); - return; - } - - value[0] = 1; - value[1] = 0; - ble_gattc_write_flat(peer->conn_handle, dsc->dsc.handle, - value, sizeof(value), NULL, NULL); } /** @@ -247,6 +236,9 @@ ble_spp_client_connect_if_interesting(const struct ble_gap_disc_desc *disc) rc = ble_hs_id_infer_auto(0, &own_addr_type); if (rc != 0) { MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc); +#if !(MYNEWT_VAL(BLE_HOST_ALLOW_CONNECT_WITH_SCAN)) + ble_spp_client_scan(); +#endif return; } @@ -260,6 +252,9 @@ ble_spp_client_connect_if_interesting(const struct ble_gap_disc_desc *disc) MODLOG_DFLT(ERROR, "Error: Failed to connect to device; addr_type=%d " "addr=%s; rc=%d\n", disc->addr.type, addr_str(disc->addr.val), rc); +#if !(MYNEWT_VAL(BLE_HOST_ALLOW_CONNECT_WITH_SCAN)) + ble_spp_client_scan(); +#endif return; } } @@ -346,13 +341,15 @@ ble_spp_client_gap_event(struct ble_gap_event *event, void *arg) MODLOG_DFLT(INFO, "\n"); /* Forget about peer. */ - memset(&connected_addr[event->disconnect.conn.conn_handle].val, 0, PEER_ADDR_VAL_SIZE); - if (g_attr_handle_mutex != NULL) { - xSemaphoreTake(g_attr_handle_mutex, portMAX_DELAY); - } - attribute_handle[event->disconnect.conn.conn_handle] = 0; - if (g_attr_handle_mutex != NULL) { - xSemaphoreGive(g_attr_handle_mutex); + if (event->disconnect.conn.conn_handle <= CONFIG_BT_NIMBLE_MAX_CONNECTIONS) { + memset(&connected_addr[event->disconnect.conn.conn_handle].val, 0, PEER_ADDR_VAL_SIZE); + if (g_attr_handle_mutex != NULL) { + xSemaphoreTake(g_attr_handle_mutex, portMAX_DELAY); + } + attribute_handle[event->disconnect.conn.conn_handle] = 0; + if (g_attr_handle_mutex != NULL) { + xSemaphoreGive(g_attr_handle_mutex); + } } peer_delete(event->disconnect.conn.conn_handle); @@ -499,7 +496,11 @@ static void ble_spp_uart_init(void) }; //Install UART driver, and get the queue. - uart_driver_install(UART_NUM_0, 4096, 8192, 10, &spp_common_uart_queue, 0); + esp_err_t err = uart_driver_install(UART_NUM_0, 4096, 8192, 10, &spp_common_uart_queue, 0); + if (err != ESP_OK) { + ESP_LOGE(tag, "uart_driver_install failed: %d", err); + return; + } //Set UART parameters uart_param_config(UART_NUM_0, &uart_config); //Set UART pins @@ -528,6 +529,7 @@ app_main(void) g_attr_handle_mutex = xSemaphoreCreateMutex(); if (g_attr_handle_mutex == NULL) { ESP_LOGE(tag, "Failed to create attribute handle mutex"); + nimble_port_deinit(); return; } diff --git a/examples/bluetooth/nimble/ble_spp/spp_server/main/main.c b/examples/bluetooth/nimble/ble_spp/spp_server/main/main.c index d4133bd9bcb..d4cd20e20a8 100644 --- a/examples/bluetooth/nimble/ble_spp/spp_server/main/main.c +++ b/examples/bluetooth/nimble/ble_spp/spp_server/main/main.c @@ -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 */ @@ -411,7 +411,11 @@ static void ble_spp_uart_init(void) .source_clk = UART_SCLK_DEFAULT, }; //Install UART driver, and get the queue. - uart_driver_install(UART_NUM_0, 4096, 8192, 10, &spp_common_uart_queue, 0); + esp_err_t err = uart_driver_install(UART_NUM_0, 4096, 8192, 10, &spp_common_uart_queue, 0); + if (err != ESP_OK) { + ESP_LOGE("SPP_SERVER", "uart_driver_install failed: %d", err); + return; + } //Set UART parameters uart_param_config(UART_NUM_0, &uart_config); //Set UART pins diff --git a/examples/bluetooth/nimble/blecent/main/main.c b/examples/bluetooth/nimble/blecent/main/main.c index 3ac1990f51b..99851b6b5f9 100644 --- a/examples/bluetooth/nimble/blecent/main/main.c +++ b/examples/bluetooth/nimble/blecent/main/main.c @@ -154,6 +154,10 @@ blecent_on_custom_subscribe(uint16_t conn_handle, MODLOG_DFLT(INFO, "\n"); peer = peer_find(conn_handle); + if (peer == NULL) { + MODLOG_DFLT(WARN, "Peer not found (conn_handle=%d), likely disconnected\n", conn_handle); + return 0; + } chr = peer_chr_find_uuid(peer, remote_svc_uuid, remote_chr_uuid); @@ -477,9 +481,6 @@ ext_blecent_should_connect(const struct ble_gap_ext_disc_desc *disc) { int offset = 0; int ad_struct_len = 0; -#if CONFIG_EXAMPLE_USE_CI_ADDRESS - uint32_t *addr_offset; -#endif // CONFIG_EXAMPLE_USE_CI_ADDRESS uint8_t test_addr[6]; if (disc->legacy_event_type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND && disc->legacy_event_type != BLE_HCI_ADV_RPT_EVTYPE_DIR_IND) { @@ -493,8 +494,8 @@ ext_blecent_should_connect(const struct ble_gap_ext_disc_desc *disc) #endif #if CONFIG_EXAMPLE_USE_CI_ADDRESS - addr_offset = (uint32_t *)&test_addr[1]; - *addr_offset = atoi(CONFIG_EXAMPLE_PEER_ADDR); + uint32_t addr_val = (uint32_t)atoi(CONFIG_EXAMPLE_PEER_ADDR); + memcpy(&test_addr[1], &addr_val, sizeof(addr_val)); test_addr[5] = 0xC3; test_addr[0] = CONFIG_IDF_FIRMWARE_CHIP_ID; #endif @@ -534,9 +535,6 @@ blecent_should_connect(const struct ble_gap_disc_desc *disc) struct ble_hs_adv_fields fields; int rc; int i; -#if CONFIG_EXAMPLE_USE_CI_ADDRESS - uint32_t *addr_offset; -#endif // CONFIG_EXAMPLE_USE_CI_ADDRESS uint8_t test_addr[6]; /* The device has to be advertising connectability. */ if (disc->event_type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND && @@ -558,8 +556,8 @@ blecent_should_connect(const struct ble_gap_disc_desc *disc) printf("peer--> %s\n", addr_str(test_addr)); #endif #if CONFIG_EXAMPLE_USE_CI_ADDRESS - addr_offset = (uint32_t *)&test_addr[1]; - *addr_offset = atoi(CONFIG_EXAMPLE_PEER_ADDR); + uint32_t addr_val = (uint32_t)atoi(CONFIG_EXAMPLE_PEER_ADDR); + memcpy(&test_addr[1], &addr_val, sizeof(addr_val)); test_addr[5] = 0xC3; test_addr[0] = CONFIG_IDF_FIRMWARE_CHIP_ID; #endif @@ -618,6 +616,9 @@ blecent_connect_if_interesting(void *disc) rc = ble_hs_id_infer_auto(0, &own_addr_type); if (rc != 0) { MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc); +#if !(MYNEWT_VAL(BLE_HOST_ALLOW_CONNECT_WITH_SCAN)) + blecent_scan(); +#endif return; } @@ -636,6 +637,9 @@ blecent_connect_if_interesting(void *disc) MODLOG_DFLT(ERROR, "Error: Failed to connect to device; addr_type=%d " "addr=%s; rc=%d\n", addr->type, addr_str(addr->val), rc); +#if !(MYNEWT_VAL(BLE_HOST_ALLOW_CONNECT_WITH_SCAN)) + blecent_scan(); +#endif return; } } @@ -645,17 +649,28 @@ static void blecent_power_control(uint16_t conn_handle) { int rc; - rc = ble_gap_read_remote_transmit_power_level(conn_handle, 0x01 ); // Attempting on LE 1M phy - assert (rc == 0); + rc = ble_gap_read_remote_transmit_power_level(conn_handle, 0x01); + if (rc != 0) { + MODLOG_DFLT(WARN, "ble_gap_read_remote_transmit_power_level failed; rc=%d\n", rc); + return; + } rc = ble_gap_set_transmit_power_reporting_enable(conn_handle, 0x01, 0x01); - assert (rc == 0); + if (rc != 0) { + MODLOG_DFLT(WARN, "ble_gap_set_transmit_power_reporting_enable failed; rc=%d\n", rc); + return; + } - rc = ble_gap_set_path_loss_reporting_param(conn_handle, 60, 10, 30, 10, 2 ); //demo values - assert (rc == 0); + rc = ble_gap_set_path_loss_reporting_param(conn_handle, 60, 10, 30, 10, 2); + if (rc != 0) { + MODLOG_DFLT(WARN, "ble_gap_set_path_loss_reporting_param failed; rc=%d\n", rc); + return; + } rc = ble_gap_set_path_loss_reporting_enable(conn_handle, 0x01); - assert (rc == 0); + if (rc != 0) { + MODLOG_DFLT(WARN, "ble_gap_set_path_loss_reporting_enable failed; rc=%d\n", rc); + } } #endif @@ -936,11 +951,16 @@ blecent_gap_event(struct ble_gap_event *event, void *arg) break; } } + if (i >= bearers) { + /* CID not found; nothing to remove */ + return 0; + } while (i < (bearers - 1)) { cids[i] = cids[i + 1]; i += 1; } cids[i] = 0; + bearers--; /* Now Abort */ return 0; @@ -1092,12 +1112,6 @@ app_main(void) /* XXX Need to have template for store */ ble_store_config_init(); - nimble_port_freertos_init(blecent_host_task); - -#if CONFIG_EXAMPLE_INIT_DEINIT_LOOP - stack_init_deinit(); -#endif - #if MYNEWT_VAL(BLE_EATT_CHAN_NUM) > 0 bearers = 0; for (int i = 0; i < MYNEWT_VAL(BLE_EATT_CHAN_NUM); i++) { @@ -1105,4 +1119,10 @@ app_main(void) } #endif + nimble_port_freertos_init(blecent_host_task); + +#if CONFIG_EXAMPLE_INIT_DEINIT_LOOP + stack_init_deinit(); +#endif + } diff --git a/examples/bluetooth/nimble/blecsc/main/gatt_svr.c b/examples/bluetooth/nimble/blecsc/main/gatt_svr.c index 54425cfd03f..d1e79a20875 100644 --- a/examples/bluetooth/nimble/blecsc/main/gatt_svr.c +++ b/examples/bluetooth/nimble/blecsc/main/gatt_svr.c @@ -245,7 +245,20 @@ gatt_svr_chr_access_sc_control_point(uint16_t conn_handle, break; } - /* Append response value */ + /* Append Response Op Code, Request Op Code, and Response Value */ + uint8_t rsp_op = SC_CP_OP_RESPONSE; + rc = os_mbuf_append(om_indication, &rsp_op, sizeof(rsp_op)); + if (rc != 0) { + os_mbuf_free_chain(om_indication); + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(om_indication, &op_code, sizeof(op_code)); + if (rc != 0) { + os_mbuf_free_chain(om_indication); + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + rc = os_mbuf_append(om_indication, &response, sizeof(response)); if (rc != 0){ @@ -267,14 +280,7 @@ gatt_svr_chr_access_sc_control_point(uint16_t conn_handle, rc = ble_gatts_indicate_custom(conn_handle, csc_control_point_handle, om_indication); - if (rc != 0) { - goto done; - } - - return rc; - -done: - os_mbuf_free_chain(om_indication); + /* om_indication is consumed (freed) by ble_gatts_indicate_custom regardless of result */ return rc; } @@ -328,6 +334,9 @@ gatt_svr_chr_notify_csc_measurement(uint16_t conn_handle) #endif om = ble_hs_mbuf_from_flat(data_buf, data_offset); + if (om == NULL) { + return BLE_HS_ENOMEM; + } rc = ble_gatts_notify_custom(conn_handle, csc_measurement_handle, om); return rc; diff --git a/examples/bluetooth/nimble/blecsc/main/main.c b/examples/bluetooth/nimble/blecsc/main/main.c index c146c986c5a..4643ec265aa 100644 --- a/examples/bluetooth/nimble/blecsc/main/main.c +++ b/examples/bluetooth/nimble/blecsc/main/main.c @@ -24,6 +24,7 @@ #include "console/console.h" #include "nimble/ble.h" #include "host/ble_hs.h" +#include "host/util/util.h" #include "services/gap/ble_svc_gap.h" #include "blecsc_sens.h" #include "nimble/nimble_port.h" @@ -198,14 +199,16 @@ blecsc_measurement(struct ble_npl_event *ev) { int rc; - rc = ble_npl_callout_reset(&blecsc_measure_timer, portTICK_PERIOD_MS * 10); + rc = ble_npl_callout_reset(&blecsc_measure_timer, ble_npl_time_ms_to_ticks32(1000)); assert(rc == 0); blecsc_simulate_speed_and_cadence(); if (notify_state) { rc = gatt_svr_chr_notify_csc_measurement(conn_handle); - assert(rc == 0); + if (rc != 0) { + MODLOG_DFLT(WARN, "gatt_svr_chr_notify_csc_measurement failed; rc=%d\n", rc); + } } } @@ -232,6 +235,8 @@ blecsc_gap_event(struct ble_gap_event *event, void *arg) case BLE_GAP_EVENT_DISCONNECT: MODLOG_DFLT(INFO, "disconnect; reason=%d\n", event->disconnect.reason); conn_handle = 0; + notify_state = false; + gatt_svr_set_cp_indicate(0); /* Connection terminated; resume advertising */ blecsc_advertise(); break; @@ -272,6 +277,9 @@ blecsc_on_sync(void) { int rc; + rc = ble_hs_util_ensure_addr(0); + assert(rc == 0); + /* Figure out address to use while advertising (no privacy) */ rc = ble_hs_id_infer_auto(0, &blecsc_addr_type); assert(rc == 0); @@ -321,7 +329,7 @@ app_main(void) /* Initialize measurement and notification timer */ ble_npl_callout_init(&blecsc_measure_timer, nimble_port_get_dflt_eventq(), blecsc_measurement, NULL); - rc = ble_npl_callout_reset(&blecsc_measure_timer, portTICK_PERIOD_MS * 100); + rc = ble_npl_callout_reset(&blecsc_measure_timer, ble_npl_time_ms_to_ticks32(1000)); assert(rc == 0); #if MYNEWT_VAL(BLE_GATTS) diff --git a/examples/bluetooth/nimble/blehr/main/main.c b/examples/bluetooth/nimble/blehr/main/main.c index 747a41bbbca..662f178b578 100644 --- a/examples/bluetooth/nimble/blehr/main/main.c +++ b/examples/bluetooth/nimble/blehr/main/main.c @@ -130,23 +130,7 @@ blehr_advertise(void) static void blehr_tx_hrate_stop(void) { - xTimerStop( blehr_tx_timer, 1000 / portTICK_PERIOD_MS ); -} - -/* Reset heart rate measurement */ -static void -blehr_tx_hrate_reset(void) -{ - int rc; - - if (xTimerReset(blehr_tx_timer, 1000 / portTICK_PERIOD_MS ) == pdPASS) { - rc = 0; - } else { - rc = 1; - } - - assert(rc == 0); - + xTimerStop(blehr_tx_timer, 0); } /* This function simulates heart beat and notifies it to the client */ @@ -173,11 +157,15 @@ blehr_tx_hrate(TimerHandle_t ev) } om = ble_hs_mbuf_from_flat(hrm, sizeof(hrm)); + if (om == NULL) { + MODLOG_DFLT(WARN, "ble_hs_mbuf_from_flat failed; out of memory\n"); + return; + } + rc = ble_gatts_notify_custom(conn_handle, hrs_hrm_handle, om); - - assert(rc == 0); - - blehr_tx_hrate_reset(); + if (rc != 0) { + MODLOG_DFLT(WARN, "ble_gatts_notify_custom failed; rc=%d\n", rc); + } } static int @@ -218,10 +206,11 @@ blehr_gap_event(struct ble_gap_event *event, void *arg) event->subscribe.cur_notify, hrs_hrm_handle); if (event->subscribe.attr_handle == hrs_hrm_handle) { notify_state = event->subscribe.cur_notify; - blehr_tx_hrate_reset(); - } else if (event->subscribe.attr_handle != hrs_hrm_handle) { - notify_state = event->subscribe.cur_notify; - blehr_tx_hrate_stop(); + if (notify_state) { + xTimerStart(blehr_tx_timer, 0); + } else { + blehr_tx_hrate_stop(); + } } ESP_LOGI("BLE_GAP_SUBSCRIBE_EVENT", "conn_handle from subscribe=%d", conn_handle); break; diff --git a/examples/bluetooth/nimble/bleprph/main/gatt_svr.c b/examples/bluetooth/nimble/bleprph/main/gatt_svr.c index 8aae8a48b54..dd50caa0c48 100644 --- a/examples/bluetooth/nimble/bleprph/main/gatt_svr.c +++ b/examples/bluetooth/nimble/bleprph/main/gatt_svr.c @@ -164,9 +164,11 @@ gatt_svc_access(uint16_t conn_handle, uint16_t attr_handle, sizeof(gatt_svr_chr_val), sizeof(gatt_svr_chr_val), &gatt_svr_chr_val, NULL); - ble_gatts_chr_updated(attr_handle); - MODLOG_DFLT(INFO, "Notification/Indication scheduled for " - "all subscribed peers.\n"); + if (rc == 0) { + ble_gatts_chr_updated(attr_handle); + MODLOG_DFLT(INFO, "Notification/Indication scheduled for " + "all subscribed peers.\n"); + } return rc; } goto unknown; @@ -183,7 +185,7 @@ gatt_svc_access(uint16_t conn_handle, uint16_t attr_handle, if (ble_uuid_cmp(uuid, &gatt_svr_dsc_uuid.u) == 0) { rc = os_mbuf_append(ctxt->om, &gatt_svr_dsc_val, - sizeof(gatt_svr_chr_val)); + sizeof(gatt_svr_dsc_val)); return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; } goto unknown; diff --git a/examples/bluetooth/nimble/bleprph/main/main.c b/examples/bluetooth/nimble/bleprph/main/main.c index 8b344540435..802f813ba17 100644 --- a/examples/bluetooth/nimble/bleprph/main/main.c +++ b/examples/bluetooth/nimble/bleprph/main/main.c @@ -106,8 +106,8 @@ ext_bleprph_advertise(void) /* enable connectable advertising */ params.connectable = 1; - /* advertise using random addr */ - params.own_addr_type = BLE_OWN_ADDR_PUBLIC; + /* advertise using configured/inferred addr type */ + params.own_addr_type = own_addr_type; params.primary_phy = BLE_HCI_LE_PHY_1M; params.secondary_phy = BLE_HCI_LE_PHY_2M; @@ -186,9 +186,10 @@ bleprph_advertise(void) fields.name_is_complete = 1; #endif - fields.uuids16 = (ble_uuid16_t[]) { + static const ble_uuid16_t adv_uuids16[] = { BLE_UUID16_INIT(GATT_SVR_SVC_ALERT_UUID) }; + fields.uuids16 = adv_uuids16; fields.num_uuids16 = 1; fields.uuids16_is_complete = 1; @@ -216,11 +217,16 @@ static void bleprph_power_control(uint16_t conn_handle) { int rc; - rc = ble_gap_read_remote_transmit_power_level(conn_handle, 0x01 ); // Attempting on LE 1M phy - assert (rc == 0); + rc = ble_gap_read_remote_transmit_power_level(conn_handle, 0x01); + if (rc != 0) { + MODLOG_DFLT(WARN, "ble_gap_read_remote_transmit_power_level failed; rc=%d\n", rc); + return; + } rc = ble_gap_set_transmit_power_reporting_enable(conn_handle, 0x1, 0x1); - assert (rc == 0); + if (rc != 0) { + MODLOG_DFLT(WARN, "ble_gap_set_transmit_power_reporting_enable failed; rc=%d\n", rc); + } } #endif @@ -272,7 +278,9 @@ bleprph_gap_event(struct ble_gap_event *event, void *arg) } #if MYNEWT_VAL(BLE_POWER_CONTROL) - bleprph_power_control(event->connect.conn_handle); + if (event->connect.status == 0) { + bleprph_power_control(event->connect.conn_handle); + } #endif return 0; @@ -281,6 +289,13 @@ bleprph_gap_event(struct ble_gap_event *event, void *arg) bleprph_print_conn_desc(&event->disconnect.conn); MODLOG_DFLT(INFO, "\n"); +#if MYNEWT_VAL(BLE_EATT_CHAN_NUM) > 0 + bearers = 0; + for (int i = 0; i < MYNEWT_VAL(BLE_EATT_CHAN_NUM); i++) { + cids[i] = 0; + } +#endif + /* Connection terminated; resume advertising. */ #if CONFIG_EXAMPLE_EXTENDED_ADV ext_bleprph_advertise(); @@ -491,17 +506,21 @@ bleprph_on_reset(int reason) static void ble_app_set_addr(void) { - ble_addr_t addr; + ble_addr_t addr = {0}; int rc; /* generate new non-resolvable private address */ rc = ble_hs_id_gen_rnd(0, &addr); - assert(rc == 0); + if (rc != 0) { + MODLOG_DFLT(ERROR, "ble_hs_id_gen_rnd failed; rc=%d\n", rc); + return; + } /* set generated address */ rc = ble_hs_id_set_rnd(addr.val); - - assert(rc == 0); + if (rc != 0) { + MODLOG_DFLT(ERROR, "ble_hs_id_set_rnd failed; rc=%d\n", rc); + } } #endif @@ -621,6 +640,13 @@ app_main(void) /* XXX Need to have template for store */ ble_store_config_init(); +#if MYNEWT_VAL(BLE_EATT_CHAN_NUM) > 0 + bearers = 0; + for (int i = 0; i < MYNEWT_VAL(BLE_EATT_CHAN_NUM); i++) { + cids[i] = 0; + } +#endif + nimble_port_freertos_init(bleprph_host_task); /* Initialize command line interface to accept input from user */ @@ -628,11 +654,4 @@ app_main(void) if (rc != ESP_OK) { ESP_LOGE(tag, "scli_init() failed"); } - -#if MYNEWT_VAL(BLE_EATT_CHAN_NUM) > 0 - bearers = 0; - for (int i = 0; i < MYNEWT_VAL(BLE_EATT_CHAN_NUM); i++) { - cids[i] = 0; - } -#endif } diff --git a/examples/bluetooth/nimble/bleprph_host_only/main/gatt_svr.c b/examples/bluetooth/nimble/bleprph_host_only/main/gatt_svr.c index 60c3d2bf73b..23a4b81b166 100644 --- a/examples/bluetooth/nimble/bleprph_host_only/main/gatt_svr.c +++ b/examples/bluetooth/nimble/bleprph_host_only/main/gatt_svr.c @@ -145,9 +145,11 @@ gatt_svc_access(uint16_t conn_handle, uint16_t attr_handle, sizeof(gatt_svr_chr_val), sizeof(gatt_svr_chr_val), &gatt_svr_chr_val, NULL); - ble_gatts_chr_updated(attr_handle); - MODLOG_DFLT(INFO, "Notification/Indication scheduled for " - "all subscribed peers.\n"); + if (rc == 0) { + ble_gatts_chr_updated(attr_handle); + MODLOG_DFLT(INFO, "Notification/Indication scheduled for " + "all subscribed peers.\n"); + } return rc; } goto unknown; @@ -164,7 +166,7 @@ gatt_svc_access(uint16_t conn_handle, uint16_t attr_handle, if (ble_uuid_cmp(uuid, &gatt_svr_dsc_uuid.u) == 0) { rc = os_mbuf_append(ctxt->om, &gatt_svr_dsc_val, - sizeof(gatt_svr_chr_val)); + sizeof(gatt_svr_dsc_val)); return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; } goto unknown; diff --git a/examples/bluetooth/nimble/bleprph_host_only/main/main.c b/examples/bluetooth/nimble/bleprph_host_only/main/main.c index 2c829415f2a..0e45a58c360 100644 --- a/examples/bluetooth/nimble/bleprph_host_only/main/main.c +++ b/examples/bluetooth/nimble/bleprph_host_only/main/main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -85,8 +85,8 @@ ext_bleprph_advertise(void) /* enable connectable advertising */ params.connectable = 1; - /* advertise using random addr */ - params.own_addr_type = BLE_OWN_ADDR_PUBLIC; + /* advertise using configured/inferred addr type */ + params.own_addr_type = own_addr_type; params.primary_phy = BLE_HCI_LE_PHY_1M; params.secondary_phy = BLE_HCI_LE_PHY_2M; @@ -155,15 +155,18 @@ bleprph_advertise(void) fields.tx_pwr_lvl_is_present = 1; fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO; +#if CONFIG_BT_NIMBLE_GAP_SERVICE const char *name; name = ble_svc_gap_device_name(); fields.name = (uint8_t *)name; fields.name_len = strlen(name); fields.name_is_complete = 1; +#endif - fields.uuids16 = (ble_uuid16_t[]) { + static const ble_uuid16_t adv_uuids16[] = { BLE_UUID16_INIT(GATT_SVR_SVC_ALERT_UUID) }; + fields.uuids16 = adv_uuids16; fields.num_uuids16 = 1; fields.uuids16_is_complete = 1; @@ -191,11 +194,16 @@ static void bleprph_power_control(uint16_t conn_handle) { int rc; - rc = ble_gap_read_remote_transmit_power_level(conn_handle, 0x01 ); // Attempting on LE 1M phy - assert (rc == 0); + rc = ble_gap_read_remote_transmit_power_level(conn_handle, 0x01); + if (rc != 0) { + MODLOG_DFLT(WARN, "ble_gap_read_remote_transmit_power_level failed; rc=%d\n", rc); + return; + } rc = ble_gap_set_transmit_power_reporting_enable(conn_handle, 0x1, 0x1); - assert (rc == 0); + if (rc != 0) { + MODLOG_DFLT(WARN, "ble_gap_set_transmit_power_reporting_enable failed; rc=%d\n", rc); + } } #endif @@ -419,17 +427,21 @@ bleprph_on_reset(int reason) static void ble_app_set_addr(void) { - ble_addr_t addr; + ble_addr_t addr = {0}; int rc; /* generate new non-resolvable private address */ rc = ble_hs_id_gen_rnd(0, &addr); - assert(rc == 0); + if (rc != 0) { + MODLOG_DFLT(ERROR, "ble_hs_id_gen_rnd failed; rc=%d\n", rc); + return; + } /* set generated address */ rc = ble_hs_id_set_rnd(addr.val); - - assert(rc == 0); + if (rc != 0) { + MODLOG_DFLT(ERROR, "ble_hs_id_set_rnd failed; rc=%d\n", rc); + } } #endif diff --git a/examples/bluetooth/nimble/bleprph_host_only/main/uart_driver.c b/examples/bluetooth/nimble/bleprph_host_only/main/uart_driver.c index b9132d4bfbf..f490bfeeedb 100644 --- a/examples/bluetooth/nimble/bleprph_host_only/main/uart_driver.c +++ b/examples/bluetooth/nimble/bleprph_host_only/main/uart_driver.c @@ -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 */ @@ -53,18 +53,36 @@ static void IRAM_ATTR hci_uart_rx_task(void *arg) int len_now_read = -1; uint32_t len_to_read = 1; uint32_t len_total_read = 0; + uint32_t len_state_read = 0; uint8_t rx_st = UART_RX_TYPE; while (!s_shutdown_flag) { - // Use timeout instead of portMAX_DELAY to allow periodic shutdown flag check - len_now_read = uart_read_bytes(UART_NO, &buf[len_total_read], len_to_read, pdMS_TO_TICKS(100)); + if (len_state_read < len_to_read) { + // Use timeout instead of portMAX_DELAY to allow periodic shutdown flag check + len_now_read = uart_read_bytes(UART_NO, &buf[len_total_read], + len_to_read - len_state_read, + pdMS_TO_TICKS(100)); - // If timeout occurred, continue loop to check shutdown flag again - if (len_now_read == 0) { - continue; + // If timeout occurred, continue loop to check shutdown flag again + if (len_now_read == 0) { + continue; + } + if (len_now_read < 0) { + ESP_LOGE(TAG, "uart_read_bytes failed: %d", len_now_read); + rx_st = UART_RX_TYPE; + len_to_read = 1; + len_total_read = 0; + len_state_read = 0; + continue; + } + + len_total_read += len_now_read; + len_state_read += len_now_read; + if (len_state_read < len_to_read) { + continue; + } } - - len_total_read += len_now_read; + len_state_read = 0; switch (rx_st) { case UART_RX_TYPE: { @@ -83,6 +101,18 @@ static void IRAM_ATTR hci_uart_rx_task(void *arg) case UART_RX_LEN: { if (buf[0] == DATA_TYPE_ACL) { len_to_read = buf[3] | (buf[4] << 8); + if (len_total_read + len_to_read > sizeof(buf)) { + ESP_LOGE(TAG, "ACL packet length %lu exceeds buffer size, discarding", (unsigned long)len_to_read); + /* Drain the unread payload bytes so the UART stream stays + * synchronised; without this the next UART_RX_TYPE read + * would pick up a payload byte, not a valid H4 type byte. */ + uart_flush_input(UART_NO); + rx_st = UART_RX_TYPE; + len_to_read = 1; + len_total_read = 0; + len_state_read = 0; + break; + } } else if (buf[0] == DATA_TYPE_EVENT) { len_to_read = buf[2]; } else { @@ -107,6 +137,10 @@ static void IRAM_ATTR hci_uart_rx_task(void *arg) ESP_LOGE(TAG, "Received HCI data length at host (%d)" "exceeds maximum configured HCI event buffer size (%d).", totlen, MYNEWT_VAL(BLE_TRANSPORT_EVT_SIZE)); + rx_st = UART_RX_TYPE; + len_to_read = 1; + len_total_read = 0; + len_state_read = 0; break; } @@ -121,6 +155,10 @@ static void IRAM_ATTR hci_uart_rx_task(void *arg) /* Skip advertising report if we're out of memory */ if (!evbuf) { ESP_LOGE(TAG, "No buffers"); + rx_st = UART_RX_TYPE; + len_to_read = 1; + len_total_read = 0; + len_state_read = 0; break; } } else { @@ -141,13 +179,18 @@ static void IRAM_ATTR hci_uart_rx_task(void *arg) rx_st = UART_RX_TYPE; len_to_read = 1; len_total_read = 0; + len_state_read = 0; break; } if ((rc = os_mbuf_append(m, &data[1], len_total_read - 1)) != 0) { ESP_LOGE(TAG, "%s failed to os_mbuf_append; rc = %d", __func__, rc); os_mbuf_free_chain(m); - return; + rx_st = UART_RX_TYPE; + len_to_read = 1; + len_total_read = 0; + len_state_read = 0; + break; } ble_transport_to_hs_acl(m); @@ -156,6 +199,7 @@ static void IRAM_ATTR hci_uart_rx_task(void *arg) rx_st = UART_RX_TYPE; len_to_read = 1; len_total_read = 0; + len_state_read = 0; } break; @@ -166,7 +210,8 @@ static void IRAM_ATTR hci_uart_rx_task(void *arg) } } - vTaskDelete(NULL); + s_rx_task_hdl = NULL; + vTaskDelete(NULL); } void hci_uart_send(uint8_t *buf, uint16_t len) @@ -176,7 +221,10 @@ void hci_uart_send(uint8_t *buf, uint16_t len) while (len) { len_write = uart_write_bytes(UART_NO, p, len); - assert(len_write > 0); + if (len_write <= 0) { + ESP_LOGE(TAG, "uart_write_bytes failed: %d", len_write); + return; + } len -= len_write; p += len_write; } @@ -216,7 +264,7 @@ int ble_transport_to_ll_cmd_impl(void *buf) { int len = 3 + ((uint8_t *)buf)[2] + 1; - uint8_t data[258]; + uint8_t data[259]; data[0] = HCI_H4_CMD; memcpy(data + 1, buf, len - 1); hci_uart_send(data, len); @@ -262,7 +310,7 @@ void hci_uart_close(void) const int max_wait_count = 5; TaskHandle_t task_handle = s_rx_task_hdl; - while (wait_count < max_wait_count) { + while (wait_count < max_wait_count && s_rx_task_hdl == task_handle) { vTaskDelay(pdMS_TO_TICKS(100)); wait_count++; @@ -272,8 +320,8 @@ void hci_uart_close(void) if (s_rx_task_hdl == task_handle) { vTaskDelete(s_rx_task_hdl); vTaskDelay(pdMS_TO_TICKS(100)); + s_rx_task_hdl = NULL; } - s_rx_task_hdl = NULL; } uart_driver_delete(UART_NO); diff --git a/examples/bluetooth/nimble/bleprph_wifi_coex/main/main.c b/examples/bluetooth/nimble/bleprph_wifi_coex/main/main.c index 6d7a4505513..a631d22e514 100644 --- a/examples/bluetooth/nimble/bleprph_wifi_coex/main/main.c +++ b/examples/bluetooth/nimble/bleprph_wifi_coex/main/main.c @@ -92,6 +92,10 @@ static void event_handler(void* arg, esp_event_base_t event_base, void wifi_init_sta(void) { s_wifi_event_group = xEventGroupCreate(); + if (s_wifi_event_group == NULL) { + ESP_LOGE(TAG, "Failed to create wifi event group"); + return; + } ESP_ERROR_CHECK(esp_netif_init()); @@ -195,7 +199,7 @@ static void cmd_ping_on_ping_end(esp_ping_handle_t hdl, void *args) esp_ping_get_profile(hdl, ESP_PING_PROF_REPLY, &received, sizeof(received)); esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr)); esp_ping_get_profile(hdl, ESP_PING_PROF_DURATION, &total_time_ms, sizeof(total_time_ms)); - uint32_t loss = (uint32_t)((1 - ((float)received) / transmitted) * 100); + uint32_t loss = (transmitted > 0) ? (uint32_t)((1 - ((float)received) / transmitted) * 100) : 0; if (IP_IS_V4(&target_addr)) { printf("\n--- %s ping statistics ---\n", inet_ntoa(*ip_2_ip4(&target_addr))); } else { @@ -347,9 +351,10 @@ bleprph_advertise(void) fields.name_len = strlen(name); fields.name_is_complete = 1; - fields.uuids16 = (ble_uuid16_t[]) { + static const ble_uuid16_t adv_uuids16[] = { BLE_UUID16_INIT(GATT_SVR_SVC_ALERT_UUID) }; + fields.uuids16 = adv_uuids16; fields.num_uuids16 = 1; fields.uuids16_is_complete = 1; diff --git a/examples/bluetooth/nimble/common/nimble_central_utils/misc.c b/examples/bluetooth/nimble/common/nimble_central_utils/misc.c index bf936e80b2c..9e0c14c866c 100644 --- a/examples/bluetooth/nimble/common/nimble_central_utils/misc.c +++ b/examples/bluetooth/nimble/common/nimble_central_utils/misc.c @@ -12,12 +12,20 @@ int peer_addr_parse(const char *addr_str, uint8_t addr[PEER_ADDR_VAL_SIZE]) { + unsigned int tmp[6] = {0}; + int rc; + int i; + if (addr_str == NULL) { return 0; } - return sscanf(addr_str, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", - &addr[5], &addr[4], &addr[3], - &addr[2], &addr[1], &addr[0]); + rc = sscanf(addr_str, "%x:%x:%x:%x:%x:%x", + &tmp[5], &tmp[4], &tmp[3], + &tmp[2], &tmp[1], &tmp[0]); + for (i = 0; i < PEER_ADDR_VAL_SIZE; i++) { + addr[i] = (uint8_t)tmp[i]; + } + return rc; } /** @@ -98,7 +106,7 @@ print_conn_desc(const struct ble_gap_conn_desc *desc) } #if MYNEWT_VAL(BLE_EXT_ADV) -void +static void print_addr(const void *addr, const char *name) { const uint8_t *u8p; @@ -254,11 +262,9 @@ print_adv_fields(const struct ble_hs_adv_fields *fields) if (fields->device_addr_is_present) { MODLOG_DFLT(DEBUG, " device_addr="); - u8p = fields->device_addr; - MODLOG_DFLT(DEBUG, "%s ", addr_str(u8p)); - - u8p += BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN; - MODLOG_DFLT(DEBUG, "addr_type %d ", *u8p); + u8p = fields->device_addr; + MODLOG_DFLT(DEBUG, "%s addr_type %d ", addr_str(u8p), + fields->device_addr_type); } if (fields->le_role_is_present) { diff --git a/examples/bluetooth/nimble/common/nimble_central_utils/peer.c b/examples/bluetooth/nimble/common/nimble_central_utils/peer.c index 3d2626913d2..9ec1e726b44 100644 --- a/examples/bluetooth/nimble/common/nimble_central_utils/peer.c +++ b/examples/bluetooth/nimble/common/nimble_central_utils/peer.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -167,7 +167,7 @@ peer_dsc_add(struct peer *peer, uint16_t chr_val_handle, if (prev == NULL) { SLIST_INSERT_HEAD(&chr->dscs, dsc, next); } else { - SLIST_NEXT(prev, next) = dsc; + SLIST_INSERT_AFTER(prev, dsc, next); } return 0; @@ -196,6 +196,7 @@ peer_disc_dscs(struct peer *peer) peer_dsc_disced, peer); if (rc != 0) { peer_disc_complete(peer, rc); + return; } peer->disc_prev_chr_val = chr->chr.val_handle; @@ -357,7 +358,7 @@ peer_chr_add(struct peer *peer, uint16_t svc_start_handle, if (prev == NULL) { SLIST_INSERT_HEAD(&svc->chrs, chr, next); } else { - SLIST_NEXT(prev, next) = chr; + SLIST_INSERT_AFTER(prev, chr, next); } return 0; @@ -407,12 +408,15 @@ peer_disc_chrs(struct peer *peer) struct peer_svc *svc; int rc; - /* Search through the list of discovered service for the first service that - * contains undiscovered characteristics. Then, discover all - * characteristics belonging to that service. - */ - SLIST_FOREACH(svc, &peer->svcs, next) { - if (!peer_svc_is_empty(svc) && SLIST_EMPTY(&svc->chrs)) { + /* Advance past the last processed service, or start from the beginning. */ + if (peer->cur_svc == NULL) { + svc = SLIST_FIRST(&peer->svcs); + } else { + svc = SLIST_NEXT(peer->cur_svc, next); + } + + for (; svc != NULL; svc = SLIST_NEXT(svc, next)) { + if (!peer_svc_is_empty(svc)) { peer->cur_svc = svc; rc = ble_gattc_disc_all_chrs(peer->conn_handle, svc->svc.start_handle, @@ -596,17 +600,24 @@ peer_disc_incs(struct peer *peer) if (peer->cur_svc == NULL) { if (peer->disc_prev_chr_val > 0) { peer_disc_chrs(peer); - return; } + return; } } + + /* Skip empty services rather than aborting include discovery early. */ + while (peer->cur_svc != NULL && peer_svc_is_empty(peer->cur_svc)) { + peer->cur_svc = SLIST_NEXT(peer->cur_svc, next); + } + svc = peer->cur_svc; - if (svc != NULL && !peer_svc_is_empty(svc)) { + if (svc != NULL) { rc = ble_gattc_find_inc_svcs(peer->conn_handle, svc->svc.start_handle, svc->svc.end_handle, peer_inc_disced, peer); if (rc != 0) { + peer->cur_svc = NULL; peer_disc_chrs(peer); } } else { @@ -684,6 +695,10 @@ peer_svc_find_uuid(const struct peer *peer, const ble_uuid_t *uuid) { const struct peer_svc *svc; + if (peer == NULL || uuid == NULL) { + return NULL; + } + SLIST_FOREACH(svc, &peer->svcs, next) { if (ble_uuid_cmp(&svc->svc.uuid.u, uuid) == 0) { return svc; @@ -700,6 +715,10 @@ peer_chr_find_uuid(const struct peer *peer, const ble_uuid_t *svc_uuid, const struct peer_svc *svc; const struct peer_chr *chr; + if (chr_uuid == NULL) { + return NULL; + } + svc = peer_svc_find_uuid(peer, svc_uuid); if (svc == NULL) { return NULL; @@ -721,6 +740,10 @@ peer_dsc_find_uuid(const struct peer *peer, const ble_uuid_t *svc_uuid, const struct peer_chr *chr; const struct peer_dsc *dsc; + if (dsc_uuid == NULL) { + return NULL; + } + chr = peer_chr_find_uuid(peer, svc_uuid, chr_uuid); if (chr == NULL) { return NULL; @@ -810,6 +833,7 @@ peer_svc_disced(uint16_t conn_handle, const struct ble_gatt_error *error, #else /* All services discovered; start discovering characteristics. */ if (peer->disc_prev_chr_val > 0) { + peer->cur_svc = NULL; peer_disc_chrs(peer); } #endif @@ -979,6 +1003,7 @@ peer_free_mem(void) { free(peer_mem); peer_mem = NULL; + SLIST_INIT(&peers); free(peer_svc_mem); peer_svc_mem = NULL; diff --git a/examples/bluetooth/nimble/common/nimble_peripheral_utils/scli.c b/examples/bluetooth/nimble/common/nimble_peripheral_utils/scli.c index f7d1cedbe13..b44c05301e6 100644 --- a/examples/bluetooth/nimble/common/nimble_peripheral_utils/scli.c +++ b/examples/bluetooth/nimble/common/nimble_peripheral_utils/scli.c @@ -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 */ @@ -20,23 +20,27 @@ static TaskHandle_t cli_task; static QueueHandle_t cli_handle; -static int stop; +static volatile int stop; static int enter_passkey_handler(int argc, char *argv[]) { int key; - char pkey[8]; + char pkey[8] = {0}; int num; if (argc != 2) { return -1; } + if (cli_handle == NULL) { + return -1; + } + sscanf(argv[1], "%7s", pkey); ESP_LOGI("You entered", "%s %s", argv[0], argv[1]); num = pkey[0]; - if (isalpha(num)) { + if (isalpha((unsigned char)num)) { if ((strcasecmp(pkey, "Y") == 0) || (strcasecmp(pkey, "Yes") == 0)) { key = 1; xQueueSend(cli_handle, &key, 0); @@ -56,6 +60,9 @@ static int enter_passkey_handler(int argc, char *argv[]) int scli_receive_key(int *console_key) { + if (cli_handle == NULL) { + return pdFALSE; + } return xQueueReceive(cli_handle, console_key, BLE_RX_TIMEOUT); } @@ -108,10 +115,8 @@ static void scli_task(void *arg) } } if (event.type == UART_DATA) { - while (uart_read_bytes(uart_num, (uint8_t *) &linebuf[i], 1, 0)) { - if (i >= sizeof(linebuf) - 1) { - break; - } + while (i < sizeof(linebuf) - 1 && + uart_read_bytes(uart_num, (uint8_t *) &linebuf[i], 1, 0)) { if (linebuf[i] == '\r') { uart_write_bytes(uart_num, "\r\n", 2); } else { @@ -143,12 +148,14 @@ int scli_init(void) /* Register CLI "key " to accept input from user during pairing */ ble_register_cli(); - xTaskCreate(scli_task, "scli_cli", 4096, (void *) 0, 3, &cli_task); - if (cli_task == NULL) { + cli_handle = xQueueCreate(1, sizeof(int)); + if (cli_handle == NULL) { return ESP_FAIL; } - cli_handle = xQueueCreate( 1, sizeof(int) ); - if (cli_handle == NULL) { + xTaskCreate(scli_task, "scli_cli", 4096, (void *) 0, 3, &cli_task); + if (cli_task == NULL) { + vQueueDelete(cli_handle); + cli_handle = NULL; return ESP_FAIL; } return ESP_OK; diff --git a/examples/bluetooth/nimble/hci/main/dtm_configuration_command.c b/examples/bluetooth/nimble/hci/main/dtm_configuration_command.c index 37f221c1ecc..3f4a5996693 100644 --- a/examples/bluetooth/nimble/hci/main/dtm_configuration_command.c +++ b/examples/bluetooth/nimble/hci/main/dtm_configuration_command.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -32,7 +32,7 @@ static int dtm_set_ble_tx_power_command(int argc, char **argv) } ESP_LOGI(__func__, "Set tx power level '%d'", dtm_set_tx_power_cmd_args.cmd_params->ival[0]); - if (dtm_set_tx_power_cmd_args.cmd_params->ival[0] > 15) { + if (dtm_set_tx_power_cmd_args.cmd_params->ival[0] < 0 || dtm_set_tx_power_cmd_args.cmd_params->ival[0] > 15) { return 2; } @@ -48,6 +48,11 @@ static int dtm_get_ble_tx_power_command(int argc, char **argv) { esp_power_level_t power_level; + if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) { + esp_rom_printf("\nPlease enable BLE DTM mode first by using the command enable_ble_dtm -e 1 before sending this command.\n"); + return 2; + } + power_level = esp_ble_tx_power_get_enhanced(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); if (power_level == ESP_PWR_LVL_INVALID) { @@ -67,10 +72,18 @@ static int dtm_reconfig_uart_pins_command(int argc, char **argv) return 1; } - ESP_LOGI(__func__, "reconfig tx:'%d', rx: '%d'", - dtm_reconfig_uart_cmd_args.tx_pin->ival[0], dtm_reconfig_uart_cmd_args.rx_pin->ival[0]); - hci_uart_reconfig_pin(dtm_reconfig_uart_cmd_args.tx_pin->ival[0], - dtm_reconfig_uart_cmd_args.rx_pin->ival[0], -1, -1); + int tx_pin = dtm_reconfig_uart_cmd_args.tx_pin->ival[0]; + int rx_pin = dtm_reconfig_uart_cmd_args.rx_pin->ival[0]; + if (tx_pin < 0 || rx_pin < 0) { + ESP_LOGE(__func__, "Invalid GPIO pin: tx=%d, rx=%d", tx_pin, rx_pin); + return 1; + } + ESP_LOGI(__func__, "reconfig tx:'%d', rx: '%d'", tx_pin, rx_pin); + int rc = hci_uart_reconfig_pin(tx_pin, rx_pin, -1, -1); + if (rc != 0) { + ESP_LOGE(__func__, "Failed to reconfig UART pins; rc=%d", rc); + return 1; + } return 0; } diff --git a/examples/bluetooth/nimble/power_save/main/gatt_svr.c b/examples/bluetooth/nimble/power_save/main/gatt_svr.c index 04e170d38b7..639aa3da2eb 100644 --- a/examples/bluetooth/nimble/power_save/main/gatt_svr.c +++ b/examples/bluetooth/nimble/power_save/main/gatt_svr.c @@ -151,9 +151,11 @@ gatt_svc_access(uint16_t conn_handle, uint16_t attr_handle, sizeof(gatt_svr_chr_val), sizeof(gatt_svr_chr_val), &gatt_svr_chr_val, NULL); - ble_gatts_chr_updated(attr_handle); - MODLOG_DFLT(INFO, "Notification/Indication scheduled for " - "all subscribed peers.\n"); + if (rc == 0) { + ble_gatts_chr_updated(attr_handle); + MODLOG_DFLT(INFO, "Notification/Indication scheduled for " + "all subscribed peers.\n"); + } return rc; } goto unknown; @@ -170,7 +172,7 @@ gatt_svc_access(uint16_t conn_handle, uint16_t attr_handle, if (ble_uuid_cmp(uuid, &gatt_svr_dsc_uuid.u) == 0) { rc = os_mbuf_append(ctxt->om, &gatt_svr_dsc_val, - sizeof(gatt_svr_chr_val)); + sizeof(gatt_svr_dsc_val)); return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; } goto unknown; diff --git a/examples/bluetooth/nimble/power_save/main/main.c b/examples/bluetooth/nimble/power_save/main/main.c index 1f85cb4bf83..e80f56c8e6f 100644 --- a/examples/bluetooth/nimble/power_save/main/main.c +++ b/examples/bluetooth/nimble/power_save/main/main.c @@ -184,9 +184,10 @@ bleprph_advertise(void) fields.name_is_complete = 1; #endif - fields.uuids16 = (ble_uuid16_t[]) { + static const ble_uuid16_t adv_uuids16[] = { BLE_UUID16_INIT(GATT_SVR_SVC_ALERT_UUID) }; + fields.uuids16 = adv_uuids16; fields.num_uuids16 = 1; fields.uuids16_is_complete = 1; @@ -480,17 +481,21 @@ bleprph_on_reset(int reason) static void ble_app_set_addr(void) { - ble_addr_t addr; + ble_addr_t addr = {0}; int rc; /* generate new non-resolvable private address */ rc = ble_hs_id_gen_rnd(0, &addr); - assert(rc == 0); + if (rc != 0) { + MODLOG_DFLT(ERROR, "ble_hs_id_gen_rnd failed; rc=%d\n", rc); + return; + } /* set generated address */ rc = ble_hs_id_set_rnd(addr.val); - - assert(rc == 0); + if (rc != 0) { + MODLOG_DFLT(ERROR, "ble_hs_id_set_rnd failed; rc=%d\n", rc); + } } #endif @@ -507,8 +512,8 @@ bleprph_on_sync(void) #if CONFIG_EXAMPLE_USE_CI_ADDRESS if (strlen(CONFIG_EXAMPLE_CI_ADDRESS_OFFSET)) { uint8_t addr[6] = {0}; - uint32_t *offset = (uint32_t *)&addr[1]; - *offset = atoi(CONFIG_EXAMPLE_CI_ADDRESS_OFFSET); + uint32_t offset_val = (uint32_t)atoi(CONFIG_EXAMPLE_CI_ADDRESS_OFFSET); + memcpy(&addr[1], &offset_val, sizeof(offset_val)); addr[5] = 0xC3; addr[0] = CONFIG_IDF_FIRMWARE_CHIP_ID; rc = ble_hs_id_set_rnd(addr); diff --git a/examples/bluetooth/nimble/throughput_app/gatt/blecent_throughput/components/cmd_system/cmd_system.c b/examples/bluetooth/nimble/throughput_app/gatt/blecent_throughput/components/cmd_system/cmd_system.c index ef6ccfda967..4a0e4388e21 100644 --- a/examples/bluetooth/nimble/throughput_app/gatt/blecent_throughput/components/cmd_system/cmd_system.c +++ b/examples/bluetooth/nimble/throughput_app/gatt/blecent_throughput/components/cmd_system/cmd_system.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -169,8 +169,10 @@ static void register_heap(void) static int tasks_info(int argc, char **argv) { - const size_t bytes_per_task = 40; /* see vTaskList description */ - char *task_list_buffer = malloc(uxTaskGetNumberOfTasks() * bytes_per_task); + /* Use a larger per-task estimate (80 bytes) plus a safety margin of 10 extra + * slots to absorb TOCTOU races and SMP mode affinity fields. */ + const size_t bytes_per_task = 80; + char *task_list_buffer = malloc((uxTaskGetNumberOfTasks() + 10) * bytes_per_task); if (task_list_buffer == NULL) { ESP_LOGE(TAG, "failed to allocate buffer for vTaskList output"); return 1; @@ -218,14 +220,19 @@ static int deep_sleep(int argc, char **argv) return 1; } if (deep_sleep_args.wakeup_time->count) { - uint64_t timeout = 1000ULL * deep_sleep_args.wakeup_time->ival[0]; + int wakeup_ms = deep_sleep_args.wakeup_time->ival[0]; + if (wakeup_ms <= 0) { + ESP_LOGE(TAG, "Invalid wakeup time: %d ms (must be > 0)", wakeup_ms); + return 1; + } + uint64_t timeout = 1000ULL * wakeup_ms; ESP_LOGI(TAG, "Enabling timer wakeup, timeout=%lluus", timeout); ESP_ERROR_CHECK( esp_sleep_enable_timer_wakeup(timeout) ); } if (deep_sleep_args.wakeup_gpio_num->count) { int io_num = deep_sleep_args.wakeup_gpio_num->ival[0]; - if (!rtc_gpio_is_valid_gpio(io_num)) { - ESP_LOGE(TAG, "GPIO %d is not an RTC IO", io_num); + if (io_num < 0 || !rtc_gpio_is_valid_gpio(io_num)) { + ESP_LOGE(TAG, "GPIO %d is not a valid RTC IO", io_num); return 1; } int level = 0; @@ -236,11 +243,13 @@ static int deep_sleep(int argc, char **argv) return 1; } } +#if SOC_PM_SUPPORT_EXT1_WAKEUP ESP_LOGI(TAG, "Enabling wakeup on GPIO%d, wakeup on %s level", io_num, level ? "HIGH" : "LOW"); - -#if SOC_PM_SUPPORT_EXT1_WAKEUP ESP_ERROR_CHECK( esp_sleep_enable_ext1_wakeup_io(1ULL << io_num, level) ); +#else + ESP_LOGE(TAG, "GPIO wakeup from deep sleep not supported on this target"); + return 1; #endif } @@ -310,21 +319,43 @@ static int light_sleep(int argc, char **argv) ESP_LOGE(TAG, "Invalid wakeup level: %d", level); return 1; } + if (!GPIO_IS_VALID_GPIO(io_num)) { + ESP_LOGE(TAG, "Invalid GPIO number: %d", io_num); + return 1; + } + /* Configure the pin as input with a pull to avoid floating and false wakeups */ + gpio_config_t io_conf = { + .pin_bit_mask = 1ULL << io_num, + .mode = GPIO_MODE_INPUT, + .pull_up_en = (level == 0) ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE, + .pull_down_en = (level == 1) ? GPIO_PULLDOWN_ENABLE : GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE, + }; + esp_err_t gpio_cfg_err = gpio_config(&io_conf); + if (gpio_cfg_err != ESP_OK) { + ESP_LOGE(TAG, "gpio_config failed for GPIO%d: %s", io_num, esp_err_to_name(gpio_cfg_err)); + return 1; + } ESP_LOGI(TAG, "Enabling wakeup on GPIO%d, wakeup on %s level", io_num, level ? "HIGH" : "LOW"); - - ESP_ERROR_CHECK( gpio_wakeup_enable(io_num, level ? GPIO_INTR_HIGH_LEVEL : GPIO_INTR_LOW_LEVEL) ); + esp_err_t wakeup_err = gpio_wakeup_enable(io_num, level ? GPIO_INTR_HIGH_LEVEL : GPIO_INTR_LOW_LEVEL); + if (wakeup_err != ESP_OK) { + ESP_LOGE(TAG, "gpio_wakeup_enable failed for GPIO%d: %s", io_num, esp_err_to_name(wakeup_err)); + return 1; + } } if (io_count > 0) { ESP_ERROR_CHECK( esp_sleep_enable_gpio_wakeup() ); } - if (CONFIG_ESP_CONSOLE_UART_NUM <= UART_NUM_1) { + if (CONFIG_ESP_CONSOLE_UART_NUM >= 0 && CONFIG_ESP_CONSOLE_UART_NUM <= UART_NUM_1) { ESP_LOGI(TAG, "Enabling UART wakeup (press ENTER to exit light sleep)"); ESP_ERROR_CHECK( uart_set_wakeup_threshold(CONFIG_ESP_CONSOLE_UART_NUM, 3) ); ESP_ERROR_CHECK( esp_sleep_enable_uart_wakeup(CONFIG_ESP_CONSOLE_UART_NUM) ); } fflush(stdout); - uart_wait_tx_idle_polling(CONFIG_ESP_CONSOLE_UART_NUM); + if (CONFIG_ESP_CONSOLE_UART_NUM >= 0) { + uart_wait_tx_idle_polling(CONFIG_ESP_CONSOLE_UART_NUM); + } esp_light_sleep_start(); uint32_t causes = esp_sleep_get_wakeup_causes(); diff --git a/examples/bluetooth/nimble/throughput_app/gatt/blecent_throughput/main/main.c b/examples/bluetooth/nimble/throughput_app/gatt/blecent_throughput/main/main.c index 43a4ff8cb70..5761056de7d 100644 --- a/examples/bluetooth/nimble/throughput_app/gatt/blecent_throughput/main/main.c +++ b/examples/bluetooth/nimble/throughput_app/gatt/blecent_throughput/main/main.c @@ -71,7 +71,7 @@ static uint16_t handle; #define PHY_CODED_S8 3 #if CONFIG_EXAMPLE_EXTENDED_ADV -static int current_phy_updated; +static volatile int current_phy_updated; #endif /* State for callback-chained read throughput test */ @@ -194,8 +194,9 @@ blecent_notify(uint16_t conn_handle, uint16_t val_handle, return 0; err: - /* Terminate the connection. */ - return ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM); + /* Terminate the connection; return original error code so caller detects failure. */ + ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM); + return rc; } static int blecent_write(uint16_t conn_handle, uint16_t val_handle, @@ -599,6 +600,11 @@ read_cleanup: break; case NOTIFY_THROUGHPUT: + if (test_data[1] <= 0) { + ESP_LOGE(tag, "Please enter non-zero value for test time in seconds!!"); + break; + } + if (test_data[2] == PHY_CODED_S2) { switch_conn_params(conn_handle, &conn_params_coded_s2); } else if (test_data[2] == PHY_CODED_S8) { @@ -641,7 +647,7 @@ read_cleanup: " can be seen on peripheral terminal after %d seconds", test_data[1]); } - vTaskDelay(test_data[1]*1000 / portTICK_PERIOD_MS); + vTaskDelay((TickType_t)test_data[1] * 1000 / portTICK_PERIOD_MS); /* Unsubscribe so the next notify test triggers a fresh * BLE_GAP_EVENT_SUBSCRIBE on the peripheral (cur_notify 0→1) */ @@ -762,22 +768,17 @@ ext_blecent_should_connect(const struct ble_gap_ext_disc_desc *disc) { int offset = 0; int ad_struct_len = 0; - uint8_t test_addr[6]; uint8_t parsed_addr[6]; uint8_t phy_uuid_found = 0; - if (disc->legacy_event_type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND && - disc->legacy_event_type != BLE_HCI_ADV_RPT_EVTYPE_DIR_IND) { + if (!(disc->props & BLE_HCI_ADV_CONN_MASK)) { return 0; } if (strlen(CONFIG_EXAMPLE_PEER_ADDR) && (strncmp(CONFIG_EXAMPLE_PEER_ADDR, "ADDR_ANY", strlen("ADDR_ANY")) != 0)) { - // ESP_LOGI(tag, "Peer address from menuconfig: %s", CONFIG_EXAMPLE_PEER_ADDR); - /* Convert string to address */ + /* peer_addr_parse stores address in little-endian order matching disc->addr.val; + * no byte reversal needed. */ peer_addr_parse(CONFIG_EXAMPLE_PEER_ADDR, parsed_addr); - for (int i = 0; i < 6; i++) { - test_addr[5 - i] = parsed_addr[i]; - } - if (memcmp(test_addr, disc->addr.val, sizeof(disc->addr.val)) != 0) { + if (memcmp(parsed_addr, disc->addr.val, sizeof(disc->addr.val)) != 0) { return 0; } } @@ -860,9 +861,13 @@ blecent_should_connect(const struct ble_gap_disc_desc *disc) char serv_name[] = "nimble_prph"; if (fields.name != NULL) { - ESP_LOGI(tag, "Device Name = %s", (char *)fields.name); + /* fields.name is not null-terminated; use %.*s for safe printing */ + ESP_LOGI(tag, "Device Name = %.*s", fields.name_len, (char *)fields.name); - if (memcmp(fields.name, serv_name, fields.name_len) == 0) { + /* Require exact length match to prevent prefix false-positives and + * avoid reading past the end of serv_name (stack over-read). */ + if (fields.name_len == (uint8_t)strlen(serv_name) && + memcmp(fields.name, serv_name, fields.name_len) == 0) { ESP_LOGI(tag, "central connect to `nimble_prph` success"); return 1; } @@ -912,6 +917,9 @@ blecent_connect_if_interesting(void *disc) rc = ble_hs_id_infer_auto(0, &own_addr_type); if (rc != 0) { ESP_LOGE(tag, "error determining address type; rc=%d", rc); +#if !(MYNEWT_VAL(BLE_HOST_ALLOW_CONNECT_WITH_SCAN)) + blecent_scan(); +#endif return; } @@ -924,6 +932,9 @@ blecent_connect_if_interesting(void *disc) ESP_LOGE(tag, "Error: Failed to connect to device; addr_type=%d " "addr=%s; rc=%d\n", conn_addr.type, addr_str(conn_addr.val), rc); +#if !(MYNEWT_VAL(BLE_HOST_ALLOW_CONNECT_WITH_SCAN)) + blecent_scan(); +#endif return; } } @@ -1038,7 +1049,6 @@ blecent_gap_event(struct ble_gap_event *event, void *arg) /* Forget about peer. */ peer_delete(event->disconnect.conn.conn_handle); - vTaskDelay(200); /* Resume scanning. */ blecent_scan(); @@ -1212,9 +1222,11 @@ app_main(void) assert(rc == 0); #endif +#if CONFIG_BT_NIMBLE_GAP_SERVICE /* Set the default device name. */ rc = ble_svc_gap_device_name_set("gattc-throughput"); assert(rc == 0); +#endif /* XXX Need to have template for store */ ble_store_config_init(); @@ -1241,32 +1253,9 @@ app_main(void) printf(" | |\n"); printf("\n ===============================================================================================\n"); - const char *prompt = LOG_COLOR_I "Throughput demo >> " LOG_RESET_COLOR; - - while (true) { - /* Get a line using linenoise. - * The line is returned when ENTER is pressed. - */ - char *line = linenoise(prompt); - if (line == NULL) { /* Ignore empty lines */ - continue; - } - /* Add the command to the history */ - linenoiseHistoryAdd(line); - - /* Try to run the command */ - int ret; - esp_err_t err = esp_console_run(line, &ret); - if (err == ESP_ERR_NOT_FOUND) { - printf("Unrecognized command\n"); - } else if (err == ESP_ERR_INVALID_ARG) { - // command was empty - } else if (err == ESP_OK && ret != ESP_OK) { - printf("Command returned non-zero error code: 0x%x (%s)\n", ret, esp_err_to_name(ret)); - } else if (err != ESP_OK) { - printf("Internal error: %s\n", esp_err_to_name(err)); - } - /* linenoise allocates line buffer on the heap, so need to free it */ - linenoiseFree(line); - } + /* Start the REPL task that was created (but left blocked) by + * esp_console_new_repl_uart. Without this call the task would wait + * forever, leaking its 4 KB stack and TCB. */ + ESP_ERROR_CHECK(esp_console_start_repl(repl)); + /* app_main can now return; the REPL task handles console I/O from here. */ } diff --git a/examples/bluetooth/nimble/throughput_app/gatt/blecent_throughput/main/misc.c b/examples/bluetooth/nimble/throughput_app/gatt/blecent_throughput/main/misc.c index 1b8ba43a4b6..af1ece8ca81 100644 --- a/examples/bluetooth/nimble/throughput_app/gatt/blecent_throughput/main/misc.c +++ b/examples/bluetooth/nimble/throughput_app/gatt/blecent_throughput/main/misc.c @@ -28,30 +28,44 @@ peer_addr_parse(const char *addr_str, uint8_t addr[PEER_ADDR_VAL_SIZE]) void print_bytes(const uint8_t *bytes, int len) { + /* Build the entire hex string into a buffer first and log it in one call. + * Calling MODLOG_DFLT per byte adds a full log header and newline to each + * byte, breaking the intended colon-separated format and blocking the CPU. */ + char buf[256]; + int pos = 0; int i; - for (i = 0; i < len; i++) { - MODLOG_DFLT(DEBUG, "%s0x%02x", i != 0 ? ":" : "", bytes[i]); + for (i = 0; i < len && pos < (int)(sizeof(buf) - 5); i++) { + if (i != 0) { + buf[pos++] = ':'; + } + pos += snprintf(buf + pos, sizeof(buf) - pos, "0x%02x", bytes[i]); } + buf[pos] = '\0'; + MODLOG_DFLT(DEBUG, "%s", buf); } void print_mbuf(const struct os_mbuf *om) { - int colon, i; + char buf[512]; + int pos = 0; + int colon = 0; + int i; - colon = 0; - while (om != NULL) { - if (colon) { - MODLOG_DFLT(INFO, ":"); - } else { - colon = 1; - } - for (i = 0; i < om->om_len; i++) { - MODLOG_DFLT(INFO, "%s0x%02x", i != 0 ? ":" : "", om->om_data[i]); + while (om != NULL && pos < (int)(sizeof(buf) - 6)) { + for (i = 0; i < om->om_len && pos < (int)(sizeof(buf) - 6); i++) { + if (colon) { + buf[pos++] = ':'; + } else { + colon = 1; + } + pos += snprintf(buf + pos, sizeof(buf) - pos, "0x%02x", om->om_data[i]); } om = SLIST_NEXT(om, om_next); } + buf[pos] = '\0'; + MODLOG_DFLT(INFO, "%s", buf); } char * diff --git a/examples/bluetooth/nimble/throughput_app/gatt/blecent_throughput/main/peer.c b/examples/bluetooth/nimble/throughput_app/gatt/blecent_throughput/main/peer.c index af34f8e5821..3ef5fda13f2 100644 --- a/examples/bluetooth/nimble/throughput_app/gatt/blecent_throughput/main/peer.c +++ b/examples/bluetooth/nimble/throughput_app/gatt/blecent_throughput/main/peer.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -40,7 +40,7 @@ chr_end_handle(const struct peer_svc *svc, const struct peer_chr *chr); int chr_is_empty(const struct peer_svc *svc, const struct peer_chr *chr); static struct peer_chr * -peer_chr_find(const struct peer_svc *svc, uint16_t chr_def_handle, +peer_chr_find(const struct peer_svc *svc, uint16_t chr_val_handle, struct peer_chr **out_prev); static void peer_disc_chrs(struct peer *peer); @@ -168,7 +168,7 @@ peer_dsc_add(struct peer *peer, uint16_t chr_val_handle, if (prev == NULL) { SLIST_INSERT_HEAD(&chr->dscs, dsc, next); } else { - SLIST_NEXT(prev, next) = dsc; + SLIST_INSERT_AFTER(prev, dsc, next); } return 0; @@ -197,6 +197,7 @@ peer_disc_dscs(struct peer *peer) peer_dsc_disced, peer); if (rc != 0) { peer_disc_complete(peer, rc); + return; } peer->disc_prev_chr_val = chr->chr.val_handle; @@ -340,7 +341,7 @@ peer_chr_add(struct peer *peer, uint16_t svc_start_handle, return BLE_HS_EUNKNOWN; } - chr = peer_chr_find(svc, gatt_chr->def_handle, &prev); + chr = peer_chr_find(svc, gatt_chr->val_handle, &prev); if (chr != NULL) { /* Characteristic already discovered. */ return 0; @@ -408,13 +409,20 @@ peer_disc_chrs(struct peer *peer) struct peer_svc *svc; int rc; - /* Search through the list of discovered service for the first service that - * contains undiscovered characteristics. Then, discover all - * characteristics belonging to that service. - */ + /* Advance cur_svc to the next service to discover characteristics for. + * Starting from NULL means start from the first service in the list. + * This sequential approach prevents re-processing services that had no + * characteristics (where SLIST_EMPTY would remain true and cause an + * infinite loop with the old SLIST_FOREACH-from-start approach). */ + if (peer->cur_svc == NULL) { + peer->cur_svc = SLIST_FIRST(&peer->svcs); + } else { + peer->cur_svc = SLIST_NEXT(peer->cur_svc, next); + } - SLIST_FOREACH(svc, &peer->svcs, next) { - if (!peer_svc_is_empty(svc) && SLIST_EMPTY(&svc->chrs)) { + /* Scan forward past empty services to find the next one to process */ + for (svc = peer->cur_svc; svc != NULL; svc = SLIST_NEXT(svc, next)) { + if (!peer_svc_is_empty(svc)) { peer->cur_svc = svc; rc = ble_gattc_disc_all_chrs(peer->conn_handle, svc->svc.start_handle, @@ -600,9 +608,10 @@ peer_disc_incs(struct peer *peer) peer->cur_svc = SLIST_NEXT(peer->cur_svc, next); if (peer->cur_svc == NULL) { if (peer->disc_prev_chr_val > 0) { + /* cur_svc is already NULL: peer_disc_chrs starts from first svc */ peer_disc_chrs(peer); - return; } + return; /* Always return; don't fall through into svc processing */ } } @@ -613,10 +622,18 @@ peer_disc_incs(struct peer *peer) svc->svc.end_handle, peer_inc_disced, peer); if (rc != 0) { + /* Hard error: skip to characteristic discovery from beginning */ + peer->cur_svc = NULL; peer_disc_chrs(peer); } + } else if (svc != NULL) { + /* svc is empty: advance to next service for include discovery */ + peer_disc_incs(peer); } else { - peer_disc_chrs(peer); + /* cur_svc is NULL on entry: no services at all */ + if (peer->disc_prev_chr_val > 0) { + peer_disc_chrs(peer); + } } } #endif @@ -690,8 +707,12 @@ peer_svc_find_uuid(const struct peer *peer, const ble_uuid_t *uuid) { const struct peer_svc *svc; + if (peer == NULL || uuid == NULL) { + return NULL; + } + SLIST_FOREACH(svc, &peer->svcs, next) { - if ((uuid != NULL) && (ble_uuid_cmp(&(svc->svc.uuid.u), uuid) == 0)) { + if (ble_uuid_cmp(&(svc->svc.uuid.u), uuid) == 0) { return svc; } } @@ -727,6 +748,10 @@ peer_dsc_find_uuid(const struct peer *peer, const ble_uuid_t *svc_uuid, const struct peer_chr *chr; const struct peer_dsc *dsc; + if (peer == NULL) { + return NULL; + } + chr = peer_chr_find_uuid(peer, svc_uuid, chr_uuid); if (chr == NULL) { return NULL; @@ -816,6 +841,7 @@ peer_svc_disced(uint16_t conn_handle, const struct ble_gatt_error *error, #else /* All services discovered; start discovering characteristics. */ if (peer->disc_prev_chr_val > 0) { + peer->cur_svc = NULL; peer_disc_chrs(peer); } #endif @@ -920,6 +946,8 @@ peer_add(uint16_t conn_handle) static void peer_free_mem(void) { + SLIST_INIT(&peers); + free(peer_mem); peer_mem = NULL; diff --git a/examples/bluetooth/nimble/throughput_app/gatt/blecent_throughput/main/scli.c b/examples/bluetooth/nimble/throughput_app/gatt/blecent_throughput/main/scli.c index 1366f964818..f163708473a 100644 --- a/examples/bluetooth/nimble/throughput_app/gatt/blecent_throughput/main/scli.c +++ b/examples/bluetooth/nimble/throughput_app/gatt/blecent_throughput/main/scli.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -102,7 +102,7 @@ static int conn_mtu_handler(int argc, char *argv[]) static int throughput_demo_handler(int argc, char *argv[]) { - char pkey[8]; + char pkey[8] = {0}; struct cli_msg msg = { .type = CLI_MSG_TYPE_THROUGHPUT, }; @@ -111,7 +111,15 @@ static int throughput_demo_handler(int argc, char *argv[]) return -1; } - sscanf(argv[1], "%7s", pkey); + if (cli_handle == NULL) { + ESP_LOGE("CLI", "Queue not initialized"); + return -1; + } + + if (sscanf(argv[1], "%7s", pkey) != 1) { + ESP_LOGE("CLI", "Failed to parse throughput type"); + return -1; + } if (strcmp(pkey, "read") == 0) { msg.data.key[0] = 1; @@ -133,14 +141,17 @@ static int throughput_demo_handler(int argc, char *argv[]) static int yesno_handler(int argc, char *argv[]) { - char yesno[4]; + char yesno[4] = {0}; bool yes; if (argc != 2) { return -1; } - sscanf(argv[1], "%3s", yesno); + if (sscanf(argv[1], "%3s", yesno) != 1) { + ESP_LOGE("CLI", "Failed to parse yes/no argument"); + return -1; + } if (strcmp(yesno, "Yes") == 0 || strcmp(yesno, "YES") == 0 || strcmp(yesno, "yes") == 0) { yes = 1; @@ -151,23 +162,29 @@ static int yesno_handler(int argc, char *argv[]) } ESP_LOGI("User entered", "%s %s", argv[0], yesno); - /* Send as 24-byte buffer to match queue item size */ - uint8_t yesno_buf[24] = {0}; - yesno_buf[0] = (uint8_t)yes; + /* Use struct cli_msg to exactly match the queue item size (sizeof(struct cli_msg)) + * and avoid stack buffer over-read from sending undersized raw buffers. */ + struct cli_msg msg = { + .type = CLI_MSG_TYPE_YESNO, + .data.yes = yes, + }; if (cli_handle) { - xQueueSend(cli_handle, yesno_buf, 500 / portTICK_PERIOD_MS); + xQueueSend(cli_handle, &msg, 500 / portTICK_PERIOD_MS); } return 0; } int scli_receive_yesno(bool *console_key) { - /* Receive into temporary 24-byte buffer to match queue item size, - * then extract bool value to prevent buffer overflow */ - uint8_t temp_buf[24]; - int ret = xQueueReceive(cli_handle, temp_buf, YES_NO_PARAM); + struct cli_msg msg; + int ret; + + if (cli_handle == NULL) { + return pdFALSE; + } + ret = xQueueReceive(cli_handle, &msg, YES_NO_PARAM); if (ret == pdPASS) { - *console_key = (bool)temp_buf[0]; /* Extract first byte as bool */ + *console_key = msg.data.yes; } return ret; } @@ -175,6 +192,9 @@ int scli_receive_yesno(bool *console_key) int scli_receive_key(int console_key[6]) { struct cli_msg msg; + if (cli_handle == NULL) { + return 0; + } if (xQueueReceive(cli_handle, &msg, BLE_RX_PARAM) != pdTRUE) { return 0; } @@ -198,6 +218,9 @@ int scli_receive_key(int console_key[6]) int cli_receive_key(int console_key[6]) { struct cli_msg msg; + if (cli_handle == NULL) { + return 0; + } if (xQueueReceive(cli_handle, &msg, BLE_RX_TIMEOUT) != pdTRUE) { return 0; } diff --git a/examples/bluetooth/nimble/throughput_app/gatt/bleprph_throughput/main/main.c b/examples/bluetooth/nimble/throughput_app/gatt/bleprph_throughput/main/main.c index a17495cc464..9fa5242aa75 100644 --- a/examples/bluetooth/nimble/throughput_app/gatt/bleprph_throughput/main/main.c +++ b/examples/bluetooth/nimble/throughput_app/gatt/bleprph_throughput/main/main.c @@ -67,10 +67,17 @@ ext_get_data(uint8_t ext_adv_pattern[], int size) int rc; data = os_msys_get_pkthdr(size, 0); - assert(data); + if (!data) { + ESP_LOGE(tag, "ext_get_data: mbuf alloc failed"); + return NULL; + } rc = os_mbuf_append(data, ext_adv_pattern, size); - assert(rc == 0); + if (rc != 0) { + ESP_LOGE(tag, "ext_get_data: mbuf_append failed; rc=%d", rc); + os_mbuf_free_chain(data); + return NULL; + } return data; } @@ -146,13 +153,16 @@ ext_bleprph_advertise(void) /*enable connectable advertising for all Phy*/ params.connectable = 1; - /* advertise using random addr */ - params.own_addr_type = BLE_OWN_ADDR_PUBLIC; + /* Use dynamically inferred address type (set in gatts_on_sync via ble_hs_id_infer_auto) */ + params.own_addr_type = gatts_addr_type; /* Set current phy; get mbuf for scan rsp data; fill mbuf with scan rsp data */ params.primary_phy = BLE_HCI_LE_PHY_1M_PREF_MASK ; params.secondary_phy = BLE_HCI_LE_PHY_2M_PREF_MASK ; data = ext_get_data(ext_adv_pattern, sizeof(ext_adv_pattern)); + if (!data) { + return; + } params.sid = 0; params.itvl_min = BLE_GAP_ADV_FAST_INTERVAL1_MIN; @@ -281,7 +291,11 @@ notify_task(void *arg) /* Memory not available for mbuf, yield briefly */ vTaskDelay(1); } - } while (om == NULL); + } while (om == NULL && notify_state); + if (om == NULL) { + /* notify_state went false while waiting; stop test */ + break; + } rc = ble_gatts_notify_custom(conn_handle, notify_handle, om); if (rc != 0) { @@ -347,12 +361,14 @@ gatts_gap_event(struct ble_gap_event *event, void *arg) } if (event->connect.status != 0) { - /* Connection failed; resume advertising */ + /* Connection failed; resume advertising. Skip HCI/conn_handle + * updates since the connection handle is invalid on failure. */ #if CONFIG_EXAMPLE_EXTENDED_ADV ext_bleprph_advertise(); #else gatts_advertise(); #endif + break; } rc = ble_hs_hci_util_set_data_len(event->connect.conn_handle, @@ -418,10 +434,15 @@ gatts_gap_event(struct ble_gap_event *event, void *arg) } } else { ESP_LOGI(tag, "Notifications disabled"); + /* Wake up notify_task so it can exit the test loop cleanly; + * without this the task would block forever on ulTaskNotifyTake. */ + if (notify_task_handle) { + xTaskNotifyGive(notify_task_handle); + } } - } else if (event->subscribe.attr_handle != notify_handle) { - notify_state = event->subscribe.cur_notify; } + /* Do NOT modify notify_state for other characteristics: that would + * corrupt the throughput test state while it is running. */ break; case BLE_GAP_EVENT_NOTIFY_TX: @@ -532,7 +553,8 @@ void app_main(void) BaseType_t task_rc = xTaskCreate(notify_task, "notify_task", 4096, NULL, 10, ¬ify_task_handle); if (task_rc != pdPASS) { ESP_LOGE(tag, "Failed to create notify_task (rc=%d)", task_rc); - return ; + nimble_port_deinit(); + return; } #if MYNEWT_VAL(BLE_GATTS) rc = gatt_svr_init(); diff --git a/examples/bluetooth/nimble/throughput_app/l2cap_coc/l2cap_coc_cent/main/main.c b/examples/bluetooth/nimble/throughput_app/l2cap_coc/l2cap_coc_cent/main/main.c index 09f2c989884..1fb92ff086b 100644 --- a/examples/bluetooth/nimble/throughput_app/l2cap_coc/l2cap_coc_cent/main/main.c +++ b/examples/bluetooth/nimble/throughput_app/l2cap_coc/l2cap_coc_cent/main/main.c @@ -22,7 +22,7 @@ static const char *TAG = "l2cap_coc_cent"; -#define L2CAP_COC_PSM 0x1002 +#define L2CAP_COC_PSM 0x0080 /* valid dynamic LE L2CAP CoC PSM (0x0080-0x00FF) */ #define L2CAP_COC_MTU CONFIG_EXAMPLE_L2CAP_COC_MTU #define COC_BUF_COUNT (6 * MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)) /* Block size must include mbuf headers so each SDU fits in one pool entry. */ @@ -130,12 +130,9 @@ static void cent_l2cap_coc_connect(uint16_t conn_handle) if (rc != 0) { ESP_LOGE(TAG, "L2CAP COC connect failed; rc=%d", rc); l2cap_connecting = false; - /* EINVAL: NimBLE returns before chan alloc, sdu_rx not consumed — free it. - * ENOTCONN: NimBLE frees sdu_rx on all ENOTCONN paths (early !conn check - * and late TX failure via ble_l2cap_coc_cleanup_chan). Do not free here. */ - if (rc == BLE_HS_EINVAL) { - os_mbuf_free_chain(sdu_rx); - } + /* NimBLE takes ownership of sdu_rx on ALL error paths from ble_l2cap_connect + * (freed via ble_l2cap_chan_free → ble_l2cap_coc_cleanup_chan or directly in + * ble_l2cap_sig_coc_connect validation). Never free here to avoid double-free. */ } } @@ -713,6 +710,8 @@ void app_main(void) ret = nimble_port_init(); if (ret != ESP_OK) { ESP_LOGE(TAG, "nimble_port_init failed; rc=%d", ret); + vEventGroupDelete(coc_event_group); + coc_event_group = NULL; return; } @@ -731,6 +730,9 @@ void app_main(void) if (xTaskCreate(cent_send_task, "cent_send_task", 4096, NULL, 5, NULL) != pdPASS) { ESP_LOGE(TAG, "Failed to create cent_send_task"); + nimble_port_deinit(); + vEventGroupDelete(coc_event_group); + coc_event_group = NULL; return; } diff --git a/examples/bluetooth/nimble/throughput_app/l2cap_coc/l2cap_coc_prph/main/main.c b/examples/bluetooth/nimble/throughput_app/l2cap_coc/l2cap_coc_prph/main/main.c index 99767c15b84..0ea0a1cbf8d 100644 --- a/examples/bluetooth/nimble/throughput_app/l2cap_coc/l2cap_coc_prph/main/main.c +++ b/examples/bluetooth/nimble/throughput_app/l2cap_coc/l2cap_coc_prph/main/main.c @@ -20,7 +20,7 @@ static const char *TAG = "l2cap_coc_prph"; -#define L2CAP_COC_PSM 0x1002 +#define L2CAP_COC_PSM 0x0080 /* valid dynamic LE L2CAP CoC PSM (0x0080-0x00FF) */ #define L2CAP_COC_MTU CONFIG_EXAMPLE_L2CAP_COC_MTU #define COC_BUF_COUNT (6 * MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)) /* Block size must include mbuf headers so each SDU fits in one pool entry. */ @@ -149,7 +149,11 @@ static void prph_advertise(void) fields.name_len = strlen(name); fields.name_is_complete = 1; #endif - fields.uuids16 = (ble_uuid16_t[]){ BLE_UUID16_INIT(L2CAP_COC_UUID) }; + /* Must be static: ble_gap_adv_set_fields copies the pointer, not the data. + * A stack compound literal becomes dangling after prph_advertise returns, + * causing corruption when BLE_NIMBLE_ENABLE_CONN_REATTEMPT re-uses the pointer. */ + static const ble_uuid16_t adv_uuids16[] = { BLE_UUID16_INIT(L2CAP_COC_UUID) }; + fields.uuids16 = adv_uuids16; fields.num_uuids16 = 1; fields.uuids16_is_complete = 1; @@ -188,7 +192,11 @@ static int prph_l2cap_coc_accept(struct ble_l2cap_chan *chan) return BLE_HS_ENOMEM; } int rc = ble_l2cap_recv_ready(chan, sdu_rx); - if (rc != 0) { + /* ble_l2cap_coc_recv_ready stores sdu_rx AFTER the BLE_HS_EBUSY check but + * BEFORE the BLE_HS_ENOENT check. On BLE_HS_EBUSY the buffer was never + * stored and must be freed here; on success or BLE_HS_ENOENT the buffer is + * owned by chan->coc_rx.sdus[] and freed by ble_l2cap_coc_cleanup_chan. */ + if (rc != 0 && rc != BLE_HS_ENOENT) { os_mbuf_free_chain(sdu_rx); } return rc;