diff --git a/DOXYGEN_FRONTPAGE.md b/DOXYGEN_FRONTPAGE.md
new file mode 100644
index 0000000..6f286f8
--- /dev/null
+++ b/DOXYGEN_FRONTPAGE.md
@@ -0,0 +1,16 @@
+#BLE API
+
+The BLE module within mbed OS offers a high level abstraction for using
+Bluetooth Low Energy on multiple platforms.
+
+This documentation describes the internal structure of mbed
+(BLE_API)[https://github.com/armmbed/ble]. It was automatically generated from
+specially formatted comment blocks in BLE_API's source code using Doxygen.
+(See http://www.stack.nl/~dimitri/doxygen/ for more information on Doxygen).
+
+For getting started with BLE on mbed, check our (introduction
+page)[https://docs.mbed.com/docs/ble-intros/en/latest/].
+
+For mbed OS examples using BLE, check (this
+repository)[https://github.com/armmbed/ble-examples]. For mbed-classic
+examples, refer to (code under mbed.org)[https://developer.mbed.org/teams/Bluetooth-Low-Energy/code/].
diff --git a/README.md b/README.md
index b3afc24..a91f8ef 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
This is the Github repo for the `BLE_API` used by developer.mbed.org. Please see the [mbed BLE Homepage](https://developer.mbed.org/teams/Bluetooth-Low-Energy/) for all documentation, code examples and general help.
# Supported Services
-Supported GATT services and constantly being added and can be found in the `ble/source/services/` folder.
+Supported GATT services and constantly being added and can be found in the (`ble/ble/services/`)[https://github.com/ARMmbed/ble/tree/master/ble/services] folder.
Currently supported services include:
* Battery
diff --git a/ble/GapAdvertisingData.h b/ble/GapAdvertisingData.h
index 4088a30..8d0ffb5 100644
--- a/ble/GapAdvertisingData.h
+++ b/ble/GapAdvertisingData.h
@@ -89,22 +89,23 @@ public:
*/
/**********************************************************************/
enum DataType_t {
- FLAGS = 0x01, /**< \ref *Flags. */
- INCOMPLETE_LIST_16BIT_SERVICE_IDS = 0x02, /**< Incomplete list of 16-bit service IDs. */
- COMPLETE_LIST_16BIT_SERVICE_IDS = 0x03, /**< Complete list of 16-bit service IDs. */
- INCOMPLETE_LIST_32BIT_SERVICE_IDS = 0x04, /**< Incomplete list of 32-bit service IDs (not relevant for Bluetooth 4.0). */
- COMPLETE_LIST_32BIT_SERVICE_IDS = 0x05, /**< Complete list of 32-bit service IDs (not relevant for Bluetooth 4.0). */
- INCOMPLETE_LIST_128BIT_SERVICE_IDS = 0x06, /**< Incomplete list of 128-bit service IDs. */
- COMPLETE_LIST_128BIT_SERVICE_IDS = 0x07, /**< Complete list of 128-bit service IDs. */
- SHORTENED_LOCAL_NAME = 0x08, /**< Shortened local name. */
- COMPLETE_LOCAL_NAME = 0x09, /**< Complete local name. */
- TX_POWER_LEVEL = 0x0A, /**< TX power level (in dBm). */
- DEVICE_ID = 0x10, /**< Device ID. */
- SLAVE_CONNECTION_INTERVAL_RANGE = 0x12, /**< Slave connection interval range. */
- SERVICE_DATA = 0x16, /**< Service data. */
- APPEARANCE = 0x19, /**< \ref Appearance. */
- ADVERTISING_INTERVAL = 0x1A, /**< Advertising interval. */
- MANUFACTURER_SPECIFIC_DATA = 0xFF /**< Manufacturer specific data. */
+ FLAGS = 0x01, /**< \ref *Flags */
+ INCOMPLETE_LIST_16BIT_SERVICE_IDS = 0x02, /**< Incomplete list of 16-bit Service IDs */
+ COMPLETE_LIST_16BIT_SERVICE_IDS = 0x03, /**< Complete list of 16-bit Service IDs */
+ INCOMPLETE_LIST_32BIT_SERVICE_IDS = 0x04, /**< Incomplete list of 32-bit Service IDs (not relevant for Bluetooth 4.0) */
+ COMPLETE_LIST_32BIT_SERVICE_IDS = 0x05, /**< Complete list of 32-bit Service IDs (not relevant for Bluetooth 4.0) */
+ INCOMPLETE_LIST_128BIT_SERVICE_IDS = 0x06, /**< Incomplete list of 128-bit Service IDs */
+ COMPLETE_LIST_128BIT_SERVICE_IDS = 0x07, /**< Complete list of 128-bit Service IDs */
+ SHORTENED_LOCAL_NAME = 0x08, /**< Shortened Local Name */
+ COMPLETE_LOCAL_NAME = 0x09, /**< Complete Local Name */
+ TX_POWER_LEVEL = 0x0A, /**< TX Power Level (in dBm) */
+ DEVICE_ID = 0x10, /**< Device ID */
+ SLAVE_CONNECTION_INTERVAL_RANGE = 0x12, /**< Slave Connection Interval Range */
+ LIST_128BIT_SOLICITATION_IDS = 0x15, /**< List of 128 bit service UUIDs the device is looking for */
+ SERVICE_DATA = 0x16, /**< Service Data */
+ APPEARANCE = 0x19, /**< \ref Appearance */
+ ADVERTISING_INTERVAL = 0x1A, /**< Advertising Interval */
+ MANUFACTURER_SPECIFIC_DATA = 0xFF /**< Manufacturer Specific Data */
};
typedef enum DataType_t DataType; /* Deprecated type alias. This may be dropped in a future release. */
@@ -210,27 +211,98 @@ public:
*/
ble_error_t addData(DataType advDataType, const uint8_t *payload, uint8_t len)
{
- /* To Do: Check if an AD type already exists and if the existing */
- /* value is exclusive or not (flags and so on). */
+ ble_error_t result = BLE_ERROR_BUFFER_OVERFLOW;
- /* Make sure we don't exceed the 31 byte payload limit. */
- if (_payloadLen + len + 2 > GAP_ADVERTISING_DATA_MAX_PAYLOAD) {
- return BLE_ERROR_BUFFER_OVERFLOW;
+ // find field
+ uint8_t* field = findField(advDataType);
+
+ // Field type already exist, either add to field or replace
+ if (field) {
+ switch(advDataType) {
+ // These fields will be overwritten with the new value
+ case FLAGS:
+ case SHORTENED_LOCAL_NAME:
+ case COMPLETE_LOCAL_NAME:
+ case TX_POWER_LEVEL:
+ case DEVICE_ID:
+ case SLAVE_CONNECTION_INTERVAL_RANGE:
+ case SERVICE_DATA:
+ case APPEARANCE:
+ case ADVERTISING_INTERVAL:
+ case MANUFACTURER_SPECIFIC_DATA: {
+ // current field length, with the type subtracted
+ uint8_t dataLength = field[0] - 1;
+
+ // new data has same length, do in-order replacement
+ if (len == dataLength) {
+ for (uint8_t idx = 0; idx < dataLength; idx++) {
+ field[2 + idx] = payload[idx];
+ }
+ } else {
+ // check if data fits
+ if ((_payloadLen - dataLength + len) <= GAP_ADVERTISING_DATA_MAX_PAYLOAD) {
+
+ // remove old field
+ while ((field + dataLength + 2) < &_payload[_payloadLen]) {
+ *field = field[dataLength + 2];
+ field++;
+ }
+
+ // reduce length
+ _payloadLen -= dataLength + 2;
+
+ // add new field
+ result = appendField(advDataType, payload, len);
+ }
+ }
+
+ break;
+ }
+ // These fields will have the new data appended if there is sufficient space
+ case INCOMPLETE_LIST_16BIT_SERVICE_IDS:
+ case COMPLETE_LIST_16BIT_SERVICE_IDS:
+ case INCOMPLETE_LIST_32BIT_SERVICE_IDS:
+ case COMPLETE_LIST_32BIT_SERVICE_IDS:
+ case INCOMPLETE_LIST_128BIT_SERVICE_IDS:
+ case COMPLETE_LIST_128BIT_SERVICE_IDS:
+ case LIST_128BIT_SOLICITATION_IDS: {
+ // check if data fits
+ if ((_payloadLen + len) <= GAP_ADVERTISING_DATA_MAX_PAYLOAD) {
+ // make room for new field by moving the remainder of the
+ // advertisement payload "to the right" starting after the
+ // TYPE field.
+ uint8_t* end = &_payload[_payloadLen];
+
+ while (&field[1] < end) {
+ end[len] = *end;
+ end--;
+ }
+
+ // insert new data
+ for (uint8_t idx = 0; idx < len; idx++) {
+ field[2 + idx] = payload[idx];
+ }
+
+ // increment lengths
+ field[0] += len;
+ _payloadLen += len;
+
+ result = BLE_ERROR_NONE;
+ }
+
+ break;
+ }
+ // Field exists but updating it is not supported. Abort operation.
+ default:
+ result = BLE_ERROR_NOT_IMPLEMENTED;
+ break;
+ }
+ } else {
+ // field doesn't exists, insert new
+ result = appendField(advDataType, payload, len);
}
- /* Field length. */
- memset(&_payload[_payloadLen], len + 1, 1);
- _payloadLen++;
-
- /* Field ID. */
- memset(&_payload[_payloadLen], (uint8_t)advDataType, 1);
- _payloadLen++;
-
- /* Payload. */
- memcpy(&_payload[_payloadLen], payload, len);
- _payloadLen += len;
-
- return BLE_ERROR_NONE;
+ return result;
}
/**
@@ -345,7 +417,63 @@ public:
return (uint16_t)_appearance;
}
+ /**
+ * Search advertisement data for field.
+ * Returns pointer to the first element in the field if found, NULL otherwise.
+ * Where the first element is the length of the field.
+ */
+ const uint8_t* findField(DataType_t type) const {
+ return findField(type);
+ }
+
private:
+ /**
+ * Append advertising data based on the specified AD type (see DataType)
+ */
+ ble_error_t appendField(DataType advDataType, const uint8_t *payload, uint8_t len)
+ {
+ /* Make sure we don't exceed the 31 byte payload limit */
+ if (_payloadLen + len + 2 > GAP_ADVERTISING_DATA_MAX_PAYLOAD) {
+ return BLE_ERROR_BUFFER_OVERFLOW;
+ }
+
+ /* Field length. */
+ memset(&_payload[_payloadLen], len + 1, 1);
+ _payloadLen++;
+
+ /* Field ID. */
+ memset(&_payload[_payloadLen], (uint8_t)advDataType, 1);
+ _payloadLen++;
+
+ /* Payload. */
+ memcpy(&_payload[_payloadLen], payload, len);
+ _payloadLen += len;
+
+ return BLE_ERROR_NONE;
+ }
+
+ /**
+ * Search advertisement data for field.
+ * Returns pointer to the first element in the field if found, NULL otherwise.
+ * Where the first element is the length of the field.
+ */
+ uint8_t* findField(DataType_t type) {
+ // scan through advertisement data
+ for (uint8_t idx = 0; idx < _payloadLen; ) {
+ uint8_t fieldType = _payload[idx + 1];
+
+ if (fieldType == type) {
+ return &_payload[idx];
+ }
+
+ // advance to next field
+ idx += _payload[idx] + 1;
+ }
+
+ // field not found
+ return NULL;
+ }
+
uint8_t _payload[GAP_ADVERTISING_DATA_MAX_PAYLOAD];
uint8_t _payloadLen;
uint16_t _appearance;
diff --git a/ble/services/BatteryService.h b/ble/services/BatteryService.h
index 965fb20..16f40b2 100644
--- a/ble/services/BatteryService.h
+++ b/ble/services/BatteryService.h
@@ -21,8 +21,8 @@
/**
* @class BatteryService
-* @brief BLE Battery Service. This service displays the battery level from 0%->100% represented as a 8bit number.
-* Service: https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.battery_service.xml
+* @brief BLE Battery Service. This service displays the battery level from 0% to 100%, represented as an 8bit number.
+* Service: https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.battery_service.xml
* Battery Level Char: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.battery_level.xml
*/
class BatteryService {
@@ -45,11 +45,11 @@ public:
}
/**
- * @brief Update the battery level with a new value. Valid values range from
- * 0..100. Anything outside this range will be ignored.
+ * @brief Update the battery level with a new value. [Valid values lie between 0 and 100];
+ * anything outside this range will be ignored.
*
* @param newLevel
- * update to battery level.
+ * Update to battery level.
*/
void updateBatteryLevel(uint8_t newLevel) {
batteryLevel = newLevel;
diff --git a/ble/services/DFUService.h b/ble/services/DFUService.h
index 253890e..032489a 100644
--- a/ble/services/DFUService.h
+++ b/ble/services/DFUService.h
@@ -37,20 +37,20 @@ extern const uint8_t DFUServicePacketCharacteristicUUID[];
class DFUService {
public:
/**
- * @brief Signature for the handover callback. The application may provide such a
- * callback when setting up the DFU service, in which case it will be
+ * @brief Signature for the handover callback. The application may provide this
+ * callback when setting up the DFU service. The callback is then
* invoked before handing control over to the bootloader.
*/
typedef void (*ResetPrepare_t)(void);
public:
/**
- * @brief Adds Device Firmware Update service to an existing ble object.
+ * @brief Adds Device Firmware Update Service to an existing BLE object.
*
* @param[ref] _ble
* BLE object for the underlying controller.
* @param[in] _handoverCallback
- * Application specific handover callback.
+ * Application-specific handover callback.
*/
DFUService(BLE &_ble, ResetPrepare_t _handoverCallback = NULL) :
ble(_ble),
@@ -59,12 +59,12 @@ public:
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE),
controlBytes(),
packetBytes() {
- static bool serviceAdded = false; /* We should only ever need to add the DFU service once. */
+ static bool serviceAdded = false; /* We only add the DFU service once. */
if (serviceAdded) {
return;
}
- /* Set an initial value for control bytes so that the application's DFUService can
+ /* Set an initial value for control bytes, so that the application's DFU service can
* be distinguished from the real DFU service provided by the bootloader. */
controlBytes[0] = 0xFF;
controlBytes[1] = 0xFF;
@@ -80,7 +80,7 @@ public:
}
/**
- * @brief get the handle for the value attribute of the control characteristic.
+ * @brief Get the handle for the value attribute of the control characteristic.
*/
uint16_t getControlHandle(void) const {
return controlPoint.getValueHandle();
@@ -88,7 +88,7 @@ public:
/**
* @brief This callback allows the DFU service to receive the initial trigger to
- * handover control to the bootloader; but first the application is given a
+ * hand control over to the bootloader. First, the application is given a
* chance to clean up.
*
* @param[in] params
@@ -96,7 +96,7 @@ public:
*/
virtual void onDataWritten(const GattWriteCallbackParams *params) {
if (params->handle == controlPoint.getValueHandle()) {
- /* At present, writing anything will do the trick--this needs to be improved. */
+ /* At present, writing anything will do the trick - this needs to be improved. */
if (handoverCallback) {
handoverCallback();
}
@@ -112,22 +112,22 @@ protected:
protected:
BLE &ble;
- /**< Writing to the control characteristic triggers the handover to dfu-
- * bootloader. At present, writing anything will do the trick--this needs
+ /**< Writing to the control characteristic triggers the handover to DFU
+ * bootloader. At present, writing anything will do the trick - this needs
* to be improved. */
WriteOnlyArrayGattCharacteristic controlPoint;
- /**< The packet characteristic in this service doesn't do anything meaningful, but
- * is only a placeholder to mimic the corresponding characteristic in the
+ /**< The packet characteristic in this service doesn't do anything meaningful;
+ * it is only a placeholder to mimic the corresponding characteristic in the
* actual DFU service implemented by the bootloader. Without this, some
- * FOTA clients might get confused as service definitions change after
+ * FOTA clients might get confused, because service definitions change after
* handing control over to the bootloader. */
GattCharacteristic packet;
uint8_t controlBytes[SIZEOF_CONTROL_BYTES];
uint8_t packetBytes[SIZEOF_PACKET_BYTES];
- static ResetPrepare_t handoverCallback; /**< application specific handover callback. */
+ static ResetPrepare_t handoverCallback; /**< Application-specific handover callback. */
};
#endif /* #ifndef __BLE_DFU_SERVICE_H__*/
diff --git a/ble/services/DeviceInformationService.h b/ble/services/DeviceInformationService.h
index 0151eeb..e0b8f87 100644
--- a/ble/services/DeviceInformationService.h
+++ b/ble/services/DeviceInformationService.h
@@ -21,41 +21,30 @@
/**
* @class DeviceInformationService
-* @brief BLE Device Information Service
-* Service: https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.device_information.xml
+* @brief BLE Device Information Service
+* Service: https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.device_information.xml
* Manufacturer Name String Char: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.manufacturer_name_string.xml
*/
class DeviceInformationService {
public:
/**
- * @brief Device Information Service Constructor.
+ * @brief Device Information Service Constructor: copies device-specific information
+ * into the BLE stack.
*
* @param[ref] _ble
* BLE object for the underlying controller.
* @param[in] manufacturersName
- * This characteristic represents the name of the
- * manufacturer of the device. The name is copied into the
- * BLE stack during this constructor.
+ * The name of the manufacturer of the device.
* @param[in] modelNumber
- * This characteristic represents the model number that is
- * assigned by the device vendor. The value is copied into
- * the BLE stack during this constructor.
+ * The model number that is assigned by the device vendor.
* @param[in] serialNumber
- * This characteristic represents the serial number for a
- * particular instance of the device. The value is copied
- * into the BLE stack during this constructor.
+ * The serial number for a particular instance of the device.
* @param[in] hardwareRevision
- * This characteristic represents the hardware revision for
- * the hardware within the device. The value is copied
- * into the BLE stack during this constructor.
+ * The hardware revision for the hardware within the device.
* @param[in] firmwareRevision
- * This characteristic represents the firmware revision for
- * the firmware within the device. The value is copied
- * into the BLE stack during this constructor.
+ * The device's firmware version.
* @param[in] softwareRevision
- * This characteristic represents the software revision for
- * the software within the device. The value is copied
- * into the BLE stack during this constructor.
+ * The device's software version.
*/
DeviceInformationService(BLE &_ble,
const char *manufacturersName = NULL,
@@ -67,36 +56,36 @@ public:
ble(_ble),
manufacturersNameStringCharacteristic(GattCharacteristic::UUID_MANUFACTURER_NAME_STRING_CHAR,
(uint8_t *)manufacturersName,
- (manufacturersName != NULL) ? strlen(manufacturersName) : 0, /* minLength */
- (manufacturersName != NULL) ? strlen(manufacturersName) : 0, /* maxLength */
+ (manufacturersName != NULL) ? strlen(manufacturersName) : 0, /* Min length */
+ (manufacturersName != NULL) ? strlen(manufacturersName) : 0, /* Max length */
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ),
modelNumberStringCharacteristic(GattCharacteristic::UUID_MODEL_NUMBER_STRING_CHAR,
(uint8_t *)modelNumber,
- (modelNumber != NULL) ? strlen(modelNumber) : 0, /* minLength */
- (modelNumber != NULL) ? strlen(modelNumber) : 0, /* maxLength */
+ (modelNumber != NULL) ? strlen(modelNumber) : 0, /* Min length */
+ (modelNumber != NULL) ? strlen(modelNumber) : 0, /* Max length */
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ),
serialNumberStringCharacteristic(GattCharacteristic::UUID_SERIAL_NUMBER_STRING_CHAR,
(uint8_t *)serialNumber,
- (serialNumber != NULL) ? strlen(serialNumber) : 0, /* minLength */
- (serialNumber != NULL) ? strlen(serialNumber) : 0, /* maxLength */
+ (serialNumber != NULL) ? strlen(serialNumber) : 0, /* Min length */
+ (serialNumber != NULL) ? strlen(serialNumber) : 0, /* Max length */
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ),
hardwareRevisionStringCharacteristic(GattCharacteristic::UUID_HARDWARE_REVISION_STRING_CHAR,
(uint8_t *)hardwareRevision,
- (hardwareRevision != NULL) ? strlen(hardwareRevision) : 0, /* minLength */
- (hardwareRevision != NULL) ? strlen(hardwareRevision) : 0, /* maxLength */
+ (hardwareRevision != NULL) ? strlen(hardwareRevision) : 0, /* Min length */
+ (hardwareRevision != NULL) ? strlen(hardwareRevision) : 0, /* Max length */
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ),
firmwareRevisionStringCharacteristic(GattCharacteristic::UUID_FIRMWARE_REVISION_STRING_CHAR,
(uint8_t *)firmwareRevision,
- (firmwareRevision != NULL) ? strlen(firmwareRevision) : 0, /* minLength */
- (firmwareRevision != NULL) ? strlen(firmwareRevision) : 0, /* maxLength */
+ (firmwareRevision != NULL) ? strlen(firmwareRevision) : 0, /* Min length */
+ (firmwareRevision != NULL) ? strlen(firmwareRevision) : 0, /* Max length */
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ),
softwareRevisionStringCharacteristic(GattCharacteristic::UUID_SOFTWARE_REVISION_STRING_CHAR,
(uint8_t *)softwareRevision,
- (softwareRevision != NULL) ? strlen(softwareRevision) : 0, /* minLength */
- (softwareRevision != NULL) ? strlen(softwareRevision) : 0, /* maxLength */
+ (softwareRevision != NULL) ? strlen(softwareRevision) : 0, /* Min length */
+ (softwareRevision != NULL) ? strlen(softwareRevision) : 0, /* Max length */
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ)
{
- static bool serviceAdded = false; /* We should only ever need to add the information service once. */
+ static bool serviceAdded = false; /* We only add the information service once. */
if (serviceAdded) {
return;
}