Hi Andrzej, That all sounds good to me.
Thanks, Chris On Fri, Jan 13, 2017 at 02:58:19PM +0100, Andrzej Kaczmarek wrote: > Hi, > > I've refactored Nimble code to use dedicated type for UUID handling instead > of generic byte-array. Full diff is available here (it is split into > several patches for now to separate changes in stack and apps): > > https://github.com/andrzej-kaczmarek/incubator-mynewt-core/c > ompare/develop...andrzej-kaczmarek:nimble/uuid > > Start by looking at ble_uuid.h which defines new structures and helpers for > UUIDs (or see below where I included essential part): > > https://github.com/andrzej-kaczmarek/incubator-mynewt-core/b > lob/1f571c7aeb22eb4e2ae96ca6d01d612afb338fd4/net/nimble/host > /include/host/ble_uuid.h > > Now, let me explain what it is all about: > > Current implementation handles all UUIDs as long 128-bit values so they are > passed like this (byte-array) in API and stored internally. This creates > overhead for handling short 16-bit UUIDs in terms of both memory and > processing time because: > - short values are stored as long ones anyway, > - they have to be converted back and forth since short UUID cannot be put > as long one in ATT PDU, > - there is no generic code to handle the above so similar patterns are > repeated over and over again. > > With new approach there is dedicated type to pass UUID which contains also > its type so this information is available immediately - this is used e.g. > BlueZ and Zephyr. > > enum { > BLE_UUID_TYPE_16 = 16, > BLE_UUID_TYPE_32 = 32, > BLE_UUID_TYPE_128 = 128, > }; > > /* Generic UUID type, to be used only as a pointer */ > typedef struct { > uint8_t type; > } ble_uuid_t; > > typedef struct { > ble_uuid_t u; > uint16_t value; > } ble_uuid16_t; > > typedef struct { > ble_uuid_t u; > uint32_t value; > } ble_uuid32_t; > > typedef struct { > ble_uuid_t u; > uint8_t value[16]; > } ble_uuid128_t; > > /* Universal UUID type, to be used for any-UUID static allocation */ > typedef union { > ble_uuid_t u; > ble_uuid16_t u16; > ble_uuid32_t u32; > ble_uuid128_t u128; > } ble_uuid_any_t; > > This particular approach to handle UUIDs comes from Zephyr which uses neat > trick to have common type for any UUID yet it allows to store 16-bit values > using less memory than for 128-bit values. There are dedicated types for > 16- and 128-bit UUIDs so memory for an UUID can be allocated, but the API > uses "stub" type which defines only UUID type and is used as a pointer to > an actual UUID variable. You can use helpers to get UUID value or compare > them quickly without need to convert between 16- and 128-bit values. See > following examples how this works (or see sample apps): > > // 16-bit UUID value with initialization > ble_uuid16_t uuid16 = BLE_UUID16_INIT(0x2801); > // 128-bit UUID value with initialization > ble_uuid128_t uuid128 = BLE_UUID128_INIT(0x00, 0x11, ... 0xFF); > > // "stub" type is used to pass any type of UUID via API > ble_uuid_t *uuid1 = &uuid16.u; > ble_uuid_t *uuid2 = &uuid128.u; > > // comparing UUIDs is really easy now > if (ble_uuid_cmp(uuid1, uuid2) == 0) { /* equal */ ) > > // since in most cases we use 16-bit UUIDs, it's convenient to easily > retrieve 16-bit value (or 0 if UUID is not 16-bit) > uint16_t u16 = ble_uuid_u16(uuid1); > > // the above is equivalent of > u16 = uuid1->type == BLE_UUID_TYPE_16 ? BLE_UUID16(uuid1)->value : 0; > > // we can easily define UUID inline as well, e.g. when defining service > static const struct ble_gatt_svc_def ble_svc_gap_defs[] = { > { > .type = BLE_GATT_SVC_TYPE_PRIMARY, > .uuid = BLE_UUID16_DECLARE(BLE_SVC_GAP_UUID16), > (...) > > // finally, if we need to store any UUID there is an union defined to help > ble_uuid_any_t uuid; > uuid.u16 = uuid16; > > *IMPORTANT NOTE*: > There are two major differences between old and new API: > - Shen defining and registering services, in old API UUID value is copied > to attribute structure so it does not matter where UUID passed as parameter > is defined. In new API only pointer to UUID is stored thus you cannot e.g. > define value on stack since it will be destroyed. > - You need to make sure that 16-bit UUIDs are defined using helpers > dedicated for 16-bit UUIDs only, i.e. you should not create 128-bit UUID > with Bluetooth base since it will not be detected as 16-bit UUID. > > Finally, there are of course some savings in both flash and RAM: > > before: > < 136 286 *fill* > < 30738 5027 apps_bletiny.a > < 53633 3411 net_nimble_host.a > < 880 290 net_nimble_host_services_ans.a > < 496 289 net_nimble_host_services_gap.a > < 306 86 net_nimble_host_services_gatt.a > < 160884 2784 15828 179496 2bd28 > /home/andk/devel/mynewt/bletiny/bin/targets/bletiny/ > app/apps/bletiny/bletiny.elf > > after: > > 143 364 *fill* > > 30470 5053 apps_bletiny.a > > 53409 3415 net_nimble_host.a > > 880 218 net_nimble_host_services_ans.a > > 496 217 net_nimble_host_services_gap.a > > 306 62 net_nimble_host_services_gatt.a > > 160396 2724 15828 178948 2bb04 > /home/andk/devel/mynewt/bletiny/bin/targets/bletiny/ > app/apps/bletiny/bletiny.elf > > Comments are welcome! :-) > > BR, > Andrzej