[Info]: BLE: service_uuid_len must be multiple of 16

User avatar
kolban
Posts: 1683
Joined: Mon Nov 16, 2015 4:43 pm
Location: Texas, USA

[Info]: BLE: service_uuid_len must be multiple of 16

Postby kolban » Sun Jun 25, 2017 7:00 pm

Ive been working on BLE recently and trying to set up a BLE peripheral that advertises itself. I was trying to advertise a service with 16bit UUID of "180d". To that end, I was calling:

esp_ble_gap_config_adv_data(&m_advData)

where in the m_advData structure I was setting:

m_advData.service_uuid_len = 2
m_advData.p_service_uuid = &(myUint16t)

When I called esp_ble_gap_config_adv_data() I failed and got the return code indicating an invalid argument. I hunted the docs high and low and eventually resorted to looking at the ESP-IDF source code. It was there that I found an explicit check that tested to see if service_uuid_len was a multiple of 16. So 0, 16, 32 ... etc would have passed but 2 would not.

I wanted to call this out in case someone else trips over this in future. If I were to make a guess, I'd say that ESP-IDF is explicitly ONLY allowing 16 byte UUIDs in advertising packets which seems odd given the apparent desire to minimize the byte size of adverts.

As is always the case, I may be missing something so would welcome any discussions on this topic.
Free book on ESP32 available here: https://leanpub.com/kolban-ESP32

ESP_Tianhao
Posts: 28
Joined: Thu Jan 05, 2017 10:46 am

Re: [Info]: BLE: service_uuid_len must be multiple of 16

Postby ESP_Tianhao » Thu Jun 29, 2017 7:43 am

all 16bit(2bytes) and 32bit(4byte) are simplified by 128bit(16bytes) UUID.
For example (in ESP-IDF bluetooth/gatt_server demo)

Code: Select all

static uint8_t test_service_uuid128[32] = {
    /* LSB <--------------------------------------------------------------------------------> MSB */
    //first uuid, 16bit, [12],[13] is the value
    0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xAB, 0xCD, 0x00, 0x00,
    //second uuid, 32bit, [12], [13], [14], [15] is the value
    0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xAB, 0xCD, 0xAB, 0xCD,
};
See the first uuid, the index [12][13] is exactly 16bit UUID valid value.
See the second UUID, the index [12][13][14][15] is exactly 32bit UUID valid value.
[0]~[11] ( 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00) is the public value same as any other 16 bit UUID and 32 bit UUID. If any bit changed in [0][11], it means it is not 16bit and 32bit UUID, it's 128bit UUID.

Why we use this style, because it is easy to write and handle. It doesn't need complex struct to store different style UUID and need not do many convert in bluetooth program. Maybe, it is good to help some people understand UUID. :)

ESP_Island
Posts: 35
Joined: Thu Jun 29, 2017 7:20 am

Re: [Info]: BLE: service_uuid_len must be multiple of 16

Postby ESP_Island » Thu Jun 29, 2017 8:24 am

Hi, Kolban

In fact, ESP32 supports all 2-Byte UUID, 4-Byte UUID and 16-Byte UUID in advertising packets. But all types of UUID need to be converted to 16-Byte UUID format while setting advertising data using esp_ble_gap_config_adv_data. Bluedroid will re-convert the 16-Byte UUID to original UUID before sending advertising data.

The method to convert short UUID to 16-Byte UUID is by adding Bluetooth Base UUID. The 12 least significant octets need to be set to base UUID, and 4 most significant octets need to be set to 2-Byte UUID or 4-Byte UUID.

There is an example in our demo “gatt_server”, for example, to add a 4-Byte UUID 0xCDABCDAB, set the uuid as followed:
0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xAB, 0xCD, 0xAB, 0xCD, the 12 LSB bytes are base-uuid (0xfb,0x34,…..0x00), and the 4 MSB bytes are 4-Byte UUID to be sent in advertising data.

Another example, to add a 2-Byte UUID 0xCDAB, the 4 MSB need to be set as 0x0000CDAB, set the uuid as followed
0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xAB, 0xCD, 0x00, 0x00

It inherits the design of Bluedroid, and be sure that it is not very convenient to be used. So we have added another API esp_ble_gap_config_adv_data_raw and esp_ble_gap_config_scan_rsp_data_raw. It is allowed to advertise any data you have passed. Be care that completed events to those two APIs are ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT and ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT.

kevinh
Posts: 1
Joined: Sun Jul 02, 2017 6:20 pm

Re: [Info]: BLE: service_uuid_len must be multiple of 16

Postby kevinh » Sun Jul 02, 2017 6:25 pm

BTW -
The example for the gate_security_server, looks to have the UUID for Heart Rate wrong

Code: Select all

