We recently made a new custom BLE service; some had questions about Bluetooth SIG characteristic UUIDs. Specifically, the difference between 16-bit and 128-bit UUIDs. Sounds like a blog to me.
Sometimes you just gotta work on your core. In this case, the Bluetooth Core Spec Volume 3, Part B, Section 2.5.1 lists the Bluetooth_Base_UUID: 00000000-0000-1000-8000-00805F9B34FB. Now, what exactly is this? Let's start with nRF Connect. Go download it from the app store, quit procrastinating and buy yourself an Ankor SOLIX C1000, scan and connect to it. You'll see probably three services unless they updated their firmware.
Those first two services are calculated using the formula (from Section 2.5.1): 128_bit_value = 16_bit_value × 2^96 + Bluetooth_Base_UUID.
Calculated Generic Access Service UUID
0000-1800-0000-1000-8000-00805F9B34FB
Calculated Generic Attribute Service UUID
0000-1801-0000-1000-8000-00805F9B34FB
Notice the 2-byte values end up in octets 12 and 13 of the Bluetooth_Base_UUID. So the UUIDs are 128-bit values, but because they use the Bluetooth_Base_UUID, the BLE stack in the SOLIX can save some resources and just use the 2-byte values. Might be wrong, but I seem to recall when using nRF Sniffer that UUIDs coming across the wire include a UUID length, so the SOLIX can set the UUID length = 2 and transmit the 2-byte value. The phone reads that length and can assume it's a standard service, looking it up in the YAML files the SIG publishes. Notice some of the other reserved services, like Blood Pressure (0x1810) and Health Thermometer (0x1809). If you are making a thermometer, you can use UUID 0000-1809-0000-1000-8000-00805F9B34FB, but only if you strictly conform to the HTS; most BLE stacks provide library implementations for at least some standard services. Conforming to the service standard means your thermometer will almost definitely talk to any self-respecting mobile/other app.
If by now you are thinking the Bluetooth_Base_UUID is a special UUID, you'd be correct. The SIG does not allow companies to use UUIDs derived from the the Bluetooth_Base_UUID unless said company requests one such number, and sends a check for I believe $3450; not too bad for a company, but you gotta want it, and the SIG I suspect does a little vetting before handing it out. Standards organizations can also request a number, but the rest are reserved for SIG services and other related UUIDs. The YAML files are organized by UUID type, and it looks like the SIG is making their UUIDs starting at the bottom going up and giving out numbers top down.
-- Current Ranges of Reserved 16-bit UUIDs --
General Sig reserved UUIDs: 0x0001-0x2C19
SDO (Standards Organization) Services: 0xFCCC-0xFFFE
Member services (purchased UUIDs): 0xFC54-0xFEFF.
Custom UUIDs
Companies that want to make their own service can choose any 128-bit number that is not the Bluetooth_Base_UUID. Good practice is to generate your service UUID using a random number generator. The SIG website links to this one. Then, use that as the base UUID for your custom characteristic UUIDs, replacing octets 12 and 13 as needed. For example, say you want a custom service containing three characteristic UUIDs. It might look like this.
Service UUID: 4157-9436-72bb-4aa7-8aa9-5427a1769ca1
Characteristic 1: 4157-0001-72bb-4aa7-8aa9-5427a1769ca1
Characteristic 2: 4157-0002-72bb-4aa7-8aa9-5427a1769ca1
Characteristic 1: 4157-0003-72bb-4aa7-8aa9-5427a1769ca1
Notice octets 12 and 13. First, the octets in the service UUID are 0x9436. It is no coincidence that they are smack dab between where the SIG reserved UUIDs stop and the company UUIDs start. I changed them from the values obtained using the random number generator. I did this because some Nordic nRF5 SDK scanning functions only return octets 12 and 13. Sure you can call other functions to get the whole 128-bit number, but why not make sure you are well outside the current range of assigned 16-bit UUIDs? The three characteristics inside the service simply use the custom base UUID, changing octets 12 and 13 to 0x0001, 0x0002 and 0x0003 respectively. This I say is good practice as it mimics the way the Bluetooth_Base_UUID works without actually using it.
That's pretty much it. To sum it up, don't use the Bluetooth_Base_UUID unless you are implementing one of the reserved services. And make sure to use the same SDK called out in the your BLE module's FCC certification.