Release 0.2.4

=============

Features
~~~~~~~~

* Introduce GattServer::initializeGattDatabase(). This populates the GATT
  server with added services.

* Add helper funcs: Gap::MSEC_TO_GAP_DURATION_UNITS() to ease setting up of
  connection parameters.

* Enhance connectionEventCallback() to take in peer addr information.

* Minor cleanup of a few public API classes and removal of unnecessary header-file includes.

Bugfixes
~~~~~~~~

* Increase GAP_ADV_PARAMS_INTERVAL_MAX to 0x4000. This addresses mbedmicro/BLE_API/issues/2.

Compatibility
~~~~~~~~~~~~~

One new API has been added (GattServer::initializeGattDatabase()) and
Gap::ConnectionEventCallback_t has been extended. Applications depending on
these should be updated.
This commit is contained in:
Rohit Grover 2014-11-21 09:04:07 +00:00
commit 80f4417363
10 changed files with 356 additions and 490 deletions

View file

@ -14,12 +14,14 @@
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include "UUID.h"
UUID::UUID(ShortUUIDBytes_t shortUUID) : type(UUID_TYPE_SHORT), baseUUID(), shortUUID(shortUUID) {
/* empty */
}
/**************************************************************************/
/*!
@brief Creates a new 128-bit UUID
@ -90,24 +92,3 @@ UUID::UUID(const LongUUIDBytes_t longUUID) : type(UUID_TYPE_SHORT), baseUUID(),
}
}
/**************************************************************************/
/*!
@brief Creates a short (16-bit) UUID
@param[in] ble_uuid
The 16-bit BLE UUID value.
*/
/**************************************************************************/
UUID::UUID(ShortUUIDBytes_t shortUUID) : type(UUID_TYPE_SHORT), baseUUID(), shortUUID(shortUUID)
{
/* empty */
}
/**************************************************************************/
/*!
@brief UUID destructor
*/
/**************************************************************************/
UUID::~UUID(void)
{
}

View file