static uint8_t sec_service_uuid[16] = {
    /* LSB <--------------------------------------------------------------------------------> MSB */
    //first uuid, 16bit, [12],[13] is the value
    0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x18, 0x0D, 0x00, 0x00,
};
Should be:

Code: Select all

    0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x0D, 0x18, 0x00, 0x00,
ESP_Island wrote:Hi, Kolban

In fact, ESP32 supports all 2-Byte UUID, 4-Byte UUID and 16-Byte UUID in advertising packets. But all types of UUID need to be converted to 16-Byte UUID format while setting advertising data using esp_ble_gap_config_adv_data. Bluedroid will re-convert the 16-Byte UUID to original UUID before sending advertising data.

The method to convert short UUID to 16-Byte UUID is by adding Bluetooth Base UUID. The 12 least significant octets need to be set to base UUID, and 4 most significant octets need to be set to 2-Byte UUID or 4-Byte UUID.

There is an example in our demo “gatt_server”, for example, to add a 4-Byte UUID 0xCDABCDAB, set the uuid as followed:
0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xAB, 0xCD, 0xAB, 0xCD, the 12 LSB bytes are base-uuid (0xfb,0x34,…..0x00), and the 4 MSB bytes are 4-Byte UUID to be sent in advertising data.

Another example, to add a 2-Byte UUID 0xCDAB, the 4 MSB need to be set as 0x0000CDAB, set the uuid as followed
0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xAB, 0xCD, 0x00, 0x00

It inherits the design of Bluedroid, and be sure that it is not very convenient to be used. So we have added another API esp_ble_gap_config_adv_data_raw and esp_ble_gap_config_scan_rsp_data_raw. It is allowed to advertise any data you have passed. Be care that completed events to those two APIs are ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT and ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT.

User avatar
kolban
Posts: 1683
Joined: Mon Nov 16, 2015 4:43 pm
Location: Texas, USA

Re: [Info]: BLE: service_uuid_len must be multiple of 16

Postby kolban » Mon Jul 03, 2017 4:36 am

To my simplistic way of thinking, a 128 bit UUID is 16 bytes (16 * 8 = 128). For example, if we take the heart-rate service seen here:

https://www.bluetooth.com/specification ... t_rate.xml

Its "short" UUID is the 16 bits of 0x180d. Since this is the "16 bit" representation of the UUID, its full 128 version would become:

0000180D-0000-1000-8000-00805F9B34FB

(written in conventional UUID form).

I would typically think of this as existing in RAM as

0x00 0x00 0x18 0x1D 0x00 0x00 0x10 0x00 0x80 0x00 0x00 0x80 0x5F 0x9B 0xB3 0x34 0xFB

If we now contrast this with what is supplied as parameters to a call to esp_ble_gap_config_adv_data() we seem to find that the data should be in reverse order:

0xFB 0x34 0xB3 0x9B 0x5F 0x80 0x00 0x00 0x80 0x00 0x10 0x00 0x00 0x1D 0x18 0x00 0x00

Based on this observation and the last post, I ask the question "why?"

What is the "thinking" behind the ESP-IDF API requiring the UUID to be in "non-intuitive" order?

If I were to try and make a guess, it would be that the ESP32 is a "little endian" device meaning that numerical values are stored in memory in least significant byte first. For example, the 32 bit number represented in hex as 0x12345678 would be stored in sequential storage as the bytes:

0x78 0x56 0x34 0x12

I can follow that ... the notion of how to store in memory a numerical value is the definition of the "big endian" vs "little endian" choice ... and when it comes to machine architectures ... if we read 16bits or 32 bits using machine instructions, it makes sense to read them from memory in "native" format. However, does this apply to artificial values? Do we really want to represent a UUID as a 128 bit numeric value or do should we think about it as 16 bytes of consecutive storage?

My gut is saying that we want to represent it as a 16 byte unit. It makes sense to compare UUIDs for equality ... but beyond that, I'm not sure there is meaning in other numeric operations ... for example UUID1 > UUID2 or X = UUID + 1. If we hold that notion ... and think of a UUID as a 16 byte opaque value then we would seem to want to store it in byte order as opposed to numeric little endian order.

For example, no one expects the String "Hello World" to be stored as:

'd', 'l', 'r', 'o', 'W', ' ', 'o', 'l', 'l', 'e', 'H'

but yet the UUID written as 0000180D-0000-1000-8000-00805F9B34FB does seem to need to be stored as:

0xFB 0x34 0xB3 0x9B 0x5F 0x80 0x00 0x00 0x80 0x00 0x10 0x00 0x00 0x1D 0x18 0x00 0x00
Free book on ESP32 available here: https://leanpub.com/kolban-ESP32

Who is online

Users browsing this forum: AlexESP32, Bing [Bot], Google [Bot] and 29 guests