High level Bluetooth Low Energy API and radio abstraction layer

Dependents:   BLE_ANCS_SDAPI BLE_temperature BLE_HeartRate BLE_ANCS_SDAPI_IRC ... more

Overview

The BLE_API is a high level abstraction for using Bluetooth Low Energy on multiple platforms. For details and examples using the BLE_API please see the BLE_API Summary Page. Or click on the API Documentation tab above.

Supported Services

Supported services can be found in the BLE_API/services folder.

Files at this revision

API Documentation at this revision

Comitter:
vcoubard
Date:
Mon Jan 11 08:51:52 2016 +0000
Parent:
1095:7eaddbe4fad0
Child:
1097:4d22814faf46
Commit message:
Synchronized with git rev 39e3e8d1
Author: Andres Amaya Garcia
Modify functions that manipulate adv payload

Modify the functions addData() and updateData() to correctly update the payload
information for a specified AD type if that type was already present in the
payload. For addData() if the AD type is not found, it is added to the payload.
In contrast, in updateData() if the AD type is not found an error is returned.

Documentation was updated accordingly.

Changed in this revision

ble/Gap.h Show annotated file Show diff for this revision Revisions of this file
ble/GapAdvertisingData.h Show annotated file Show diff for this revision Revisions of this file
module.json Show annotated file Show diff for this revision Revisions of this file
--- a/ble/Gap.h	Mon Jan 11 08:51:52 2016 +0000
+++ b/ble/Gap.h	Mon Jan 11 08:51:52 2016 +0000
@@ -620,8 +620,7 @@
 
     /**
      * Update a particular ADV field in the advertising payload (based on
-     * matching type and length). Note: the length of the new data must be the
-     * same as the old one.
+     * matching type).
      *
      * @param[in] type  The ADV type field describing the variable length data.
      * @param[in] data  Data bytes.
@@ -630,7 +629,7 @@
      * @note: If advertisements are enabled, then the update will take effect immediately.
      *
      * @return BLE_ERROR_NONE if the advertisement payload was updated based on
-     *         a <type, len> match; otherwise, an appropriate error.
+     *         matching AD type; otherwise, an appropriate error.
      */
     ble_error_t updateAdvertisingPayload(GapAdvertisingData::DataType type, const uint8_t *data, uint8_t len) {
         if (type == GapAdvertisingData::COMPLETE_LOCAL_NAME) {
--- a/ble/GapAdvertisingData.h	Mon Jan 11 08:51:52 2016 +0000
+++ b/ble/GapAdvertisingData.h	Mon Jan 11 08:51:52 2016 +0000
@@ -202,149 +202,63 @@
 
     /**
      * Adds advertising data based on the specified AD type (see DataType).
-     *
-     * @param  advDataType The Advertising 'DataType' to add.
-     * @param  payload     Pointer to the payload contents.
-     * @param  len         Size of the payload in bytes.
-     *
-     * @return BLE_ERROR_BUFFER_OVERFLOW if the specified data would cause the
-     * advertising buffer to overflow, else BLE_ERROR_NONE.
-     */
-    ble_error_t addData(DataType advDataType, const uint8_t *payload, uint8_t len)
-    {
-        ble_error_t result = 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);
-        }
-
-        return result;
-    }
-
-    /**
-     * Update a particular ADV field in the advertising payload (based on
-     * matching type and length). Note: the length of the new data must be the
-     * same as the old one.
+     * If the supplied AD type is already present in the advertising
+     * payload, then the value is updated.
      *
      * @param[in] advDataType  The Advertising 'DataType' to add.
      * @param[in] payload      Pointer to the payload contents.
      * @param[in] len          Size of the payload in bytes.
      *
-     * @return BLE_ERROR_UNSPECIFIED if the specified field is not found, else
-     * BLE_ERROR_NONE.
+     * @return BLE_ERROR_BUFFER_OVERFLOW if the new value causes the
+     *         advertising buffer to overflow. BLE_ERROR_NONE is returned
+     *         on success.
+     *
+     * @note When the specified AD type is INCOMPLETE_LIST_16BIT_SERVICE_IDS,
+     *       COMPLETE_LIST_16BIT_SERVICE_IDS, INCOMPLETE_LIST_32BIT_SERVICE_IDS,
+     *       COMPLETE_LIST_32BIT_SERVICE_IDS, INCOMPLETE_LIST_128BIT_SERVICE_IDS,
+     *       COMPLETE_LIST_128BIT_SERVICE_IDS or LIST_128BIT_SOLICITATION_IDS the
+     *       supplied value is appended to the values previously added to the
+     *       payload.
+     */
+    ble_error_t addData(DataType_t advDataType, const uint8_t *payload, uint8_t len)
+    {
+        // find field
+        uint8_t* field = findField(advDataType);
+
+        if (field) {
+            // Field type already exist, either add to field or replace
+            return updateFieldPayload(advDataType, payload, len, field);
+        } else {
+            // field doesn't exists, insert new
+            return appendField(advDataType, payload, len);
+        }
+    }
+
+    /**
+     * Update a particular ADV field in the advertising payload (based on
+     * matching type).
+     *
+     * @param[in] advDataType  The Advertising 'DataType' to add.
+     * @param[in] payload      Pointer to the payload contents.
+     * @param[in] len          Size of the payload in bytes.
+     *
+     * @return BLE_ERROR_UNSPECIFIED if the specified field is not found,
+     *         BLE_ERROR_BUFFER_OVERFLOW if the new value causes the
+     *         advertising buffer to overflow. BLE_ERROR_NONE is returned
+     *         on success.
      */
     ble_error_t updateData(DataType_t advDataType, const uint8_t *payload, uint8_t len)
     {
-        if ((payload == NULL) || (len == 0)) {
-            return BLE_ERROR_INVALID_PARAM;
-        }
-
-        /* A local struct to describe an ADV field. This definition comes from the Bluetooth Core Spec. (v4.2) Part C, Section 11. */
-        struct ADVField_t {
-            uint8_t  len;      /* Describes the length (in bytes) of the following type and bytes. */
-            uint8_t  type;     /* Should have the same representation of DataType_t (above). */
-            uint8_t  bytes[0]; /* A placeholder for variable length data. */
-        };
+        // find field
+        uint8_t* field = findField(advDataType);
 
-        /* Iterate over the adv fields looking for the first match. */
-        uint8_t byteIndex = 0;
-        while (byteIndex < _payloadLen) {
-            ADVField_t *currentADV = (ADVField_t *)&_payload[byteIndex];
-            if ((currentADV->len  == (len + 1)) && /* Incoming len only describes the payload, whereas ADV->len describes [type + payload]. */
-                (currentADV->type == advDataType)) {
-                memcpy(currentADV->bytes, payload, len);
-                return BLE_ERROR_NONE;
-            }
-
-            byteIndex += (currentADV->len + 1); /* Advance by len+1; '+1' is needed to span the len field itself. */
+        if (field) {
+            // Field type already exist, either add to field or replace
+            return updateFieldPayload(advDataType, payload, len, field);
+        } else {
+            // field doesn't exists, return an error
+            return BLE_ERROR_UNSPECIFIED;
         }
-
-        return BLE_ERROR_UNSPECIFIED;
     }
 
     /**
@@ -475,6 +389,85 @@
         return NULL;
     }
 
+    /**
+     * Given the a pointer to a field in the advertising payload it replaces
+     * the existing data in the field with the supplied data.
+     * Returns BLE_ERROR_NONE on success.
+     */
+    ble_error_t updateFieldPayload(DataType_t advDataType, const uint8_t *payload, uint8_t len, uint8_t* field)
+    {
+        ble_error_t result = BLE_ERROR_BUFFER_OVERFLOW;
+
+        switch(advDataType) {
+            // 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;
+            }
+            //  These fields will be overwritten with the new value
+            default: {
+                // 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;
+            }
+        }
+
+        return result;
+    }
+
     uint8_t  _payload[GAP_ADVERTISING_DATA_MAX_PAYLOAD];
     uint8_t  _payloadLen;
     uint16_t _appearance;
--- a/module.json	Mon Jan 11 08:51:52 2016 +0000
+++ b/module.json	Mon Jan 11 08:51:52 2016 +0000
@@ -1,6 +1,6 @@
 {
   "name": "ble",
-  "version": "2.2.1",
+  "version": "2.2.0",
   "description": "The BLE module offers a high level abstraction for using Bluetooth Low Energy on multiple platforms.",
   "keywords": [
     "Bluetooth",