Fitting data into advertisement packet nRF52840

Hi there, 

I'm trying to advertise my changing sensor data over BLE, and according to my calculations it should fit without a scan response, but it isn't fitting--what am I missing? Is there a way to get it to compress to send the data in one packet? I'm really trying to accomplish this without a scan response. Here are the details: 

This is where I define my manufacturer specific data. I need to send 7 floats, so 28 bytes of data of a supposed 31 byte limit.

typedef struct adv_mfg_data {
 
	float cap_val_0; // 4 bytes
	float cap_val_1;
	float cap_val_2;

	float w_scaled;
	float x_scaled;
	float y_scaled;
	float z_scaled;

} adv_mfg_data_type;

and here is where I assemble the advertising packet:

static const struct bt_data ad[] = {	
	BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_NO_BREDR),	
	BT_DATA(BT_DATA_MANUFACTURER_DATA,(unsigned char *)&adv_mfg_data, sizeof(adv_mfg_data)),
};

When I try to run the code, however, it gives me a packet "too big" error. Where's the extra space coming from? How can I make this work in one packet? Is there a different structure I could use?

Clarification: it works with one less float, but I think the flags and other members of the BT_DATA() structures send me one byte over to 32 bytes--is this correct? If so, is there a way to fit that one byte in there? Can I get rid of the company ID? Is there a 3-byte float? I don't need 4 bytes of precision on 3 of the floats, but I don't think there's another structure that would work. I roughly need to represent a double-digit decimal value with 2-3 decimal places: XX.XXX. What might this fit in?

Some other questions, too: 

1. I'm using a sniffer (with Wireshark) to look at packets, but I'm not sure how to decode my data back to the floats I started with--do you have advice on this?

2. I need to configure a nRF52840 as a central device that retrieves the data from the adv packets of 20 of these BLE beacons, is there an example code using the nRF Connect SDK that I could start with? Or any advice you have?

3. To identify each of the 20 devices to the central, is there room for a random static address (or would something else be easier?) so I can know which peripheral I'm receiving data from? Would this add to the advertising packet or just change it?

4. The functions to start advertising and update advertising necessitate including a scan response--is there a way to remove the scanning feature? This is how I configured BT, and my functions to start and update advertisement. 

static struct bt_le_adv_param *adv_param = BT_LE_ADV_PARAM(0, /* 0 = BT_LE_ADV_NCONN */ //want ADV_NONCONN_IND, but doesn't recognize
                800, /*Min Advertising Interval 500ms (800*0.625ms) */
                801, /*Max Advertising Interval 500.625ms (801*0.625ms)*/
                NULL); /* Set to NULL for undirected advertising*/ //but I could set to peer

	err = bt_le_adv_start(adv_param, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));

bt_le_adv_update_data(ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); //my changing variables will be in ad

If it would be useful for any of this, I can attach my whole main.c. Let me know, and thank you so much!

  • Hello

    When I try to run the code, however, it gives me a packet "too big" error. Where's the extra space coming from?

    I believe you have 2 bytes Company ID, 1 byte for length, one byte for type, and then you have 27 bytes left. You should be able to see this structure pretty clearly in Wireshark. You can read about different advertising structures/options here:

    https://novelbits.io/maximum-data-bluetooth-advertising-packet-ble/

    So your options would be to either use extended advertising, or to represent your data using fewer bytes.

    Is there a 3-byte float? I don't need 4 bytes of precision on 3 of the floats

    You could represent a float with two ints, one uint8_t and one uint16_t for example.

    Is there really any good reason to send this data as floats anyway? How is the raw sensor data represented?

    1. I'm using a sniffer (with Wireshark) to look at packets, but I'm not sure how to decode my data back to the floats I started with--do you have advice on this?

    You could put known data into your packet (eg [1.2, 3.4, 5.6, 7.8]), then it'd be easier to see what's going on in your BLE data.

    Doesn't Wireshark usually decode the data for you anyway?

    2. I need to configure a nRF52840 as a central device that retrieves the data from the adv packets of 20 of these BLE beacons, is there an example code using the nRF Connect SDK that I could start with? Or any advice you have?

    There are BLE central role samples available yes:

    https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/samples/bl.html

    https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/zephyr/samples/bluetooth/bluetooth.html

    3. To identify each of the 20 devices to the central, is there room for a random static address (or would something else be easier?) so I can know which peripheral I'm receiving data from? Would this add to the advertising packet or just change it?

    The advertiser's address is included in the advertisement payload before the advertisement data, you should be able to see this in Wireshark, so it should be possible to tell advertisements from different devices apart.

    You could add an identifier to your advertising data of course, but yes that would add to the advertising packet.

    4. The functions to start advertising and update advertising necessitate including a scan response--is there a way to remove the scanning feature?

    Looks like Zephyr's beacon sample uses BT_LE_ADV_NCONN_IDENTITY (though they are also defining a scan response):

    https://github.com/zephyrproject-rtos/zephyr/blob/main/samples/bluetooth/beacon/src/main.c#L57

    Best regards,

    Einar

Related