Parse adv_data from BLE scan event

#1

If you are asking a question, please follow this template:

  1. My goal is: Retrieve the manufacturer beacon data from a BLE service advertisement, which is in bold in following service data result from mgos_bt_gap debug:

Scan result debug:
SCAN_RESULT 0 e9:83:8f:e4:a0:90 [ST10202988] manu [] dt 2 at 1 et 0 rssi -56 adl 31 [0201060fff008aeeb3589b203f1514ff6400090b0953543130323032393838] srl 18 [110763fe4ef0b6e24bab901c8128010001a9]

  1. My actions are:
const struct mg_str manufacturerData = mgos_bt_gap_parse_adv_data(ble_data->adv_data, MGOS_BT_GAP_EIR_MANUFACTURER_SPECIFIC_DATA);

(that enum means 0xFF / 255, which matches the manufacturer’s datasheet as well)
3. The result I see is:
Absolutely empty.

  1. My expectation & question is: pulling out the data “008aeeb3589b203f1514ff640009” per the scan result. I’ve even modified esp32_bt_gap to make sure something wasn’t overwriting the data.
          const struct mg_str name = mgos_bt_gap_parse_name(arg.adv_data);
          const struct mg_str manuData = mgos_bt_gap_parse_adv_data(
              arg.adv_data, MGOS_BT_GAP_EIR_MANUFACTURER_SPECIFIC_DATA);

          LOG(LL_DEBUG,
              ("SCAN_RESULT %d %s [%.*s] manu [%.*s] dt %d at %d et %d rssi %d "
               "adl %d [%s] srl %d [%s]",
               p->search_evt, esp32_bt_addr_to_str(p->bda, buf), (int) name.len,
               name.p, 
               (int) manuData.len, manuData.p, 
               p->dev_type,
               p->ble_addr_type, p->ble_evt_type, p->rssi,
               (int) arg.adv_data.len, ad_hex, (int) arg.scan_rsp.len, sr_hex));

What I got:
SCAN_RESULT 0 e9:83:8f:e4:a0:90 [ST10202988] manu [] dt 2 at 1 et 0 rssi -56 adl 31 [0201060fff008aeeb3589b203f1514ff6400090b0953543130323032393838] srl 18 [110763fe4ef0b6e24bab901c8128010001a9]

Please, any tips?

#2

Where are you standing ? How do you get ble_data ? What type is it ? Did you log it to see if it really has the data and is formatted as that function call would expect (has the 0xFF) ?

The log logs ad_hex here
The function you call is here

#3

Hi!
So, the data is showing up in the SCAN_RESULT debug. That long string is the advertised data, which starts with the device ID, then goes to the manufacturer data (in bold in bullet 1) above. That section is known as manufacturer specific data according to the spec.

I have a suspicion there is a simple mismatch between 0xFF which is a data type according to the Bluetooth 4.1 spec (which ironically is linked to even in the mgos code above the MGOS_BT_GAP_EIR_MANUFACTURER_SPECIFIC_DATA enum header declaration). I’m not that great a C coder, it looks like the mgos code in mgos_bt_gap_parse_adv_data uses it as a length rather than knowing as a BLE spec data TYPE there is a defined starting and ending point and the data has a length of 15 (actually 14…). I could be completely reading it wrong though!

At this stage I suspect what the code should be doing is going to the starting point of the advertised data in hex, then extracting 14 and adding a terminator.

#4

I’ll update the thread with how I go :slight_smile:

#5

I’m sorry I’m not able to follow what you are actually doing.
I observed the source code for the function call and the log. The logging function does not call that parsing function to obtain that string.
The parsing function scans the block searching for the key you pass, so if it does not return the string you want, I guess that key is not there.
The logging function just takes the text from a fixed position; that is why I asked, I don’t know what you have in your code. Here is a simplified version:

      struct ble_scan_result_evt_param *p = &ep->scan_rst;   // do you have this struct in your funciton ?
          char ad_hex[MGOS_BT_GAP_ADV_DATA_MAX_LEN * 2 + 1];  // memory for string
          struct mgos_bt_gap_scan_result arg = {.rssi = p->rssi}; // memory for struct
          arg.adv_data =  mg_strdup(mg_mk_str_n((char *) p->ble_adv, p->adv_data_len)); // this is key
          cs_to_hex(ad_hex, (void *) arg.adv_data.p, arg.adv_data.len); // convert to hex

The key part is: the function takes from that scan_result_evt_param structure two pieces of info
p->ble_adv is a pointer to where the string is, p->adv_data_len is the length of that string;
then it converts it to an internal string type (mg_str) and copies it.
So, in this function, there is no parsing for 0xFF but the data is clearly defined as being pointed to by the field ble_adv in the scan_result_evt_param structure.
Give or take some possible mistakes on my side, that is close to what happens there.
Now, in your code, I don’t know.

1 Like
#6

Thanks for the assistance, appreciated!

The key thing I was stupidly missing was the conversion to HEX. I naively thought that since it had been mapped to a mg string struct that it had been converted.

Solution in user land :

mgos_event_add_handler(MGOS_BT_GAP_EVENT_SCAN_RESULT, ble_scan_cb, &result);

static void ble_scan_cb(int ev, void*ev_data, void *data) {
    // struct mgos_ads1x1x *ads = (struct mgos_ads1x1x *)data;
    struct mgos_bt_gap_scan_result *ble_data  = (struct mgos_bt_gap_scan_result *)ev_data;
    const struct mg_str manufacturerData = mgos_bt_gap_parse_adv_data(ble_data->adv_data, MGOS_BT_GAP_EIR_MANUFACTURER_SPECIFIC_DATA);
.....
    char ad_hex2[MGOS_BT_GAP_ADV_DATA_MAX_LEN * 2 + 1];
    cs_to_hex(ad_hex2, reinterpret_cast<const unsigned char*>(manufacturerData.p), manufacturerData.len);
    LOG(LL_INFO,
                    ("SCAN_RESULT MATCH FOUND NAME [%.*s] MANUDATA2 %d [%s] ",
                        (int)name.len,
                        name.p,
                        (int)MGOS_BT_GAP_ADV_DATA_MAX_LEN * 2 + 1,
                        ad_hex2));

#7

… and as the first byte is a 0x00… you were seeing an empty string…