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.

  • The extra & was left over from when I was accessing a different structure. I noticed that and fixed it shortly after I sent you the code.

    The suggested functions look like exactly what I need. However, they show up as undeclared when I use them in my code. Is there a header file I need to include? Recall that I'm using the older devkit materials, so perhaps there are equivalent functions there that I should use instead?

  • Hi,

    What do you mean by "older devkit materials"? Which exact nRF5 SDK version are you using? For now, I am assuming that you use SDK 17.1.0 which is the latest nRF5 SDK release, from August 2021.

    Have you included ble_advdata.h? That is where ble_advdata_search() is declared.

  • Correct assumption on the SDK rev.

    Aha, ble_advdata.h is what I was looking for. Now the compiler complains about p_d, which I'll go hunt down. Probably a typo in my copying of your code, or an obvious oversight (or maybe a missing declaration for p_d, which I can figure out. Back in a few minutes....

  • Found it! I dropped the declaration for p_d when I copied your code.

    Now I'm getting all nulls in the Name field. Looking at

               memcpy (Seen [NumSeen].Name, &p_d->p_data [offset], n);

    should that be

               memcpy (Seen [NumSeen].Name, &p_d->p_data + offset, n);

  • Further info: 

    The change from [offset] to + offset I suggested above doesn't seem to help.

    I have added probes to my code to show that the searches for both COMPLETE_LOCAL_NAME and SHORT_LOCAL_NAME are returning zero length, hence I'm getting all nulls in .Name.

    Next?

Reply Children
  • Hi,

    No, it has to be

    memcpy (Seen [NumSeen].Name, &p_d->p_data [offset], n);

    With your change you are making a double pointer again, and then shifting that with the offset. That is not what you want here and will not work.

    Can you show your updated code so that I can get an understanding of what you are doing?

    Secondly, Do you handle advertising packets without a name? Including a name (short or full) is optional, and if you are parsing advertising packets without a name and do not handle that, could that be why you end up with an empty string?

  • 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.

Related