This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

How do I send an unsigned float over the air as a characteristic value?

I have a vendor specific characteristic for the battery voltage in my device, expressed as an actual voltage rather than a percentage. Values are 0.000V to about 4.300V and I need millivolt precision. My voltage variable is simply:

#include <float.h>

float m_battery_voltage;

The issue is that the value pointer on ble_gatts_attr_t is to a uint8_t:

typedef struct
{
  ble_uuid_t*          p_uuid;
  ble_gatts_attr_md_t* p_attr_md;
  uint16_t             init_len;
  uint16_t             init_offs;
  uint16_t             max_len;
  uint8_t*             p_value;
} ble_gatts_attr_t;

I have tried to hack a float into this by assuming it's four bytes and just casting it like this:

attr_char_value.p_uuid    = &char_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len  = 4;
attr_char_value.init_offs = 0;
attr_char_value.max_len   = 4;
attr_char_value.p_value   = (uint8_t*)&m_battery_voltage;

and then doing the same sort of thing on the notify:

hvx_params.handle = p_bts->voltage_handles.value_handle;
hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
hvx_params.offset = 0;
hvx_params.p_len = &len;
hvx_params.p_data = (uint8_t*)&m_battery_voltage;

The value that shows up in the Master Control Panel looks like this (presumably in hex):

00 80 89 40

As for the Android app that's supposed to be reading the value, this results in a value of negative infinity:

Float voltageFloat = c.getFloatValue(BluetoothGattCharacteristic.FORMAT_FLOAT, 0);

There's also this I could try, but haven't yet:

Float voltageFloat = c.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, 0);

I'm aware that I can't simply treat a pointer to a float as if it's a pointer to a uint8_t, but am at a loss as to what else I can do, given the type of ble_gatts_attr_t.p_value.

Related