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