@ -42,13 +42,13 @@ public:
* Set the BTLE MAC address and type.
* @return BLE_ERROR_NONE on success.
*/
ble_error_t setAddress(Gap::addr_type_t type, const uint8_t address[Gap::ADDR_LEN]);
ble_error_t setAddress(Gap::addr_type_t type, const Gap::address_t address);
/**
* Fetch the BTLE MAC address and type.
* @return BLE_ERROR_NONE on success.
*/
ble_error_t getAddress(Gap::addr_type_t *typeP, uint8_t address[Gap::ADDR_LEN]);
ble_error_t getAddress(Gap::addr_type_t *typeP, Gap::address_t address);
/**
* @param[in] advType
@ -228,7 +228,7 @@ public:
* some object.
*/
void onDataWritten(void (*callback)(const GattCharacteristicWriteCBParams *eventDataP));
template <typename T> void onDataWritten(T *objPtr, void (T::*memberPtr)(const GattCharacteristicWriteCBParams *context));
template <typename T> void onDataWritten(T * objPtr, void (T::*memberPtr)(const GattCharacteristicWriteCBParams *context));
void onUpdatesEnabled(GattServer::EventCallback_t callback);
void onUpdatesDisabled(GattServer::EventCallback_t callback);
@ -253,7 +253,7 @@ public:
* @param localOnly
* Only update the characteristic locally regardless of notify/indicate flags in the CCCD.
*/
ble_error_t updateCharacteristicValue(uint16_t handle, const uint8_t* value, uint16_t size, bool localOnly = false);
ble_error_t updateCharacteristicValue(uint16_t handle, const uint8_t *value, uint16_t size, bool localOnly = false);
/**
* Yield control to the BLE stack or to other tasks waiting for events. This
@ -276,56 +276,56 @@ public:
*/
const char *getVersion(void);
/**
* Set the device name characteristic in the GAP service.
* @param deviceName The new value for the device-name. This is a UTF-8 encoded, <b>NULL-terminated</b> string.
*/
ble_error_t setDeviceName(const uint8_t *deviceName);
/**
* Set the device name characteristic in the GAP service.
* @param deviceName The new value for the device-name. This is a UTF-8 encoded, <b>NULL-terminated</b> string.
*/
ble_error_t setDeviceName(const uint8_t *deviceName);
/**
* Get the value of the device name characteristic in the GAP service.
* @param[out] deviceName Pointer to an empty buffer where the UTF-8 *non NULL-
* terminated* string will be placed. Set this
* value to NULL in order to obtain the deviceName-length
* from the 'length' parameter.
*
* @param[in/out] lengthP (on input) Length of the buffer pointed to by deviceName;
* (on output) the complete device name length (without the
* null terminator).
*
* @note If the device name is longer than the size of the supplied buffer,
* length will return the complete device name length,
* and not the number of bytes actually returned in deviceName.
* The application may use this information to retry with a suitable buffer size.
*
* Sample use:
* uint8_t deviceName[20];
* unsigned length = sizeof(deviceName);
* ble.getDeviceName(deviceName, &length);
* if (length < sizeof(deviceName)) {
* deviceName[length] = 0;
* }
* DEBUG("length: %u, deviceName: %s\r\n", length, deviceName);
*/
ble_error_t getDeviceName(uint8_t *deviceName, unsigned *lengthP);
/**
* Get the value of the device name characteristic in the GAP service.
* @param[out] deviceName Pointer to an empty buffer where the UTF-8 *non NULL-
* terminated* string will be placed. Set this
* value to NULL in order to obtain the deviceName-length
* from the 'length' parameter.
*
* @param[in/out] lengthP (on input) Length of the buffer pointed to by deviceName;
* (on output) the complete device name length (without the
* null terminator).
*
* @note If the device name is longer than the size of the supplied buffer,
* length will return the complete device name length,
* and not the number of bytes actually returned in deviceName.
* The application may use this information to retry with a suitable buffer size.
*
* Sample use:
* uint8_t deviceName[20];
* unsigned length = sizeof(deviceName);
* ble.getDeviceName(deviceName, &length);
* if (length < sizeof(deviceName)) {
* deviceName[length] = 0;
* }
* DEBUG("length: %u, deviceName: %s\r\n", length, deviceName);
*/
ble_error_t getDeviceName(uint8_t *deviceName, unsigned *lengthP);
/**
* Set the appearance characteristic in the GAP service.
* @param[in] appearance The new value for the device-appearance.
*/
ble_error_t setAppearance(uint16_t appearance);
/**
* Set the appearance characteristic in the GAP service.
* @param[in] appearance The new value for the device-appearance.
*/
ble_error_t setAppearance(uint16_t appearance);
/**
* Set the appearance characteristic in the GAP service.
* @param[out] appearance The new value for the device-appearance.
*/
ble_error_t getAppearance(uint16_t *appearanceP);
/**
* Set the appearance characteristic in the GAP service.
* @param[out] appearance The new value for the device-appearance.
*/
ble_error_t getAppearance(uint16_t *appearanceP);
/**
* Set the radio's transmit power.
* @param[in] txPower Radio transmit power in dBm.
*/
ble_error_t setTxPower(int8_t txPower);
/**
* Set the radio's transmit power.
* @param[in] txPower Radio transmit power in dBm.
*/
ble_error_t setTxPower(int8_t txPower);
public:
BLEDevice() : transport(createBLEDeviceInstance()), advParams(), advPayload(), scanResponse(), needToSetAdvPayload(true) {
@ -365,13 +365,13 @@ BLEDevice::reset(void)
}
inline ble_error_t
BLEDevice::setAddress(Gap::addr_type_t type, const uint8_t address[Gap::ADDR_LEN])
BLEDevice::setAddress(Gap::addr_type_t type, const Gap::address_t address)
{
return transport->getGap().setAddress(type, address);
}
inline ble_error_t
BLEDevice::getAddress(Gap::addr_type_t *typeP, uint8_t address[Gap::ADDR_LEN])
BLEDevice::getAddress(Gap::addr_type_t *typeP, Gap::address_t address)
{
return transport->getGap().getAddress(typeP, address);
}
@ -418,6 +418,7 @@ inline ble_error_t
BLEDevice::accumulateAdvertisingPayload(GapAdvertisingData::Appearance app)
{
needToSetAdvPayload = true;
transport->getGap().setAppearance(app);
return advPayload.addAppearance(app);
}
@ -432,6 +433,9 @@ inline ble_error_t
BLEDevice::accumulateAdvertisingPayload(GapAdvertisingData::DataType type, const uint8_t *data, uint8_t len)
{
needToSetAdvPayload = true;
if (type == GapAdvertisingData::COMPLETE_LOCAL_NAME) {
transport->getGap().setDeviceName(data);
}
return advPayload.addData(type, data, len);
}
@ -451,8 +455,11 @@ BLEDevice::setAdvertisingPayload(void) {
inline ble_error_t
BLEDevice::startAdvertising(void)
{
ble_error_t rc;
if ((rc = transport->getGattServer().initializeGATTDatabase()) != BLE_ERROR_NONE) {
return rc;
}
if (needToSetAdvPayload) {
ble_error_t rc;
if ((rc = setAdvertisingPayload()) != BLE_ERROR_NONE) {
return rc;
}
@ -507,7 +514,6 @@ BLEDevice::onDataWritten(T *objPtr, void (T::*memberPtr)(const GattCharacteristi
transport->getGattServer().setOnDataWritten(objPtr, memberPtr);
}
inline void
BLEDevice::onUpdatesEnabled(GattServer::EventCallback_t callback)
{
@ -544,7 +550,7 @@ inline ble_error_t BLEDevice::readCharacteristicValue(uint16_t handle, uint8_t *
}
inline ble_error_t
BLEDevice::updateCharacteristicValue(uint16_t handle, const uint8_t* value, uint16_t size, bool localOnly)
BLEDevice::updateCharacteristicValue(uint16_t handle, const uint8_t *value, uint16_t size, bool localOnly)
{
return transport->getGattServer().updateValue(handle, const_cast<uint8_t *>(value), size, localOnly);
}

View file

@ -58,7 +58,7 @@
template <typename ContextType>
class CallChainOfFunctionPointersWithContext {
public:
typedef FunctionPointerWithContext<ContextType>* pFunctionPointerWithContext_t;
typedef FunctionPointerWithContext<ContextType> *pFunctionPointerWithContext_t;
public:
/** Create an empty chain
@ -120,8 +120,9 @@ public:
* chained FunctionPointers.
*/
void call(ContextType context) {
if (chainHead)
if (chainHead) {
chainHead->call(context);
}
}
private:

View file

@ -17,20 +17,11 @@
#ifndef __GAP_H__
#define __GAP_H__
#include "blecommon.h"
#include "GapAdvertisingData.h"
#include "GapAdvertisingParams.h"
#include "GapEvents.h"
/**************************************************************************/
/*!
\brief
The base class used to abstract GAP functionality to a specific radio
transceiver, SOC or BLE Stack.
*/
/**************************************************************************/
class Gap
{
class Gap {
public:
typedef enum addr_type_e {
ADDR_TYPE_PUBLIC = 0,
@ -40,9 +31,10 @@ public:
} addr_type_t;
static const unsigned ADDR_LEN = 6;
typedef uint8_t address_t[ADDR_LEN];
/**
* enumeration for disconnection reasons. The values for these reasons are
* Enumeration for disconnection reasons. The values for these reasons are
* derived from Nordic's implementation; but the reasons are meant to be
* independent of the transport. If you are returned a reason which is not
* covered by this enumeration, then please refer to the underlying
@ -63,48 +55,59 @@ public:
typedef uint16_t Handle_t;
typedef struct {
uint16_t minConnectionInterval; /**< Minimum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/
uint16_t maxConnectionInterval; /**< Maximum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/
uint16_t slaveLatency; /**< Slave Latency in number of connection events, see @ref BLE_GAP_CP_LIMITS.*/
uint16_t connectionSupervisionTimeout; /**< Connection Supervision Timeout in 10 ms units, see @ref BLE_GAP_CP_LIMITS.*/
uint16_t minConnectionInterval; /**< Minimum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/
uint16_t maxConnectionInterval; /**< Maximum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/
uint16_t slaveLatency; /**< Slave Latency in number of connection events, see @ref BLE_GAP_CP_LIMITS.*/
uint16_t connectionSupervisionTimeout; /**< Connection Supervision Timeout in 10 ms units, see @ref BLE_GAP_CP_LIMITS.*/
} ConnectionParams_t;
public:
/* These functions must be defined in the sub-class */
virtual ble_error_t setAddress(addr_type_t type, const uint8_t address[ADDR_LEN]) = 0;
virtual ble_error_t getAddress(addr_type_t *typeP, uint8_t address[ADDR_LEN]) = 0;
virtual ble_error_t setAdvertisingData(const GapAdvertisingData &, const GapAdvertisingData &) = 0;
virtual ble_error_t startAdvertising(const GapAdvertisingParams &) = 0;
virtual ble_error_t stopAdvertising(void) = 0;
virtual ble_error_t disconnect(DisconnectionReason_t reason) = 0;
virtual ble_error_t getPreferredConnectionParams(ConnectionParams_t *params) = 0;
virtual ble_error_t setPreferredConnectionParams(const ConnectionParams_t *params) = 0;
virtual ble_error_t updateConnectionParams(Handle_t handle, const ConnectionParams_t *params) = 0;
virtual ble_error_t setDeviceName(const uint8_t *deviceName) = 0;
virtual ble_error_t getDeviceName(uint8_t *deviceName, unsigned *lengthP) = 0;
virtual ble_error_t setAppearance(uint16_t appearance) = 0;
virtual ble_error_t getAppearance(uint16_t *appearanceP) = 0;
static const uint16_t UNIT_1_25_MS = 1250; /**< Number of microseconds in 1.25 milliseconds. */
static uint16_t MSEC_TO_GAP_DURATION_UNITS(uint32_t durationInMillis) {
return (durationInMillis * 1000) / UNIT_1_25_MS;
}
typedef void (*EventCallback_t)(void);
typedef void (*ConnectionEventCallback_t)(Handle_t, const ConnectionParams_t *);
typedef void (*ConnectionEventCallback_t)(Handle_t, addr_type_t peerAddrType, const address_t peerAddr, const ConnectionParams_t *);
typedef void (*DisconnectionEventCallback_t)(Handle_t, DisconnectionReason_t);
friend class BLEDevice;
private:
/* These functions must be defined in the sub-class */
virtual ble_error_t setAddress(addr_type_t type, const address_t address) = 0;
virtual ble_error_t getAddress(addr_type_t *typeP, address_t address) = 0;
virtual ble_error_t setAdvertisingData(const GapAdvertisingData &, const GapAdvertisingData &) = 0;
virtual ble_error_t startAdvertising(const GapAdvertisingParams &) = 0;
virtual ble_error_t stopAdvertising(void) = 0;
virtual ble_error_t disconnect(DisconnectionReason_t reason) = 0;
virtual ble_error_t getPreferredConnectionParams(ConnectionParams_t *params) = 0;
virtual ble_error_t setPreferredConnectionParams(const ConnectionParams_t *params) = 0;
virtual ble_error_t updateConnectionParams(Handle_t handle, const ConnectionParams_t *params) = 0;
virtual ble_error_t setDeviceName(const uint8_t *deviceName) = 0;
virtual ble_error_t getDeviceName(uint8_t *deviceName, unsigned *lengthP) = 0;
virtual ble_error_t setAppearance(uint16_t appearance) = 0;
virtual ble_error_t getAppearance(uint16_t *appearanceP) = 0;
private:
/* Event callback handlers */
void setOnTimeout(EventCallback_t callback) {
onTimeout = callback;
}
void setOnConnection(ConnectionEventCallback_t callback) {
onConnection = callback;
}
void setOnDisconnection(DisconnectionEventCallback_t callback) {
onDisconnection = callback;
void setOnTimeout(EventCallback_t callback) {onTimeout = callback;}
void setOnConnection(ConnectionEventCallback_t callback) {onConnection = callback;}
void setOnDisconnection(DisconnectionEventCallback_t callback) {onDisconnection = callback;}
GapState_t getState(void) const {
return state;
}
void processConnectionEvent(Handle_t handle, const ConnectionParams_t *params) {
protected:
Gap() : state(), onTimeout(NULL), onConnection(NULL), onDisconnection(NULL) {
/* empty */
}
public:
void processConnectionEvent(Handle_t handle, addr_type_t type, const address_t addr, const ConnectionParams_t *params) {
state.connected = 1;
if (onConnection) {
onConnection(handle, params);
onConnection(handle, type, addr, params);
}
}
@ -126,22 +129,18 @@ public:
}
}
GapState_t getState(void) const {
return state;
}
protected:
Gap() : state(), onTimeout(NULL), onConnection(NULL), onDisconnection(NULL) {
/* empty */
}
protected:
GapState_t state;
GapState_t state;
private:
EventCallback_t onTimeout;
ConnectionEventCallback_t onConnection;
DisconnectionEventCallback_t onDisconnection;
private:
/* disallow copy and assignment */
Gap(const Gap &);
Gap& operator=(const Gap &);
};
#endif // ifndef __GAP_H__

View file

@ -17,13 +17,6 @@
#ifndef __GAP_ADVERTISING_PARAMS_H__
#define __GAP_ADVERTISING_PARAMS_H__
#include "blecommon.h"
#define GAP_ADV_PARAMS_INTERVAL_MIN (0x0020)
#define GAP_ADV_PARAMS_INTERVAL_MIN_NONCON (0x00A0)
#define GAP_ADV_PARAMS_INTERVAL_MAX (0x1000)
#define GAP_ADV_PARAMS_TIMEOUT_MAX (0x3FFF)
/**************************************************************************/
/*!
\brief
@ -37,19 +30,15 @@
\li \c Bluetooth Core Specification 4.0 (Vol. 6), Part B, Section 2.3.1
\li \c Bluetooth Core Specification 4.0 (Vol. 3), Part C, Section 9.3
\par EXAMPLE
\code
// ToDo
\endcode
*/
/**************************************************************************/
class GapAdvertisingParams
{
class GapAdvertisingParams {
public:
static const unsigned GAP_ADV_PARAMS_INTERVAL_MIN = 0x0020;
static const unsigned GAP_ADV_PARAMS_INTERVAL_MIN_NONCON = 0x00A0;
static const unsigned GAP_ADV_PARAMS_INTERVAL_MAX = 0x4000;
static const unsigned GAP_ADV_PARAMS_TIMEOUT_MAX = 0x3FFF;
/**************************************************************************/
/*!
\brief
@ -70,72 +59,28 @@ public:
ADV_NON_CONNECTABLE_UNDIRECTED /**< Vol 3, Part C, Section 9.3.2 and Vol 6, Part B, Section 2.3.1.3 */
};
public:
GapAdvertisingParams(AdvertisingType advType = GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED,
uint16_t interval = GAP_ADV_PARAMS_INTERVAL_MIN_NONCON,
uint16_t timeout = 0);
virtual ~GapAdvertisingParams(void);
void setAdvertisingType(AdvertisingType newAdvType);
void setInterval(uint16_t newInterval);
void setTimeout(uint16_t newTimeout);
AdvertisingType getAdvertisingType(void) const {return _advType; }
uint16_t getInterval(void) const {return _interval;}
uint16_t getTimeout(void) const {return _timeout; }
virtual AdvertisingType getAdvertisingType(void) const;
virtual uint16_t getInterval(void) const;
virtual uint16_t getTimeout(void) const;
void setAdvertisingType(AdvertisingType newAdvType) {_advType = newAdvType; }
void setInterval(uint16_t newInterval) {_interval = newInterval;}
void setTimeout(uint16_t newTimeout) {_timeout = newTimeout; }
private:
AdvertisingType _advType;
uint16_t _interval;
uint16_t _timeout;
private:
/* disallow copy constructor */
GapAdvertisingParams(const GapAdvertisingParams &);
};
inline void
GapAdvertisingParams::setAdvertisingType(AdvertisingType newAdvType) {
_advType = newAdvType;
}
inline void
GapAdvertisingParams::setInterval(uint16_t newInterval) {
_interval = newInterval;
}
inline void
GapAdvertisingParams::setTimeout(uint16_t newTimeout) {
_timeout = newTimeout;
}
/**************************************************************************/
/*!
\brief returns the current Advertising Type value
*/
/**************************************************************************/
inline GapAdvertisingParams::AdvertisingType
GapAdvertisingParams::getAdvertisingType(void) const
{
return _advType;
}
/**************************************************************************/
/*!
\brief returns the current Advertising Delay (in units of 0.625ms)
*/
/**************************************************************************/
inline uint16_t
GapAdvertisingParams::getInterval(void) const
{
return _interval;
}
/**************************************************************************/
/*!
\brief returns the current Advertising Timeout (in seconds)
*/
/**************************************************************************/
inline uint16_t
GapAdvertisingParams::getTimeout(void) const
{
return _timeout;
}
#endif // ifndef __GAP_ADVERTISING_PARAMS_H__

View file

@ -14,20 +14,10 @@
* limitations under the License.
*/
#ifndef __GATT_ATTRIBUTE_H__
#define __GATT_ATTRIBUTE_H__
#include "blecommon.h"
#include "UUID.h"
/**************************************************************************/
/*!
\brief GATT attribute
*/
/**************************************************************************/
class GattAttribute
{
class GattAttribute {
public:
typedef uint16_t Handle_t;
@ -56,41 +46,29 @@ public:
*/
/**************************************************************************/
GattAttribute(const UUID &uuid, uint8_t *valuePtr = NULL, uint16_t initialLen = 0, uint16_t maxLen = 0) :
_uuid(uuid), _valuePtr(valuePtr), _initialLen(initialLen), _lenMax(maxLen), _handle(){
_uuid(uuid), _valuePtr(valuePtr), _initialLen(initialLen), _lenMax(maxLen), _handle() {
/* empty */
}
public:
Handle_t getHandle(void) const {
return _handle;
}
Handle_t getHandle(void) const {return _handle; }
const UUID &getUUID(void) const {return _uuid; }
uint16_t getInitialLength(void) const {return _initialLen;}
uint16_t getMaxLength(void) const {return _lenMax; }
void setHandle(Handle_t id) {_handle = id; }
uint8_t *getValuePtr(void) {return _valuePtr; }
void setHandle(Handle_t id) {
_handle = id;
}
const UUID &getUUID(void) const {
return _uuid;
}
uint16_t getInitialLength(void) const {
return _initialLen;
}
uint16_t getMaxLength(void) const {
return _lenMax;
}
uint8_t *getValuePtr(void) {
return _valuePtr;
}
protected:
private:
UUID _uuid; /* Characteristic UUID */
uint8_t *_valuePtr;
uint16_t _initialLen; /* Initial length of the value */
uint16_t _lenMax; /* Maximum length of the value */
Handle_t _handle;
private:
/* disallow copy and assignment */
GattAttribute(const GattAttribute &);
GattAttribute& operator=(const GattAttribute &);
};
#endif // ifndef __GATT_ATTRIBUTE_H__

View file

@ -14,21 +14,12 @@
* limitations under the License.
*/
#ifndef __GATT_CHARACTERISTIC_H__
#define __GATT_CHARACTERISTIC_H__
#include "blecommon.h"
#include "UUID.h"
#include "GattAttribute.h"
/**************************************************************************/
/*!
\brief GATT characteristic
*/
/**************************************************************************/
class GattCharacteristic
{
class GattCharacteristic {
public:
enum {
UUID_BATTERY_LEVEL_STATE_CHAR = 0x2A1B,
@ -104,122 +95,122 @@ public:
/**************************************************************************/
/*!
\brief Standard GATT characteristic presentation format unit types.
These unit types are used to decribe what the raw numeric
These unit types are used to describe what the raw numeric
data in a characteristic actually represents.
\note See https://developer.bluetooth.org/gatt/units/Pages/default.aspx
*/
/**************************************************************************/
typedef enum ble_gatt_unit_e {
BLE_GATT_UNIT_NONE = 0x2700, /**< No specified unit type */
BLE_GATT_UNIT_LENGTH_METRE = 0x2701, /**< Length, Metre */
BLE_GATT_UNIT_MASS_KILOGRAM = 0x2702, /**< Mass, Kilogram */
BLE_GATT_UNIT_TIME_SECOND = 0x2703, /**< Time, Second */
BLE_GATT_UNIT_ELECTRIC_CURRENT_AMPERE = 0x2704, /**< Electric Current, Ampere */
BLE_GATT_UNIT_THERMODYNAMIC_TEMPERATURE_KELVIN = 0x2705, /**< Thermodynamic Temperature, Kelvin */
BLE_GATT_UNIT_AMOUNT_OF_SUBSTANCE_MOLE = 0x2706, /**< Amount of Substance, Mole */
BLE_GATT_UNIT_LUMINOUS_INTENSITY_CANDELA = 0x2707, /**< Luminous Intensity, Candela */
BLE_GATT_UNIT_AREA_SQUARE_METRES = 0x2710, /**< Area, Square Metres */
BLE_GATT_UNIT_VOLUME_CUBIC_METRES = 0x2711, /**< Volume, Cubic Metres*/
BLE_GATT_UNIT_VELOCITY_METRES_PER_SECOND = 0x2712, /**< Velocity, Metres per Second*/
BLE_GATT_UNIT_ACCELERATION_METRES_PER_SECOND_SQUARED = 0x2713, /**< Acceleration, Metres per Second Squared */
BLE_GATT_UNIT_WAVENUMBER_RECIPROCAL_METRE = 0x2714, /**< Wave Number Reciprocal, Metre */
BLE_GATT_UNIT_DENSITY_KILOGRAM_PER_CUBIC_METRE = 0x2715, /**< Density, Kilogram per Cubic Metre */
BLE_GATT_UNIT_SURFACE_DENSITY_KILOGRAM_PER_SQUARE_METRE = 0x2716, /**< */
BLE_GATT_UNIT_SPECIFIC_VOLUME_CUBIC_METRE_PER_KILOGRAM = 0x2717, /**< */
BLE_GATT_UNIT_CURRENT_DENSITY_AMPERE_PER_SQUARE_METRE = 0x2718, /**< */
BLE_GATT_UNIT_MAGNETIC_FIELD_STRENGTH_AMPERE_PER_METRE = 0x2719, /**< Magnetic Field Strength, Ampere per Metre */
BLE_GATT_UNIT_AMOUNT_CONCENTRATION_MOLE_PER_CUBIC_METRE = 0x271A, /**< */
BLE_GATT_UNIT_MASS_CONCENTRATION_KILOGRAM_PER_CUBIC_METRE = 0x271B, /**< */
BLE_GATT_UNIT_LUMINANCE_CANDELA_PER_SQUARE_METRE = 0x271C, /**< */
BLE_GATT_UNIT_REFRACTIVE_INDEX = 0x271D, /**< */
BLE_GATT_UNIT_RELATIVE_PERMEABILITY = 0x271E, /**< */
BLE_GATT_UNIT_PLANE_ANGLE_RADIAN = 0x2720, /**< */
BLE_GATT_UNIT_SOLID_ANGLE_STERADIAN = 0x2721, /**< */
BLE_GATT_UNIT_FREQUENCY_HERTZ = 0x2722, /**< Frequency, Hertz */
BLE_GATT_UNIT_FORCE_NEWTON = 0x2723, /**< Force, Newton */
BLE_GATT_UNIT_PRESSURE_PASCAL = 0x2724, /**< Pressure, Pascal */
BLE_GATT_UNIT_ENERGY_JOULE = 0x2725, /**< Energy, Joule */
BLE_GATT_UNIT_POWER_WATT = 0x2726, /**< Power, Watt */
BLE_GATT_UNIT_ELECTRIC_CHARGE_COULOMB = 0x2727, /**< Electrical Charge, Coulomb */
BLE_GATT_UNIT_ELECTRIC_POTENTIAL_DIFFERENCE_VOLT = 0x2728, /**< Electrical Potential Difference, Voltage */
BLE_GATT_UNIT_CAPACITANCE_FARAD = 0x2729, /**< */
BLE_GATT_UNIT_ELECTRIC_RESISTANCE_OHM = 0x272A, /**< */
BLE_GATT_UNIT_ELECTRIC_CONDUCTANCE_SIEMENS = 0x272B, /**< */
BLE_GATT_UNIT_MAGNETIC_FLEX_WEBER = 0x272C, /**< */
BLE_GATT_UNIT_MAGNETIC_FLEX_DENSITY_TESLA = 0x272D, /**< */
BLE_GATT_UNIT_INDUCTANCE_HENRY = 0x272E, /**< */
BLE_GATT_UNIT_THERMODYNAMIC_TEMPERATURE_DEGREE_CELSIUS = 0x272F, /**< */
BLE_GATT_UNIT_LUMINOUS_FLUX_LUMEN = 0x2730, /**< */
BLE_GATT_UNIT_ILLUMINANCE_LUX = 0x2731, /**< */
BLE_GATT_UNIT_ACTIVITY_REFERRED_TO_A_RADIONUCLIDE_BECQUEREL = 0x2732, /**< */
BLE_GATT_UNIT_ABSORBED_DOSE_GRAY = 0x2733, /**< */
BLE_GATT_UNIT_DOSE_EQUIVALENT_SIEVERT = 0x2734, /**< */
BLE_GATT_UNIT_CATALYTIC_ACTIVITY_KATAL = 0x2735, /**< */
BLE_GATT_UNIT_DYNAMIC_VISCOSITY_PASCAL_SECOND = 0x2740, /**< */
BLE_GATT_UNIT_MOMENT_OF_FORCE_NEWTON_METRE = 0x2741, /**< */
BLE_GATT_UNIT_SURFACE_TENSION_NEWTON_PER_METRE = 0x2742, /**< */
BLE_GATT_UNIT_ANGULAR_VELOCITY_RADIAN_PER_SECOND = 0x2743, /**< */
BLE_GATT_UNIT_ANGULAR_ACCELERATION_RADIAN_PER_SECOND_SQUARED = 0x2744, /**< */
BLE_GATT_UNIT_HEAT_FLUX_DENSITY_WATT_PER_SQUARE_METRE = 0x2745, /**< */
BLE_GATT_UNIT_HEAT_CAPACITY_JOULE_PER_KELVIN = 0x2746, /**< */
BLE_GATT_UNIT_SPECIFIC_HEAT_CAPACITY_JOULE_PER_KILOGRAM_KELVIN = 0x2747, /**< */
BLE_GATT_UNIT_SPECIFIC_ENERGY_JOULE_PER_KILOGRAM = 0x2748, /**< */
BLE_GATT_UNIT_THERMAL_CONDUCTIVITY_WATT_PER_METRE_KELVIN = 0x2749, /**< */
BLE_GATT_UNIT_ENERGY_DENSITY_JOULE_PER_CUBIC_METRE = 0x274A, /**< */
BLE_GATT_UNIT_ELECTRIC_FIELD_STRENGTH_VOLT_PER_METRE = 0x274B, /**< */
BLE_GATT_UNIT_ELECTRIC_CHARGE_DENSITY_COULOMB_PER_CUBIC_METRE = 0x274C, /**< */
BLE_GATT_UNIT_SURFACE_CHARGE_DENSITY_COULOMB_PER_SQUARE_METRE = 0x274D, /**< */
BLE_GATT_UNIT_ELECTRIC_FLUX_DENSITY_COULOMB_PER_SQUARE_METRE = 0x274E, /**< */
BLE_GATT_UNIT_PERMITTIVITY_FARAD_PER_METRE = 0x274F, /**< */
BLE_GATT_UNIT_PERMEABILITY_HENRY_PER_METRE = 0x2750, /**< */
BLE_GATT_UNIT_MOLAR_ENERGY_JOULE_PER_MOLE = 0x2751, /**< */
BLE_GATT_UNIT_MOLAR_ENTROPY_JOULE_PER_MOLE_KELVIN = 0x2752, /**< */
BLE_GATT_UNIT_EXPOSURE_COULOMB_PER_KILOGRAM = 0x2753, /**< */
BLE_GATT_UNIT_ABSORBED_DOSE_RATE_GRAY_PER_SECOND = 0x2754, /**< */
BLE_GATT_UNIT_RADIANT_INTENSITY_WATT_PER_STERADIAN = 0x2755, /**< */
BLE_GATT_UNIT_RADIANCE_WATT_PER_SQUARE_METRE_STERADIAN = 0x2756, /**< */
BLE_GATT_UNIT_CATALYTIC_ACTIVITY_CONCENTRATION_KATAL_PER_CUBIC_METRE = 0x2757, /**< */
BLE_GATT_UNIT_TIME_MINUTE = 0x2760, /**< Time, Minute */
BLE_GATT_UNIT_TIME_HOUR = 0x2761, /**< Time, Hour */
BLE_GATT_UNIT_TIME_DAY = 0x2762, /**< Time, Day */
BLE_GATT_UNIT_PLANE_ANGLE_DEGREE = 0x2763, /**< */
BLE_GATT_UNIT_PLANE_ANGLE_MINUTE = 0x2764, /**< */
BLE_GATT_UNIT_PLANE_ANGLE_SECOND = 0x2765, /**< */
BLE_GATT_UNIT_AREA_HECTARE = 0x2766, /**< */
BLE_GATT_UNIT_VOLUME_LITRE = 0x2767, /**< */
BLE_GATT_UNIT_MASS_TONNE = 0x2768, /**< */
BLE_GATT_UNIT_PRESSURE_BAR = 0x2780, /**< Pressure, Bar */
BLE_GATT_UNIT_PRESSURE_MILLIMETRE_OF_MERCURY = 0x2781, /**< Pressure, Millimetre of Mercury */
BLE_GATT_UNIT_LENGTH_ANGSTROM = 0x2782, /**< */
BLE_GATT_UNIT_LENGTH_NAUTICAL_MILE = 0x2783, /**< */
BLE_GATT_UNIT_AREA_BARN = 0x2784, /**< */
BLE_GATT_UNIT_VELOCITY_KNOT = 0x2785, /**< */
BLE_GATT_UNIT_LOGARITHMIC_RADIO_QUANTITY_NEPER = 0x2786, /**< */
BLE_GATT_UNIT_LOGARITHMIC_RADIO_QUANTITY_BEL = 0x2787, /**< */
BLE_GATT_UNIT_LENGTH_YARD = 0x27A0, /**< Length, Yard */
BLE_GATT_UNIT_LENGTH_PARSEC = 0x27A1, /**< Length, Parsec */
BLE_GATT_UNIT_LENGTH_INCH = 0x27A2, /**< Length, Inch */
BLE_GATT_UNIT_LENGTH_FOOT = 0x27A3, /**< Length, Foot */
BLE_GATT_UNIT_LENGTH_MILE = 0x27A4, /**< Length, Mile */
BLE_GATT_UNIT_PRESSURE_POUND_FORCE_PER_SQUARE_INCH = 0x27A5, /**< */
BLE_GATT_UNIT_VELOCITY_KILOMETRE_PER_HOUR = 0x27A6, /**< Velocity, Kilometre per Hour */
BLE_GATT_UNIT_VELOCITY_MILE_PER_HOUR = 0x27A7, /**< Velocity, Mile per Hour */
BLE_GATT_UNIT_ANGULAR_VELOCITY_REVOLUTION_PER_MINUTE = 0x27A8, /**< Angular Velocity, Revolution per Minute */
BLE_GATT_UNIT_ENERGY_GRAM_CALORIE = 0x27A9, /**< Energy, Gram Calorie */
BLE_GATT_UNIT_ENERGY_KILOGRAM_CALORIE = 0x27AA, /**< Energy, Kilogram Calorie */
BLE_GATT_UNIT_ENERGY_KILOWATT_HOUR = 0x27AB, /**< Energy, Killowatt Hour */
BLE_GATT_UNIT_THERMODYNAMIC_TEMPERATURE_DEGREE_FAHRENHEIT = 0x27AC, /**< */
BLE_GATT_UNIT_PERCENTAGE = 0x27AD, /**< Percentage */
BLE_GATT_UNIT_PER_MILLE = 0x27AE, /**< */
BLE_GATT_UNIT_PERIOD_BEATS_PER_MINUTE = 0x27AF, /**< */
BLE_GATT_UNIT_ELECTRIC_CHARGE_AMPERE_HOURS = 0x27B0, /**< */
BLE_GATT_UNIT_MASS_DENSITY_MILLIGRAM_PER_DECILITRE = 0x27B1, /**< */
BLE_GATT_UNIT_MASS_DENSITY_MILLIMOLE_PER_LITRE = 0x27B2, /**< */
BLE_GATT_UNIT_TIME_YEAR = 0x27B3, /**< Time, Year */
BLE_GATT_UNIT_TIME_MONTH = 0x27B4, /**< Time, Month */
BLE_GATT_UNIT_CONCENTRATION_COUNT_PER_CUBIC_METRE = 0x27B5, /**< */
BLE_GATT_UNIT_IRRADIANCE_WATT_PER_SQUARE_METRE = 0x27B6 /**< */
BLE_GATT_UNIT_NONE = 0x2700, /**< No specified unit type */
BLE_GATT_UNIT_LENGTH_METRE = 0x2701, /**< Length, Metre */
BLE_GATT_UNIT_MASS_KILOGRAM = 0x2702, /**< Mass, Kilogram */
BLE_GATT_UNIT_TIME_SECOND = 0x2703, /**< Time, Second */
BLE_GATT_UNIT_ELECTRIC_CURRENT_AMPERE = 0x2704, /**< Electric Current, Ampere */
BLE_GATT_UNIT_THERMODYNAMIC_TEMPERATURE_KELVIN = 0x2705, /**< Thermodynamic Temperature, Kelvin */
BLE_GATT_UNIT_AMOUNT_OF_SUBSTANCE_MOLE = 0x2706, /**< Amount of Substance, Mole */
BLE_GATT_UNIT_LUMINOUS_INTENSITY_CANDELA = 0x2707, /**< Luminous Intensity, Candela */
BLE_GATT_UNIT_AREA_SQUARE_METRES = 0x2710, /**< Area, Square Metres */
BLE_GATT_UNIT_VOLUME_CUBIC_METRES = 0x2711, /**< Volume, Cubic Metres*/
BLE_GATT_UNIT_VELOCITY_METRES_PER_SECOND = 0x2712, /**< Velocity, Metres per Second*/
BLE_GATT_UNIT_ACCELERATION_METRES_PER_SECOND_SQUARED = 0x2713, /**< Acceleration, Metres per Second Squared */
BLE_GATT_UNIT_WAVENUMBER_RECIPROCAL_METRE = 0x2714, /**< Wave Number Reciprocal, Metre */
BLE_GATT_UNIT_DENSITY_KILOGRAM_PER_CUBIC_METRE = 0x2715, /**< Density, Kilogram per Cubic Metre */
BLE_GATT_UNIT_SURFACE_DENSITY_KILOGRAM_PER_SQUARE_METRE = 0x2716, /**< */
BLE_GATT_UNIT_SPECIFIC_VOLUME_CUBIC_METRE_PER_KILOGRAM = 0x2717, /**< */
BLE_GATT_UNIT_CURRENT_DENSITY_AMPERE_PER_SQUARE_METRE = 0x2718, /**< */
BLE_GATT_UNIT_MAGNETIC_FIELD_STRENGTH_AMPERE_PER_METRE = 0x2719, /**< Magnetic Field Strength, Ampere per Metre */
BLE_GATT_UNIT_AMOUNT_CONCENTRATION_MOLE_PER_CUBIC_METRE = 0x271A, /**< */
BLE_GATT_UNIT_MASS_CONCENTRATION_KILOGRAM_PER_CUBIC_METRE = 0x271B, /**< */
BLE_GATT_UNIT_LUMINANCE_CANDELA_PER_SQUARE_METRE = 0x271C, /**< */
BLE_GATT_UNIT_REFRACTIVE_INDEX = 0x271D, /**< */
BLE_GATT_UNIT_RELATIVE_PERMEABILITY = 0x271E, /**< */
BLE_GATT_UNIT_PLANE_ANGLE_RADIAN = 0x2720, /**< */
BLE_GATT_UNIT_SOLID_ANGLE_STERADIAN = 0x2721, /**< */
BLE_GATT_UNIT_FREQUENCY_HERTZ = 0x2722, /**< Frequency, Hertz */
BLE_GATT_UNIT_FORCE_NEWTON = 0x2723, /**< Force, Newton */
BLE_GATT_UNIT_PRESSURE_PASCAL = 0x2724, /**< Pressure, Pascal */
BLE_GATT_UNIT_ENERGY_JOULE = 0x2725, /**< Energy, Joule */
BLE_GATT_UNIT_POWER_WATT = 0x2726, /**< Power, Watt */
BLE_GATT_UNIT_ELECTRIC_CHARGE_COULOMB = 0x2727, /**< Electrical Charge, Coulomb */
BLE_GATT_UNIT_ELECTRIC_POTENTIAL_DIFFERENCE_VOLT = 0x2728, /**< Electrical Potential Difference, Voltage */
BLE_GATT_UNIT_CAPACITANCE_FARAD = 0x2729, /**< */
BLE_GATT_UNIT_ELECTRIC_RESISTANCE_OHM = 0x272A, /**< */
BLE_GATT_UNIT_ELECTRIC_CONDUCTANCE_SIEMENS = 0x272B, /**< */
BLE_GATT_UNIT_MAGNETIC_FLEX_WEBER = 0x272C, /**< */
BLE_GATT_UNIT_MAGNETIC_FLEX_DENSITY_TESLA = 0x272D, /**< */
BLE_GATT_UNIT_INDUCTANCE_HENRY = 0x272E, /**< */
BLE_GATT_UNIT_THERMODYNAMIC_TEMPERATURE_DEGREE_CELSIUS = 0x272F, /**< */
BLE_GATT_UNIT_LUMINOUS_FLUX_LUMEN = 0x2730, /**< */
BLE_GATT_UNIT_ILLUMINANCE_LUX = 0x2731, /**< */
BLE_GATT_UNIT_ACTIVITY_REFERRED_TO_A_RADIONUCLIDE_BECQUEREL = 0x2732, /**< */
BLE_GATT_UNIT_ABSORBED_DOSE_GRAY = 0x2733, /**< */
BLE_GATT_UNIT_DOSE_EQUIVALENT_SIEVERT = 0x2734, /**< */
BLE_GATT_UNIT_CATALYTIC_ACTIVITY_KATAL = 0x2735, /**< */
BLE_GATT_UNIT_DYNAMIC_VISCOSITY_PASCAL_SECOND = 0x2740, /**< */
BLE_GATT_UNIT_MOMENT_OF_FORCE_NEWTON_METRE = 0x2741, /**< */
BLE_GATT_UNIT_SURFACE_TENSION_NEWTON_PER_METRE = 0x2742, /**< */
BLE_GATT_UNIT_ANGULAR_VELOCITY_RADIAN_PER_SECOND = 0x2743, /**< */
BLE_GATT_UNIT_ANGULAR_ACCELERATION_RADIAN_PER_SECOND_SQUARED = 0x2744, /**< */
BLE_GATT_UNIT_HEAT_FLUX_DENSITY_WATT_PER_SQUARE_METRE = 0x2745, /**< */
BLE_GATT_UNIT_HEAT_CAPACITY_JOULE_PER_KELVIN = 0x2746, /**< */
BLE_GATT_UNIT_SPECIFIC_HEAT_CAPACITY_JOULE_PER_KILOGRAM_KELVIN = 0x2747, /**< */
BLE_GATT_UNIT_SPECIFIC_ENERGY_JOULE_PER_KILOGRAM = 0x2748, /**< */
BLE_GATT_UNIT_THERMAL_CONDUCTIVITY_WATT_PER_METRE_KELVIN = 0x2749, /**< */
BLE_GATT_UNIT_ENERGY_DENSITY_JOULE_PER_CUBIC_METRE = 0x274A, /**< */
BLE_GATT_UNIT_ELECTRIC_FIELD_STRENGTH_VOLT_PER_METRE = 0x274B, /**< */
BLE_GATT_UNIT_ELECTRIC_CHARGE_DENSITY_COULOMB_PER_CUBIC_METRE = 0x274C, /**< */
BLE_GATT_UNIT_SURFACE_CHARGE_DENSITY_COULOMB_PER_SQUARE_METRE = 0x274D, /**< */
BLE_GATT_UNIT_ELECTRIC_FLUX_DENSITY_COULOMB_PER_SQUARE_METRE = 0x274E, /**< */
BLE_GATT_UNIT_PERMITTIVITY_FARAD_PER_METRE = 0x274F, /**< */
BLE_GATT_UNIT_PERMEABILITY_HENRY_PER_METRE = 0x2750, /**< */
BLE_GATT_UNIT_MOLAR_ENERGY_JOULE_PER_MOLE = 0x2751, /**< */
BLE_GATT_UNIT_MOLAR_ENTROPY_JOULE_PER_MOLE_KELVIN = 0x2752, /**< */
BLE_GATT_UNIT_EXPOSURE_COULOMB_PER_KILOGRAM = 0x2753, /**< */
BLE_GATT_UNIT_ABSORBED_DOSE_RATE_GRAY_PER_SECOND = 0x2754, /**< */
BLE_GATT_UNIT_RADIANT_INTENSITY_WATT_PER_STERADIAN = 0x2755, /**< */
BLE_GATT_UNIT_RADIANCE_WATT_PER_SQUARE_METRE_STERADIAN = 0x2756, /**< */
BLE_GATT_UNIT_CATALYTIC_ACTIVITY_CONCENTRATION_KATAL_PER_CUBIC_METRE = 0x2757, /**< */
BLE_GATT_UNIT_TIME_MINUTE = 0x2760, /**< Time, Minute */
BLE_GATT_UNIT_TIME_HOUR = 0x2761, /**< Time, Hour */
BLE_GATT_UNIT_TIME_DAY = 0x2762, /**< Time, Day */
BLE_GATT_UNIT_PLANE_ANGLE_DEGREE = 0x2763, /**< */
BLE_GATT_UNIT_PLANE_ANGLE_MINUTE = 0x2764, /**< */
BLE_GATT_UNIT_PLANE_ANGLE_SECOND = 0x2765, /**< */
BLE_GATT_UNIT_AREA_HECTARE = 0x2766, /**< */
BLE_GATT_UNIT_VOLUME_LITRE = 0x2767, /**< */
BLE_GATT_UNIT_MASS_TONNE = 0x2768, /**< */
BLE_GATT_UNIT_PRESSURE_BAR = 0x2780, /**< Pressure, Bar */
BLE_GATT_UNIT_PRESSURE_MILLIMETRE_OF_MERCURY = 0x2781, /**< Pressure, Millimetre of Mercury */
BLE_GATT_UNIT_LENGTH_ANGSTROM = 0x2782, /**< */
BLE_GATT_UNIT_LENGTH_NAUTICAL_MILE = 0x2783, /**< */
BLE_GATT_UNIT_AREA_BARN = 0x2784, /**< */
BLE_GATT_UNIT_VELOCITY_KNOT = 0x2785, /**< */
BLE_GATT_UNIT_LOGARITHMIC_RADIO_QUANTITY_NEPER = 0x2786, /**< */
BLE_GATT_UNIT_LOGARITHMIC_RADIO_QUANTITY_BEL = 0x2787, /**< */
BLE_GATT_UNIT_LENGTH_YARD = 0x27A0, /**< Length, Yard */
BLE_GATT_UNIT_LENGTH_PARSEC = 0x27A1, /**< Length, Parsec */
BLE_GATT_UNIT_LENGTH_INCH = 0x27A2, /**< Length, Inch */
BLE_GATT_UNIT_LENGTH_FOOT = 0x27A3, /**< Length, Foot */
BLE_GATT_UNIT_LENGTH_MILE = 0x27A4, /**< Length, Mile */
BLE_GATT_UNIT_PRESSURE_POUND_FORCE_PER_SQUARE_INCH = 0x27A5, /**< */
BLE_GATT_UNIT_VELOCITY_KILOMETRE_PER_HOUR = 0x27A6, /**< Velocity, Kilometre per Hour */
BLE_GATT_UNIT_VELOCITY_MILE_PER_HOUR = 0x27A7, /**< Velocity, Mile per Hour */
BLE_GATT_UNIT_ANGULAR_VELOCITY_REVOLUTION_PER_MINUTE = 0x27A8, /**< Angular Velocity, Revolution per Minute */
BLE_GATT_UNIT_ENERGY_GRAM_CALORIE = 0x27A9, /**< Energy, Gram Calorie */
BLE_GATT_UNIT_ENERGY_KILOGRAM_CALORIE = 0x27AA, /**< Energy, Kilogram Calorie */
BLE_GATT_UNIT_ENERGY_KILOWATT_HOUR = 0x27AB, /**< Energy, Killowatt Hour */
BLE_GATT_UNIT_THERMODYNAMIC_TEMPERATURE_DEGREE_FAHRENHEIT = 0x27AC, /**< */
BLE_GATT_UNIT_PERCENTAGE = 0x27AD, /**< Percentage */
BLE_GATT_UNIT_PER_MILLE = 0x27AE, /**< */
BLE_GATT_UNIT_PERIOD_BEATS_PER_MINUTE = 0x27AF, /**< */
BLE_GATT_UNIT_ELECTRIC_CHARGE_AMPERE_HOURS = 0x27B0, /**< */
BLE_GATT_UNIT_MASS_DENSITY_MILLIGRAM_PER_DECILITRE = 0x27B1, /**< */
BLE_GATT_UNIT_MASS_DENSITY_MILLIMOLE_PER_LITRE = 0x27B2, /**< */
BLE_GATT_UNIT_TIME_YEAR = 0x27B3, /**< Time, Year */
BLE_GATT_UNIT_TIME_MONTH = 0x27B4, /**< Time, Month */
BLE_GATT_UNIT_CONCENTRATION_COUNT_PER_CUBIC_METRE = 0x27B5, /**< */
BLE_GATT_UNIT_IRRADIANCE_WATT_PER_SQUARE_METRE = 0x27B6 /**< */
} ble_gatt_unit_t;
/**************************************************************************/
@ -263,7 +254,7 @@ public:
/**************************************************************************/
/*!
\brief Standard GATT characteritic properties
\brief Standard GATT characteristic properties
\note See Bluetooth Specification 4.0 (Vol. 3), Part G, Section 3.3.1.1
and Section 3.3.3.1 for Extended Properties
@ -275,8 +266,8 @@ public:
BLE_GATT_CHAR_PROPERTIES_READ = 0x02, /**< Permits reads of the Characteristic Value. */
BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE = 0x04, /**< Permits writes of the Characteristic Value without response. */
BLE_GATT_CHAR_PROPERTIES_WRITE = 0x08, /**< Permits writes of the Characteristic Value with response. */
BLE_GATT_CHAR_PROPERTIES_NOTIFY = 0x10, /**< Permits notifications of a Characteristic Value without acknowledgement. */
BLE_GATT_CHAR_PROPERTIES_INDICATE = 0x20, /**< Permits indications of a Characteristic Value with acknowledgement. */
BLE_GATT_CHAR_PROPERTIES_NOTIFY = 0x10, /**< Permits notifications of a Characteristic Value without acknowledgment. */
BLE_GATT_CHAR_PROPERTIES_INDICATE = 0x20, /**< Permits indications of a Characteristic Value with acknowledgment. */
BLE_GATT_CHAR_PROPERTIES_AUTHENTICATED_SIGNED_WRITES = 0x40, /**< Permits signed writes to the Characteristic Value. */
BLE_GATT_CHAR_PROPERTIES_EXTENDED_PROPERTIES = 0x80 /**< Additional characteristic properties are defined in the Characteristic Extended Properties Descriptor */
} ble_gatt_char_properties_t;
@ -297,34 +288,34 @@ public:
uint16_t gatt_nsdesc; /**< Namespace description from Bluetooth Assigned Numbers, normally '0', see @ref BLE_GATT_CPF_NAMESPACES. */
} presentation_format_t;
/**
* @brief Creates a new GattCharacteristic using the specified 16-bit
* UUID, value length, and properties
*
* @note The UUID value must be unique in the service and is normally >1
*
* @param[in] uuid
* The UUID to use for this characteristic
* @param[in] valuePtr
* The memory holding the initial value. The value is copied
* into the stack when the enclosing service is added; and
* thereafter maintained internally by the stack.
* @param[in] initialLen
* The min length in bytes of this characteristic's value
* @param[in] maxLen
* The max length in bytes of this characteristic's value
* @param[in] props
* The 8-bit bit field containing the characteristic's properties
* @param[in] descriptors
* A pointer to an array of descriptors to be included within this characteristic
* @param[in] numDescriptors
* The number of descriptors
*
* @NOTE: If valuePtr == NULL, initialLength == 0, and properties == READ
* for the value attribute of a characteristic, then that particular
* characteristic may be considered optional and dropped while
* instantiating the service with the underlying BLE stack.
*/
/**
* @brief Creates a new GattCharacteristic using the specified 16-bit
* UUID, value length, and properties
*
* @note The UUID value must be unique in the service and is normally >1
*
* @param[in] uuid
* The UUID to use for this characteristic
* @param[in] valuePtr
* The memory holding the initial value. The value is copied
* into the stack when the enclosing service is added; and
* thereafter maintained internally by the stack.
* @param[in] initialLen
* The min length in bytes of this characteristic's value
* @param[in] maxLen
* The max length in bytes of this characteristic's value
* @param[in] props
* The 8-bit bit field containing the characteristic's properties
* @param[in] descriptors
* A pointer to an array of descriptors to be included within this characteristic
* @param[in] numDescriptors
* The number of descriptors
*
* @NOTE: If valuePtr == NULL, initialLength == 0, and properties == READ
* for the value attribute of a characteristic, then that particular
* characteristic may be considered optional and dropped while
* instantiating the service with the underlying BLE stack.
*/
/**************************************************************************/
GattCharacteristic(const UUID &uuid, uint8_t *valuePtr = NULL, uint16_t initialLen = 0, uint16_t maxLen = 0,
uint8_t props = BLE_GATT_CHAR_PROPERTIES_NONE,
@ -333,15 +324,10 @@ public:
}
public:
GattAttribute& getValueAttribute() {
return _valueAttribute;
}
uint8_t getProperties(void) const {
return _properties;
}
uint8_t getDescriptorCount(void) const {
return _descriptorCount;
}
GattAttribute& getValueAttribute() {return _valueAttribute; }
uint8_t getProperties(void) const {return _properties; }
uint8_t getDescriptorCount(void) const {return _descriptorCount;}
GattAttribute *getDescriptor(uint8_t index) {
if (index >= _descriptorCount) {
return NULL;
@ -351,10 +337,15 @@ public:
}
private:
GattAttribute _valueAttribute;
uint8_t _properties;
GattAttribute ** _descriptors;
uint8_t _descriptorCount;
GattAttribute _valueAttribute;
uint8_t _properties;
GattAttribute **_descriptors;
uint8_t _descriptorCount;
private:
/* disallow copy and assignment */
GattCharacteristic(const GattCharacteristic &);
GattCharacteristic& operator=(const GattCharacteristic &);
};
#endif // ifndef __GATT_CHARACTERISTIC_H__

View file

@ -17,56 +17,47 @@
#ifndef __GATT_SERVER_H__
#define __GATT_SERVER_H__
#include "blecommon.h"
#include "GattService.h"
#include "GattServerEvents.h"
#include "GattCharacteristicWriteCBParams.h"
#include "CallChainOfFunctionPointersWithContext.h"
/**************************************************************************/
/*!
\brief
The base class used to abstract GATT Server functionality to a specific
radio transceiver, SOC or BLE Stack.
*/
/**************************************************************************/
class GattServer
{
class GattServer {
public:
/* Event callback handlers. */
typedef void (*EventCallback_t)(uint16_t attributeHandle);
typedef void (*ServerEventCallback_t)(void); /**< independent of any particular attribute */
typedef void (*ServerEventCallbackWithCount_t)(unsigned count); /**< independent of any particular attribute */
protected:
GattServer() : serviceCount(0), characteristicCount(0), onDataSent(NULL), onDataWritten(), onUpdatesEnabled(NULL), onUpdatesDisabled(NULL), onConfirmationReceived(NULL) {
/* empty */
}
friend class BLEDevice;
private:
/* These functions must be defined in the sub-class */
virtual ble_error_t addService(GattService &) = 0;
virtual ble_error_t readValue(uint16_t handle, uint8_t buffer[], uint16_t *const lengthP) = 0;
virtual ble_error_t updateValue(uint16_t, uint8_t[], uint16_t, bool localOnly = false) = 0;
virtual ble_error_t initializeGATTDatabase(void) = 0;
// ToDo: For updateValue, check the CCCD to see if the value we are
// updating has the notify or indicate bits sent, and if BOTH are set
// be sure to call sd_ble_gatts_hvx() twice with notify then indicate!
// Strange use case, but valid and must be covered!
/* Event callback handlers. */
typedef void (*EventCallback_t)(uint16_t attributeHandle);
typedef void (*ServerEventCallback_t)(void); /**< independent of any particular attribute */
typedef void (*ServerEventCallbackWithCount_t)(unsigned count); /**< independent of any particular attribute */
void setOnDataSent(ServerEventCallbackWithCount_t callback) {
onDataSent = callback;
}
void setOnDataWritten(void (*callback)(const GattCharacteristicWriteCBParams *eventDataP)) {
onDataWritten.add(callback);
}
void setOnDataSent(ServerEventCallbackWithCount_t callback) {onDataSent = callback;}
void setOnDataWritten(void (*callback)(const GattCharacteristicWriteCBParams *eventDataP)) {onDataWritten.add(callback);}
template <typename T>
void setOnDataWritten(T *objPtr, void (T::*memberPtr)(const GattCharacteristicWriteCBParams *context)) {
onDataWritten.add(objPtr, memberPtr);
}
void setOnUpdatesEnabled(EventCallback_t callback) {
onUpdatesEnabled = callback;
}
void setOnUpdatesDisabled(EventCallback_t callback) {
onUpdatesDisabled = callback;
}
void setOnConfirmationReceived(EventCallback_t callback) {
onConfirmationReceived = callback;
}
void setOnUpdatesEnabled(EventCallback_t callback) {onUpdatesEnabled = callback;}
void setOnUpdatesDisabled(EventCallback_t callback) {onUpdatesDisabled = callback;}
void setOnConfirmationReceived(EventCallback_t callback) {onConfirmationReceived = callback;}
protected:
void handleDataWrittenEvent(const GattCharacteristicWriteCBParams *params) {
if (onDataWritten.hasCallbacksAttached()) {
onDataWritten.call(params);
@ -99,15 +90,9 @@ public:
}
}
protected:
GattServer() : serviceCount(0), characteristicCount(0), onDataSent(NULL), onDataWritten(), onUpdatesEnabled(NULL), onUpdatesDisabled(NULL), onConfirmationReceived(NULL) {
/* empty */
}
protected:
uint8_t serviceCount;
uint8_t characteristicCount;
uint8_t descriptorCount;
private:
ServerEventCallbackWithCount_t onDataSent;
@ -115,6 +100,11 @@ private:
EventCallback_t onUpdatesEnabled;
EventCallback_t onUpdatesDisabled;
EventCallback_t onConfirmationReceived;
private:
/* disallow copy and assignment */
GattServer(const GattServer &);
GattServer& operator=(const GattServer &);
};
#endif // ifndef __GATT_SERVER_H__

View file

@ -14,39 +14,14 @@
* limitations under the License.
*/
#ifndef __GATT_SERVICE_H__
#define __GATT_SERVICE_H__
#include "blecommon.h"
#include "UUID.h"
#include "GattCharacteristic.h"
/**************************************************************************/
/*!
\brief GATT service
*/
/**************************************************************************/
class GattService
{
class GattService {
public:
/**
* @brief Creates a new GattCharacteristic using the specified 16-bit
* UUID, value length, and properties
*
* @note The UUID value must be unique in the service and is normally >1
*
* @param[in] uuid
* The UUID to use for this characteristic
* @param[in] characteristics
* A pointer to an array of characteristics to be included within this service
* @param[in] numCharacteristics
* The number of characteristics
*/
/**************************************************************************/
GattService(const UUID &uuid, GattCharacteristic *characteristics[], unsigned numCharacteristics);
enum {
UUID_ALERT_NOTIFICATION_SERVICE = 0x1811,
UUID_BATTERY_SERVICE = 0x180F,
@ -68,18 +43,27 @@ public:
UUID_TX_POWER_SERVICE = 0x1804
};
const UUID &getUUID(void) const {
return _primaryServiceID;
}
uint16_t getHandle(void) const {
return _handle;
}
void setHandle(uint16_t handle) {
_handle = handle;
}
uint8_t getCharacteristicCount(void) const {
return _characteristicCount;
}
public:
/**
* @brief Creates a new GattCharacteristic using the specified 16-bit
* UUID, value length, and properties
*
* @note The UUID value must be unique in the service and is normally >1
*
* @param[in] uuid
* The UUID to use for this characteristic
* @param[in] characteristics
* A pointer to an array of characteristics to be included within this service
* @param[in] numCharacteristics
* The number of characteristics
*/
GattService(const UUID &uuid, GattCharacteristic *characteristics[], unsigned numCharacteristics);
const UUID &getUUID(void) const {return _primaryServiceID; }
uint16_t getHandle(void) const {return _handle; }
uint8_t getCharacteristicCount(void) const {return _characteristicCount;}
void setHandle(uint16_t handle) {_handle = handle;}
GattCharacteristic *getCharacteristic(uint8_t index) {
if (index >= _characteristicCount) {
return NULL;

View file

@ -14,7 +14,6 @@
* limitations under the License.
*/
#ifndef __UUID_H__
#define __UUID_H__
@ -24,8 +23,7 @@ const unsigned LENGTH_OF_LONG_UUID = 16;
typedef uint16_t ShortUUIDBytes_t;
typedef uint8_t LongUUIDBytes_t[LENGTH_OF_LONG_UUID];
class UUID
{
class UUID {
public:
enum {
UUID_TYPE_SHORT = 0, // Short BLE UUID
@ -35,18 +33,11 @@ public:
public:
UUID(const LongUUIDBytes_t);
UUID(ShortUUIDBytes_t);
virtual ~UUID(void);
public:
uint8_t shortOrLong(void) const {
return type;
}
const uint8_t* getBaseUUID(void) const {
return baseUUID;
}
ShortUUIDBytes_t getShortUUID(void) const {
return shortUUID;
}
uint8_t shortOrLong(void) const {return type; }
const uint8_t *getBaseUUID(void) const {return baseUUID; }
ShortUUIDBytes_t getShortUUID(void) const {return shortUUID;}
private:
uint8_t type; // UUID_TYPE_SHORT or UUID_TYPE_LONG