Has the format of ble_gap_evt_adv_report_t changed recently?

I have modified code for the Dongle to allow reporting multiple advertising devices, and select one device to connect to the USB/serial port. I can display the 64-bit unit ID and can connect and transfer data in both directions. My device inserts the name of the software in the advertising packet per some Nordic examples, and it shows up on the Android nRF Connect app. That app also shows "Raw Data" where I can clearly see the same field. When I attempt to make use of the name field in the Dongle code, sometimes it shows up, sometimes it's shifted a few bytes, and sometimes I get complete gibberish. From what I read, there is a ble_data_t field named data, with elements p_data that should point to the string, and len that gives the number of bytes. How should I use these to extract the text sent from my device?

Parents
  • Hi,

    There has not been a nRF5 SDK nor SoftDevice release for quite a few years, so there has not been any recent changes. If you can elaborate more on what you do (and also what you have changed if it worked before), I can attempt to understand what the problem is.

    Based on what you write where the data is seemingly sometimes corrupted, two things come to mind. One is some sort of parser error as I do not know how you parse the data, but another possibility is if you restart scanning before the data has been parsed. If that is doen with the same scan buffer it could be that the buffer is updated while or before being parsed.

  • I have these declarations in my code, most of which came from Nordic-provided code:

    static struct
       {
       ble_gap_evt_adv_report_t Adv;
       ble_gap_scan_params_t Scan;
       ble_gap_conn_params_t Conn;
       uint8_t ConnCfgTag;
       uint8_t Name [32];
       }
    Seen [50];
    int NumSeen = 0;

    Within the scan evt handler is this code, with my added code highlighted:

       case NRF_BLE_SCAN_EVT_FILTER_MATCH:
          {
          int i;
          nrf_ble_scan_evt_filter_match_t const * p_filter_match = &(p_scan_evt -> params.filter_match);
          if (NumSeen >= 50) NumSeen = 0;
          if (NumSeen < 50)
             {
             Seen [NumSeen].Adv = *(p_filter_match -> p_adv_report);
             for (int j = 0; j < sizeof Seen [NumSeen].Name - 1; ++j)
                Seen [NumSeen].Name [j] = ((uint8_t *) &Seen [NumSeen].Adv.data.p_data) [j];
             Seen [NumSeen].Name [31] = 0;
             Seen [NumSeen].Scan.extended = 0;
             Seen [NumSeen].Scan.report_incomplete_evts = 0;
             Seen [NumSeen].Scan.active = 1;
             Seen [NumSeen].Scan.filter_policy = 0;
             Seen [NumSeen].Scan.scan_phys = 1;
             Seen [NumSeen].Scan.interval = 160;
             Seen [NumSeen].Scan.window = 80;
             Seen [NumSeen].Scan.timeout = 0;
             Seen [NumSeen].Conn.min_conn_interval = 6; // Minimum Connection Interval in 1.25 ms units
             Seen [NumSeen].Conn.max_conn_interval = 24; // Maximum Connection Interval in 1.25 ms units
             Seen [NumSeen].Conn.slave_latency = 0; // Slave Latency in number of connection events
             Seen [NumSeen].Conn.conn_sup_timeout = 400; // Connection Supervision Timeout in 10 ms units
             Seen [NumSeen].ConnCfgTag = MyConfigTag;
             for (i = 0; i < NumSeen; ++i)
                if (!memcmp (&Seen [NumSeen].Adv.peer_addr, &Seen [i].Adv.peer_addr, sizeof Seen [NumSeen].Adv.peer_addr))
                   break;
             if (i == NumSeen)
                {
                ++NumSeen;
                if (!ShowPeripheralsFlag) ShowPeripherals (1);
                }
             }
          }
          break;

    The Name field is my own addition to the struct (named Seen[] in my code) that records all the info found in the scanning for advertisements. I added the copy here (boldface code above) because it appeared that the .Adv.data was getting corrupted later. Are you suggesting that I might be copying too early, before it's all filled in? I'm just trying to capture the name of the device, as it is set via the sd_ble_gap_device_name_set call within the device's application code. Is there a better way to get that field? The Android nRF Connect app gets it flawlessly, so I know it's there to be harvested.

  • Aha. I failed to notice the & before p_d. So the equivalent, as I would have written it, would be to drop the ampersand and use + offset rather than [offset]. Am I missing anything here?

    Updated code below. Still claims to find the name, and the correct length, but the text is gibberish.

    There are currently no anonymous advertisers in range. But it appears to me the code handles that correctly. First search for Complete name, if not found, search for Short name, and if that's not found, set Name to a null string. Did I miss a place to fall thru the cracks?

    Here's the code:

       case NRF_BLE_SCAN_EVT_FILTER_MATCH:
          {
          int i;
          nrf_ble_scan_evt_filter_match_t const * p_filter_match = &(p_scan_evt -> params.filter_match);
          if (NumSeen >= 50) NumSeen = 0;
          if (NumSeen < 50)
             {
             Seen [NumSeen].Adv = *(p_filter_match -> p_adv_report);
             ble_data_t const *p_d;
             p_d = &p_filter_match -> p_adv_report -> data;
             offset = 0;
             name_len = ble_advdata_search (p_d->p_data, p_d->len, &offset, BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME);
             if (!name_len) name_len = p_d -> len;
             if (name_len == 0)
                {
                offset = 0;
                name_len = ble_advdata_search (p_d->p_data, p_d->len, &offset, BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME);
                }
             if (name_len > 0)
                {
                uint16_t n = name_len < sizeof Seen [NumSeen].Name - 1
                           ? name_len : sizeof Seen [NumSeen].Name - 1;
                memcpy (Seen [NumSeen].Name, &p_d -> p_data [offset], n);
                Seen [NumSeen].Name [n] = 0;
                }
             else
                {
                Seen [NumSeen].Name [0] = '\0';
                }

  • Guessing that you're gone for the weekend, as you're several hours ahead of us on EDT. Hoping for further guidance as I will be able to spend some time on this over the weekend.

  • Hi,

    There is a logical flaw in this snippet.

    You first hav this line which checks name_len and then writes to it if it is 0:

    if (!name_len) name_len = p_d -> len;

    On the next line you check if it is 0, but this can never be true due to the line above. So this code never runs:

    if (name_len == 0)
       {
       offset = 0;
       name_len = ble_advdata_search (p_d->p_data, p_d->len, &offset, BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME);
       }

    The fix here seems to be to remove the line I highlighted, as I do not see the purpose of it, and it clearly breaks the logic.

  • No joy. Actually, it may be a clue to whatever I'm doing wrong. The only name advertised by the unit is the COMPLETE_LOCAL_NAME (type 9), and there's no SHORT_LOCAL_NAME (type 8) included. Yet the first ble_advdata_search returns null, even though it sets p_d->len to the correct value of 18. Hence my attempt to make use of that. But clearly even at that, the pointer it returns in p_d->p_data is not correct.

    Since the issue appears to be in that pointer, please address my question above: Isn't p_d->p_data + offset, equivalent to &p_d->p_data [offset] ?

  • SteveHx said:
    Since the issue appears to be in that pointer, please address my question above: Isn't p_d->p_data + offset, equivalent to &p_d->p_data [offset] ?

    Yes, this is equivalent C code. 

Reply Children
  • And what about the main issue - The pointer returned does not point to the string, and the return value of the function is null while it should be the same as the value in p_d->len?

  • I am a bit confused here. Did you fix the issue described i my previous post? Can you share your code so that I can see? If not, this is expected.

    If you don't make progress you can instead refer to this sample that works and does the job of extracting short and full name, from advertising and scan respons packets. ble_app_name_scanner.zip

  • The suggested example is exactly the same code (with different formatting) as what I'm using from a Nordic-provided example (so long ago that I don't remember the specifics). I have tried looking up to 128 bytes out from p_data and the text is not present. Here's my code. Why doesn't p_data get pointed properly to the COMPLETE_LOCAL_NAME?

       case NRF_BLE_SCAN_EVT_FILTER_MATCH:
          {
          int i;
          nrf_ble_scan_evt_filter_match_t const * p_filter_match = &(p_scan_evt -> params.filter_match);
          if (NumSeen >= 50) NumSeen = 0;
          if (NumSeen < 50)
             {
             Seen [NumSeen].Adv = *(p_filter_match -> p_adv_report);
             ble_data_t const *p_d;
             p_d = &p_filter_match -> p_adv_report -> data;
             offset = 0;
             name_len = ble_advdata_search (p_d->p_data, p_d->len, &offset, BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME);
             if (!name_len) name_len = p_d -> len;
             if (name_len == 0)
                {
                offset = 0;
                name_len = ble_advdata_search (p_d->p_data, p_d->len, &offset, BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME);
                }

Related