fix(nimble): Fix vulnerabilities in NimBLE examples

This commit is contained in:
Shreeyash
2026-01-22 15:36:50 +05:30
parent 41f15f5329
commit bd971c5d0e
43 changed files with 894 additions and 317 deletions
@@ -18,6 +18,7 @@
void send_heart_rate_indication(void);
void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg);
void gatt_svr_subscribe_cb(struct ble_gap_event *event);
void gatt_svr_reset_heart_rate_subscription(void);
int gatt_svc_init(void);
#endif // GATT_SVR_H
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -80,7 +80,7 @@ static void heart_rate_task(void *param) {
void app_main(void) {
/* Local variables */
int rc = 0;
BaseType_t rc = 0;
esp_err_t ret;
/* LED initialization */
@@ -129,7 +129,17 @@ 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);
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;
}
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;
}
@@ -186,6 +186,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;
@@ -23,7 +23,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;
@@ -240,6 +240,12 @@ void gatt_svr_subscribe_cb(struct ble_gap_event *event) {
}
}
void gatt_svr_reset_heart_rate_subscription(void) {
heart_rate_chr_conn_handle = BLE_HS_CONN_HANDLE_NONE;
heart_rate_chr_conn_handle_inited = false;
heart_rate_ind_status = false;
}
/*
* GATT server initialization
* 1. Initialize GATT service
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -103,7 +103,7 @@ char *CategoryID_to_String(uint8_t CategoryID)
void ble_receive_apple_notification_source(uint8_t *message, uint16_t message_len)
{
if (!message || message_len < 5) {
if (!message || message_len < 8) {
return;
}
@@ -126,14 +126,19 @@ void ble_receive_apple_data_source(uint8_t *message, uint16_t message_len)
switch (Command_id)
{
case CommandIDGetNotificationAttributes: {
if (message_len < 5) {
ESP_LOGE(NimBLE_ANCS_TAG, "Invalid message length for attributes: %d",
message_len);
return;
}
uint32_t NotificationUID = (message[1]) | (message[2]<< 8) | (message[3]<< 16) | (message[4] << 24);
uint32_t remian_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(remian_attr_len > 0) {
while(remian_attr_len >= 3) {
uint8_t AttributeID = attrs[0];
uint16_t len = attrs[1] | (attrs[2] << 8);
if(len > (remian_attr_len -3)) {
if(len > remian_attr_len - 3) {
ESP_LOGE(NimBLE_ANCS_TAG, "data error");
break;
}
+17 -11
View File
@@ -72,7 +72,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, 0x11,
0x0e, BLE_HS_ADV_TYPE_COMP_NAME, 'n', 'i', 'm', 'b', 'l', 'e', '-', 'a', 'n', 'c', 's', '-', 'e',
0x0d, BLE_HS_ADV_TYPE_COMP_NAME, 'n', 'i', 'm', 'b', 'l', 'e', '-', 'a', 'n', 'c', 's', '-', 'e',
};
#endif
@@ -338,14 +338,14 @@ ext_ble_ancs_advertise(void)
}
/* use defaults for non-set params */
memset (&params, 0, sizeof(params));
memset(&params, 0, sizeof(params));
/* enable connectable advertising */
/* enable connectable, scannable advertising */
params.connectable = 1;
params.scannable = 1;
/* advertise using random addr */
/* advertise using configured addr */
params.own_addr_type = BLE_OWN_ADDR_PUBLIC;
params.primary_phy = BLE_HCI_LE_PHY_1M;
params.secondary_phy = BLE_HCI_LE_PHY_2M;
params.tx_power = 127;
@@ -359,8 +359,6 @@ ext_ble_ancs_advertise(void)
ble_ancs_gap_event, NULL);
assert (rc == 0);
/* in this case only scan response is allowed */
/* get mbuf for scan rsp data */
data = os_msys_get_pkthdr(sizeof(ext_adv_pattern_1), 0);
assert(data);
@@ -369,7 +367,7 @@ ext_ble_ancs_advertise(void)
rc = os_mbuf_append(data, ext_adv_pattern_1, sizeof(ext_adv_pattern_1));
assert(rc == 0);
rc = ble_gap_ext_adv_set_data(instance, data);
rc = ble_gap_ext_adv_rsp_set_data(instance, data);
assert (rc == 0);
/* start advertising */
@@ -578,10 +576,18 @@ ble_ancs_gap_event(struct ble_gap_event *event, void *arg)
notificationUID, sizeof(p_attr)/sizeof(ble_noti_attr_list_t), p_attr);
}
} else if (event->notify_rx.attr_handle == data_source_handle) {
uint16_t new_len = data_buffer.len + event->notify_rx.om->om_len;
if (new_len > sizeof(data_buffer.buffer)) {
MODLOG_DFLT(ERROR, "data_buffer overflow: %d + %d > %d",
data_buffer.len, event->notify_rx.om->om_len,
(int)sizeof(data_buffer.buffer));
data_buffer.len = 0;
return 0;
}
memcpy(&data_buffer.buffer[data_buffer.len],
event->notify_rx.om->om_data,
event->notify_rx.om->om_len);
data_buffer.len += event->notify_rx.om->om_len;
event->notify_rx.om->om_data,
event->notify_rx.om->om_len);
data_buffer.len = new_len;
if (event->notify_rx.om->om_len == (MTU_size - 3)) {
esp_timer_start_periodic(periodic_timer, 500000);
@@ -69,14 +69,16 @@ int blecent_on_subscribe(uint16_t conn_handle,
MODLOG_DFLT(INFO, "Subscribe complete; status=%d conn_handle=%d "
"attr_handle=%d\n",
error->status, conn_handle, attr->handle);
subscribe_all++;
if (subscribe_all == 4){
struct ble_cs_initiator_procedure_start_params param;
memset(&param,0,sizeof param);
param.conn_handle=conn_handle;
param.cb=blecs_gap_event;
param.cb_arg=NULL;
ble_cs_initiator_procedure_start(&param);
if (error->status == 0) {
subscribe_all++;
if (subscribe_all == 4){
struct ble_cs_initiator_procedure_start_params param;
memset(&param,0,sizeof param);
param.conn_handle=conn_handle;
param.cb=blecs_gap_event;
param.cb_arg=NULL;
ble_cs_initiator_procedure_start(&param);
}
}
return 0;
@@ -161,13 +163,16 @@ blecent_on_custom_read(uint16_t conn_handle,
MODLOG_DFLT(INFO, "Read complete RAS FEATURES; status=%d conn_handle=%d", error->status, conn_handle);
if (error->status == 0) {
uint32_t var;
uint32_t var = 0;
int rc = 0;
if (attr->om && OS_MBUF_PKTLEN(attr->om) > 0) {
os_mbuf_copydata(attr->om, 0, OS_MBUF_PKTLEN(attr->om), &var);
} else {
MODLOG_DFLT(ERROR, "Error: No data in the attribute\n");
}
uint16_t pktlen = (attr->om ? OS_MBUF_PKTLEN(attr->om) : 0);
if (attr->om && pktlen > 0 && pktlen <= sizeof(var)) {
os_mbuf_copydata(attr->om, 0, pktlen, &var);
}
else {
MODLOG_DFLT(ERROR, "Error: Invalid data length=%u in the attribute\n", pktlen);
return -1;
}
MODLOG_DFLT(INFO, " attr_handle = %u value = %" PRIu32, attr->handle, var);
if (var & REAL_TIME_RANGING_DATA_BIT) {
@@ -400,8 +405,8 @@ static int blecs_gap_event(struct ble_cs_event *event, void *arg){
return 0;
}
if (event->subev_result.num_steps_reported) {
memcpy(&local_cs_steps_data, event->subev_result.steps, sizeof local_cs_steps_data);
size_t copy_size = event->subev_result.num_steps_reported * sizeof(struct cs_steps_data);
memcpy(&local_cs_steps_data, event->subev_result.steps, MIN(copy_size, sizeof(local_cs_steps_data)));
}
nap=event->subev_result.num_antenna_paths;
most_recent_local_ranging_counter=event->subev_result.procedure_counter;
@@ -486,6 +491,7 @@ blecent_gap_event(struct ble_gap_event *event, void *arg)
return 0;
}
connh = event->connect.conn_handle;
subscribe_all = 0;
rc = ble_gap_security_initiate(event->connect.conn_handle);
if (rc != 0) {
MODLOG_DFLT(INFO, "Security could not be initiated, rc = %d\n", rc);
@@ -580,7 +586,7 @@ blecent_gap_event(struct ble_gap_event *event, void *arg)
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=0;
most_recent_local_ranging_counter= ranging_counter;
if (most_recent_peer_ranging_counter!=most_recent_local_ranging_counter) {
MODLOG_DFLT(INFO, "Ranging counter mismatch : %" PRId32 " , %" PRId32,
@@ -601,14 +607,26 @@ blecent_gap_event(struct ble_gap_event *event, void *arg)
} else if (ble_svc_ras_od_val_handle == event->notify_rx.attr_handle) {
MODLOG_DFLT(INFO, "Received On Demand Ranging Data\n");
struct segment ras_segment;
int notif_len = OS_MBUF_PKTLEN(event->notify_rx.om);
os_mbuf_copydata(event->notify_rx.om, 0,notif_len , &ras_segment);
MODLOG_DFLT(INFO, "Received On Demand Ranging Data , len = %d\n",notif_len);
uint8_t * data= (uint8_t *)ras_segment.data;
for(int i=0;i<notif_len-sizeof(struct segment_header);i++){
MODLOG_DFLT(INFO, "data[%d] = %d\n",i,data[i]);
#define RAS_OD_RX_BUF_MAX 512
if (notif_len >= sizeof(struct segment_header) && notif_len <= RAS_OD_RX_BUF_MAX) {
uint8_t ras_buf[RAS_OD_RX_BUF_MAX];
int rc_copy = os_mbuf_copydata(event->notify_rx.om, 0, notif_len, ras_buf);
if (rc_copy == 0) {
uint8_t *data = ras_buf + sizeof(struct segment_header);
size_t data_len = notif_len - sizeof(struct segment_header);
MODLOG_DFLT(INFO,
"Received On Demand Ranging Data , len = %d\n",
notif_len);
for (size_t i = 0; i < data_len; i++) {
MODLOG_DFLT(INFO, "data[%d] = %d\n", (int)i, data[i]);
}
}
}
#undef RAS_OD_RX_BUF_MAX
/*
handle the incoming notification
@@ -116,8 +116,9 @@ static int blecs_gap_event(struct ble_cs_event *event, void *arg)
most_recent_local_ranging_counter=event->subev_result.procedure_counter;
} else if(event->subev_result.procedure_done_status == BLE_HCI_LE_CS_SUBEVENT_DONE_STATUS_PARTIAL) {
ranging_subevent.type=BLE_CS_EVENT_SUBEVET_RESULT;
ranging_subevent.subev_result= event->subev_result;
memset(&ranging_subevent, 0, sizeof(ranging_subevent));
ranging_subevent.type = BLE_CS_EVENT_SUBEVET_RESULT;
ranging_subevent.subev_result = event->subev_result;
idx++;
if (idx==1) {
most_recent_local_ranging_counter=event->subev_result.procedure_counter;
@@ -133,6 +134,7 @@ 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
@@ -81,7 +81,11 @@ uint8_t antenna_signal_index[4] = {CTE_ANT0_IDX, CTE_ANT1_IDX, CTE_ANT2_IDX, CTE
int ble_direction_finding_antenna_init(uint8_t* gpio_array,uint8_t gpio_array_len){
int rc;
// GPIO configuration
uint32_t gpio_pin_maks = 0;
uint64_t gpio_pin_maks = 0;
if (!gpio_array || gpio_array_len > 4 || gpio_array_len == 0) {
return ESP_ERR_INVALID_ARG;
}
for (int i = 0; i < gpio_array_len; i++){
gpio_pin_maks |= (1ULL << gpio_array[i]);
}
@@ -95,6 +99,7 @@ int ble_direction_finding_antenna_init(uint8_t* gpio_array,uint8_t gpio_array_le
rc = gpio_config(&gpio_conf);
if(rc != 0) {
ESP_LOGE("DF","config fault GPIO failed");
return rc;
}
// gpio bind signal
for (int i = 0; i < gpio_array_len; i++){
@@ -19,8 +19,8 @@
static const char *tag = "NimBLE_CTS_CENT";
static int ble_cts_cent_gap_event(struct ble_gap_event *event, void *arg);
static char *day_of_week[7] = {
"Unknown"
static char *day_of_week[8] = {
"Unknown",
"Monday",
"Tuesday",
"Wednesday",
@@ -33,10 +33,14 @@ void ble_store_config_init(void);
static void ble_cts_cent_scan(void);
void printtime(struct ble_svc_cts_curr_time ctime) {
uint8_t dow = ctime.et_256.d_d_t.day_of_week;
const char *dow_str = (dow >= 1 && dow <= 7) ? day_of_week[dow] : day_of_week[0];
if (dow >= 8) {
dow = 0;
}
ESP_LOGI(tag, "Date : %d/%d/%d %s", ctime.et_256.d_d_t.d_t.day,
ctime.et_256.d_d_t.d_t.month,
ctime.et_256.d_d_t.d_t.year,
day_of_week[ctime.et_256.d_d_t.day_of_week]);
ctime.et_256.d_d_t.d_t.year, dow_str);
ESP_LOGI(tag, "hours : %d minutes : %d ",
ctime.et_256.d_d_t.d_t.hours,
ctime.et_256.d_d_t.d_t.minutes);
@@ -55,6 +59,7 @@ ble_cts_cent_on_read(uint16_t conn_handle,
struct ble_gatt_attr *attr,
void *arg)
{
int rc = 0;
struct ble_svc_cts_curr_time ctime; /* store the read time */
MODLOG_DFLT(INFO, "Read Current time complete; status=%d conn_handle=%d\n",
error->status, conn_handle);
@@ -66,8 +71,12 @@ ble_cts_cent_on_read(uint16_t conn_handle,
goto err;
}
MODLOG_DFLT(INFO, "\n");
ble_hs_mbuf_to_flat(attr->om, &ctime, sizeof(ctime), NULL);
printtime(ctime);
rc = ble_hs_mbuf_to_flat(attr->om, &ctime, sizeof(ctime), NULL);
if (rc == 0 && ctime.et_256.d_d_t.day_of_week <= 7) {
printtime(ctime);
} else {
MODLOG_DFLT(WARN, "Invalid CTS time data; rc=%d day_of_week=%d\n", rc, ctime.et_256.d_d_t.day_of_week);
}
return 0;
err:
/* Terminate the connection. */
@@ -234,7 +243,7 @@ ext_ble_cts_cent_should_connect(const struct ble_gap_ext_disc_desc *disc)
/* Search if cts UUID is advertised */
if (disc->data[offset + 1] == 0x03) {
int temp = 2;
while(temp < disc->data[offset + 1]) {
while (temp < ad_struct_len) {
if(disc->data[offset + temp] == 0x05 &&
disc->data[offset + temp + 1] == 0x18) {
return 1;
@@ -491,7 +500,7 @@ ble_cts_cent_gap_event(struct ble_gap_event *event, void *arg)
#else
#if MYNEWT_VAL(BLE_GATTC)
/*** Go for service discovery after encryption has been successfully enabled ***/
rc = peer_disc_all(event->connect.conn_handle,
rc = peer_disc_all(event->enc_change.conn_handle,
ble_cts_cent_on_disc_complete, NULL);
if (rc != 0) {
MODLOG_DFLT(ERROR, "Failed to discover services; rc=%d\n", rc);
@@ -510,7 +519,7 @@ ble_cts_cent_gap_event(struct ble_gap_event *event, void *arg)
event->cache_assoc.status,
(event->cache_assoc.cache_state == 0) ? "INVALID" : "LOADED");
/* Perform service discovery */
rc = peer_disc_all(event->connect.conn_handle,
rc = peer_disc_all(event->cache_assoc.conn_handle,
blecent_on_disc_complete, NULL);
if(rc != 0) {
MODLOG_DFLT(ERROR, "Failed to discover services; rc=%d\n", rc);
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2017-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -16,6 +16,7 @@
#include <time.h>
#include "sys/time.h"
static const char *TAG = "CTS_GATT_SVR";
void
gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
@@ -85,7 +86,21 @@ int fetch_current_time(struct ble_svc_cts_curr_time *ctime) {
int set_current_time(struct ble_svc_cts_curr_time ctime) {
time_t now;
struct tm timeinfo;
struct timeval tv_now;
struct timeval tv_now = {0};
/* Basic sanity validation for incoming time fields */
if (ctime.et_256.d_d_t.d_t.year < 1900 ||
ctime.et_256.d_d_t.d_t.year > 9999 ||
ctime.et_256.d_d_t.d_t.month < 1 || ctime.et_256.d_d_t.d_t.month > 12 ||
ctime.et_256.d_d_t.d_t.day < 1 || ctime.et_256.d_d_t.d_t.day > 31 ||
ctime.et_256.d_d_t.d_t.hours > 23 ||
ctime.et_256.d_d_t.d_t.minutes > 59 ||
ctime.et_256.d_d_t.d_t.seconds > 59 ||
ctime.et_256.d_d_t.day_of_week < 1 || ctime.et_256.d_d_t.day_of_week > 7) {
ESP_LOGE(TAG, "Invalid current time parameters");
return -1;
}
/* fill date_time */
timeinfo.tm_year= ctime.et_256.d_d_t.d_t.year - 1900 ;
timeinfo.tm_mon = ctime.et_256.d_d_t.d_t.month - 1;
@@ -95,7 +110,12 @@ int set_current_time(struct ble_svc_cts_curr_time ctime) {
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;
now = mktime(&timeinfo);
if (now == (time_t)-1) {
ESP_LOGE(TAG, "Failed to convert current time");
return -1;
}
tv_now.tv_sec = now;
tv_now.tv_usec = 0;
settimeofday(&tv_now, NULL);
/* set the last updated */
gettimeofday(&last_updated, NULL);
@@ -102,8 +102,21 @@ enc_adv_data_cent_on_read(uint16_t conn_handle,
value_ead.km = (struct key_material *) malloc (sizeof(struct key_material));
if (value_ead.km == NULL) {
MODLOG_DFLT(ERROR, "Failed to allocate memory for key material");
goto err;
}
memset(value_ead.km, 0, sizeof(struct key_material));
/* Validate mbuf has enough data before copying */
if (attr->om == NULL || OS_MBUF_PKTLEN(attr->om) < (BLE_EAD_KEY_SIZE + BLE_EAD_IV_SIZE)) {
MODLOG_DFLT(ERROR, "Invalid mbuf or insufficient data size");
free(value_ead.km);
value_ead.km = NULL;
goto err;
}
os_mbuf_copydata(attr->om, 0, BLE_EAD_KEY_SIZE, &value_ead.km->session_key);
os_mbuf_copydata(attr->om, BLE_EAD_KEY_SIZE, BLE_EAD_IV_SIZE, &value_ead.km->iv);
@@ -120,8 +133,17 @@ enc_adv_data_cent_on_read(uint16_t conn_handle,
MODLOG_DFLT(INFO, "Writing of session key, iv, and peer addr to NVS success");
}
if (value_ead.km != NULL) {
free(value_ead.km);
value_ead.km = NULL;
}
err:
/* Terminate the connection. */
if (value_ead.km != NULL) {
free(value_ead.km);
value_ead.km = NULL;
}
return ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM);
}
@@ -244,6 +266,10 @@ enc_adv_data_cent_decrypt(uint8_t length_data, const uint8_t *data, const uint8_
switch (op) {
case BLE_GAP_ENC_ADV_DATA:
enc_data = (uint8_t *) malloc (sizeof(uint8_t) * len);
if (enc_data == NULL) {
MODLOG_DFLT(ERROR, "Failed to allocate enc_data");
return 0;
}
memcpy(enc_data, data + offset + 2, len);
memcpy(&key_ead.peer_addr.val, peer_addr, PEER_ADDR_VAL_SIZE);
@@ -262,6 +288,7 @@ enc_adv_data_cent_decrypt(uint8_t length_data, const uint8_t *data, const uint8_
MODLOG_DFLT(INFO, "Decryption of adv data done successfully");
} else {
MODLOG_DFLT(INFO, "Decryption of adv data failed");
free(enc_data);
return 0;
}
@@ -272,6 +299,7 @@ enc_adv_data_cent_decrypt(uint8_t length_data, const uint8_t *data, const uint8_
MODLOG_DFLT(INFO, "0x%02X ", temp[i]);
}
MODLOG_DFLT(INFO, "\n");
free(enc_data);
return 1;
default:
@@ -68,8 +68,8 @@ enc_adv_data_prph_print_conn_desc(struct ble_gap_conn_desc *desc)
desc->sec_state.bonded);
}
static void
enc_adv_data_prph_encrypt_set(uint8_t * out_encrypted_adv_data,
static int
enc_adv_data_prph_encrypt_set(uint8_t *out_encrypted_adv_data,
const unsigned encrypted_adv_data_len)
{
int rc;
@@ -85,13 +85,13 @@ enc_adv_data_prph_encrypt_set(uint8_t * out_encrypted_adv_data,
print_bytes(unencrypted_adv_data, unencrypted_adv_data_len);
MODLOG_DFLT(INFO, "\n");
rc = ble_ead_encrypt(km.session_key, km.iv, unencrypted_adv_data, unencrypted_adv_data_len, encrypted_adv_data);
if (rc == 0) {
MODLOG_DFLT(INFO, "Encryption of adv data done successfully");
} else {
MODLOG_DFLT(INFO, "Encryption of adv data failed");
return;
rc = ble_ead_encrypt(km.session_key, km.iv, unencrypted_adv_data,
unencrypted_adv_data_len, encrypted_adv_data);
if (rc != 0) {
MODLOG_DFLT(ERROR, "Encryption of adv data failed; rc=%d", rc);
return rc;
}
MODLOG_DFLT(INFO, "Encryption of adv data done successfully");
MODLOG_DFLT(INFO, "Data after encryption:");
print_bytes(encrypted_adv_data, encrypted_adv_data_len);
@@ -99,6 +99,7 @@ enc_adv_data_prph_encrypt_set(uint8_t * out_encrypted_adv_data,
/** Contains Randomiser ## Encrypted Advertising Data ## MIC */
memcpy(out_encrypted_adv_data, encrypted_adv_data, encrypted_adv_data_len);
return 0;
}
/**
@@ -111,7 +112,6 @@ enc_adv_data_prph_advertise(void)
{
struct ble_gap_adv_params params;
struct ble_hs_adv_fields fields;
uint8_t own_addr_type;
int rc;
const unsigned encrypted_adv_data_len = BLE_EAD_ENCRYPTED_PAYLOAD_SIZE(sizeof(unencrypted_adv_pattern));
@@ -149,7 +149,10 @@ enc_adv_data_prph_advertise(void)
fields.uuids16_is_complete = 1;
/** Getting the encrypted advertising data */
enc_adv_data_prph_encrypt_set(encrypted_adv_data, encrypted_adv_data_len);
rc = enc_adv_data_prph_encrypt_set(encrypted_adv_data, encrypted_adv_data_len);
if (rc != 0) {
return;
}
fields.enc_adv_data = encrypted_adv_data;
fields.enc_adv_data_len = encrypted_adv_data_len;
@@ -21,9 +21,20 @@ static bool 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));
if (rc != 0) {
return rc;
}
} else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC) {
static uint8_t dsc_data[1] = {0x01}; // Example descriptor value
return os_mbuf_append(ctxt->om, dsc_data, sizeof(dsc_data));
}
else if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
MODLOG_DFLT(INFO, "Characteristic written");
return 0;
}
return 0;
}
@@ -162,6 +162,10 @@ ble_htp_cent_on_read(uint16_t conn_handle,
uint16_t value;
int rc;
const struct peer *peer = peer_find(conn_handle);
if (peer == NULL) {
MODLOG_DFLT(ERROR, "Lost peer 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(BLE_SVC_HTP_UUID16),
@@ -330,7 +334,7 @@ ext_ble_htp_cent_should_connect(const struct ble_gap_ext_disc_desc *disc)
/* Conversion */
for (int i=0; i<6; i++) {
test_addr[i] = (uint8_t )peer_addr[i];
test_addr[i] = (uint8_t )peer_addr[5 - i];
}
if (memcmp(test_addr, disc->addr.val, sizeof(disc->addr.val)) != 0) {
@@ -341,23 +345,23 @@ ext_ble_htp_cent_should_connect(const struct ble_gap_ext_disc_desc *disc)
/* The device has to advertise support for the Health thermometer
* service (0x1809).
*/
do {
while (offset < disc->length_data) {
ad_struct_len = disc->data[offset];
if (!ad_struct_len) {
if (ad_struct_len == 0 || offset + ad_struct_len + 1 > disc->length_data) {
break;
}
/* Search if HTP UUID is advertised */
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 + 1] == 0x03) {
if (disc->data[offset + 2] == 0x09 && disc->data[offset + 3] == 0x18) {
return 1;
}
}
offset += ad_struct_len + 1;
} while ( offset < disc->length_data );
}
return 0;
}
@@ -605,7 +609,7 @@ ble_htp_cent_gap_event(struct ble_gap_event *event, void *arg)
#else
#if MYNEWT_VAL(BLE_GATTC)
/*** Go for service discovery after encryption has been successfully enabled ***/
rc = peer_disc_all(event->connect.conn_handle,
rc = peer_disc_all(event->enc_change.conn_handle,
ble_htp_cent_on_disc_complete, NULL);
if (rc != 0) {
MODLOG_DFLT(ERROR, "Failed to discover services; rc=%d\n", rc);
@@ -624,7 +628,7 @@ ble_htp_cent_gap_event(struct ble_gap_event *event, void *arg)
event->cache_assoc.status,
(event->cache_assoc.cache_state == 0) ? "INVALID" : "LOADED");
/* Perform service discovery */
rc = peer_disc_all(event->connect.conn_handle,
rc = peer_disc_all(event->cache_assoc.conn_handle,
blecent_on_disc_complete, NULL);
if(rc != 0) {
MODLOG_DFLT(ERROR, "Failed to discover services; rc=%d\n", rc);
@@ -44,6 +44,8 @@ blecent_l2cap_coc_send_data(struct ble_l2cap_chan *chan)
int rc = 0;
int len = 512;
uint8_t value[len];
int retry = 0;
const int max_retry = 10;
for (int i = 0; i < len; i++) {
value[i] = i;
@@ -53,20 +55,32 @@ blecent_l2cap_coc_send_data(struct ble_l2cap_chan *chan)
sdu_rx_data = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0);
if (sdu_rx_data == NULL) {
vTaskDelay(10 / portTICK_PERIOD_MS);
sdu_rx_data = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0);
retry++;
}
} while (sdu_rx_data == NULL);
} while (sdu_rx_data == NULL && retry < max_retry);
if (sdu_rx_data == NULL) {
MODLOG_DFLT(ERROR, "Failed to alloc mbuf after %d retries", max_retry);
return;
}
os_mbuf_append(sdu_rx_data, value, len);
print_mbuf_data(sdu_rx_data);
rc = ble_l2cap_send(chan, sdu_rx_data);
while (rc == BLE_HS_ESTALLED) {
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);
return;
}
if (rc == 0) {
MODLOG_DFLT(INFO, "Data sent successfully");
} else {
@@ -75,6 +89,7 @@ blecent_l2cap_coc_send_data(struct ble_l2cap_chan *chan)
}
}
/**
* After connection is established on GAP layer, service discovery is performed. On
* it's completion, this API is called for making a connection is on L2CAP layer.
@@ -83,11 +98,25 @@ static void
blecent_l2cap_coc_on_disc_complete(const struct peer *peer, int status, void *arg)
{
uint16_t psm = 0x1002;
struct os_mbuf *sdu_rx;
struct os_mbuf *sdu_rx = NULL;
int rc;
if (status != 0) {
MODLOG_DFLT(WARN, "Service discovery failed (status=%d), skip L2CAP COC", status);
return;
}
sdu_rx = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0);
ble_l2cap_connect(conn_handle_coc, psm, MTU, sdu_rx, blecent_l2cap_coc_event_cb,
NULL);
if (sdu_rx == NULL) {
MODLOG_DFLT(ERROR, "Failed to allocate sdu_rx");
return;
}
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);
}
}
/**
@@ -265,22 +294,31 @@ ext_blecent_should_connect(const struct ble_gap_ext_disc_desc *disc)
/* The device has to advertise support for L2CAP COC UUID (0x1812).
*/
do {
if (offset + 1 > disc->length_data) {
break;
}
ad_struct_len = disc->data[offset];
if (!ad_struct_len) {
break;
}
/* Search if ANS UUID is advertised */
if (disc->data[offset] == 0x03 && disc->data[offset + 1] == 0x03) {
if ( disc->data[offset + 2] == 0x18 && disc->data[offset + 3] == 0x12 ) {
return 1;
}
if (offset + ad_struct_len + 1 > disc->length_data) {
break;
}
/* AD Type (1) + UUID16 (2) requires at least 4 bytes total */
if (ad_struct_len >= 3 &&
disc->data[offset + 1] == 0x03 &&
disc->data[offset + 2] == 0x18 &&
disc->data[offset + 3] == 0x12) {
return 1;
}
offset += ad_struct_len + 1;
} while ( offset < disc->length_data );
} while (offset < disc->length_data);
return 0;
}
#else
@@ -340,6 +340,9 @@ bleprph_gap_event(struct ble_gap_event *event, void *arg)
bleprph_print_conn_desc(&desc);
#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) >= 1
rc = ble_l2cap_create_server(psm, MTU, bleprph_l2cap_coc_event_cb, NULL);
if (rc != 0) {
MODLOG_DFLT(ERROR, "Failed to create L2CAP CoC server; rc=%d", rc);
}
#endif
}
return 0;
@@ -13,6 +13,8 @@
#include "services/gatt/ble_svc_gatt.h"
#include "multi_adv.h"
static uint8_t gatt_svr_chr_val = 0x01; /* Example characteristic value */
static const ble_uuid128_t gatt_svr_svc_uuid =
BLE_UUID128_INIT(0x2d, 0x71, 0xa2, 0x59, 0xb4, 0x58, 0xc8, 0x12,
0x99, 0x99, 0x43, 0x95, 0x12, 0x2f, 0x46, 0x59);
@@ -81,24 +83,39 @@ static int
gatt_svc_access(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg)
{
int rc = 0;
switch (ctxt->op) {
case BLE_GATT_ACCESS_OP_READ_CHR:
MODLOG_DFLT(INFO, "Characteristic read; conn_handle=%d attr_handle=%d\n",
conn_handle, attr_handle);
return 0;
rc = os_mbuf_append(ctxt->om,
&gatt_svr_chr_val,
sizeof(gatt_svr_chr_val));
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
break;
case BLE_GATT_ACCESS_OP_WRITE_CHR:
MODLOG_DFLT(INFO, "Characteristic write; conn_handle=%d attr_handle=%d",
conn_handle, attr_handle);
return 0;
rc = os_mbuf_copydata(ctxt->om,
0,
sizeof(gatt_svr_chr_val),
&gatt_svr_chr_val);
return rc == 0 ? 0 : BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
break;
case BLE_GATT_ACCESS_OP_READ_DSC:
MODLOG_DFLT(INFO, "Descriptor read; conn_handle=%d attr_handle=%d\n",
conn_handle, attr_handle);
return 0;
rc = os_mbuf_append(ctxt->om,
&gatt_svr_dsc_val,
sizeof(gatt_svr_dsc_val));
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
break;
case BLE_GATT_ACCESS_OP_WRITE_DSC:
goto unknown;
break;
default:
goto unknown;
@@ -70,6 +70,7 @@ gap_event_cb(struct ble_gap_event *event, void *arg)
uint8_t adv_handle;
uint8_t subevent;
uint8_t phy_mask;
uint8_t actual_sent = 0;
switch (event->type) {
@@ -101,26 +102,38 @@ 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;
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);
ESP_LOGE(TAG, "No memory at subevt %d", i);
// Free previously allocated data to prevent memory leak
for (uint8_t j = 0; j < actual_sent; j++) {
os_mbuf_free_chain(sub_data_params[j].data);
sub_data_params[j].data = NULL;
}
actual_sent = 0; // Do not call set_periodic_adv_subev_data
break;
}
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);
os_mbuf_append(data, sub_data_pattern, BLE_PAWR_SUB_DATA_LEN);
if (os_mbuf_append(data, sub_data_pattern, BLE_PAWR_SUB_DATA_LEN) != 0) {
os_mbuf_free_chain(data);
break;
}
sub_data_params[i].subevent = sub;
sub_data_params[i].response_slot_start = 0;
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);
if (rc) {
ESP_LOGE(TAG, "Failed to set Subevent Data, rc = 0x%x", rc);
if (actual_sent > 0) {
rc = ble_gap_set_periodic_adv_subev_data(event->periodic_adv_subev_data_req.adv_handle,
actual_sent, sub_data_params);
if (rc) {
ESP_LOGE(TAG, "Failed to set Subevent Data, rc = 0x%x", rc);
}
}
return 0;
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -114,11 +114,11 @@ periodic_sync_gap_event(struct ble_gap_event *event, void *arg)
struct ble_gap_ext_disc_desc *disc = ((struct ble_gap_ext_disc_desc *)(&event->ext_disc));
if (disc->sid == 2 && synced == 0) {
synced++;
const ble_addr_t addr;
ble_addr_t addr;
uint8_t adv_sid;
struct ble_gap_periodic_sync_params params;
int rc;
memcpy((void *)&addr, (void *)&disc->addr, sizeof(disc->addr));
memcpy(&addr, &disc->addr, sizeof(disc->addr));
memcpy(&adv_sid, &disc->sid, sizeof(disc->sid));
params.skip = 10;
params.sync_timeout = 1000;
@@ -236,6 +236,7 @@ ext_blecent_should_connect(const struct ble_gap_ext_disc_desc *disc)
int ad_struct_len = 0;
uint8_t test_addr[6];
uint32_t peer_addr[6];
uint8_t type = 0;
memset(peer_addr, 0x0, sizeof peer_addr);
@@ -252,7 +253,7 @@ ext_blecent_should_connect(const struct ble_gap_ext_disc_desc *disc)
/* Conversion */
for (int i=0; i<6; i++) {
test_addr[i] = (uint8_t )peer_addr[i];
test_addr[5 - i] = (uint8_t )peer_addr[i];
}
if (memcmp(test_addr, disc->addr.val, sizeof(disc->addr.val)) != 0) {
@@ -264,21 +265,20 @@ ext_blecent_should_connect(const struct ble_gap_ext_disc_desc *disc)
*/
do {
ad_struct_len = disc->data[offset];
if (!ad_struct_len) {
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;
type = disc->data[offset + 1];
if ((type == 0x02 || type == 0x03) && ad_struct_len >= 3) {
/* Scan UUID bytes for LE_PHY_UUID16 (little-endian: 0xF2 0xAB) */
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 );
} while (offset < disc->length_data);
return 0;
}
@@ -484,42 +484,37 @@ blecent_on_sync(void)
rc = ble_hs_util_ensure_addr(0);
assert(rc == 0);
s_current_phy = BLE_HCI_LE_PHY_1M_PREF_MASK;
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);
if (s_current_phy != BLE_HCI_LE_PHY_1M_PREF_MASK) {
/* Check if peer address is set in EXAMPLE_PEER_ADDR */
if (strlen(CONFIG_EXAMPLE_PEER_ADDR) &&
(strncmp(CONFIG_EXAMPLE_PEER_ADDR, "ADDR_ANY", strlen("ADDR_ANY")) != 0)) {
/* User wants to connect on 2M or coded phy directly */
sscanf(CONFIG_EXAMPLE_PEER_ADDR, "%lx:%lx:%lx:%lx:%lx:%lx",
&peer_addr[5], &peer_addr[4], &peer_addr[3],
&peer_addr[2], &peer_addr[1], &peer_addr[0]);
if (strlen(CONFIG_EXAMPLE_PEER_ADDR) &&
(strncmp(CONFIG_EXAMPLE_PEER_ADDR, "ADDR_ANY", strlen("ADDR_ANY")) != 0)) {
/* User wants to connect on 2M or coded phy directly */
sscanf(CONFIG_EXAMPLE_PEER_ADDR, "%lx:%lx:%lx:%lx:%lx:%lx",
&peer_addr[5], &peer_addr[4], &peer_addr[3],
&peer_addr[2], &peer_addr[1], &peer_addr[0]);
/* Conversion */
for (int i=0; i<6; i++) {
test_addr[i] = (uint8_t )peer_addr[i];
}
for(ii = 0 ;ii < 6; ii++)
conn_addr.val[ii] = test_addr[ii];
conn_addr.type = 0;
vTaskDelay(300);
if (s_current_phy == BLE_HCI_LE_PHY_2M_PREF_MASK)
s_current_phy = BLE_HCI_LE_PHY_1M_PREF_MASK | 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);
/* Conversion */
for (int i=0; i<6; i++) {
test_addr[i] = (uint8_t )peer_addr[i];
}
for(ii = 0 ;ii < 6; ii++)
conn_addr.val[ii] = test_addr[ii];
conn_addr.type = 0;
vTaskDelay(300);
s_current_phy = BLE_HCI_LE_PHY_1M_PREF_MASK | 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);
}
else {
/* Begin scanning for a peripheral to connect to. */
s_current_phy = BLE_HCI_LE_PHY_1M_PREF_MASK;
/* Begin scanning for a peripheral to connect to. */
blecent_scan();
}
}
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -69,22 +69,26 @@ gatt_svr_chr_access_le_phy(uint16_t conn_handle, uint16_t attr_handle,
case BLE_GATT_ACCESS_OP_WRITE_CHR:
len = OS_MBUF_PKTLEN(ctxt->om);
if (len > 0) {
le_phy_val = (uint8_t *)malloc(len * sizeof(uint8_t));
if (le_phy_val) {
rc = ble_hs_mbuf_to_flat(ctxt->om, le_phy_val, len, &copied_len);
if (rc == 0) {
MODLOG_DFLT(INFO, "Write received of len = %d", copied_len);
return 0;
} else {
MODLOG_DFLT(ERROR, "Failed to receive write characteristic");
}
}
if (len == 0) {
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
}
break;
le_phy_val = (uint8_t *)malloc(len);
if (le_phy_val == NULL) {
return BLE_ATT_ERR_INSUFFICIENT_RES;
}
rc = ble_hs_mbuf_to_flat(ctxt->om, le_phy_val, len, &copied_len);
free(le_phy_val);
if (rc == 0) {
MODLOG_DFLT(INFO, "Write received of len = %d", (int)copied_len);
return 0;
}
MODLOG_DFLT(ERROR, "Failed to receive write characteristic");
return BLE_ATT_ERR_INSUFFICIENT_RES;
default:
break;
return BLE_ATT_ERR_UNLIKELY;
}
}
@@ -70,7 +70,10 @@ ble_prox_cent_on_write(uint16_t conn_handle,
const struct peer_chr *chr;
int rc;
const struct peer *peer = peer_find(conn_handle);
if (peer == NULL) {
MODLOG_DFLT(ERROR, "Error: peer not found for conn_handle=%d", conn_handle);
return 0;
}
chr = peer_chr_find_uuid(peer,
BLE_UUID16_DECLARE(BLE_SVC_TX_POWER_UUID16),
BLE_UUID16_DECLARE(BLE_SVC_PROX_CHR_UUID16_TX_PWR_LVL));
@@ -247,7 +250,7 @@ ext_ble_prox_cent_should_connect(const struct ble_gap_ext_disc_desc *disc)
/* Conversion */
for (int i=0; i<6; i++) {
test_addr[i] = (uint8_t )peer_addr[i];
test_addr[5 - i] = (uint8_t )peer_addr[i];
}
if (memcmp(test_addr, disc->addr.val, sizeof(disc->addr.val)) != 0) {
@@ -266,9 +269,15 @@ ext_ble_prox_cent_should_connect(const struct ble_gap_ext_disc_desc *disc)
}
/* Search if Proximity Sensor (Link loss) UUID is advertised */
if (disc->data[offset] == 0x03 && disc->data[offset + 1] == 0x03) {
if ( disc->data[offset + 2] == 0x18 && disc->data[offset + 3] == 0x03 ) {
return 1;
if (disc->data[offset + 1] == 0x03) {
int uuid_offset = offset + 2;
int uuid_end = offset + 1 + disc->data[offset]; // len includes type+data
while (uuid_offset + 1 < uuid_end) {
// BLE uses little-endian: 0x1803 is stored as 0x03 0x18
if (disc->data[uuid_offset] == 0x03 && disc->data[uuid_offset + 1] == 0x18) {
return 1;
}
uuid_offset += 2;
}
}
@@ -553,7 +562,7 @@ ble_prox_cent_gap_event(struct ble_gap_event *event, void *arg)
#else
#if MYNEWT_VAL(BLE_GATTC)
/*** Go for service discovery after encryption has been successfully enabled ***/
rc = peer_disc_all(event->connect.conn_handle,
rc = peer_disc_all(event->enc_change.conn_handle,
ble_prox_cent_on_disc_complete, NULL);
if (rc != 0) {
MODLOG_DFLT(ERROR, "Failed to discover services; rc=%d\n", rc);
@@ -572,7 +581,7 @@ ble_prox_cent_gap_event(struct ble_gap_event *event, void *arg)
event->cache_assoc.status,
(event->cache_assoc.cache_state == 0) ? "INVALID" : "LOADED");
/* Perform service discovery */
rc = peer_disc_all(event->connect.conn_handle,
rc = peer_disc_all(event->cache_assoc.conn_handle,
blecent_on_disc_complete, NULL);
if(rc != 0) {
MODLOG_DFLT(ERROR, "Failed to discover services; rc=%d\n", rc);
@@ -636,7 +645,7 @@ ble_prox_cent_gap_event(struct ble_gap_event *event, void *arg)
void
ble_prox_cent_path_loss_task(void *pvParameters)
{
int8_t rssi;
int8_t rssi = 0;
int rc;
int path_loss;
@@ -685,7 +694,10 @@ ble_prox_cent_link_loss_task(void *pvParameters)
while (1) {
for (int i = 0; i <= MYNEWT_VAL(BLE_MAX_CONNECTIONS); i++) {
if (disconn_peer[i].link_lost && disconn_peer[i].addr != NULL) {
MODLOG_DFLT(INFO, "Link lost for device with conn_handle %d", i);
MODLOG_DFLT(INFO, "Link lost for peer %02x:%02x:%02x:%02x:%02x:%02x, slot %d",
disconn_peer[i].addr[5], disconn_peer[i].addr[4],
disconn_peer[i].addr[3], disconn_peer[i].addr[2],
disconn_peer[i].addr[1], disconn_peer[i].addr[0], i);
}
}
vTaskDelay(5000 / portTICK_PERIOD_MS);
@@ -23,6 +23,7 @@ static int ble_spp_client_gap_event(struct ble_gap_event *event, void *arg);
QueueHandle_t spp_common_uart_queue = NULL;
void ble_store_config_init(void);
uint16_t attribute_handle[CONFIG_BT_NIMBLE_MAX_CONNECTIONS + 1];
static SemaphoreHandle_t g_attr_handle_mutex = NULL;
static void ble_spp_client_scan(void);
static ble_addr_t connected_addr[CONFIG_BT_NIMBLE_MAX_CONNECTIONS + 1];
@@ -73,8 +74,19 @@ ble_spp_client_set_handle(const struct peer *peer)
chr = peer_chr_find_uuid(peer,
BLE_UUID16_DECLARE(GATT_SPP_SVC_UUID),
BLE_UUID16_DECLARE(GATT_SPP_CHR_UUID));
if (chr == NULL) {
MODLOG_DFLT(ERROR, "Error: Peer lacks SPP characteristic\n");
return;
}
if (g_attr_handle_mutex != NULL) {
xSemaphoreTake(g_attr_handle_mutex, portMAX_DELAY);
}
attribute_handle[peer->conn_handle] = chr->chr.val_handle;
MODLOG_DFLT(INFO, "attribute_handle %x\n", attribute_handle[peer->conn_handle]);
if (g_attr_handle_mutex != NULL) {
xSemaphoreGive(g_attr_handle_mutex);
}
dsc = peer_dsc_find_uuid(peer,
BLE_UUID16_DECLARE(GATT_SPP_SVC_UUID),
@@ -295,8 +307,10 @@ ble_spp_client_gap_event(struct ble_gap_event *event, void *arg)
MODLOG_DFLT(INFO, "Connection established ");
rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
assert(rc == 0);
memcpy(&connected_addr[event->connect.conn_handle].val, desc.peer_id_addr.val,
PEER_ADDR_VAL_SIZE);
if (event->connect.conn_handle <= CONFIG_BT_NIMBLE_MAX_CONNECTIONS) {
memcpy(&connected_addr[event->connect.conn_handle].val, desc.peer_id_addr.val,
PEER_ADDR_VAL_SIZE);
}
print_conn_desc(&desc);
MODLOG_DFLT(INFO, "\n");
@@ -333,7 +347,13 @@ ble_spp_client_gap_event(struct ble_gap_event *event, void *arg)
/* 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);
}
peer_delete(event->disconnect.conn.conn_handle);
/* Resume scanning. */
@@ -422,19 +442,39 @@ void ble_client_uart_task(void *pvParameters)
}
memset(temp, 0x0, event.size);
uart_read_bytes(UART_NUM_0, temp, event.size, portMAX_DELAY);
for ( i = 0; i <= CONFIG_BT_NIMBLE_MAX_CONNECTIONS; i++) {
/* Collect valid connections while holding mutex to prevent race conditions */
struct {
uint16_t conn_handle;
uint16_t attr_handle;
} valid_conns[CONFIG_BT_NIMBLE_MAX_CONNECTIONS + 1];
int valid_count = 0;
if (g_attr_handle_mutex != NULL) {
xSemaphoreTake(g_attr_handle_mutex, portMAX_DELAY);
}
for (i = 0; i <= CONFIG_BT_NIMBLE_MAX_CONNECTIONS; i++) {
if (attribute_handle[i] != 0) {
#if MYNEWT_VAL(BLE_GATTC)
rc = ble_gattc_write_flat(i, attribute_handle[i], temp, event.size, NULL, NULL);
if (rc == 0) {
ESP_LOGI(tag, "Write in uart task success!");
} else {
ESP_LOGI(tag, "Error in writing characteristic rc=%d", rc);
}
#endif
vTaskDelay(10);
valid_conns[valid_count].conn_handle = i;
valid_conns[valid_count].attr_handle = attribute_handle[i];
valid_count++;
}
}
if (g_attr_handle_mutex != NULL) {
xSemaphoreGive(g_attr_handle_mutex);
}
/* Write to all valid connections (outside mutex to avoid blocking) */
for (i = 0; i < valid_count; i++) {
#if MYNEWT_VAL(BLE_GATTC)
rc = ble_gattc_write_flat(valid_conns[i].conn_handle, valid_conns[i].attr_handle, temp, event.size, NULL, NULL);
if (rc == 0) {
ESP_LOGI(tag, "Write in uart task success!");
} else {
ESP_LOGI(tag, "Error in writing characteristic rc=%d", rc);
}
#endif
vTaskDelay(10);
}
free(temp);
}
break;
@@ -484,6 +524,13 @@ app_main(void)
return;
}
/* Initialize mutex for attribute_handle protection */
g_attr_handle_mutex = xSemaphoreCreateMutex();
if (g_attr_handle_mutex == NULL) {
ESP_LOGE(tag, "Failed to create attribute handle mutex");
return;
}
/* Initialize UART driver and start uart task */
ble_spp_uart_init();
@@ -163,7 +163,9 @@ ble_spp_server_gap_event(struct ble_gap_event *event, void *arg)
ble_spp_server_print_conn_desc(&event->disconnect.conn);
MODLOG_DFLT(INFO, "\n");
conn_handle_subs[event->disconnect.conn.conn_handle] = false;
if (event->disconnect.conn.conn_handle <= CONFIG_BT_NIMBLE_MAX_CONNECTIONS) {
conn_handle_subs[event->disconnect.conn.conn_handle] = false;
}
/* Connection terminated; resume advertising. */
ble_spp_server_advertise();
@@ -202,7 +204,9 @@ ble_spp_server_gap_event(struct ble_gap_event *event, void *arg)
event->subscribe.cur_notify,
event->subscribe.prev_indicate,
event->subscribe.cur_indicate);
conn_handle_subs[event->subscribe.conn_handle] = true;
if (event->subscribe.conn_handle <= CONFIG_BT_NIMBLE_MAX_CONNECTIONS) {
conn_handle_subs[event->subscribe.conn_handle] = true;
}
return 0;
default:
@@ -360,6 +364,10 @@ void ble_server_uart_task(void *pvParameters)
if (event.size) {
uint8_t *ntf;
ntf = (uint8_t *)malloc(sizeof(uint8_t) * event.size);
if (ntf == NULL) {
MODLOG_DFLT(ERROR, "malloc failed for UART data, size=%u", event.size);
continue;
}
memset(ntf, 0x00, event.size);
uart_read_bytes(UART_NUM_0, ntf, event.size, portMAX_DELAY);
+14 -3
View File
@@ -121,6 +121,10 @@ blecent_on_custom_write(uint16_t conn_handle,
error->status, conn_handle, attr->handle);
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);
@@ -257,6 +261,7 @@ blecent_on_subscribe(uint16_t conn_handle,
if (peer == NULL) {
MODLOG_DFLT(ERROR, "Error in finding peer, aborting...");
ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM);
return 0;
}
/* Subscribe to, write to, and read the custom characteristic*/
blecent_custom_gatt_operations(peer);
@@ -286,7 +291,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, "Error: peer not found for conn_handle=%d", conn_handle);
return ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM); // Use conn_handle to avoid dereference
}
dsc = peer_dsc_find_uuid(peer,
BLE_UUID16_DECLARE(BLECENT_SVC_ALERT_UUID),
BLE_UUID16_DECLARE(BLECENT_CHR_UNR_ALERT_STAT_UUID),
@@ -338,7 +346,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, "Error: peer not found for conn_handle=%d", conn_handle);
return ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM);
}
chr = peer_chr_find_uuid(peer,
BLE_UUID16_DECLARE(BLECENT_SVC_ALERT_UUID),
BLE_UUID16_DECLARE(BLECENT_CHR_ALERT_NOT_CTRL_PT));
@@ -877,7 +888,7 @@ blecent_gap_event(struct ble_gap_event *event, void *arg)
event->cache_assoc.status,
(event->cache_assoc.cache_state == 0) ? "INVALID" : "LOADED");
/* Perform service discovery */
rc = peer_disc_all(event->connect.conn_handle,
rc = peer_disc_all(event->cache_assoc.conn_handle,
blecent_on_disc_complete, NULL);
if(rc != 0) {
MODLOG_DFLT(ERROR, "Failed to discover services; rc=%d\n", rc);
@@ -191,6 +191,9 @@ gatt_svr_chr_access_sc_control_point(uint16_t conn_handle,
/* Allocate response buffer */
om_indication = ble_hs_mbuf_att_pkt();
if (om_indication == NULL) {
return BLE_HS_ENOMEM;
}
switch(op_code){
#if (CSC_FEATURES & CSC_FEATURE_WHEEL_REV_DATA)
@@ -200,6 +203,7 @@ gatt_svr_chr_access_sc_control_point(uint16_t conn_handle,
sizeof(new_cumulative_wheel_rev_arr),
new_cumulative_wheel_rev_arr);
if (rc != 0){
os_mbuf_free_chain(om_indication);
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
}
@@ -216,7 +220,8 @@ gatt_svr_chr_access_sc_control_point(uint16_t conn_handle,
/* Read new sensor location value*/
rc = os_mbuf_copydata(ctxt->om, 1, 1, &new_sensor_location);
if (rc != 0){
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
os_mbuf_free_chain(om_indication);
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
}
@@ -244,7 +249,8 @@ gatt_svr_chr_access_sc_control_point(uint16_t conn_handle,
rc = os_mbuf_append(om_indication, &response, sizeof(response));
if (rc != 0){
return BLE_ATT_ERR_INSUFFICIENT_RES;
os_mbuf_free_chain(om_indication);
return BLE_ATT_ERR_INSUFFICIENT_RES;
}
#if (CSC_FEATURES & CSC_FEATURE_MULTIPLE_SENSOR_LOC)
@@ -252,17 +258,24 @@ gatt_svr_chr_access_sc_control_point(uint16_t conn_handle,
if (op_code == SC_CP_OP_REQ_SUPPORTED_SENSOR_LOCATIONS){
rc = os_mbuf_append(om_indication, &csc_supported_sensor_locations,
sizeof(csc_supported_sensor_locations));
}
if (rc != 0){
return BLE_ATT_ERR_INSUFFICIENT_RES;
if (rc != 0){
os_mbuf_free_chain(om_indication);
return BLE_ATT_ERR_INSUFFICIENT_RES;
}
}
#endif
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);
return rc;
}
static int
@@ -200,6 +200,9 @@ blehr_gap_event(struct ble_gap_event *event, void *arg)
case BLE_GAP_EVENT_DISCONNECT:
MODLOG_DFLT(INFO, "disconnect; reason=%d\n", event->disconnect.reason);
notify_state = false;
blehr_tx_hrate_stop();
conn_handle = BLE_HS_CONN_HANDLE_NONE;
/* Connection terminated; resume advertising */
blehr_advertise();
break;
@@ -245,7 +245,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;
@@ -497,6 +499,7 @@ app_main(void)
ret = nimble_port_init();
if (ret != ESP_OK) {
ESP_LOGE(tag, "Failed to init nimble %d ", ret);
hci_uart_close();
return;
}
/* Initialize the NimBLE host configuration. */
@@ -1,11 +1,12 @@
/*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
@@ -44,6 +45,7 @@ enum {
};
TaskHandle_t s_rx_task_hdl;
static volatile bool s_shutdown_flag = false;
static void IRAM_ATTR hci_uart_rx_task(void *arg)
{
@@ -53,9 +55,15 @@ static void IRAM_ATTR hci_uart_rx_task(void *arg)
uint32_t len_total_read = 0;
uint8_t rx_st = UART_RX_TYPE;
while (1) {
len_now_read = uart_read_bytes(UART_NO, &buf[len_total_read], len_to_read, portMAX_DELAY);
assert(len_now_read == len_to_read);
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 timeout occurred, continue loop to check shutdown flag again
if (len_now_read == 0) {
continue;
}
len_total_read += len_now_read;
switch (rx_st) {
@@ -130,6 +138,10 @@ static void IRAM_ATTR hci_uart_rx_task(void *arg)
m = ble_transport_alloc_acl_from_ll();
if (!m) {
ESP_LOGE(TAG, "No buffers");
rx_st = UART_RX_TYPE;
len_to_read = 1;
len_total_read = 0;
break;
}
if ((rc = os_mbuf_append(m, &data[1], len_total_read - 1)) != 0) {
@@ -180,7 +192,7 @@ ble_transport_ll_init(void)
void
ble_transport_ll_deinit(void)
{
hci_uart_close();
}
int
@@ -228,6 +240,7 @@ void hci_uart_open(void)
intr_alloc_flags = ESP_INTR_FLAG_IRAM;
#endif
s_shutdown_flag = false; // Reset shutdown flag on open
ESP_ERROR_CHECK(uart_driver_install(UART_NO, UART_BUF_SZ * 2, UART_BUF_SZ * 2, 0, NULL, intr_alloc_flags));
ESP_ERROR_CHECK(uart_param_config(UART_NO, &uart_config));
ESP_ERROR_CHECK(uart_set_pin(UART_NO, UART_TX_PIN, UART_RX_PIN, -1, -1));
@@ -238,7 +251,26 @@ void hci_uart_open(void)
void hci_uart_close(void)
{
if (s_rx_task_hdl) {
vTaskDelete(s_rx_task_hdl);
s_shutdown_flag = true;
int wait_count = 0;
const int max_wait_count = 5;
TaskHandle_t task_handle = s_rx_task_hdl;
while (wait_count < max_wait_count) {
vTaskDelay(pdMS_TO_TICKS(100));
wait_count++;
}
if (s_rx_task_hdl == task_handle) {
vTaskDelete(s_rx_task_hdl);
vTaskDelay(pdMS_TO_TICKS(100));
}
s_rx_task_hdl = NULL;
}
uart_driver_delete(UART_NO);
}
@@ -167,8 +167,10 @@ static void cmd_ping_on_ping_success(esp_ping_handle_t hdl, void *args)
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
esp_ping_get_profile(hdl, ESP_PING_PROF_SIZE, &recv_len, sizeof(recv_len));
esp_ping_get_profile(hdl, ESP_PING_PROF_TIMEGAP, &elapsed_time, sizeof(elapsed_time));
const char *ip_str = IP_IS_V4(&target_addr) ? inet_ntoa(*ip_2_ip4(&target_addr)) :
inet6_ntoa(*ip_2_ip6(&target_addr));
printf("%" PRIu32 "bytes from %s icmp_seq=%d ttl=%d time=%" PRIu32 "ms\n",
recv_len, inet_ntoa(target_addr.u_addr.ip4), seqno, ttl, elapsed_time);
recv_len, ip_str, seqno, ttl, elapsed_time);
}
static void cmd_ping_on_ping_timeout(esp_ping_handle_t hdl, void *args)
@@ -177,7 +179,9 @@ static void cmd_ping_on_ping_timeout(esp_ping_handle_t hdl, void *args)
ip_addr_t target_addr;
esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
printf("From %s icmp_seq=%d timeout\n", inet_ntoa(target_addr.u_addr.ip4), seqno);
const char *ip_str = IP_IS_V4(&target_addr) ? inet_ntoa(*ip_2_ip4(&target_addr)) :
inet6_ntoa(*ip_2_ip6(&target_addr));
printf("From %s icmp_seq=%d timeout\n", ip_str, seqno);
}
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -152,9 +152,12 @@ print_adv_fields(const struct ble_hs_adv_fields *fields)
}
if (fields->name != NULL) {
assert(fields->name_len < sizeof s - 1);
memcpy(s, fields->name, fields->name_len);
s[fields->name_len] = '\0';
size_t copy_len = fields->name_len;
if (copy_len >= sizeof(s)) {
copy_len = sizeof(s) - 1;
}
memcpy(s, fields->name, copy_len);
s[copy_len] = '\0';
MODLOG_DFLT(DEBUG, " name(%scomplete)=%s\n",
fields->name_is_complete ? "" : "in", s);
}
@@ -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);
@@ -341,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;
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -32,7 +32,7 @@ static int enter_passkey_handler(int argc, char *argv[])
return -1;
}
sscanf(argv[1], "%s", pkey);
sscanf(argv[1], "%7s", pkey);
ESP_LOGI("You entered", "%s %s", argv[0], argv[1]);
num = pkey[0];
@@ -45,7 +45,9 @@ static int enter_passkey_handler(int argc, char *argv[])
xQueueSend(cli_handle, &key, 0);
}
} else {
sscanf(pkey, "%d", &key);
if (sscanf(pkey, "%d", &key) != 1) {
key = 0;
}
xQueueSend(cli_handle, &key, 0);
}
@@ -84,14 +86,14 @@ static void scli_task(void *arg)
QueueHandle_t uart_queue;
uart_event_t event;
uart_driver_install(uart_num, 256, 0, 8, &uart_queue, 0);
ESP_ERROR_CHECK(uart_driver_install(uart_num, 256, 0, 8, &uart_queue, 0));
/* Initialize the console */
esp_console_config_t console_config = {
.max_cmdline_args = 8,
.max_cmdline_length = 256,
};
esp_console_init(&console_config);
ESP_ERROR_CHECK(esp_console_init(&console_config));
while (!stop) {
i = 0;
@@ -107,6 +109,9 @@ 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;
}
if (linebuf[i] == '\r') {
uart_write_bytes(uart_num, "\r\n", 2);
} else {
@@ -115,12 +120,16 @@ static void scli_task(void *arg)
i++;
}
}
} while ((i < 255) && linebuf[i - 1] != '\r');
} while ((i < 255) && (i == 0 || linebuf[i - 1] != '\r'));
if (stop) {
break;
}
/* Remove the truncating \r\n */
linebuf[strlen((char *)linebuf) - 1] = '\0';
size_t len = strlen((char *)linebuf);
if (len > 0) {
linebuf[len - 1] = '\0';
}
ret = esp_console_run((char *) linebuf, &cmd_ret);
if (ret < 0) {
break;
@@ -144,3 +153,40 @@ int scli_init(void)
}
return ESP_OK;
}
int scli_deinit(void)
{
if (cli_task == NULL) {
return ESP_OK; // Already deinitialized
}
// Signal task to exit
stop = 1;
// Wait for task to exit (it will clean up UART and console)
int timeout_ms = 200;
while (timeout_ms > 0 && cli_task != NULL && eTaskGetState(cli_task) != eDeleted) {
vTaskDelay(pdMS_TO_TICKS(10));
timeout_ms -= 10;
}
// Force delete if still running (shouldn't happen if task exits properly)
if (cli_task != NULL && eTaskGetState(cli_task) != eDeleted) {
vTaskDelete(cli_task);
// If force-deleted, clean up resources manually
uart_driver_delete(0);
esp_console_deinit();
}
cli_task = NULL;
// Clean up queue
if (cli_handle != NULL) {
vQueueDelete(cli_handle);
cli_handle = NULL;
}
// Reset stop flag
stop = 0;
return ESP_OK;
}
@@ -46,9 +46,16 @@ static int dtm_set_ble_tx_power_command(int argc, char **argv)
static int dtm_get_ble_tx_power_command(int argc, char **argv)
{
esp_power_level_t power_level = 0xFF;
esp_power_level_t power_level;
power_level = esp_ble_tx_power_get_enhanced(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0);
printf("\nCurrent BLE TX power is %d level\n", power_level);
if (power_level == ESP_PWR_LVL_INVALID) {
ESP_LOGI(__func__,"TX power is not available!\n");
return 1;
}
ESP_LOGI(__func__,"\nCurrent BLE TX power is %d level\n", power_level);
return 0;
}
@@ -227,15 +227,21 @@ bleprph_advertise(void)
#endif
#if MYNEWT_VAL(BLE_POWER_CONTROL)
static void bleprph_power_control(uint16_t conn_handle)
static int 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);
if (rc != 0) {
return rc;
}
rc = ble_gap_set_transmit_power_reporting_enable(conn_handle, 0x1, 0x1);
assert (rc == 0);
if (rc != 0) {
return rc;
}
return 0;
}
#endif
@@ -317,10 +323,13 @@ bleprph_gap_event(struct ble_gap_event *event, void *arg)
}
#if MYNEWT_VAL(BLE_POWER_CONTROL)
bleprph_power_control(event->connect.conn_handle);
ble_gap_event_listener_register(&power_control_event_listener,
bleprph_gap_power_event, NULL);
if (event->connect.status == 0) {
rc = bleprph_power_control(event->connect.conn_handle);
if (rc == 0) {
ble_gap_event_listener_register(&power_control_event_listener,
bleprph_gap_power_event, NULL);
}
}
#endif
return 0;
@@ -63,6 +63,7 @@ static int get_version(int argc, char **argv)
{
esp_chip_info_t info;
uint32_t flash_size;
const char *model_str;
esp_chip_info(&info);
if(esp_flash_get_size(NULL, &flash_size) != ESP_OK) {
printf("Get flash size failed");
@@ -70,7 +71,18 @@ static int get_version(int argc, char **argv)
}
printf("IDF Version:%s\r\n", esp_get_idf_version());
printf("Chip info:\r\n");
printf("\tmodel:%s\r\n", info.model == CHIP_ESP32 ? "ESP32" : "Unknown");
switch (info.model) {
case CHIP_ESP32: model_str = "ESP32"; break;
case CHIP_ESP32S3: model_str = "ESP32-S3"; break;
case CHIP_ESP32C3: model_str = "ESP32-C3"; break;
case CHIP_ESP32C2: model_str = "ESP32-C2"; break;
case CHIP_ESP32C6: model_str = "ESP32-C6"; break;
case CHIP_ESP32H2: model_str = "ESP32-H2"; break;
case CHIP_ESP32C61: model_str = "ESP32-C61"; break;
case CHIP_ESP32C5: model_str = "ESP32-C5"; break;
default: model_str = "Unknown"; break;
}
printf("\tmodel:%s\r\n", model_str);
printf("\tcores:%d\r\n", info.cores);
printf("\tfeature:%s%s%s%s%" PRIu32 "%s\r\n",
info.features & CHIP_FEATURE_WIFI_BGN ? "/802.11bgn" : "",
@@ -111,8 +111,8 @@ peer_find(uint16_t conn_handle);
/* Console */
int scli_init(void);
void ble_register_cli(void);
int scli_receive_key(int *key);
int cli_receive_key(int *key);
int scli_receive_key(int key[6]);
int cli_receive_key(int key[6]);
int scli_receive_yesno(bool *key);
void scli_reset_queue(void);
@@ -58,9 +58,10 @@ static int blecent_gap_event(struct ble_gap_event *event, void *arg);
static SemaphoreHandle_t xSemaphore;
static int mbuf_len_total;
static int failure_count;
static TaskHandle_t throughput_task_handle = NULL;
static int conn_params_def[] = {40, 40, 0, 500, 80, 80};
/* test_data accepts test_name and test_time from CLI */
static int test_data[] = {1, 600, 0};
static int test_data[6] = {1, 600, 0, 0, 0, 0};
static int mtu_def = 512;
static ble_addr_t conn_addr;
static uint16_t handle;
@@ -225,6 +226,7 @@ static int blecent_read(uint16_t conn_handle, uint16_t val_handle,
return 0;
err:
xSemaphoreGive(xSemaphore);
/* Terminate the connection. */
vTaskDelay(100 / portTICK_PERIOD_MS);
return ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
@@ -240,7 +242,8 @@ int update_phy(uint16_t conn_handle, uint8_t phy_mode)
current_phy_updated = 0;
rc = ble_gap_set_prefered_le_phy(conn_handle, BLE_HCI_LE_PHY_1M_PREF_MASK, BLE_HCI_LE_PHY_1M_PREF_MASK, 0);
if(rc != 0) {
ESP_LOGI(tag, "Requested PHY: 1M failed.");
current_phy_updated = 1;
ESP_LOGE(tag, "Requested PHY: 1M failed, rc=%d", rc);
}
else {
ESP_LOGI(tag, "Requested PHY: 1M");
@@ -251,7 +254,8 @@ int update_phy(uint16_t conn_handle, uint8_t phy_mode)
current_phy_updated = 0;
rc = ble_gap_set_prefered_le_phy(conn_handle, BLE_HCI_LE_PHY_2M_PREF_MASK, BLE_HCI_LE_PHY_2M_PREF_MASK, 0);
if(rc != 0) {
ESP_LOGI(tag, "Requested PHY: 2M failed.");
current_phy_updated = 1;
ESP_LOGE(tag, "Requested PHY: 2M failed, rc=%d", rc);
}
else {
ESP_LOGI(tag, "Requested PHY: 2M");
@@ -262,7 +266,8 @@ int update_phy(uint16_t conn_handle, uint8_t phy_mode)
current_phy_updated = 0;
rc = ble_gap_set_prefered_le_phy(conn_handle, BLE_HCI_LE_PHY_CODED_PREF_MASK, BLE_HCI_LE_PHY_CODED_PREF_MASK, 0x01);
if(rc != 0) {
ESP_LOGI(tag, "Requested PHY: Coded S2 failed.");
current_phy_updated = 1;
ESP_LOGE(tag, "Requested PHY: Coded S2 failed, rc=%d", rc);
}
else {
ESP_LOGI(tag, "Requested PHY: Coded S2");
@@ -273,7 +278,8 @@ int update_phy(uint16_t conn_handle, uint8_t phy_mode)
current_phy_updated = 0;
rc = ble_gap_set_prefered_le_phy(conn_handle, BLE_HCI_LE_PHY_CODED_PREF_MASK, BLE_HCI_LE_PHY_CODED_PREF_MASK, 0x02);
if(rc != 0) {
ESP_LOGI(tag, "Requested PHY: Coded S8 failed.");
current_phy_updated = 1;
ESP_LOGE(tag, "Requested PHY: Coded S8 failed, rc=%d", rc);
}
else {
ESP_LOGI(tag, "Requested PHY: Coded S8");
@@ -294,9 +300,29 @@ static void throughput_task(void *arg)
struct peer *peer = (struct peer *)arg;
const struct peer_chr *chr;
const struct peer_dsc *dsc;
struct ble_gap_conn_desc desc;
uint16_t conn_handle;
int rc = 0;
/* Store conn_handle immediately to avoid UAF if peer is freed */
if (peer == NULL) {
ESP_LOGE(tag, "Invalid peer, deleting task");
throughput_task_handle = NULL;
vTaskDelete(NULL);
return;
}
conn_handle = peer->conn_handle;
while (1) {
/* Check if connection is still valid using stored conn_handle */
rc = ble_gap_conn_find(conn_handle, &desc);
if (rc != 0) {
ESP_LOGI(tag, "Connection lost, deleting throughput task");
throughput_task_handle = NULL;
vTaskDelete(NULL);
return;
}
vTaskDelay(4000 / portTICK_PERIOD_MS);
ESP_LOGI(tag, "Format for throughput demo:: throughput read 100");
printf(" ====================================================================================\n");
@@ -329,12 +355,15 @@ static void throughput_task(void *arg)
scli_reset_queue();
#if CONFIG_EXAMPLE_EXTENDED_ADV
if(test_data[2] >= 0) {
rc = update_phy(handle, test_data[2]);
rc = update_phy(conn_handle, test_data[2]);
if(rc != 0) {
ESP_LOGI(tag, "Failed to update phy.\n");
}
while (!current_phy_updated) {
vTaskDelay(100 / portTICK_PERIOD_MS);
ESP_LOGE(tag, "Failed to update phy, rc=%d. Skipping PHY update wait.", rc);
/* Flag is already set to 1 on failure, but skip wait loop for clarity */
} else {
/* Wait for PHY update event to complete */
while (!current_phy_updated) {
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}
}
#endif
@@ -354,10 +383,17 @@ static void throughput_task(void *arg)
}
if (test_data[1] > 0) {
rc = blecent_read(peer->conn_handle, chr->chr.val_handle,
rc = blecent_read(conn_handle, chr->chr.val_handle,
blecent_repeat_read, (void *) peer, test_data[1]);
if (rc != 0) {
ESP_LOGE(tag, "Error while reading from GATTS; rc = %d", rc);
/* Delete task on critical error (connection lost or fatal error) */
if (rc == BLE_HS_ENOTCONN || rc == BLE_HS_EDONE) {
ESP_LOGI(tag, "Connection error, deleting throughput task");
throughput_task_handle = NULL;
vTaskDelete(NULL);
return;
}
}
} else {
ESP_LOGE(tag, "Please enter non-zero value for test time in seconds!!");
@@ -375,9 +411,16 @@ static void throughput_task(void *arg)
}
if (test_data[1] > 0) {
rc = blecent_write(peer->conn_handle, chr->chr.val_handle, (void *) peer, test_data[1]);
rc = blecent_write(conn_handle, chr->chr.val_handle, (void *) peer, test_data[1]);
if (rc != 0) {
ESP_LOGE(tag, "Error while writing data; rc = %d", rc);
/* Delete task on critical error (connection lost or fatal error) */
if (rc == BLE_HS_ENOTCONN || rc == BLE_HS_EDONE) {
ESP_LOGI(tag, "Connection error, deleting throughput task");
throughput_task_handle = NULL;
vTaskDelete(NULL);
return;
}
}
} else {
ESP_LOGE(tag, "Please enter non-zero value for test time in seconds!!");
@@ -403,10 +446,17 @@ static void throughput_task(void *arg)
break;
}
rc = blecent_notify(peer->conn_handle, dsc->dsc.handle,
rc = blecent_notify(conn_handle, dsc->dsc.handle,
NULL, (void *) peer, test_data[1]);
if (rc != 0) {
ESP_LOGE(tag, "Subscribing to notification failed; rc = %d ", rc);
/* Delete task on critical error (connection lost or fatal error) */
if (rc == BLE_HS_ENOTCONN || rc == BLE_HS_EDONE) {
ESP_LOGI(tag, "Connection error, deleting throughput task");
throughput_task_handle = NULL;
vTaskDelete(NULL);
return;
}
} else {
ESP_LOGI(tag, "Subscribed to notifications. Throughput number"
" can be seen on peripheral terminal after %d seconds",
@@ -421,13 +471,20 @@ static void throughput_task(void *arg)
vTaskDelay(5000 / portTICK_PERIOD_MS);
}
vTaskDelete(NULL);
}
static void
blecent_read_write_subscribe(const struct peer *peer)
{
xTaskCreate(throughput_task, "throughput_task", 4096, (void *) peer, 10, NULL);
/* Delete previous task if it exists */
/* Capture handle and set global to NULL atomically to prevent race condition
* where task deletes itself between NULL check and vTaskDelete call */
TaskHandle_t task_to_delete = throughput_task_handle;
throughput_task_handle = NULL;
if (task_to_delete != NULL) {
vTaskDelete(task_to_delete);
}
xTaskCreate(throughput_task, "throughput_task", 4096, (void *) peer, 10, &throughput_task_handle);
return;
}
@@ -515,6 +572,7 @@ ext_blecent_should_connect(const struct ble_gap_ext_disc_desc *disc)
uint8_t test_addr[6];
uint32_t peer_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) {
return 0;
@@ -526,9 +584,9 @@ ext_blecent_should_connect(const struct ble_gap_ext_disc_desc *disc)
&peer_addr[5], &peer_addr[4], &peer_addr[3],
&peer_addr[2], &peer_addr[1], &peer_addr[0]);
/* Conversion */
/* Conversion */
for (int i=0; i<6; i++) {
test_addr[i] = (uint8_t )peer_addr[i];
test_addr[5 - i] = (uint8_t )peer_addr[i];
}
if (memcmp(test_addr, disc->addr.val, sizeof(disc->addr.val)) != 0) {
return 0;
@@ -538,17 +596,21 @@ ext_blecent_should_connect(const struct ble_gap_ext_disc_desc *disc)
/* The device has to advertise support LE PHY UUID (0xABF2).
*/
do {
ad_struct_len = disc->data[offset];
if (!ad_struct_len) {
if (offset + 1 >= (int)disc->length_data) { /* At least read length and type */
break;
}
ad_struct_len = disc->data[offset];
if (!ad_struct_len || offset + ad_struct_len + 1 > (int)disc->length_data) {
break;
}
/* Search for Complete Local Name (AD type 0x09) */
if (disc->data[offset + 1] == 0x09 && phy_uuid_found) {
int name_len = disc->data[offset] - 1; /* Length minus type byte */
char serv_name[] = "nimble_prph";
if (name_len > 0) {
ESP_LOGI(tag, "Device Name = %.*s",name_len, (char *)&disc->data[offset + 2]);
ESP_LOGI(tag, "Device Name = %.*s", name_len, (char *)&disc->data[offset + 2]);
if (name_len == strlen(serv_name) &&
memcmp(&disc->data[offset + 2], serv_name, name_len) == 0) {
ESP_LOGI(tag, "central connect to `nimble_prph` success");
@@ -556,18 +618,18 @@ ext_blecent_should_connect(const struct ble_gap_ext_disc_desc *disc)
}
return 0;
}
}
}
/* 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 ) {
phy_uuid_found = 1;
}
}
/* Search if LE PHY UUID is advertised */
if (disc->data[offset] == 0x03 && disc->data[offset + 1] == 0x03 &&
offset + 3 < (int)disc->length_data &&
disc->data[offset + 2] == 0xAB && disc->data[offset + 3] == 0xF2) {
phy_uuid_found = 1;
}
offset += ad_struct_len + 1;
} while ( offset < disc->length_data );
} while (offset < (int)disc->length_data);
return phy_uuid_found;
}
@@ -788,6 +850,15 @@ blecent_gap_event(struct ble_gap_event *event, void *arg)
print_conn_desc(&event->disconnect.conn);
ESP_LOGI(tag, " ");
/* Delete throughput task if it exists */
/* Capture handle and set global to NULL atomically to prevent race condition
* where task deletes itself between NULL check and vTaskDelete call */
TaskHandle_t task_to_delete = throughput_task_handle;
throughput_task_handle = NULL;
if (task_to_delete != NULL) {
vTaskDelete(task_to_delete);
}
/* Forget about peer. */
peer_delete(event->disconnect.conn.conn_handle);
vTaskDelay(200);
@@ -882,7 +953,9 @@ blecent_on_sync(void)
if (scli_receive_yesno(&yes)) {
if (yes) {
ESP_LOGI(tag, " Enter preferred MTU, format:: `MTU 512` ");
if (scli_receive_key(&mtu_def)) {
int mtu_buf[6];
if (scli_receive_key(mtu_buf)) {
mtu_def = mtu_buf[0];
ESP_LOGI(tag, "MTU provided by user= %d", mtu_def);
} else {
ESP_LOGD(tag, "No input for setting MTU; use default mtu = %d", mtu_def);
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -131,9 +131,12 @@ print_adv_fields(const struct ble_hs_adv_fields *fields)
}
if (fields->name != NULL) {
assert(fields->name_len < sizeof s - 1);
memcpy(s, fields->name, fields->name_len);
s[fields->name_len] = '\0';
size_t copy_len = fields->name_len;
if (copy_len >= sizeof(s)) {
copy_len = sizeof(s) - 1;
}
memcpy(s, fields->name, copy_len);
s[copy_len] = '\0';
MODLOG_DFLT(DEBUG, " name(%scomplete)=%s\n",
fields->name_is_complete ? "" : "in", s);
}
@@ -358,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;
@@ -492,31 +492,7 @@ peer_inc_add(struct peer *peer, uint16_t svc_start_handle,
svc = peer_svc_find(peer, gatt_incl_svc->start_handle, &prev);
if (!svc) {
/* secondary service */
svc = os_memblock_get(&peer_svc_pool);
if (svc == NULL) {
/* out of memory */
return BLE_HS_ENOMEM;
}
memset(svc, 0, sizeof *svc);
svc->svc.start_handle = gatt_incl_svc->start_handle;
svc->svc.end_handle = gatt_incl_svc->end_handle;
memcpy(&svc->svc.uuid, &gatt_incl_svc->uuid, sizeof(ble_uuid_any_t));
SLIST_INIT(&svc->chrs);
SLIST_INIT(&svc->incl_svc);
if (prev == NULL) {
SLIST_INSERT_HEAD(&peer->svcs, svc, next);
} else {
SLIST_INSERT_AFTER(prev, svc, next);
}
}
/* Including the services into inlucding list */
cur_svc = peer_svc_find_range(peer, gatt_incl_svc->handle);
if (cur_svc == NULL) {
@@ -533,11 +509,38 @@ peer_inc_add(struct peer *peer, uint16_t svc_start_handle,
return 0;
}
/* Allocate incl_svc first, before allocating secondary service.
* This ensures we don't leak a secondary service if incl_svc allocation fails. */
incl_svc = os_memblock_get(&peer_incl_svc_pool);
if (incl_svc == NULL) {
return BLE_HS_ENOMEM;
}
/* Now allocate secondary service if needed, after incl_svc allocation succeeds */
if (!svc) {
/* secondary service */
svc = os_memblock_get(&peer_svc_pool);
if (svc == NULL) {
/* Free incl_svc before returning */
os_memblock_put(&peer_incl_svc_pool, incl_svc);
return BLE_HS_ENOMEM;
}
memset(svc, 0, sizeof *svc);
svc->svc.start_handle = gatt_incl_svc->start_handle;
svc->svc.end_handle = gatt_incl_svc->end_handle;
memcpy(&svc->svc.uuid, &gatt_incl_svc->uuid, sizeof(ble_uuid_any_t));
SLIST_INIT(&svc->chrs);
SLIST_INIT(&svc->incl_svc);
if (prev == NULL) {
SLIST_INSERT_HEAD(&peer->svcs, svc, next);
} else {
SLIST_INSERT_AFTER(prev, svc, next);
}
}
incl_svc->svc = *gatt_incl_svc;
if (incl_svc_prev == NULL) {
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -8,6 +8,7 @@
#include <ctype.h>
#include "esp_log.h"
#include <string.h>
#include <strings.h>
#include <esp_log.h>
#include <esp_console.h>
#include "esp_vfs_dev.h"
@@ -22,9 +23,23 @@
#define YES_NO_PARAM (5000 / portTICK_PERIOD_MS)
static QueueHandle_t cli_handle;
static int key[3];
static int conn_param[10];
static int mtu;
#define CLI_CONN_PARAM_COUNT 6
#define CLI_MSG_TYPE_CONN_PARAM 1
#define CLI_MSG_TYPE_MTU 2
#define CLI_MSG_TYPE_THROUGHPUT 3
#define CLI_MSG_TYPE_YESNO 4
struct cli_msg {
int type;
union {
int conn_param[CLI_CONN_PARAM_COUNT];
int mtu;
int key[3];
bool yes;
} data;
};
#define CONSOLE_PROMPT_LEN_MAX (32)
@@ -41,56 +56,77 @@ static int conn_param_handler(int argc, char *argv[])
return -1;
}
sscanf(argv[1], "%d", &conn_param[0]);
sscanf(argv[2], "%d", &conn_param[1]);
sscanf(argv[3], "%d", &conn_param[2]);
sscanf(argv[4], "%d", &conn_param[3]);
sscanf(argv[5], "%d", &conn_param[4]);
sscanf(argv[6], "%d", &conn_param[5]);
struct cli_msg msg = {
.type = CLI_MSG_TYPE_CONN_PARAM,
};
ESP_LOGI("You entered", "%s %d %d %d %d %d %d", argv[0], conn_param[0], conn_param[1],
conn_param[2], conn_param[3], conn_param[4], conn_param[5]);
xQueueSend(cli_handle, &conn_param[0], 500 / portTICK_PERIOD_MS);
sscanf(argv[1], "%d", &msg.data.conn_param[0]);
sscanf(argv[2], "%d", &msg.data.conn_param[1]);
sscanf(argv[3], "%d", &msg.data.conn_param[2]);
sscanf(argv[4], "%d", &msg.data.conn_param[3]);
sscanf(argv[5], "%d", &msg.data.conn_param[4]);
sscanf(argv[6], "%d", &msg.data.conn_param[5]);
ESP_LOGI("You entered", "%s %d %d %d %d %d %d", argv[0], msg.data.conn_param[0], msg.data.conn_param[1],
msg.data.conn_param[2], msg.data.conn_param[3], msg.data.conn_param[4], msg.data.conn_param[5]);
if (cli_handle == NULL) {
ESP_LOGE("CLI", "Queue not initialized");
return -1;
}
xQueueSend(cli_handle, &msg, 500 / portTICK_PERIOD_MS);
return 0;
}
static int conn_mtu_handler(int argc, char *argv[])
{
int ret;
int mtu;
ESP_LOGI("MTU Arguments entered", "%d", argc);
if (argc != 2) {
return -1;
}
sscanf(argv[1], "%d", &mtu);
ESP_LOGI("You entered", "%s %d", argv[0], mtu);
xQueueSend(cli_handle, &mtu, 500 / portTICK_PERIOD_MS);
ret = sscanf(argv[1], "%d", &mtu);
if (ret != 1) {
return -1;
}
struct cli_msg msg = {
.type = CLI_MSG_TYPE_MTU,
.data.mtu = mtu,
};
if (cli_handle) {
xQueueSend(cli_handle, &msg, 500 / portTICK_PERIOD_MS);
}
return 0;
}
static int throughput_demo_handler(int argc, char *argv[])
{
char pkey[8];
struct cli_msg msg = {
.type = CLI_MSG_TYPE_THROUGHPUT,
};
if (argc != 4) {
return -1;
}
sscanf(argv[1], "%s", pkey);
sscanf(argv[1], "%7s", pkey);
if (strcmp(pkey, "read") == 0) {
key[0] = 1;
msg.data.key[0] = 1;
} else if (strcmp(pkey, "write") == 0) {
key[0] = 2;
msg.data.key[0] = 2;
} else if (strcmp(pkey, "notify") == 0) {
key[0] = 3;
msg.data.key[0] = 3;
} else {
key[0] = 0;
msg.data.key[0] = 0;
}
sscanf(argv[2], "%d", &key[1]);
sscanf(argv[3], "%d", &key[2]);
ESP_LOGI("Throughput demo handler", "%s %s %d %d", argv[0], argv[1], key[1], key[2]);
xQueueSend(cli_handle, &key[0], 500 / portTICK_PERIOD_MS);
sscanf(argv[2], "%d", &msg.data.key[1]);
sscanf(argv[3], "%d", &msg.data.key[2]);
ESP_LOGI("Throughput demo handler", "%s %s %d %d", argv[0], argv[1], msg.data.key[1], msg.data.key[2]);
xQueueSend(cli_handle, &msg, 500 / portTICK_PERIOD_MS);
return 0;
}
@@ -104,32 +140,80 @@ static int yesno_handler(int argc, char *argv[])
return -1;
}
sscanf(argv[1], "%s", yesno);
sscanf(argv[1], "%3s", yesno);
if (strcmp(yesno, "Yes") || strcmp (yesno, "YES") || strcmp(yesno, "yes")) {
if (strcmp(yesno, "Yes") == 0 || strcmp(yesno, "YES") == 0 || strcmp(yesno, "yes") == 0) {
yes = 1;
} else {
} else if (strcmp(yesno, "No") == 0 || strcmp(yesno, "NO") == 0 || strcmp(yesno, "no") == 0) {
yes = 0;
} else {
yes = 0; /* invalid input */
}
ESP_LOGI("User entered", "%s %s", argv[0], yesno);
xQueueSend(cli_handle, &yes, 500 / portTICK_PERIOD_MS);
/* Send as 24-byte buffer to match queue item size */
uint8_t yesno_buf[24] = {0};
yesno_buf[0] = (uint8_t)yes;
if (cli_handle) {
xQueueSend(cli_handle, yesno_buf, 500 / portTICK_PERIOD_MS);
}
return 0;
}
int scli_receive_yesno(bool *console_key)
{
return xQueueReceive(cli_handle, console_key, YES_NO_PARAM);
/* 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);
if (ret == pdPASS) {
*console_key = (bool)temp_buf[0]; /* Extract first byte as bool */
}
return ret;
}
int scli_receive_key(int *console_key)
int scli_receive_key(int console_key[6])
{
return xQueueReceive(cli_handle, console_key, BLE_RX_PARAM);
struct cli_msg msg;
if (xQueueReceive(cli_handle, &msg, BLE_RX_PARAM) != pdTRUE) {
return 0;
}
switch (msg.type) {
case CLI_MSG_TYPE_MTU:
console_key[0] = msg.data.mtu;
return 1;
case CLI_MSG_TYPE_CONN_PARAM:
memcpy(console_key, msg.data.conn_param,
sizeof(msg.data.conn_param));
return 1;
case CLI_MSG_TYPE_THROUGHPUT:
memcpy(console_key, msg.data.key, sizeof(msg.data.key));
return 1;
default:
return 0;
}
}
int cli_receive_key(int *console_key)
int cli_receive_key(int console_key[6])
{
return xQueueReceive(cli_handle, console_key, BLE_RX_TIMEOUT);
struct cli_msg msg;
if (xQueueReceive(cli_handle, &msg, BLE_RX_TIMEOUT) != pdTRUE) {
return 0;
}
switch (msg.type) {
case CLI_MSG_TYPE_CONN_PARAM:
memcpy(console_key, msg.data.conn_param, sizeof(msg.data.conn_param));
return 1;
case CLI_MSG_TYPE_THROUGHPUT:
memcpy(console_key, msg.data.key, sizeof(msg.data.key));
return 1;
case CLI_MSG_TYPE_MTU:
console_key[0] = msg.data.mtu;
return 1;
default:
return 0;
}
}
void scli_reset_queue(void)
@@ -169,7 +253,7 @@ void ble_register_cli(void)
esp_console_cmd_register(&cmds[i]);
}
cli_handle = xQueueCreate( 1, sizeof(int) * 6);
cli_handle = xQueueCreate(1, sizeof(struct cli_msg));
if (cli_handle == NULL) {
return;
}
@@ -507,8 +507,11 @@ void app_main(void)
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
/* Initialize Notify Task */
xTaskCreate(notify_task, "notify_task", 4096, NULL, 10, NULL);
BaseType_t task_rc = xTaskCreate(notify_task, "notify_task", 4096, NULL, 10, NULL);
if (task_rc != pdPASS) {
ESP_LOGE(tag, "Failed to create notify_task (rc=%d)", task_rc);
return ;
}
#if MYNEWT_VAL(BLE_GATTS)
rc = gatt_svr_init();
assert(rc == 0);