I'm learning bluetooth, specifically how to implement GATT characteristic specs so I can write peripheral drivers. In almost all specs, they look to be using integer data types to hold decimal values (when the data is a decimal value).
For example, the Cycling Power Measurement spec spec stores the Pedal Power Balance
into a uint8
. As you can see the Pedal Power Balance
value has resolution of 1 decimal place (ex: 10.1
). The GATT format types spec has plenty of types for decimal point numbers (float32
etc).
Why does GATT not use a data type designed to hold decimal numbers? My guess is to limit size of data sent over BLE. Is that correct?
I'm writing NodeJs code to quickly prove out some tech. With my hypothesis, here is how I'm guessing one "packs" a decimal with one digit of precision into a signed 8-bit integer. I'm using acceleration here (can be +/- so using signed int):
'use strict';
const oneG = -9.806649999788;
let int8Buf = new Buffer.alloc(8); //to hold signed 8-bit integer
int8Buf.writeInt8(oneG * 10, 0);
console.log(int8Buf.readInt8(0) / 10);
Running this outputs -9.8
as I expected.
Questions:
Scaled integers like these are used to simplify the implementation on small embedded devices.
For cost and power consumption reasons, the microcontrollers used often do not have an FPU (i.e. hardware support for floating point calculations). On those that don't have an FPU it is possible to use software floating point libraries, but these are slow (and so they consume power), and they take up code space. Even on microcontrollers that do have an FPU, using it increases power consumption, and using four bytes for a floating point number will also increase RAM usage (another scarce resource) compared to only one byte for the scaled integer version.
For these reasons, it is the norm in the embedded world to use scaled integers when fractional quantities are needed.
In the case of a GATT characteristic, it is also desirable to use smaller data types because you usually want your characteristic's value to be no longer than 20 bytes. This is because the ATT MTU is usually set to 23 bytes (and ATT has a 3 bytes overhead), as this is the longest ATT packet that can be included in a single Link Layer packet (if the Data Length Extension of Bluetooth 4.2 is not implemented).