This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

How to get manufacturer's data from a received advertising message?

In my application, I'm setting a message as manufacturer's data to be sent with the advertising message. To do that is simple, since I have a data type ble_advdata_t, and I can set a pointer to an object of type ble_advdata_manuf_data_t.

But when I receive a advertising event, the type I get is ble_gap_evt_adv_report_t. This type has a field data[31], where the manufacturer's data is included, but also a bunch of other data sent with the advertising.

I'm looking for a way to get just the manufacture's data. Maybe a "parser" to a variable of type ble_advdata_t.

I have tried to use the function ble_advdata_set, passing the first argument as NULL and the second as a pointer to a variable of type ble_advdata_t, like this:

ble_advdata_set(NULL, &advdata)

since in the documentation it says that it is a function for encoding and setting the advertising data and/or scan response data. Setting the first argument to NULL would just scan response data. But this doesn't seem to work.

Do anybody know what can I do?

Thanks in advance.

  • ble_advdata_set() is only for encoding data and setting it for outgoing advertising, the scan response in that API isn't a response you got from a scan to be decoded, it's the data you want to set as advertising data into the scan response you're going to send out when you advertise yourself. So that's not going to help you, ble_advdata_set() is only used to set advertising data.

    The advertising data is in a very simple format however. It's .. where length is 1 byte and is the length of the + , the type is the type, there's a list here and in the spec, manufacturer is 0xFF, then it's data, if there's another field it's directly afterwards.

    So all you have to do is start at the beginning, figure out the type of the field which is the second byte, if it's not advertising you use the length to skip to the next field and do it again until you find your manufacturer data and/or consume the whole buffer. You don't even need to decode the other fields if you don't need them, since you have the length, you can skip right over them. If you wrote a function to find data of a specific type and return the address and length, or NULL if it's not there, it would probably be 3 lines of code.

  • See the scanning part of the BLE central tutorial

    Use this function:

    static uint32_t adv_report_parse(uint8_t type, data_t * p_advdata, data_t * p_typedata)
    
    {
        uint32_t index = 0;
        uint8_t * p_data;
    
        p_data = p_advdata->p_data;
    
        while (index < p_advdata->data_len)
        {
            uint8_t field_length = p_data[index];
            uint8_t field_type = p_data[index+1];
    
            if (field_type == type)
            {
                p_typedata->p_data = &p_data[index+2];
                p_typedata->data_len = field_length-1;
                return NRF_SUCCESS;
            }
            index += field_length+1;
        }
        return NRF_ERROR_NOT_FOUND;
    }
    

    Call it with type = BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA (0xFF)

  • Thank you for the explanation. All I really wanted to know was if I was really going to implement it that way.

  • Thank you, very much. I was going to implement a parser for the advertising myself but this was really handy for me.

  • In NRF SDK 15.2 there is a method 

    uint8_t * ble_advdata_parse(uint8_t  * p_encoded_data, uint16_t data_len, uint8_t ad_type);

    It returns pointer to the specified ad_type.

    Example:

    static void ble_evt_handler(ble_evt_t const *p_ble_evt, void *p_context) {
        if (p_ble_evt->header.evt_id != BLE_GAP_EVT_ADV_REPORT) // is this GAP advertisement?
            return;
        const ble_gap_evt_adv_report_t *p_adv_report = &p_ble_evt->evt.gap_evt.params.adv_report;
        const ble_data_t *data = &p_adv_report->data;
        uint8_t *mfd_data = ble_advdata_parse(data->p_data, data->len, BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA);
        // *mfd_data is a pointer to BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA data
    }

Related