I want to update/modify advertising data at run time,
How can I do so?
I want to update/modify advertising data at run time,
How can I do so?
Hello,
Please see Lesson 2 from the Bluetooth Low Energy fundamentals course on DevAcademy for information on Bluetooth LE advertising and specifically Exercise 2 which demonstrates dynamically changing the advertising data.
Best regards,
Maria
#include <zephyr/kernel.h> #include <zephyr/sys/printk.h> #include <zephyr/logging/log.h> #include <zephyr/bluetooth/bluetooth.h> #include <zephyr/bluetooth/hci.h> #include <zephyr/bluetooth/gap.h> #include <zephyr/bluetooth/gatt.h> LOG_MODULE_REGISTER(ilumi); #define NETWORK_KEY_UNCOMMISSIONED 0xFFEEDDCC #define NETWORK_MATER_KEY 0x4DBF315A #define BLE_MAX_BROADCAST_SIZE 31 typedef struct { uint8_t option_length; uint8_t manu_type; //0xff type union { uint8_t header[10]; uint8_t bytes[29]; } payload; } MANU_OPTION_t; typedef struct { uint16_t ilumi_id; uint8_t msg_type; uint8_t other_seq_num; // lower 4 bits are sequence number, rotate between 1 to 7 uint8_t dsdv_seq_num; uint8_t model_num; uint16_t firmware_ver; uint16_t network_id; union { uint8_t status_bits; uint8_t status; }; uint8_t mesh_depth; uint16_t bootload_ver; uint16_t ble_stack_ver; uint16_t gatt_handle; uint8_t current_status[6]; // 6 bytes for current status } iLumi_adv_heart_beat_t; typedef struct { uint8_t is_commissioned:1; uint8_t is_connected_as_slave:1; uint8_t is_can_connect_more:1; uint8_t is_neighbor_parentable:1; uint8_t expecting_parent_mesh_depth:4; } ilumi_scan_resp_status; typedef struct { uint16_t service_uuid; uint8_t routing_entry_amount; union { ilumi_scan_resp_status status_bits; uint8_t status; }; uint8_t mac_address[6]; // Define the MAC_ADDRESS_t as an array of 6 bytes uint16_t firmware_ver; uint16_t network_id; } iLumi_scanResp_ServiceData_t; typedef struct __PACKED_STRUCT_BEGIN__ { uint8_t byte[6]; } MAC_ADDRESS_t; void update_heart_beat_data(void); uint8_t get_dsdv_seq_no(void); void update_adv_data(void); void start_advertising(void); void set_device_name(); void set_default_scan_resp_data(void); uint8_t create_adv_resp_data(uint8_t *Scan_Response_Data, uint8_t buffer_size, uint8_t *my_mac_address, uint8_t *Local_Device_Name); uint8_t Local_Device_Name[16]; static iLumi_adv_heart_beat_t adv_heartbeat_pkt; static MANU_OPTION_t newpkt_data; static uint8_t new_adv_data[31]; static uint8_t dsdv_seq_no = 0; MAC_ADDRESS_t ilumi_local_mac_address; struct k_timer update_dsdv_seq_timer; static uint8_t Scan_Response_Data[29]; iLumi_scanResp_ServiceData_t scan_resp_option; static bool is_ble_adv_on = false; static uint8_t adv_data_count = 0; uint8_t uuid128[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x00, 0x40, 0x51, 0x04, 0xC0, 0xF0, 0x00, 0xF0}; struct bt_le_adv_param adv_param = { .options = BT_LE_ADV_OPT_CONNECTABLE,\ BT_LE_ADV_OPT_USE_NAME | \ BT_LE_ADV_OPT_FORCE_NAME_IN_AD, .id = BT_ID_DEFAULT, .interval_min = 0x0020, .interval_max = 0x4000 }; struct bt_data manu_spec_adv_data[2]; struct bt_data scan_rsp_data[2]; static void update_dsdsv_seq_no(struct k_timer *timer){ dsdv_seq_no+=2; printk("dsdv_seq_no : %d\r\n",dsdv_seq_no); k_timer_start(&update_dsdv_seq_timer, K_SECONDS(1), K_NO_WAIT); update_adv_data(); } static void on_connected(struct bt_conn *conn, uint8_t err) { if (err) { printk("Connection failed (err %d)\n", err); } else { printk("Connected\n"); } } static void on_disconnected(struct bt_conn *conn, uint8_t reason) { printk("Disconnected (reason %d)\n", reason); } BT_CONN_CB_DEFINE(conn_callbacks)={ .connected = on_connected, .disconnected = on_disconnected, }; static ssize_t write_callback(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, uint16_t len, uint16_t offset, uint8_t flags) { LOG_INF("Data received, length: %d", len); LOG_HEXDUMP_INF(buf, len, "Received data"); return len; } BT_GATT_SERVICE_DEFINE(my_service, BT_GATT_PRIMARY_SERVICE(BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0xF000F0C0, 0x0451, 0x4000, 0xB000, 0x000000000000))), BT_GATT_CHARACTERISTIC(BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0xF000F0C0, 0x0451, 0x4000, 0xB000, 0x000000000000)), BT_GATT_CHRC_WRITE, BT_GATT_PERM_WRITE, NULL, write_callback, NULL), ); uint8_t get_dsdv_seq_no(void){ return dsdv_seq_no; } void update_heart_beat_data(void) { memset(&adv_heartbeat_pkt, 0, sizeof(adv_heartbeat_pkt)); adv_heartbeat_pkt.ilumi_id = 0xFACE; // Example company_id adv_heartbeat_pkt.firmware_ver = 0x01DD; // Example firmware version adv_heartbeat_pkt.msg_type = 6; // ILUMI_AD_MSG_ROUTE_HEART_BEAT adv_heartbeat_pkt.model_num = 0x51; // Example model number adv_heartbeat_pkt.dsdv_seq_num = get_dsdv_seq_no(); // Example DSDV sequence number adv_heartbeat_pkt.network_id = 0x00CC; // Example network ID adv_heartbeat_pkt.mesh_depth = 0; adv_heartbeat_pkt.bootload_ver = 0x106; adv_heartbeat_pkt.ble_stack_ver = 0x101; //whenever change heart beat, send out A.S.A.P memcpy(newpkt_data.payload.bytes, &adv_heartbeat_pkt, sizeof(adv_heartbeat_pkt)); newpkt_data.manu_type = 0xFF; // Example manufacturer specific type newpkt_data.option_length = sizeof(adv_heartbeat_pkt) + 1; memcpy(&new_adv_data, &newpkt_data.payload, sizeof(newpkt_data.payload)); } uint8_t add_advertise_parameter(uint8_t *buffer, uint8_t *tail, uint8_t length, uint8_t type, uint8_t *data) { uint8_t total_len = 2 + length; if ((buffer + total_len) > (tail + 1)) { // not enough buffer to add new parameter return 0; } else { buffer[0] = total_len - 1; // not including type itself buffer[1] = type; memcpy(&buffer[2], data, length); return total_len; } } uint8_t create_adv_resp_data(uint8_t *Scan_Response_Data, uint8_t buffer_size, uint8_t *my_mac_address, uint8_t *Local_Device_Name) { uint8_t ad_offset = 0; // iLumi_scanResp_ServiceData_t scan_resp_option; memset(Scan_Response_Data, 0, buffer_size); /* <0> iLumi local device name */ ad_offset += add_advertise_parameter(&Scan_Response_Data[ad_offset], &Scan_Response_Data[BLE_MAX_BROADCAST_SIZE - 1], 11, BT_DATA_NAME_COMPLETE, Local_Device_Name); /* <1> iLumi Service data with MAC address */ scan_resp_option.service_uuid = 0xF0C0; // Example UUID scan_resp_option.status = 0; scan_resp_option.status_bits.is_commissioned = 0; // Example value scan_resp_option.status_bits.is_connected_as_slave = 0; // Example value scan_resp_option.routing_entry_amount = 5; // Example value scan_resp_option.network_id = 0xFFFF; // Example value scan_resp_option.firmware_ver = 0x0102; // Example value memcpy(scan_resp_option.mac_address, my_mac_address, sizeof(scan_resp_option.mac_address)); ad_offset += add_advertise_parameter(&Scan_Response_Data[ad_offset], &Scan_Response_Data[BLE_MAX_BROADCAST_SIZE - 1], sizeof(scan_resp_option), BT_DATA_SVC_DATA16, (uint8_t*)&scan_resp_option); return ad_offset; } void update_scan_response_data(void){ // memset(Scan_Response_Data, 0, buffer_size); memset(&scan_resp_option,0,sizeof(scan_resp_option)); /* <1> iLumi Service data with MAC address */ scan_resp_option.service_uuid = 0xF0C0; // Example UUID scan_resp_option.status = 0; scan_resp_option.status_bits.is_commissioned = 0; // Example value scan_resp_option.status_bits.is_connected_as_slave = 0; // Example value scan_resp_option.routing_entry_amount = 0; // Example value scan_resp_option.network_id = 0x00CC; // Example value scan_resp_option.firmware_ver = 0x01DD; // Example value memcpy(scan_resp_option.mac_address, &ilumi_local_mac_address, sizeof(scan_resp_option.mac_address)); } void set_default_scan_resp_data(void) { printk("MAC ADDRESS: %02X:%02X:%02X:%02X:%02X:%02X\r\n",ilumi_local_mac_address.byte[0],ilumi_local_mac_address.byte[1],ilumi_local_mac_address.byte[2], ilumi_local_mac_address.byte[3],ilumi_local_mac_address.byte[4],ilumi_local_mac_address.byte[5]); create_adv_resp_data(Scan_Response_Data, BLE_MAX_BROADCAST_SIZE,(uint8_t*)&ilumi_local_mac_address, Local_Device_Name); } void start_advertising(void) { adv_param.interval_min = 160; adv_param.interval_max = 800; manu_spec_adv_data[0].type = BT_DATA_FLAGS; manu_spec_adv_data[0].data_len = 1; manu_spec_adv_data[0].data = (uint8_t []) { 0x06 }; manu_spec_adv_data[1].type = BT_DATA_MANUFACTURER_DATA; manu_spec_adv_data[1].data_len = sizeof(adv_heartbeat_pkt); memcpy(&new_adv_data, &newpkt_data.payload, sizeof(new_adv_data)); manu_spec_adv_data[1].data = new_adv_data; adv_data_count = 1; scan_rsp_data[0].type = BT_DATA_NAME_COMPLETE; scan_rsp_data[0].data_len = 12; scan_rsp_data[0].data = Local_Device_Name; scan_rsp_data[1].type = BT_DATA_SVC_DATA16; scan_rsp_data[1].data_len = sizeof(scan_resp_option); scan_rsp_data[1].data = (uint8_t*)&scan_resp_option; for(uint8_t i = 0; i<sizeof(manu_spec_adv_data)/sizeof(struct bt_data) ; i++){ LOG_INF("ADV DATA-%d TYPE: %02x, DATA_LENGTH : %02X",i,manu_spec_adv_data[i].type,manu_spec_adv_data[i].data_len); LOG_HEXDUMP_INF(manu_spec_adv_data[i].data,manu_spec_adv_data[i].data_len,"ADV DATA"); } for(uint8_t i = 0; i<sizeof(scan_rsp_data)/sizeof(struct bt_data) ; i++){ LOG_INF("SCAN RESP-%d TYPE: %02x, DATA_LENGTH : %02X",i,scan_rsp_data[i].type,scan_rsp_data[i].data_len); LOG_HEXDUMP_INF(scan_rsp_data[i].data,scan_rsp_data[i].data_len,"SCAN RESP"); } error_t err = bt_le_adv_start(&adv_param, manu_spec_adv_data, ARRAY_SIZE(manu_spec_adv_data), scan_rsp_data, ARRAY_SIZE(scan_rsp_data)); if (err) { printk("Advertising failed to start (err %d)\r\n", err); is_ble_adv_on = false; return; }else{ is_ble_adv_on = true; printk("Advertising successfully started\r\n"); } } void update_adv_data(void){ if(is_ble_adv_on){ error_t err = bt_le_adv_stop(); if(err){ printk("unable to stop adv err : %d\r\n",err); return; }else{ printk("Adv stopped successfully\r\n"); } } if(adv_data_count == 0){ adv_data_count = 1; manu_spec_adv_data[0].type = BT_DATA_FLAGS; manu_spec_adv_data[0].data_len = 1; manu_spec_adv_data[0].data = (uint8_t []) { 0x06 }; manu_spec_adv_data[1].type = BT_DATA_MANUFACTURER_DATA; manu_spec_adv_data[1].data_len = sizeof(adv_heartbeat_pkt); memcpy(&new_adv_data, &newpkt_data.payload, sizeof(new_adv_data)); manu_spec_adv_data[1].data = new_adv_data; }else{ adv_data_count = 0; adv_data_count = 1; manu_spec_adv_data[0].type = BT_DATA_UUID128_ALL; manu_spec_adv_data[0].data_len = sizeof(uuid128); manu_spec_adv_data[0].data = uuid128; manu_spec_adv_data[1].type = BT_DATA_TX_POWER; manu_spec_adv_data[1].data_len = 1; manu_spec_adv_data[1].data = (uint8_t[]){0x0C}; } scan_rsp_data[0].type = BT_DATA_NAME_COMPLETE; scan_rsp_data[0].data_len = 12; scan_rsp_data[0].data = Local_Device_Name; scan_rsp_data[1].type = BT_DATA_SVC_DATA16; scan_rsp_data[1].data_len = sizeof(scan_resp_option); scan_rsp_data[1].data = (uint8_t*)&scan_resp_option; for(uint8_t i = 0; i<sizeof(manu_spec_adv_data)/sizeof(struct bt_data) ; i++){ LOG_INF("ADV DATA-%d TYPE: %02x, DATA_LENGTH : %02X",i,manu_spec_adv_data[i].type,manu_spec_adv_data[i].data_len); LOG_HEXDUMP_INF(manu_spec_adv_data[i].data,manu_spec_adv_data[i].data_len,"ADV DATA"); } for(uint8_t i = 0; i<sizeof(scan_rsp_data)/sizeof(struct bt_data) ; i++){ LOG_INF("SCAN RESP-%d TYPE: %02x, DATA_LENGTH : %02X",i,scan_rsp_data[i].type,scan_rsp_data[i].data_len); LOG_HEXDUMP_INF(scan_rsp_data[i].data,scan_rsp_data[i].data_len,"SCAN RESP"); } error_t err = bt_le_adv_update_data(manu_spec_adv_data, ARRAY_SIZE(manu_spec_adv_data), scan_rsp_data, ARRAY_SIZE(scan_rsp_data)); if(err){ printk("Unable to update adv data error: %d\r\n",err); }else{ printk("Advertisment parameters updated successfuly\r\n"); } bt_le_adv_resume(); } void set_device_name(){ char addr_s[BT_ADDR_LE_STR_LEN]; bt_addr_le_t addr = {0}; size_t count = 1; bt_id_get(&addr, &count); bt_addr_le_to_str(&addr, addr_s, sizeof(addr_s)); memcpy(&ilumi_local_mac_address, addr.a.val, sizeof(MAC_ADDRESS_t)); sprintf((char *)Local_Device_Name, "%s%02X%02X%02X", "Nrdic", ilumi_local_mac_address.byte[2], ilumi_local_mac_address.byte[1], ilumi_local_mac_address.byte[0]); printk("Device Name: %s\r\n", Local_Device_Name); error_t err = bt_set_name(Local_Device_Name); if(err){ LOG_ERR("Unable sto set the device name : %d",err); } } void bt_ready(int err) { if (err) { LOG_ERR("Bluetooth init failed (err %d)\r\n", err); return; } printk("Bluetooth initialized\r\n"); } void main(void) { int err; K_SECONDS(1); k_timer_init(&update_dsdv_seq_timer, update_dsdsv_seq_no, NULL); k_timer_start(&update_dsdv_seq_timer, K_SECONDS(1), K_NO_WAIT); err = bt_enable(bt_ready); if (err) { LOG_ERR("Bluetooth enable failed (err %d)", err); } set_device_name(); update_scan_response_data(); update_heart_beat_data(); start_advertising(); }
Error I got after using the adv update function:
*** Booting nRF Connect SDK v3.5.99-ncs1-1 *** [00:00:00.000,488] <inf> bt_sdc_hci_driver: SoftDevice Controller build revision: 36 f0 e5 0e 87 68 48 fb 02 fd 9f 82 cc 32 e5 7b |6....hH. .....2.{ 91 b1 5c ed |..\. [00:00:00.002,807] <inf> bt_hci_core: HW Platform: Nordic Semiconductor (0x0002) [00:00:00.002,838] <inf> bt_hci_core: HW Variant: nRF52x (0x0002) [00:00:00.002,868] <inf> bt_hci_core: Firmware: Standard Bluetooth controller (0x00) Version 54.58864 Build 1214809870 [00:00:00.003,723] <inf> bt_hci_core: Identity: DB:FD:39:59:2A:7F (random) [00:00:00.003,753] <inf> bt_hci_core: HCI: version 5.4 (0x0d) revision 0x118f, manufacturer 0x0059 [00:00:00.003,784] <inf> bt_hci_core: LMP: version 5.4 (0x0d) subver 0x118f Bluetooth initialized Device Name: Nrdic592A7F [00:00:00.003,967] <inf> ilumi: ADV DATA-0 TYPE: 01, DATA_LENGTH : 01 [00:00:00.003,997] <inf> ilumi: ADV DATA 06 |. [00:00:00.003,997] <inf> ilumi: ADV DATA-1 TYPE: ff, DATA_LENGTH : 18 [00:00:00.004,028] <inf> ilumi: ADV DATA ce fa 06 00 00 51 dd 01 cc 00 00 00 06 01 01 01 |.....Q.. ........ 00 00 00 00 00 00 00 00 |........ [00:00:00.004,058] <inf> ilumi: SCAN RESP-0 TYPE: 09, DATA_LENGTH : 0C [00:00:00.004,058] <inf> ilumi: SCAN RESP 4e 72 64 69 63 35 39 32 41 37 46 00 |Nrdic592 A7F. [00:00:00.004,089] <inf> ilumi: SCAN RESP-1 TYPE: 16, DATA_LENGTH : 0E [00:00:00.004,119] <inf> ilumi: SCAN RESP c0 f0 00 00 7f 2a 59 39 fd db dd 01 cc 00 |.....*Y9 ...... Advertising successfully started dsdv_seq_no : 2 ASSERTION FAIL [err == 0] @ WEST_TOPDIR/zephyr/subsys/bluetooth/host/hci_core.c:331 command opcode 0x2039 timeout with err -11 [00:00:01.068,084] <err> fatal_error: k_sys_fatal_error_handler: Resetting system
Hi,
It is somewhat difficult to make conclusions from your project when it is not a minimal example.
Did you successfully run the (completed) code from the BLE exercise I linked?
For further debugging, I recommend that you revert back to a version of your project which had no errors, and introduce new features gradually to find out which part of it is the cause of the error.
I can see from the log that it is hci_core which throws the error, but I can't go much further because error -11 = -EAGAIN which means either that a semaphore was updated while waiting or that the wait timed out for k_sem_take.
Best regards,
Maria