From e8e3a7aa2b0c51438c8919b6dbe98fc46358ce60 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 10:01:16 +0000 Subject: [PATCH 01/51] add Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS() --- public/Gap.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/public/Gap.h b/public/Gap.h index 8061931..1ac2c3c 100644 --- a/public/Gap.h +++ b/public/Gap.h @@ -61,10 +61,14 @@ public: uint16_t connectionSupervisionTimeout; /**< Connection Supervision Timeout in 10 ms units, see @ref BLE_GAP_CP_LIMITS.*/ } ConnectionParams_t; - static const uint16_t UNIT_1_25_MS = 1250; /**< Number of microseconds in 1.25 milliseconds. */ + static const uint16_t UNIT_1_25_MS = 1250; /**< Number of microseconds in 1.25 milliseconds. */ + static const uint16_t UNIT_0_625_MS = 650; /**< Number of microseconds in 0.625 milliseconds. */ static uint16_t MSEC_TO_GAP_DURATION_UNITS(uint32_t durationInMillis) { return (durationInMillis * 1000) / UNIT_1_25_MS; } + static uint16_t MSEC_TO_ADVERTISEMENT_DURATION_UNITS(uint32_t durationInMillis) { + return (durationInMillis * 1000) / UNIT_0_625_MS; + } typedef void (*EventCallback_t)(void); typedef void (*ConnectionEventCallback_t)(Handle_t, addr_type_t peerAddrType, const address_t peerAddr, const ConnectionParams_t *); From dca34515873cffea58619507bed7d184500d2878 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Wed, 26 Nov 2014 09:57:25 +0000 Subject: [PATCH 02/51] initial commit for URIBeacon Service. --- services/URIBeacon2Service.h | 85 ++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 services/URIBeacon2Service.h diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h new file mode 100644 index 0000000..8adbf02 --- /dev/null +++ b/services/URIBeacon2Service.h @@ -0,0 +1,85 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __BLE_URI_BEACON_2_SERVICE_H__ +#define __BLE_URI_BEACON_2_SERVICE_H__ + +#include "BLEDevice.h" + +class URIBeacon2Service { +public: + + // ee0c2080-8786-40ba-ab96-99b91ac981d8 + + URIBeacon2Service(BLEDevice &ble_, const uint8_t urldata_[], size_t sizeofURLData) : ble(ble_), payload() { + if ((sizeofURLData + 4) > 24) { + return; + } + + const uint8_t BEACON_UUID[] = {0xD8, 0xFE}; + + payload[0] = BEACON_UUID[0]; + payload[1] = BEACON_UUID[1]; + payload[2] = 0x00; /* flags */ + payload[3] = 0x20; /* power */ + encodeURIData(urldata_, sizeofURLData); + + ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, BEACON_UUID, sizeof(BEACON_UUID)); + ble.accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, payload, sizeofURLData + 4); + } + +private: + void encodeURIData(const uint8_t urldata_[], size_t sizeofURLData) { + memcpy(&payload[4], urldata_, sizeofURLData); +// |Decimal | Hex | Expansion +// |:------- | :--------- | :-------- +// |0 | 0x00 | http://www. +// |1 | 0x01 | https://www. +// |2 | 0x02 | http:// +// |3 | 0x03 | https:// +// |4 | 0x04 | urn:uuid: + } + + // URIBeacon2Service(BLEDevice &_ble, uint8_t level = 100) : + // ble(_ble), + // batteryLevel(level), + // batteryLevelCharacteristic(GattCharacteristic::UUID_BATTERY_LEVEL_CHAR, &batteryLevel, sizeof(batteryLevel), sizeof(batteryLevel), + // GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) { + + // static bool serviceAdded = false; /* We should only ever need to add the heart rate service once. */ + // if (serviceAdded) { + // return; + // } + + // GattCharacteristic *charTable[] = {&batteryLevelCharacteristic}; + // GattService batteryService(GattService::UUID_BATTERY_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *)); + + // ble.addService(batteryService); + // serviceAdded = true; + // } + // + +private: + static const size_t MAX_SIZEOF_PAYLOAD = 32; /* TODO */ + +private: + BLEDevice &ble; + uint8_t payload[MAX_SIZEOF_PAYLOAD]; + // uint8_t batteryLevel; + // GattCharacteristic batteryLevelCharacteristic; +}; + +#endif /* #ifndef __BLE_URI_BEACON_2_SERVICE_H__*/ From 74849dd90b808811d5b71751c57a82020edcb6a8 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Wed, 26 Nov 2014 11:19:24 +0000 Subject: [PATCH 03/51] fleshed out encodeURIData to detect prefixes. --- services/URIBeacon2Service.h | 58 ++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 8adbf02..d8f46a1 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -24,35 +24,59 @@ public: // ee0c2080-8786-40ba-ab96-99b91ac981d8 - URIBeacon2Service(BLEDevice &ble_, const uint8_t urldata_[], size_t sizeofURLData) : ble(ble_), payload() { + URIBeacon2Service(BLEDevice &ble_, const char *urldata, size_t sizeofURLData) : ble(ble_), payloadIndex(0), payload() { if ((sizeofURLData + 4) > 24) { return; } const uint8_t BEACON_UUID[] = {0xD8, 0xFE}; - payload[0] = BEACON_UUID[0]; - payload[1] = BEACON_UUID[1]; - payload[2] = 0x00; /* flags */ - payload[3] = 0x20; /* power */ - encodeURIData(urldata_, sizeofURLData); + payload[payloadIndex++] = BEACON_UUID[0]; + payload[payloadIndex++] = BEACON_UUID[1]; + payload[payloadIndex++] = 0x00; /* flags */ + payload[payloadIndex++] = 0x20; /* power */ + size_t encodedBytes = encodeURIData(urldata, sizeofURLData); ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, BEACON_UUID, sizeof(BEACON_UUID)); - ble.accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, payload, sizeofURLData + 4); + ble.accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, payload, encodedBytes + 4); } private: - void encodeURIData(const uint8_t urldata_[], size_t sizeofURLData) { - memcpy(&payload[4], urldata_, sizeofURLData); -// |Decimal | Hex | Expansion -// |:------- | :--------- | :-------- -// |0 | 0x00 | http://www. -// |1 | 0x01 | https://www. -// |2 | 0x02 | http:// -// |3 | 0x03 | https:// -// |4 | 0x04 | urn:uuid: + size_t encodeURIData(const char *urldata, size_t sizeofURLData) { + if (sizeofURLData == 0) { + return 0; + } + + const char *prefixes[] = { + "http://www.", + "https://www.", + "http://", + "https://", + "urn:uuid:" + }; + size_t encodedBytes = 0; + + const size_t NUM_PREFIXES = sizeof(prefixes) / sizeof(char *); + for (unsigned i = 0; i < NUM_PREFIXES; i++) { + size_t prefixLen = strlen(prefixes[i]); + if (strncmp(urldata, prefixes[i], prefixLen) == 0) { + payload[payloadIndex++] = i; + ++encodedBytes; + + urldata += prefixLen; + sizeofURLData -= prefixLen; + break; + } + } + + memcpy(&payload[payloadIndex], urldata, sizeofURLData); + encodedBytes += sizeofURLData; + + return encodedBytes; } + // size_t encodePrefix(const char *&urldata, ) + // URIBeacon2Service(BLEDevice &_ble, uint8_t level = 100) : // ble(_ble), // batteryLevel(level), @@ -77,6 +101,8 @@ private: private: BLEDevice &ble; + + size_t payloadIndex; uint8_t payload[MAX_SIZEOF_PAYLOAD]; // uint8_t batteryLevel; // GattCharacteristic batteryLevelCharacteristic; From 3ea0f708fd2c885b6418ef02c35f975ba371de86 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Wed, 26 Nov 2014 11:31:58 +0000 Subject: [PATCH 04/51] add encodePrefix() --- services/URIBeacon2Service.h | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index d8f46a1..fb5a35d 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -47,6 +47,15 @@ private: return 0; } + size_t encodedBytes = encodePrefix(urldata, sizeofURLData); + + /* memcpy the rest for now. */ + memcpy(&payload[payloadIndex], urldata, sizeofURLData); + encodedBytes += sizeofURLData; + return encodedBytes; + } + + size_t encodePrefix(const char *&urldata, size_t &sizeofURLData) { const char *prefixes[] = { "http://www.", "https://www.", @@ -54,14 +63,14 @@ private: "https://", "urn:uuid:" }; - size_t encodedBytes = 0; + size_t encodedBytes = 0; const size_t NUM_PREFIXES = sizeof(prefixes) / sizeof(char *); for (unsigned i = 0; i < NUM_PREFIXES; i++) { size_t prefixLen = strlen(prefixes[i]); if (strncmp(urldata, prefixes[i], prefixLen) == 0) { payload[payloadIndex++] = i; - ++encodedBytes; + encodedBytes = 1; urldata += prefixLen; sizeofURLData -= prefixLen; @@ -69,14 +78,9 @@ private: } } - memcpy(&payload[payloadIndex], urldata, sizeofURLData); - encodedBytes += sizeofURLData; - return encodedBytes; } - // size_t encodePrefix(const char *&urldata, ) - // URIBeacon2Service(BLEDevice &_ble, uint8_t level = 100) : // ble(_ble), // batteryLevel(level), From 2586b27aaf4adfaec97e89c8421c150fdca31a3a Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Wed, 26 Nov 2014 13:26:33 +0000 Subject: [PATCH 05/51] add copyURLCheckingForSuffixes() --- services/URIBeacon2Service.h | 74 +++++++++++++++++++++++++++++------- 1 file changed, 61 insertions(+), 13 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index fb5a35d..1cffa9c 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -21,38 +21,37 @@ class URIBeacon2Service { public: - // ee0c2080-8786-40ba-ab96-99b91ac981d8 - - URIBeacon2Service(BLEDevice &ble_, const char *urldata, size_t sizeofURLData) : ble(ble_), payloadIndex(0), payload() { - if ((sizeofURLData + 4) > 24) { - return; - } - + URIBeacon2Service(BLEDevice &ble_, const char *urldata) : ble(ble_), payloadIndex(0), payload() { const uint8_t BEACON_UUID[] = {0xD8, 0xFE}; payload[payloadIndex++] = BEACON_UUID[0]; payload[payloadIndex++] = BEACON_UUID[1]; payload[payloadIndex++] = 0x00; /* flags */ payload[payloadIndex++] = 0x20; /* power */ + + size_t sizeofURLData = strlen(urldata); size_t encodedBytes = encodeURIData(urldata, sizeofURLData); ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, BEACON_UUID, sizeof(BEACON_UUID)); ble.accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, payload, encodedBytes + 4); } + void dumpEncoded() { + printf("encoded: '"); + for (unsigned i = 0; i < payloadIndex; i++) { + printf(" %02x", payload[i]); + } + printf("'\r\n"); + } + private: size_t encodeURIData(const char *urldata, size_t sizeofURLData) { if (sizeofURLData == 0) { return 0; } - size_t encodedBytes = encodePrefix(urldata, sizeofURLData); - - /* memcpy the rest for now. */ - memcpy(&payload[payloadIndex], urldata, sizeofURLData); - encodedBytes += sizeofURLData; - return encodedBytes; + return encodePrefix(urldata, sizeofURLData) + copyURLCheckingForSuffixes(urldata, sizeofURLData); } size_t encodePrefix(const char *&urldata, size_t &sizeofURLData) { @@ -81,6 +80,55 @@ private: return encodedBytes; } + size_t copyURLCheckingForSuffixes(const char *urldata, size_t sizeofURLData) { + const char *suffixes[] = { + ".com/", + ".org/", + ".edu/", + ".net/", + ".info/", + ".biz/", + ".gov/", + ".com", + ".org", + ".edu", + ".net", + ".info", + ".biz", + ".gov" + }; + const size_t NUM_SUFFIXES = sizeof(suffixes) / sizeof(char *); + + size_t encodedBytes = 0; + while (sizeofURLData && (payloadIndex < MAX_SIZEOF_PAYLOAD)) { + /* check for suffix match */ + unsigned i; + for (i = 0; i < NUM_SUFFIXES; i++) { + size_t suffixLen = strlen(suffixes[i]); + if ((suffixLen == 0) || (sizeofURLData < suffixLen)) { + continue; + } + + if (strncmp(urldata, suffixes[i], suffixLen) == 0) { + payload[payloadIndex++] = i; + ++encodedBytes; + urldata += suffixLen; + sizeofURLData -= suffixLen; + break; /* from the for loop for checking against suffixes */ + } + } + /* This is the default case where we've got an ordinary character which doesn't match a suffix. */ + if (i == NUM_SUFFIXES) { + payload[payloadIndex++] = *urldata; + ++encodedBytes; + ++urldata; + --sizeofURLData; + } + } + + return encodedBytes; + } + // URIBeacon2Service(BLEDevice &_ble, uint8_t level = 100) : // ble(_ble), // batteryLevel(level), From 07b87a6412eb3791f249e639ebf5731fb689d81a Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Wed, 26 Nov 2014 13:36:25 +0000 Subject: [PATCH 06/51] add default arguments to the constructor for URIBeacon; and minor renames. --- services/URIBeacon2Service.h | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 1cffa9c..e2f2400 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -22,39 +22,39 @@ class URIBeacon2Service { public: // ee0c2080-8786-40ba-ab96-99b91ac981d8 - URIBeacon2Service(BLEDevice &ble_, const char *urldata) : ble(ble_), payloadIndex(0), payload() { + URIBeacon2Service(BLEDevice &ble_, const char *urldata, uint8_t flags = 0, uint8_t power = 0) : ble(ble_), payloadIndex(0), serviceDataPayload() { const uint8_t BEACON_UUID[] = {0xD8, 0xFE}; - payload[payloadIndex++] = BEACON_UUID[0]; - payload[payloadIndex++] = BEACON_UUID[1]; - payload[payloadIndex++] = 0x00; /* flags */ - payload[payloadIndex++] = 0x20; /* power */ + serviceDataPayload[payloadIndex++] = BEACON_UUID[0]; + serviceDataPayload[payloadIndex++] = BEACON_UUID[1]; + serviceDataPayload[payloadIndex++] = flags; + serviceDataPayload[payloadIndex++] = power; size_t sizeofURLData = strlen(urldata); - size_t encodedBytes = encodeURIData(urldata, sizeofURLData); + size_t encodedBytes = encodeServiceData(urldata, sizeofURLData); ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, BEACON_UUID, sizeof(BEACON_UUID)); - ble.accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, payload, encodedBytes + 4); + ble.accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, serviceDataPayload, encodedBytes + 4); } - void dumpEncoded() { + void dumpEncodedSeviceData() const { printf("encoded: '"); for (unsigned i = 0; i < payloadIndex; i++) { - printf(" %02x", payload[i]); + printf(" %02x", serviceDataPayload[i]); } printf("'\r\n"); } private: - size_t encodeURIData(const char *urldata, size_t sizeofURLData) { + size_t encodeServiceData(const char *urldata, size_t sizeofURLData) { if (sizeofURLData == 0) { return 0; } - return encodePrefix(urldata, sizeofURLData) + copyURLCheckingForSuffixes(urldata, sizeofURLData); + return encodeURISchemePrefix(urldata, sizeofURLData) + encodeURI(urldata, sizeofURLData); } - size_t encodePrefix(const char *&urldata, size_t &sizeofURLData) { + size_t encodeURISchemePrefix(const char *&urldata, size_t &sizeofURLData) { const char *prefixes[] = { "http://www.", "https://www.", @@ -68,7 +68,7 @@ private: for (unsigned i = 0; i < NUM_PREFIXES; i++) { size_t prefixLen = strlen(prefixes[i]); if (strncmp(urldata, prefixes[i], prefixLen) == 0) { - payload[payloadIndex++] = i; + serviceDataPayload[payloadIndex++] = i; encodedBytes = 1; urldata += prefixLen; @@ -80,7 +80,7 @@ private: return encodedBytes; } - size_t copyURLCheckingForSuffixes(const char *urldata, size_t sizeofURLData) { + size_t encodeURI(const char *urldata, size_t sizeofURLData) { const char *suffixes[] = { ".com/", ".org/", @@ -110,7 +110,7 @@ private: } if (strncmp(urldata, suffixes[i], suffixLen) == 0) { - payload[payloadIndex++] = i; + serviceDataPayload[payloadIndex++] = i; ++encodedBytes; urldata += suffixLen; sizeofURLData -= suffixLen; @@ -119,7 +119,7 @@ private: } /* This is the default case where we've got an ordinary character which doesn't match a suffix. */ if (i == NUM_SUFFIXES) { - payload[payloadIndex++] = *urldata; + serviceDataPayload[payloadIndex++] = *urldata; ++encodedBytes; ++urldata; --sizeofURLData; @@ -155,7 +155,7 @@ private: BLEDevice &ble; size_t payloadIndex; - uint8_t payload[MAX_SIZEOF_PAYLOAD]; + uint8_t serviceDataPayload[MAX_SIZEOF_PAYLOAD]; // uint8_t batteryLevel; // GattCharacteristic batteryLevelCharacteristic; }; From 5e083c2fcefc746e7a043d1f584befdfc2e8e543 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Wed, 26 Nov 2014 13:40:14 +0000 Subject: [PATCH 07/51] use ble.setTxPower() --- services/URIBeacon2Service.h | 1 + 1 file changed, 1 insertion(+) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index e2f2400..ca09774 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -33,6 +33,7 @@ public: size_t sizeofURLData = strlen(urldata); size_t encodedBytes = encodeServiceData(urldata, sizeofURLData); + ble.setTxPower(power); ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, BEACON_UUID, sizeof(BEACON_UUID)); ble.accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, serviceDataPayload, encodedBytes + 4); } From 84c99e724cf40d6b0f94cb0146742c77de0c3887 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Wed, 26 Nov 2014 14:52:59 +0000 Subject: [PATCH 08/51] remove un-necessary comment block. --- services/URIBeacon2Service.h | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index ca09774..34ac5f4 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -130,25 +130,6 @@ private: return encodedBytes; } - // URIBeacon2Service(BLEDevice &_ble, uint8_t level = 100) : - // ble(_ble), - // batteryLevel(level), - // batteryLevelCharacteristic(GattCharacteristic::UUID_BATTERY_LEVEL_CHAR, &batteryLevel, sizeof(batteryLevel), sizeof(batteryLevel), - // GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) { - - // static bool serviceAdded = false; /* We should only ever need to add the heart rate service once. */ - // if (serviceAdded) { - // return; - // } - - // GattCharacteristic *charTable[] = {&batteryLevelCharacteristic}; - // GattService batteryService(GattService::UUID_BATTERY_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *)); - - // ble.addService(batteryService); - // serviceAdded = true; - // } - // - private: static const size_t MAX_SIZEOF_PAYLOAD = 32; /* TODO */ From e387fac6c26c22ac50eadfb6e818acaf7dce9ff3 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Wed, 26 Nov 2014 15:44:15 +0000 Subject: [PATCH 09/51] remove legacy commented code from battery service. --- services/URIBeacon2Service.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 34ac5f4..6dd949d 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -138,8 +138,6 @@ private: size_t payloadIndex; uint8_t serviceDataPayload[MAX_SIZEOF_PAYLOAD]; - // uint8_t batteryLevel; - // GattCharacteristic batteryLevelCharacteristic; }; #endif /* #ifndef __BLE_URI_BEACON_2_SERVICE_H__*/ From 2cef97c117446b5a2cc0ac139b9a37879530913b Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Wed, 26 Nov 2014 15:45:42 +0000 Subject: [PATCH 10/51] rename to MAX_SIZEOF_SERVICE_DATA_PAYLOAD --- services/URIBeacon2Service.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 6dd949d..e7ceb93 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -101,7 +101,7 @@ private: const size_t NUM_SUFFIXES = sizeof(suffixes) / sizeof(char *); size_t encodedBytes = 0; - while (sizeofURLData && (payloadIndex < MAX_SIZEOF_PAYLOAD)) { + while (sizeofURLData && (payloadIndex < MAX_SIZEOF_SERVICE_DATA_PAYLOAD)) { /* check for suffix match */ unsigned i; for (i = 0; i < NUM_SUFFIXES; i++) { @@ -131,13 +131,13 @@ private: } private: - static const size_t MAX_SIZEOF_PAYLOAD = 32; /* TODO */ + static const size_t MAX_SIZEOF_SERVICE_DATA_PAYLOAD = 32; /* TODO */ private: BLEDevice &ble; size_t payloadIndex; - uint8_t serviceDataPayload[MAX_SIZEOF_PAYLOAD]; + uint8_t serviceDataPayload[MAX_SIZEOF_SERVICE_DATA_PAYLOAD]; }; #endif /* #ifndef __BLE_URI_BEACON_2_SERVICE_H__*/ From 4eb693065cd042798d5ede50cd2da855ab55d6b7 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Wed, 26 Nov 2014 15:46:17 +0000 Subject: [PATCH 11/51] remove un-necessary comment. --- services/URIBeacon2Service.h | 1 - 1 file changed, 1 deletion(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index e7ceb93..652d132 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -21,7 +21,6 @@ class URIBeacon2Service { public: - // ee0c2080-8786-40ba-ab96-99b91ac981d8 URIBeacon2Service(BLEDevice &ble_, const char *urldata, uint8_t flags = 0, uint8_t power = 0) : ble(ble_), payloadIndex(0), serviceDataPayload() { const uint8_t BEACON_UUID[] = {0xD8, 0xFE}; From fc8788b5406cadc33a7cb42843934d5f60cecabf Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Wed, 26 Nov 2014 15:59:46 +0000 Subject: [PATCH 12/51] MAX_SIZEOF_SERVICE_DATA_PAYLOAD to 27 --- services/URIBeacon2Service.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 652d132..22de689 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -130,7 +130,7 @@ private: } private: - static const size_t MAX_SIZEOF_SERVICE_DATA_PAYLOAD = 32; /* TODO */ + static const size_t MAX_SIZEOF_SERVICE_DATA_PAYLOAD = 27; private: BLEDevice &ble; From 29a046faa8dc3fd475ea7d354c0840cc18b176cf Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Wed, 26 Nov 2014 16:26:28 +0000 Subject: [PATCH 13/51] extracted a setup(). --- services/URIBeacon2Service.h | 54 +++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 22de689..a8faf6d 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -21,20 +21,19 @@ class URIBeacon2Service { public: - URIBeacon2Service(BLEDevice &ble_, const char *urldata, uint8_t flags = 0, uint8_t power = 0) : ble(ble_), payloadIndex(0), serviceDataPayload() { - const uint8_t BEACON_UUID[] = {0xD8, 0xFE}; + URIBeacon2Service(BLEDevice &ble_, const char *urldata, uint8_t flags_ = 0, uint8_t power_ = 0) : + ble(ble_), payloadIndex(0), serviceDataPayload(), + uriDataLength(0), + uriDataValue(), + flags(flags_), + power(power_) + { + if ((urldata == NULL) || ((uriDataLength = strlen(urldata)) == 0)) { + return; + } + strncpy(reinterpret_cast(uriDataValue), urldata, MAX_SIZE_URI_DATA_CHAR_VALUE); - serviceDataPayload[payloadIndex++] = BEACON_UUID[0]; - serviceDataPayload[payloadIndex++] = BEACON_UUID[1]; - serviceDataPayload[payloadIndex++] = flags; - serviceDataPayload[payloadIndex++] = power; - - size_t sizeofURLData = strlen(urldata); - size_t encodedBytes = encodeServiceData(urldata, sizeofURLData); - - ble.setTxPower(power); - ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, BEACON_UUID, sizeof(BEACON_UUID)); - ble.accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, serviceDataPayload, encodedBytes + 4); + setup(); } void dumpEncodedSeviceData() const { @@ -46,12 +45,22 @@ public: } private: - size_t encodeServiceData(const char *urldata, size_t sizeofURLData) { - if (sizeofURLData == 0) { - return 0; - } + void setup(void) { + payloadIndex = 0; - return encodeURISchemePrefix(urldata, sizeofURLData) + encodeURI(urldata, sizeofURLData); + const uint8_t BEACON_UUID[] = {0xD8, 0xFE}; + serviceDataPayload[payloadIndex++] = BEACON_UUID[0]; + serviceDataPayload[payloadIndex++] = BEACON_UUID[1]; + serviceDataPayload[payloadIndex++] = flags; + serviceDataPayload[payloadIndex++] = power; + + const char *urlData = reinterpret_cast(uriDataValue); + size_t sizeofURLData = uriDataLength; + size_t encodedBytes = encodeURISchemePrefix(urlData, sizeofURLData) + encodeURI(urlData, sizeofURLData); + + ble.setTxPower(power); + ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, BEACON_UUID, sizeof(BEACON_UUID)); + ble.accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, serviceDataPayload, encodedBytes + 4); } size_t encodeURISchemePrefix(const char *&urldata, size_t &sizeofURLData) { @@ -131,12 +140,17 @@ private: private: static const size_t MAX_SIZEOF_SERVICE_DATA_PAYLOAD = 27; + static const size_t MAX_SIZE_URI_DATA_CHAR_VALUE = 48; private: BLEDevice &ble; - size_t payloadIndex; - uint8_t serviceDataPayload[MAX_SIZEOF_SERVICE_DATA_PAYLOAD]; + size_t payloadIndex; + uint8_t serviceDataPayload[MAX_SIZEOF_SERVICE_DATA_PAYLOAD]; + uint16_t uriDataLength; + uint8_t uriDataValue[MAX_SIZE_URI_DATA_CHAR_VALUE]; + uint8_t flags; + uint8_t power; }; #endif /* #ifndef __BLE_URI_BEACON_2_SERVICE_H__*/ From 4708c024face9b4935eb20e4a5b1e452d80c1bc5 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Wed, 26 Nov 2014 16:35:35 +0000 Subject: [PATCH 14/51] add a couple of characteristics --- services/URIBeacon2Service.h | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index a8faf6d..2f9bd1f 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -19,14 +19,29 @@ #include "BLEDevice.h" +#define UUID_INITIALIZER_LIST(FIRST, SECOND) { \ + 0xee, 0x0c, FIRST, SECOND, 0x87, 0x86, 0x40, 0xba, \ + 0xab, 0x96, 0x99, 0xb9, 0x1a, 0xc9, 0x81, 0xd8, \ +} +const uint8_t URIBeacon2ControlServiceUUID[] = UUID_INITIALIZER_LIST(0x20, 0x80); +const uint8_t lockedStateCharUUID[] = UUID_INITIALIZER_LIST(0x20, 0x81); +const uint8_t uriDataCharUUID[] = UUID_INITIALIZER_LIST(0x20, 0x84); + class URIBeacon2Service { public: URIBeacon2Service(BLEDevice &ble_, const char *urldata, uint8_t flags_ = 0, uint8_t power_ = 0) : ble(ble_), payloadIndex(0), serviceDataPayload(), + lockedState(false), uriDataLength(0), uriDataValue(), flags(flags_), - power(power_) + power(power_), + lockedStateChar(lockedStateCharUUID, (uint8_t *)&lockedState, 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ), + uriDataChar(uriDataCharUUID, + uriDataValue, + MAX_SIZE_URI_DATA_CHAR_VALUE, + MAX_SIZE_URI_DATA_CHAR_VALUE, + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE) { if ((urldata == NULL) || ((uriDataLength = strlen(urldata)) == 0)) { return; @@ -34,6 +49,17 @@ public: strncpy(reinterpret_cast(uriDataValue), urldata, MAX_SIZE_URI_DATA_CHAR_VALUE); setup(); + + static bool serviceAdded = false; /* We should only ever need to add the heart rate service once. */ + if (serviceAdded) { + return; + } + + GattCharacteristic *charTable[] = {&lockedStateChar, &uriDataChar}; + GattService beaconControlService(URIBeacon2ControlServiceUUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *)); + + ble.addService(beaconControlService); + serviceAdded = true; } void dumpEncodedSeviceData() const { @@ -147,10 +173,14 @@ private: size_t payloadIndex; uint8_t serviceDataPayload[MAX_SIZEOF_SERVICE_DATA_PAYLOAD]; + bool lockedState; uint16_t uriDataLength; uint8_t uriDataValue[MAX_SIZE_URI_DATA_CHAR_VALUE]; uint8_t flags; uint8_t power; + + GattCharacteristic lockedStateChar; + GattCharacteristic uriDataChar; }; #endif /* #ifndef __BLE_URI_BEACON_2_SERVICE_H__*/ From 6d5a5e36b6515a95d024bfd5647ee32d2270d7ff Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Thu, 27 Nov 2014 09:53:43 +0000 Subject: [PATCH 15/51] add support for onDataWritten for the URIValue characteristic. --- services/URIBeacon2Service.h | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 2f9bd1f..caf8ca0 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -60,8 +60,32 @@ public: ble.addService(beaconControlService); serviceAdded = true; + + ble.onDataWritten(this, &URIBeacon2Service::onDataWritten); } + /** + * This callback allows the DFU service to receive the initial trigger to + * handover control to the bootloader; but first the application is given a + * chance to clean up. + */ + virtual void onDataWritten(const GattCharacteristicWriteCBParams *params) { + if (params->charHandle == uriDataChar.getValueAttribute().getHandle()) { + /* we don't handle very large writes at the moment. */ + if ((params->offset != 0) || (params->len > MAX_SIZE_URI_DATA_CHAR_VALUE)) { + return; + } + + uriDataLength = params->len; + memcpy(uriDataValue, params->data, uriDataLength); + setup(); + ble.setAdvertisingPayload(); + } + } + + /** + * for debugging only + */ void dumpEncodedSeviceData() const { printf("encoded: '"); for (unsigned i = 0; i < payloadIndex; i++) { @@ -72,9 +96,9 @@ public: private: void setup(void) { - payloadIndex = 0; - const uint8_t BEACON_UUID[] = {0xD8, 0xFE}; + + payloadIndex = 0; serviceDataPayload[payloadIndex++] = BEACON_UUID[0]; serviceDataPayload[payloadIndex++] = BEACON_UUID[1]; serviceDataPayload[payloadIndex++] = flags; @@ -84,9 +108,11 @@ private: size_t sizeofURLData = uriDataLength; size_t encodedBytes = encodeURISchemePrefix(urlData, sizeofURLData) + encodeURI(urlData, sizeofURLData); - ble.setTxPower(power); + ble.clearAdvertisingPayload(); ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, BEACON_UUID, sizeof(BEACON_UUID)); ble.accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, serviceDataPayload, encodedBytes + 4); + + ble.setTxPower(power); } size_t encodeURISchemePrefix(const char *&urldata, size_t &sizeofURLData) { From d1bc90fa0b19903993c733f330fb693476381872 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Thu, 27 Nov 2014 13:10:37 +0000 Subject: [PATCH 16/51] trivial cosmetic change. --- services/URIBeacon2Service.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index caf8ca0..7a91cac 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -84,7 +84,7 @@ public: } /** - * for debugging only + * For debugging only. */ void dumpEncodedSeviceData() const { printf("encoded: '"); @@ -199,7 +199,7 @@ private: size_t payloadIndex; uint8_t serviceDataPayload[MAX_SIZEOF_SERVICE_DATA_PAYLOAD]; - bool lockedState; + bool lockedState; uint16_t uriDataLength; uint8_t uriDataValue[MAX_SIZE_URI_DATA_CHAR_VALUE]; uint8_t flags; From 1df22179e9edafa056513d8ac4b66c76736398c7 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Thu, 27 Nov 2014 14:22:47 +0000 Subject: [PATCH 17/51] initialize beaconPeriod to 1000ms automatically --- services/URIBeacon2Service.h | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 7a91cac..8616f81 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -26,6 +26,8 @@ const uint8_t URIBeacon2ControlServiceUUID[] = UUID_INITIALIZER_LIST(0x20, 0x80); const uint8_t lockedStateCharUUID[] = UUID_INITIALIZER_LIST(0x20, 0x81); const uint8_t uriDataCharUUID[] = UUID_INITIALIZER_LIST(0x20, 0x84); +const uint8_t flagsCharUUID[] = UUID_INITIALIZER_LIST(0x20, 0x85); +const uint8_t beaconPeriodCharUUID[] = UUID_INITIALIZER_LIST(0x20, 0x88); class URIBeacon2Service { public: @@ -36,12 +38,14 @@ public: uriDataValue(), flags(flags_), power(power_), + beaconPeriod(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(1000)), /* 1hz */ lockedStateChar(lockedStateCharUUID, (uint8_t *)&lockedState, 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ), uriDataChar(uriDataCharUUID, uriDataValue, MAX_SIZE_URI_DATA_CHAR_VALUE, MAX_SIZE_URI_DATA_CHAR_VALUE, - GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE) + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE), + flagsChar(flagsCharUUID, &flags, 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE) { if ((urldata == NULL) || ((uriDataLength = strlen(urldata)) == 0)) { return; @@ -78,9 +82,16 @@ public: uriDataLength = params->len; memcpy(uriDataValue, params->data, uriDataLength); - setup(); - ble.setAdvertisingPayload(); + } else if (params->charHandle == flagsChar.getValueAttribute().getHandle()) { + if (lockedState) { + ble.updateCharacteristicValue(flagsChar.getValueAttribute().getHandle(), &flags, 1 /* size */); + return; + } else { + flags = *(params->data); + } } + setup(); + ble.setAdvertisingPayload(); } /** @@ -112,6 +123,7 @@ private: ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, BEACON_UUID, sizeof(BEACON_UUID)); ble.accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, serviceDataPayload, encodedBytes + 4); + ble.setAdvertisingInterval(beaconPeriod); ble.setTxPower(power); } @@ -204,9 +216,11 @@ private: uint8_t uriDataValue[MAX_SIZE_URI_DATA_CHAR_VALUE]; uint8_t flags; uint8_t power; + uint16_t beaconPeriod; GattCharacteristic lockedStateChar; GattCharacteristic uriDataChar; + GattCharacteristic flagsChar; }; #endif /* #ifndef __BLE_URI_BEACON_2_SERVICE_H__*/ From 18ffab58d1ebb2ef4ab31889b43e8309ae50e88e Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Thu, 27 Nov 2014 14:23:22 +0000 Subject: [PATCH 18/51] preparing for txPower characteristic --- services/URIBeacon2Service.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 8616f81..1a43b07 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -27,6 +27,7 @@ const uint8_t URIBeacon2ControlServiceUUID[] = UUID_INITIALIZER_LIST(0x20, 0x80) const uint8_t lockedStateCharUUID[] = UUID_INITIALIZER_LIST(0x20, 0x81); const uint8_t uriDataCharUUID[] = UUID_INITIALIZER_LIST(0x20, 0x84); const uint8_t flagsCharUUID[] = UUID_INITIALIZER_LIST(0x20, 0x85); +const uint8_t txPowerCharUUID[] = UUID_INITIALIZER_LIST(0x20, 0x86); const uint8_t beaconPeriodCharUUID[] = UUID_INITIALIZER_LIST(0x20, 0x88); class URIBeacon2Service { @@ -46,6 +47,7 @@ public: MAX_SIZE_URI_DATA_CHAR_VALUE, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE), flagsChar(flagsCharUUID, &flags, 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE) + // txPowerChar(txPowerCharUUID, &power, 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE) { if ((urldata == NULL) || ((uriDataLength = strlen(urldata)) == 0)) { return; @@ -221,6 +223,7 @@ private: GattCharacteristic lockedStateChar; GattCharacteristic uriDataChar; GattCharacteristic flagsChar; + // GattCharacteristic txPowerChar; }; #endif /* #ifndef __BLE_URI_BEACON_2_SERVICE_H__*/ From f5827433451f8fe9765840ecf7534dbd867aab7b Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Thu, 27 Nov 2014 14:24:24 +0000 Subject: [PATCH 19/51] restore uriData characteristic upon receiving a write if locked. --- services/URIBeacon2Service.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 1a43b07..17ed48e 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -77,6 +77,11 @@ public: */ virtual void onDataWritten(const GattCharacteristicWriteCBParams *params) { if (params->charHandle == uriDataChar.getValueAttribute().getHandle()) { + if (lockedState) { /* when locked, the device isn't allowed to update the uriData characteristic */ + ble.updateCharacteristicValue(uriDataChar.getValueAttribute().getHandle(), uriDataValue, uriDataLength); + return; + } + /* we don't handle very large writes at the moment. */ if ((params->offset != 0) || (params->len > MAX_SIZE_URI_DATA_CHAR_VALUE)) { return; From 97b23858bf55be5027053e923b7f1fa20fbd85e5 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Thu, 27 Nov 2014 16:08:31 +0000 Subject: [PATCH 20/51] add flags characteristic to GATT server. --- services/URIBeacon2Service.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 17ed48e..67328dc 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -61,7 +61,7 @@ public: return; } - GattCharacteristic *charTable[] = {&lockedStateChar, &uriDataChar}; + GattCharacteristic *charTable[] = {&lockedStateChar, &uriDataChar, &flagsChar}; GattService beaconControlService(URIBeacon2ControlServiceUUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *)); ble.addService(beaconControlService); @@ -82,7 +82,7 @@ public: return; } - /* we don't handle very large writes at the moment. */ + /* We don't handle very large writes at the moment. */ if ((params->offset != 0) || (params->len > MAX_SIZE_URI_DATA_CHAR_VALUE)) { return; } @@ -90,7 +90,7 @@ public: uriDataLength = params->len; memcpy(uriDataValue, params->data, uriDataLength); } else if (params->charHandle == flagsChar.getValueAttribute().getHandle()) { - if (lockedState) { + if (lockedState) { /* when locked, the device isn't allowed to update the flags characteristic */ ble.updateCharacteristicValue(flagsChar.getValueAttribute().getHandle(), &flags, 1 /* size */); return; } else { From bdccaff73a9911e3b6cbbde811399be15605aaad Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Thu, 27 Nov 2014 16:08:59 +0000 Subject: [PATCH 21/51] adding a few comments. --- services/URIBeacon2Service.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 67328dc..26895b8 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -77,7 +77,8 @@ public: */ virtual void onDataWritten(const GattCharacteristicWriteCBParams *params) { if (params->charHandle == uriDataChar.getValueAttribute().getHandle()) { - if (lockedState) { /* when locked, the device isn't allowed to update the uriData characteristic */ + if (lockedState) { /* When locked, the device isn't allowed to update the uriData characteristic. */ + /* Restore GATT database with previous value. */ ble.updateCharacteristicValue(uriDataChar.getValueAttribute().getHandle(), uriDataValue, uriDataLength); return; } @@ -90,7 +91,8 @@ public: uriDataLength = params->len; memcpy(uriDataValue, params->data, uriDataLength); } else if (params->charHandle == flagsChar.getValueAttribute().getHandle()) { - if (lockedState) { /* when locked, the device isn't allowed to update the flags characteristic */ + if (lockedState) { /* When locked, the device isn't allowed to update the flags characteristic. */ + /* Restore GATT database with previous value. */ ble.updateCharacteristicValue(flagsChar.getValueAttribute().getHandle(), &flags, 1 /* size */); return; } else { From 178df43c3f8a91e499b3ecff76c0ed5884a9e6b2 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Thu, 27 Nov 2014 16:25:25 +0000 Subject: [PATCH 22/51] add beaconPeriodCharacteristic --- services/URIBeacon2Service.h | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 26895b8..b70cc2f 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -46,8 +46,10 @@ public: MAX_SIZE_URI_DATA_CHAR_VALUE, MAX_SIZE_URI_DATA_CHAR_VALUE, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE), - flagsChar(flagsCharUUID, &flags, 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE) + flagsChar(flagsCharUUID, &flags, 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE), // txPowerChar(txPowerCharUUID, &power, 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE) + beaconPeriodChar(beaconPeriodCharUUID, (uint8_t *)&beaconPeriod, 2, 2, + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE) { if ((urldata == NULL) || ((uriDataLength = strlen(urldata)) == 0)) { return; @@ -61,7 +63,7 @@ public: return; } - GattCharacteristic *charTable[] = {&lockedStateChar, &uriDataChar, &flagsChar}; + GattCharacteristic *charTable[] = {&lockedStateChar, &uriDataChar, &flagsChar, &beaconPeriodChar}; GattService beaconControlService(URIBeacon2ControlServiceUUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *)); ble.addService(beaconControlService); @@ -98,6 +100,14 @@ public: } else { flags = *(params->data); } + } else if (params->charHandle == beaconPeriodChar.getValueAttribute().getHandle()) { + if (lockedState) { /* When locked, the device isn't allowed to update the flags characteristic. */ + /* Restore GATT database with previous value. */ + ble.updateCharacteristicValue(beaconPeriodChar.getValueAttribute().getHandle(), (uint8_t *)&beaconPeriod, 2 /* size */); + return; + } else { + beaconPeriod = *((uint16_t *)(params->data)); + } } setup(); ble.setAdvertisingPayload(); @@ -231,6 +241,7 @@ private: GattCharacteristic uriDataChar; GattCharacteristic flagsChar; // GattCharacteristic txPowerChar; + GattCharacteristic beaconPeriodChar; }; #endif /* #ifndef __BLE_URI_BEACON_2_SERVICE_H__*/ From fa14fe1c463b928b2de7866df64b3b343b9ff1e0 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 21 Nov 2014 13:21:28 +0000 Subject: [PATCH 23/51] remove some un-necessary header files from BLEDevice.h --- public/BLEDevice.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/public/BLEDevice.h b/public/BLEDevice.h index 79fefc2..e1d1af3 100644 --- a/public/BLEDevice.h +++ b/public/BLEDevice.h @@ -17,8 +17,6 @@ #ifndef __BLE_DEVICE__ #define __BLE_DEVICE__ -#include "mbed.h" -#include "blecommon.h" #include "Gap.h" #include "GattServer.h" #include "BLEDeviceInstanceBase.h" From 2138c544d1c6b723ce5aefd7c2385ffb72889733 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 08:07:27 +0000 Subject: [PATCH 24/51] mark OndataWritten() as protected --- services/URIBeacon2Service.h | 1 + 1 file changed, 1 insertion(+) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index b70cc2f..b2423f1 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -72,6 +72,7 @@ public: ble.onDataWritten(this, &URIBeacon2Service::onDataWritten); } +protected: /** * This callback allows the DFU service to receive the initial trigger to * handover control to the bootloader; but first the application is given a From e5ccaa669c7cbfabedc20e378d3896ff2b3b51f5 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 12:04:44 +0000 Subject: [PATCH 25/51] minor typo --- services/UARTService.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/UARTService.h b/services/UARTService.h index 8f59948..3248fdb 100644 --- a/services/UARTService.h +++ b/services/UARTService.h @@ -41,7 +41,7 @@ public: public: UARTService(BLEDevice &_ble) : - Stream("blueart"), + Stream("bleuart"), ble(_ble), receiveBuffer(), sendBuffer(), @@ -86,7 +86,7 @@ public: * prepared to stitch these messages back. */ void retargetStdout() { - freopen("/blueart", "w", stdout); + freopen("/bleuart", "w", stdout); } /** From 3572c9c47fcf93bd1acd995626c2ce233445ff83 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 08:27:01 +0000 Subject: [PATCH 26/51] add a beaconPeriod parameter for the constructor --- services/URIBeacon2Service.h | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index b2423f1..7747791 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -32,14 +32,14 @@ const uint8_t beaconPeriodCharUUID[] = UUID_INITIALIZER_LIST(0x20, 0x88) class URIBeacon2Service { public: - URIBeacon2Service(BLEDevice &ble_, const char *urldata, uint8_t flags_ = 0, uint8_t power_ = 0) : + URIBeacon2Service(BLEDevice &ble_, const char *urldata, uint8_t flagsIn = 0, uint8_t txPowerIn = 0, uint16_t beaconPeriodIn = 1000) : ble(ble_), payloadIndex(0), serviceDataPayload(), lockedState(false), uriDataLength(0), uriDataValue(), - flags(flags_), - power(power_), - beaconPeriod(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(1000)), /* 1hz */ + flags(flagsIn), + power(txPowerIn), + beaconPeriod(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(beaconPeriodIn)), lockedStateChar(lockedStateCharUUID, (uint8_t *)&lockedState, 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ), uriDataChar(uriDataCharUUID, uriDataValue, @@ -72,6 +72,21 @@ public: ble.onDataWritten(this, &URIBeacon2Service::onDataWritten); } + void setFlags(uint8_t flagsIn) { + flags = flagsIn; + setup(); + } + + void setTxPower(uint8_t txPowerIn) { + power = txPowerIn; + setup(); + } + + void setBeaconPeriod(uint16_t beaconPeriodIn) { + beaconPeriod = beaconPeriodIn; + setup(); + } + protected: /** * This callback allows the DFU service to receive the initial trigger to From 4f8178b02f72ed9647062bf2fff8e6a4d9ef381b Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 08:27:19 +0000 Subject: [PATCH 27/51] add a comment block for the constructor. --- services/URIBeacon2Service.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 7747791..1250a9b 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -32,6 +32,20 @@ const uint8_t beaconPeriodCharUUID[] = UUID_INITIALIZER_LIST(0x20, 0x88) class URIBeacon2Service { public: + /** + * @param[ref] ble + * BLEDevice object for the underlying controller. + * @param[in] urldata + * URI as a null-terminated string. + * @param[in] flagsIn + * UriBeacon Flags. + * @param[in] txPowerIn + * UriBeacon Tx Power Level. + * @param[in] beaconPeriodIn + * The period in milliseconds that a UriBeacon packet is + * transmitted. A value of zero disables UriBeacon + * transmissions. + */ URIBeacon2Service(BLEDevice &ble_, const char *urldata, uint8_t flagsIn = 0, uint8_t txPowerIn = 0, uint16_t beaconPeriodIn = 1000) : ble(ble_), payloadIndex(0), serviceDataPayload(), lockedState(false), From d45e2b3166ab8dfb184762b6c704e6f405bd00c9 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 08:31:05 +0000 Subject: [PATCH 28/51] add comment block for setFlags. --- services/URIBeacon2Service.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 1250a9b..324c57f 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -86,6 +86,22 @@ public: ble.onDataWritten(this, &URIBeacon2Service::onDataWritten); } + /** + * Update flags of the URIBeacon dynamically. + * + * @param[in] flagsIn + * + * ### UriBeacon Flags + * Bit | Description + * :---- | :---------- + * 0 | Invisible Hint + * 1..7 | Reserved for future use. Must be zero. + * + * The `Invisible Hint` flag is a command for the user-agent that tells + * it not to access or display the UriBeacon. This is a guideline only, + * and is not a blocking method. User agents may, with user approval, + * display invisible beacons. + */ void setFlags(uint8_t flagsIn) { flags = flagsIn; setup(); From 35d665a4e05c54e5f1af0fb6694ca0fd1fccd90a Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 08:39:07 +0000 Subject: [PATCH 29/51] reanme to effectivePower. Also switch to int8_t for power. (oops) --- services/URIBeacon2Service.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 324c57f..4607e23 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -39,20 +39,20 @@ public: * URI as a null-terminated string. * @param[in] flagsIn * UriBeacon Flags. - * @param[in] txPowerIn + * @param[in] effectiveTxPowerIn * UriBeacon Tx Power Level. * @param[in] beaconPeriodIn * The period in milliseconds that a UriBeacon packet is * transmitted. A value of zero disables UriBeacon * transmissions. */ - URIBeacon2Service(BLEDevice &ble_, const char *urldata, uint8_t flagsIn = 0, uint8_t txPowerIn = 0, uint16_t beaconPeriodIn = 1000) : + URIBeacon2Service(BLEDevice &ble_, const char *urldata, uint8_t flagsIn = 0, int8_t effectiveTxPowerIn = 0, uint16_t beaconPeriodIn = 1000) : ble(ble_), payloadIndex(0), serviceDataPayload(), lockedState(false), uriDataLength(0), uriDataValue(), flags(flagsIn), - power(txPowerIn), + effectivePower(effectiveTxPowerIn), beaconPeriod(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(beaconPeriodIn)), lockedStateChar(lockedStateCharUUID, (uint8_t *)&lockedState, 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ), uriDataChar(uriDataCharUUID, @@ -61,7 +61,7 @@ public: MAX_SIZE_URI_DATA_CHAR_VALUE, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE), flagsChar(flagsCharUUID, &flags, 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE), - // txPowerChar(txPowerCharUUID, &power, 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE) + // txPowerChar(txPowerCharUUID, &effectivePower, 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE) beaconPeriodChar(beaconPeriodCharUUID, (uint8_t *)&beaconPeriod, 2, 2, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE) { @@ -107,8 +107,8 @@ public: setup(); } - void setTxPower(uint8_t txPowerIn) { - power = txPowerIn; + void setTxPower(int8_t txPowerIn) { + effectivePower = txPowerIn; setup(); } @@ -178,7 +178,7 @@ private: serviceDataPayload[payloadIndex++] = BEACON_UUID[0]; serviceDataPayload[payloadIndex++] = BEACON_UUID[1]; serviceDataPayload[payloadIndex++] = flags; - serviceDataPayload[payloadIndex++] = power; + serviceDataPayload[payloadIndex++] = effectivePower; const char *urlData = reinterpret_cast(uriDataValue); size_t sizeofURLData = uriDataLength; @@ -189,7 +189,7 @@ private: ble.accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, serviceDataPayload, encodedBytes + 4); ble.setAdvertisingInterval(beaconPeriod); - ble.setTxPower(power); + ble.setTxPower(effectivePower); } size_t encodeURISchemePrefix(const char *&urldata, size_t &sizeofURLData) { @@ -280,7 +280,7 @@ private: uint16_t uriDataLength; uint8_t uriDataValue[MAX_SIZE_URI_DATA_CHAR_VALUE]; uint8_t flags; - uint8_t power; + int8_t effectivePower; uint16_t beaconPeriod; GattCharacteristic lockedStateChar; From eb77b38a11a2a6385738b00d0b24dae1343b088f Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 08:39:46 +0000 Subject: [PATCH 30/51] add enums for TXPowerModes_t --- services/URIBeacon2Service.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 4607e23..fd0a0d1 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -31,6 +31,13 @@ const uint8_t txPowerCharUUID[] = UUID_INITIALIZER_LIST(0x20, 0x86) const uint8_t beaconPeriodCharUUID[] = UUID_INITIALIZER_LIST(0x20, 0x88); class URIBeacon2Service { + enum TXPowerModes_t { + TX_POWER_MODE_LOWEST = 0, + TX_POWER_MODE_LOW = 1, + TX_POWER_MODE_MEDIUM = 2, + TX_POWER_MODE_HIGH = 3, + }; + public: /** * @param[ref] ble From 27b57124793ee78df5c4ebe0078d66b05e7197b4 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 08:42:40 +0000 Subject: [PATCH 31/51] minor cosmetic changes. --- services/URIBeacon2Service.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index fd0a0d1..0191776 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -47,14 +47,16 @@ public: * @param[in] flagsIn * UriBeacon Flags. * @param[in] effectiveTxPowerIn - * UriBeacon Tx Power Level. + * UriBeacon Tx Power Level in dBm. * @param[in] beaconPeriodIn * The period in milliseconds that a UriBeacon packet is * transmitted. A value of zero disables UriBeacon * transmissions. */ URIBeacon2Service(BLEDevice &ble_, const char *urldata, uint8_t flagsIn = 0, int8_t effectiveTxPowerIn = 0, uint16_t beaconPeriodIn = 1000) : - ble(ble_), payloadIndex(0), serviceDataPayload(), + ble(ble_), + payloadIndex(0), + serviceDataPayload(), lockedState(false), uriDataLength(0), uriDataValue(), From 8b1e9e9581c632006ae6e480e39083886ef5cd10 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 08:47:45 +0000 Subject: [PATCH 32/51] add APIs to set power modes. --- services/URIBeacon2Service.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 0191776..75f1f3a 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -36,6 +36,7 @@ class URIBeacon2Service { TX_POWER_MODE_LOW = 1, TX_POWER_MODE_MEDIUM = 2, TX_POWER_MODE_HIGH = 3, + NUM_POWER_MODES }; public: @@ -62,6 +63,7 @@ public: uriDataValue(), flags(flagsIn), effectivePower(effectiveTxPowerIn), + powerLevels(), beaconPeriod(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(beaconPeriodIn)), lockedStateChar(lockedStateCharUUID, (uint8_t *)&lockedState, 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ), uriDataChar(uriDataCharUUID, @@ -116,8 +118,18 @@ public: setup(); } - void setTxPower(int8_t txPowerIn) { - effectivePower = txPowerIn; + /** + * Update the txPower for a particular mode in the powerLevels table. + */ + void setTxPowerLevel(TXPowerModes_t mode, int8_t txPowerIn) { + powerLevels[mode] = txPowerIn; + } + + /** + * Set the effective power mode from one of the values in the powerLevels tables. + */ + void setPowerMode(TXPowerModes_t mode) { + effectivePower = powerLevels[mode]; setup(); } @@ -290,6 +302,7 @@ private: uint8_t uriDataValue[MAX_SIZE_URI_DATA_CHAR_VALUE]; uint8_t flags; int8_t effectivePower; + int8_t powerLevels[NUM_POWER_MODES]; uint16_t beaconPeriod; GattCharacteristic lockedStateChar; From 19400a11229d6d486286a7a1d7cd4be7dc243a15 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 09:00:35 +0000 Subject: [PATCH 33/51] add TxPowerLevelsChar --- services/URIBeacon2Service.h | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 75f1f3a..4b3f13b 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -27,7 +27,7 @@ const uint8_t URIBeacon2ControlServiceUUID[] = UUID_INITIALIZER_LIST(0x20, 0x80) const uint8_t lockedStateCharUUID[] = UUID_INITIALIZER_LIST(0x20, 0x81); const uint8_t uriDataCharUUID[] = UUID_INITIALIZER_LIST(0x20, 0x84); const uint8_t flagsCharUUID[] = UUID_INITIALIZER_LIST(0x20, 0x85); -const uint8_t txPowerCharUUID[] = UUID_INITIALIZER_LIST(0x20, 0x86); +const uint8_t txPowerLevelsCharUUID[] = UUID_INITIALIZER_LIST(0x20, 0x86); const uint8_t beaconPeriodCharUUID[] = UUID_INITIALIZER_LIST(0x20, 0x88); class URIBeacon2Service { @@ -72,7 +72,11 @@ public: MAX_SIZE_URI_DATA_CHAR_VALUE, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE), flagsChar(flagsCharUUID, &flags, 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE), - // txPowerChar(txPowerCharUUID, &effectivePower, 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE) + txPowerLevelsChar(txPowerLevelsCharUUID, + reinterpret_cast(powerLevels), + NUM_POWER_MODES * sizeof(int8_t), + NUM_POWER_MODES * sizeof(int8_t), + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE), beaconPeriodChar(beaconPeriodCharUUID, (uint8_t *)&beaconPeriod, 2, 2, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE) { @@ -88,7 +92,7 @@ public: return; } - GattCharacteristic *charTable[] = {&lockedStateChar, &uriDataChar, &flagsChar, &beaconPeriodChar}; + GattCharacteristic *charTable[] = {&lockedStateChar, &uriDataChar, &flagsChar, &txPowerLevelsChar, &beaconPeriodChar}; GattService beaconControlService(URIBeacon2ControlServiceUUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *)); ble.addService(beaconControlService); @@ -160,15 +164,23 @@ protected: uriDataLength = params->len; memcpy(uriDataValue, params->data, uriDataLength); } else if (params->charHandle == flagsChar.getValueAttribute().getHandle()) { - if (lockedState) { /* When locked, the device isn't allowed to update the flags characteristic. */ + if (lockedState) { /* When locked, the device isn't allowed to update the characteristic. */ /* Restore GATT database with previous value. */ ble.updateCharacteristicValue(flagsChar.getValueAttribute().getHandle(), &flags, 1 /* size */); return; } else { flags = *(params->data); } + } else if (params->charHandle == txPowerLevelsChar.getValueAttribute().getHandle()) { + if (lockedState) { /* When locked, the device isn't allowed to update the characteristic. */ + /* Restore GATT database with previous value. */ + ble.updateCharacteristicValue(txPowerLevelsChar.getValueAttribute().getHandle(), reinterpret_cast(powerLevels), NUM_POWER_MODES * sizeof(int8_t)); + return; + } else { + memcpy(powerLevels, params->data, NUM_POWER_MODES * sizeof(int8_t)); + } } else if (params->charHandle == beaconPeriodChar.getValueAttribute().getHandle()) { - if (lockedState) { /* When locked, the device isn't allowed to update the flags characteristic. */ + if (lockedState) { /* When locked, the device isn't allowed to update the characteristic. */ /* Restore GATT database with previous value. */ ble.updateCharacteristicValue(beaconPeriodChar.getValueAttribute().getHandle(), (uint8_t *)&beaconPeriod, 2 /* size */); return; @@ -308,7 +320,7 @@ private: GattCharacteristic lockedStateChar; GattCharacteristic uriDataChar; GattCharacteristic flagsChar; - // GattCharacteristic txPowerChar; + GattCharacteristic txPowerLevelsChar; GattCharacteristic beaconPeriodChar; }; From a148eacb889aab8ab7fc6395f7a21993eee7abbe Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 09:00:57 +0000 Subject: [PATCH 34/51] minor cosmetic change --- services/URIBeacon2Service.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 4b3f13b..3cf260b 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -65,7 +65,7 @@ public: effectivePower(effectiveTxPowerIn), powerLevels(), beaconPeriod(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(beaconPeriodIn)), - lockedStateChar(lockedStateCharUUID, (uint8_t *)&lockedState, 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ), + lockedStateChar(lockedStateCharUUID, reinterpret_cast(&lockedState), 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ), uriDataChar(uriDataCharUUID, uriDataValue, MAX_SIZE_URI_DATA_CHAR_VALUE, @@ -77,7 +77,7 @@ public: NUM_POWER_MODES * sizeof(int8_t), NUM_POWER_MODES * sizeof(int8_t), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE), - beaconPeriodChar(beaconPeriodCharUUID, (uint8_t *)&beaconPeriod, 2, 2, + beaconPeriodChar(beaconPeriodCharUUID, reinterpret_cast(&beaconPeriod), 2, 2, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE) { if ((urldata == NULL) || ((uriDataLength = strlen(urldata)) == 0)) { From 077bbb23f79a77e9d79d5a98a5bb52c7eaa486af Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 09:32:19 +0000 Subject: [PATCH 35/51] add a static setupService to create a singleton URIBeaconService object. --- services/URIBeacon2Service.h | 116 +++++++++++++++++------------------ 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 3cf260b..0e5fdc3 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -31,6 +31,7 @@ const uint8_t txPowerLevelsCharUUID[] = UUID_INITIALIZER_LIST(0x20, 0x86) const uint8_t beaconPeriodCharUUID[] = UUID_INITIALIZER_LIST(0x20, 0x88); class URIBeacon2Service { +public: enum TXPowerModes_t { TX_POWER_MODE_LOWEST = 0, TX_POWER_MODE_LOW = 1, @@ -39,66 +40,13 @@ class URIBeacon2Service { NUM_POWER_MODES }; -public: - /** - * @param[ref] ble - * BLEDevice object for the underlying controller. - * @param[in] urldata - * URI as a null-terminated string. - * @param[in] flagsIn - * UriBeacon Flags. - * @param[in] effectiveTxPowerIn - * UriBeacon Tx Power Level in dBm. - * @param[in] beaconPeriodIn - * The period in milliseconds that a UriBeacon packet is - * transmitted. A value of zero disables UriBeacon - * transmissions. - */ - URIBeacon2Service(BLEDevice &ble_, const char *urldata, uint8_t flagsIn = 0, int8_t effectiveTxPowerIn = 0, uint16_t beaconPeriodIn = 1000) : - ble(ble_), - payloadIndex(0), - serviceDataPayload(), - lockedState(false), - uriDataLength(0), - uriDataValue(), - flags(flagsIn), - effectivePower(effectiveTxPowerIn), - powerLevels(), - beaconPeriod(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(beaconPeriodIn)), - lockedStateChar(lockedStateCharUUID, reinterpret_cast(&lockedState), 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ), - uriDataChar(uriDataCharUUID, - uriDataValue, - MAX_SIZE_URI_DATA_CHAR_VALUE, - MAX_SIZE_URI_DATA_CHAR_VALUE, - GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE), - flagsChar(flagsCharUUID, &flags, 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE), - txPowerLevelsChar(txPowerLevelsCharUUID, - reinterpret_cast(powerLevels), - NUM_POWER_MODES * sizeof(int8_t), - NUM_POWER_MODES * sizeof(int8_t), - GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE), - beaconPeriodChar(beaconPeriodCharUUID, reinterpret_cast(&beaconPeriod), 2, 2, - GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE) - { - if ((urldata == NULL) || ((uriDataLength = strlen(urldata)) == 0)) { - return; - } - strncpy(reinterpret_cast(uriDataValue), urldata, MAX_SIZE_URI_DATA_CHAR_VALUE); - - setup(); - - static bool serviceAdded = false; /* We should only ever need to add the heart rate service once. */ - if (serviceAdded) { - return; + static URIBeacon2Service *setupService(BLEDevice &ble_, const char *urldata, uint8_t flagsIn = 0, int8_t effectiveTxPowerIn = 0, uint16_t beaconPeriodIn = 1000) { + if ((urldata == NULL) || (strlen(urldata) == 0)) { + return NULL; } - GattCharacteristic *charTable[] = {&lockedStateChar, &uriDataChar, &flagsChar, &txPowerLevelsChar, &beaconPeriodChar}; - GattService beaconControlService(URIBeacon2ControlServiceUUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *)); - - ble.addService(beaconControlService); - serviceAdded = true; - - ble.onDataWritten(this, &URIBeacon2Service::onDataWritten); + static URIBeacon2Service service(ble_, urldata, flagsIn, effectiveTxPowerIn, beaconPeriodIn); + return &service; } /** @@ -142,6 +90,58 @@ public: setup(); } +private: + /** + * @param[ref] ble + * BLEDevice object for the underlying controller. + * @param[in] urldata + * URI as a null-terminated string. + * @param[in] flagsIn + * UriBeacon Flags. + * @param[in] effectiveTxPowerIn + * UriBeacon Tx Power Level in dBm. + * @param[in] beaconPeriodIn + * The period in milliseconds that a UriBeacon packet is + * transmitted. A value of zero disables UriBeacon + * transmissions. + */ + URIBeacon2Service(BLEDevice &ble_, const char *urldata, uint8_t flagsIn = 0, int8_t effectiveTxPowerIn = 0, uint16_t beaconPeriodIn = 1000) : + ble(ble_), + payloadIndex(0), + serviceDataPayload(), + lockedState(false), + uriDataLength(strlen(urldata)), + uriDataValue(), + flags(flagsIn), + effectivePower(effectiveTxPowerIn), + powerLevels(), + beaconPeriod(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(beaconPeriodIn)), + lockedStateChar(lockedStateCharUUID, reinterpret_cast(&lockedState), 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ), + uriDataChar(uriDataCharUUID, + uriDataValue, + MAX_SIZE_URI_DATA_CHAR_VALUE, + MAX_SIZE_URI_DATA_CHAR_VALUE, + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE), + flagsChar(flagsCharUUID, &flags, 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE), + txPowerLevelsChar(txPowerLevelsCharUUID, + reinterpret_cast(powerLevels), + NUM_POWER_MODES * sizeof(int8_t), + NUM_POWER_MODES * sizeof(int8_t), + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE), + beaconPeriodChar(beaconPeriodCharUUID, reinterpret_cast(&beaconPeriod), 2, 2, + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE) + { + strncpy(reinterpret_cast(uriDataValue), urldata, MAX_SIZE_URI_DATA_CHAR_VALUE); + + setup(); + + GattCharacteristic *charTable[] = {&lockedStateChar, &uriDataChar, &flagsChar, &txPowerLevelsChar, &beaconPeriodChar}; + GattService beaconControlService(URIBeacon2ControlServiceUUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *)); + + ble.addService(beaconControlService); + ble.onDataWritten(this, &URIBeacon2Service::onDataWritten); + } + protected: /** * This callback allows the DFU service to receive the initial trigger to From e5145420ba130f257d996ce819dd923fb4ff1278 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 09:39:39 +0000 Subject: [PATCH 36/51] add a comment header for setupService --- services/URIBeacon2Service.h | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 0e5fdc3..1c63930 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -40,6 +40,24 @@ public: NUM_POWER_MODES }; + /** + * Singleton factory. + * + * @param[ref] ble + * BLEDevice object for the underlying controller. + * @param[in] urldata + * URI as a null-terminated string. + * @param[in] flagsIn + * UriBeacon Flags. + * @param[in] effectiveTxPowerIn + * UriBeacon Tx Power Level in dBm. + * @param[in] beaconPeriodIn + * The period in milliseconds that a UriBeacon packet is + * transmitted. A value of zero disables UriBeacon + * transmissions. + * @return + * Pointer to the singleton uribeacon service if the initialization goes well; else NULL. + */ static URIBeacon2Service *setupService(BLEDevice &ble_, const char *urldata, uint8_t flagsIn = 0, int8_t effectiveTxPowerIn = 0, uint16_t beaconPeriodIn = 1000) { if ((urldata == NULL) || (strlen(urldata) == 0)) { return NULL; @@ -91,20 +109,6 @@ public: } private: - /** - * @param[ref] ble - * BLEDevice object for the underlying controller. - * @param[in] urldata - * URI as a null-terminated string. - * @param[in] flagsIn - * UriBeacon Flags. - * @param[in] effectiveTxPowerIn - * UriBeacon Tx Power Level in dBm. - * @param[in] beaconPeriodIn - * The period in milliseconds that a UriBeacon packet is - * transmitted. A value of zero disables UriBeacon - * transmissions. - */ URIBeacon2Service(BLEDevice &ble_, const char *urldata, uint8_t flagsIn = 0, int8_t effectiveTxPowerIn = 0, uint16_t beaconPeriodIn = 1000) : ble(ble_), payloadIndex(0), From 576c2fa65eae7889b88e86244ee5330ca4a39728 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 09:41:23 +0000 Subject: [PATCH 37/51] add failed to accommodate. --- services/URIBeacon2Service.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 1c63930..aea66e7 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -64,7 +64,11 @@ public: } static URIBeacon2Service service(ble_, urldata, flagsIn, effectiveTxPowerIn, beaconPeriodIn); - return &service; + if (!service.failedToAccomodate) { + return &service; + } + + return NULL; /* Oops. Failed to accommodate uridata within the advertising payload. */ } /** @@ -113,6 +117,7 @@ private: ble(ble_), payloadIndex(0), serviceDataPayload(), + failedToAccomodate(false), lockedState(false), uriDataLength(strlen(urldata)), uriDataValue(), @@ -300,6 +305,9 @@ private: --sizeofURLData; } } + if ((payloadIndex == MAX_SIZEOF_SERVICE_DATA_PAYLOAD) && (sizeofURLData != 0)) { + failedToAccomodate = true; + } return encodedBytes; } @@ -313,6 +321,8 @@ private: size_t payloadIndex; uint8_t serviceDataPayload[MAX_SIZEOF_SERVICE_DATA_PAYLOAD]; + bool failedToAccomodate; + bool lockedState; uint16_t uriDataLength; uint8_t uriDataValue[MAX_SIZE_URI_DATA_CHAR_VALUE]; From 09a38f1e57eafea40f6d04e4275af8bbe785345d Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 09:47:55 +0000 Subject: [PATCH 38/51] comment headers and minor white space diffs. --- services/URIBeacon2Service.h | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index aea66e7..5bdb2f7 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -92,6 +92,12 @@ public: setup(); } + /** + * Please note that the following public APIs are offered to allow modifying + * the service programmatically. It is also possible to do so over BLE GATT + * transactions. + */ +public: /** * Update the txPower for a particular mode in the powerLevels table. */ @@ -107,12 +113,20 @@ public: setup(); } + /** + * The period in milliseconds that a UriBeacon packet is transmitted. + * + * @Note: A value of zero disables UriBeacon transmissions. + */ void setBeaconPeriod(uint16_t beaconPeriodIn) { beaconPeriod = beaconPeriodIn; setup(); } private: + /** + * Private constructor. We want a singleton. + */ URIBeacon2Service(BLEDevice &ble_, const char *urldata, uint8_t flagsIn = 0, int8_t effectiveTxPowerIn = 0, uint16_t beaconPeriodIn = 1000) : ble(ble_), payloadIndex(0), @@ -222,9 +236,9 @@ private: serviceDataPayload[payloadIndex++] = flags; serviceDataPayload[payloadIndex++] = effectivePower; - const char *urlData = reinterpret_cast(uriDataValue); + const char *urlData = reinterpret_cast(uriDataValue); size_t sizeofURLData = uriDataLength; - size_t encodedBytes = encodeURISchemePrefix(urlData, sizeofURLData) + encodeURI(urlData, sizeofURLData); + size_t encodedBytes = encodeURISchemePrefix(urlData, sizeofURLData) + encodeURI(urlData, sizeofURLData); ble.clearAdvertisingPayload(); ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, BEACON_UUID, sizeof(BEACON_UUID)); From b4e8ed204f28253056c53320468e6d9b303d2ab6 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 10:05:25 +0000 Subject: [PATCH 39/51] rename setup as configure() and setupService() as setup() --- services/URIBeacon2Service.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 5bdb2f7..7ba937c 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -58,7 +58,7 @@ public: * @return * Pointer to the singleton uribeacon service if the initialization goes well; else NULL. */ - static URIBeacon2Service *setupService(BLEDevice &ble_, const char *urldata, uint8_t flagsIn = 0, int8_t effectiveTxPowerIn = 0, uint16_t beaconPeriodIn = 1000) { + static URIBeacon2Service *setup(BLEDevice &ble_, const char *urldata, uint8_t flagsIn = 0, int8_t effectiveTxPowerIn = 0, uint16_t beaconPeriodIn = 1000) { if ((urldata == NULL) || (strlen(urldata) == 0)) { return NULL; } @@ -89,7 +89,7 @@ public: */ void setFlags(uint8_t flagsIn) { flags = flagsIn; - setup(); + configure(); } /** @@ -110,7 +110,7 @@ public: */ void setPowerMode(TXPowerModes_t mode) { effectivePower = powerLevels[mode]; - setup(); + configure(); } /** @@ -120,7 +120,7 @@ public: */ void setBeaconPeriod(uint16_t beaconPeriodIn) { beaconPeriod = beaconPeriodIn; - setup(); + configure(); } private: @@ -156,7 +156,7 @@ private: { strncpy(reinterpret_cast(uriDataValue), urldata, MAX_SIZE_URI_DATA_CHAR_VALUE); - setup(); + configure(); GattCharacteristic *charTable[] = {&lockedStateChar, &uriDataChar, &flagsChar, &txPowerLevelsChar, &beaconPeriodChar}; GattService beaconControlService(URIBeacon2ControlServiceUUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *)); @@ -211,7 +211,7 @@ protected: beaconPeriod = *((uint16_t *)(params->data)); } } - setup(); + configure(); ble.setAdvertisingPayload(); } @@ -227,7 +227,7 @@ protected: } private: - void setup(void) { + void configure(void) { const uint8_t BEACON_UUID[] = {0xD8, 0xFE}; payloadIndex = 0; From 1ef561977ed1ca1c7fba456061d018bbd175a558 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 10:09:37 +0000 Subject: [PATCH 40/51] minor re-ordering of methods. --- services/URIBeacon2Service.h | 123 +++++++++++++++++------------------ 1 file changed, 61 insertions(+), 62 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 7ba937c..0dc9ce7 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -165,68 +165,6 @@ private: ble.onDataWritten(this, &URIBeacon2Service::onDataWritten); } -protected: - /** - * This callback allows the DFU service to receive the initial trigger to - * handover control to the bootloader; but first the application is given a - * chance to clean up. - */ - virtual void onDataWritten(const GattCharacteristicWriteCBParams *params) { - if (params->charHandle == uriDataChar.getValueAttribute().getHandle()) { - if (lockedState) { /* When locked, the device isn't allowed to update the uriData characteristic. */ - /* Restore GATT database with previous value. */ - ble.updateCharacteristicValue(uriDataChar.getValueAttribute().getHandle(), uriDataValue, uriDataLength); - return; - } - - /* We don't handle very large writes at the moment. */ - if ((params->offset != 0) || (params->len > MAX_SIZE_URI_DATA_CHAR_VALUE)) { - return; - } - - uriDataLength = params->len; - memcpy(uriDataValue, params->data, uriDataLength); - } else if (params->charHandle == flagsChar.getValueAttribute().getHandle()) { - if (lockedState) { /* When locked, the device isn't allowed to update the characteristic. */ - /* Restore GATT database with previous value. */ - ble.updateCharacteristicValue(flagsChar.getValueAttribute().getHandle(), &flags, 1 /* size */); - return; - } else { - flags = *(params->data); - } - } else if (params->charHandle == txPowerLevelsChar.getValueAttribute().getHandle()) { - if (lockedState) { /* When locked, the device isn't allowed to update the characteristic. */ - /* Restore GATT database with previous value. */ - ble.updateCharacteristicValue(txPowerLevelsChar.getValueAttribute().getHandle(), reinterpret_cast(powerLevels), NUM_POWER_MODES * sizeof(int8_t)); - return; - } else { - memcpy(powerLevels, params->data, NUM_POWER_MODES * sizeof(int8_t)); - } - } else if (params->charHandle == beaconPeriodChar.getValueAttribute().getHandle()) { - if (lockedState) { /* When locked, the device isn't allowed to update the characteristic. */ - /* Restore GATT database with previous value. */ - ble.updateCharacteristicValue(beaconPeriodChar.getValueAttribute().getHandle(), (uint8_t *)&beaconPeriod, 2 /* size */); - return; - } else { - beaconPeriod = *((uint16_t *)(params->data)); - } - } - configure(); - ble.setAdvertisingPayload(); - } - - /** - * For debugging only. - */ - void dumpEncodedSeviceData() const { - printf("encoded: '"); - for (unsigned i = 0; i < payloadIndex; i++) { - printf(" %02x", serviceDataPayload[i]); - } - printf("'\r\n"); - } - -private: void configure(void) { const uint8_t BEACON_UUID[] = {0xD8, 0xFE}; @@ -326,6 +264,67 @@ private: return encodedBytes; } + /** + * This callback allows the DFU service to receive the initial trigger to + * handover control to the bootloader; but first the application is given a + * chance to clean up. + */ + virtual void onDataWritten(const GattCharacteristicWriteCBParams *params) { + if (params->charHandle == uriDataChar.getValueAttribute().getHandle()) { + if (lockedState) { /* When locked, the device isn't allowed to update the uriData characteristic. */ + /* Restore GATT database with previous value. */ + ble.updateCharacteristicValue(uriDataChar.getValueAttribute().getHandle(), uriDataValue, uriDataLength); + return; + } + + /* We don't handle very large writes at the moment. */ + if ((params->offset != 0) || (params->len > MAX_SIZE_URI_DATA_CHAR_VALUE)) { + return; + } + + uriDataLength = params->len; + memcpy(uriDataValue, params->data, uriDataLength); + } else if (params->charHandle == flagsChar.getValueAttribute().getHandle()) { + if (lockedState) { /* When locked, the device isn't allowed to update the characteristic. */ + /* Restore GATT database with previous value. */ + ble.updateCharacteristicValue(flagsChar.getValueAttribute().getHandle(), &flags, 1 /* size */); + return; + } else { + flags = *(params->data); + } + } else if (params->charHandle == txPowerLevelsChar.getValueAttribute().getHandle()) { + if (lockedState) { /* When locked, the device isn't allowed to update the characteristic. */ + /* Restore GATT database with previous value. */ + ble.updateCharacteristicValue(txPowerLevelsChar.getValueAttribute().getHandle(), reinterpret_cast(powerLevels), NUM_POWER_MODES * sizeof(int8_t)); + return; + } else { + memcpy(powerLevels, params->data, NUM_POWER_MODES * sizeof(int8_t)); + } + } else if (params->charHandle == beaconPeriodChar.getValueAttribute().getHandle()) { + if (lockedState) { /* When locked, the device isn't allowed to update the characteristic. */ + /* Restore GATT database with previous value. */ + ble.updateCharacteristicValue(beaconPeriodChar.getValueAttribute().getHandle(), (uint8_t *)&beaconPeriod, 2 /* size */); + return; + } else { + beaconPeriod = *((uint16_t *)(params->data)); + } + } + configure(); + ble.setAdvertisingPayload(); + } + +private: + /** + * For debugging only. + */ + void dumpEncodedSeviceData() const { + printf("encoded: '"); + for (unsigned i = 0; i < payloadIndex; i++) { + printf(" %02x", serviceDataPayload[i]); + } + printf("'\r\n"); + } + private: static const size_t MAX_SIZEOF_SERVICE_DATA_PAYLOAD = 27; static const size_t MAX_SIZE_URI_DATA_CHAR_VALUE = 48; From fdfc899372b27507ad8a0631234c4ce3d386919d Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 10:14:32 +0000 Subject: [PATCH 41/51] add a comment header. --- services/URIBeacon2Service.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 0dc9ce7..902f3a5 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -165,6 +165,9 @@ private: ble.onDataWritten(this, &URIBeacon2Service::onDataWritten); } + /** + * Setup the advertisement payload and GAP settings. + */ void configure(void) { const uint8_t BEACON_UUID[] = {0xD8, 0xFE}; From f79f6b8ba7c5317daab606114e30b7817a7862c1 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 10:28:13 +0000 Subject: [PATCH 42/51] variable renames. --- services/URIBeacon2Service.h | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 902f3a5..54fdaca 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -58,12 +58,12 @@ public: * @return * Pointer to the singleton uribeacon service if the initialization goes well; else NULL. */ - static URIBeacon2Service *setup(BLEDevice &ble_, const char *urldata, uint8_t flagsIn = 0, int8_t effectiveTxPowerIn = 0, uint16_t beaconPeriodIn = 1000) { - if ((urldata == NULL) || (strlen(urldata) == 0)) { + static URIBeacon2Service *setup(BLEDevice &bleIn, const char *urlDataIn, uint8_t flagsIn = 0, int8_t effectiveTxPowerIn = 0, uint16_t beaconPeriodIn = 1000) { + if ((urlDataIn == NULL) || (strlen(urlDataIn) == 0)) { return NULL; } - static URIBeacon2Service service(ble_, urldata, flagsIn, effectiveTxPowerIn, beaconPeriodIn); + static URIBeacon2Service service(bleIn, urlDataIn, flagsIn, effectiveTxPowerIn, beaconPeriodIn); if (!service.failedToAccomodate) { return &service; } @@ -127,21 +127,21 @@ private: /** * Private constructor. We want a singleton. */ - URIBeacon2Service(BLEDevice &ble_, const char *urldata, uint8_t flagsIn = 0, int8_t effectiveTxPowerIn = 0, uint16_t beaconPeriodIn = 1000) : - ble(ble_), + URIBeacon2Service(BLEDevice &bleIn, const char *urldataIn, uint8_t flagsIn = 0, int8_t effectiveTxPowerIn = 0, uint16_t beaconPeriodIn = 1000) : + ble(bleIn), payloadIndex(0), serviceDataPayload(), failedToAccomodate(false), lockedState(false), - uriDataLength(strlen(urldata)), - uriDataValue(), + uriDataLength(strlen(urldataIn)), + uriData(), flags(flagsIn), effectivePower(effectiveTxPowerIn), powerLevels(), beaconPeriod(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(beaconPeriodIn)), lockedStateChar(lockedStateCharUUID, reinterpret_cast(&lockedState), 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ), uriDataChar(uriDataCharUUID, - uriDataValue, + uriData, MAX_SIZE_URI_DATA_CHAR_VALUE, MAX_SIZE_URI_DATA_CHAR_VALUE, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE), @@ -154,7 +154,7 @@ private: beaconPeriodChar(beaconPeriodCharUUID, reinterpret_cast(&beaconPeriod), 2, 2, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE) { - strncpy(reinterpret_cast(uriDataValue), urldata, MAX_SIZE_URI_DATA_CHAR_VALUE); + strncpy(reinterpret_cast(uriData), urldataIn, MAX_SIZE_URI_DATA_CHAR_VALUE); configure(); @@ -177,7 +177,7 @@ private: serviceDataPayload[payloadIndex++] = flags; serviceDataPayload[payloadIndex++] = effectivePower; - const char *urlData = reinterpret_cast(uriDataValue); + const char *urlData = reinterpret_cast(uriData); size_t sizeofURLData = uriDataLength; size_t encodedBytes = encodeURISchemePrefix(urlData, sizeofURLData) + encodeURI(urlData, sizeofURLData); @@ -276,7 +276,7 @@ private: if (params->charHandle == uriDataChar.getValueAttribute().getHandle()) { if (lockedState) { /* When locked, the device isn't allowed to update the uriData characteristic. */ /* Restore GATT database with previous value. */ - ble.updateCharacteristicValue(uriDataChar.getValueAttribute().getHandle(), uriDataValue, uriDataLength); + ble.updateCharacteristicValue(uriDataChar.getValueAttribute().getHandle(), uriData, uriDataLength); return; } @@ -286,7 +286,7 @@ private: } uriDataLength = params->len; - memcpy(uriDataValue, params->data, uriDataLength); + memcpy(uriData, params->data, uriDataLength); } else if (params->charHandle == flagsChar.getValueAttribute().getHandle()) { if (lockedState) { /* When locked, the device isn't allowed to update the characteristic. */ /* Restore GATT database with previous value. */ @@ -341,7 +341,7 @@ private: bool lockedState; uint16_t uriDataLength; - uint8_t uriDataValue[MAX_SIZE_URI_DATA_CHAR_VALUE]; + uint8_t uriData[MAX_SIZE_URI_DATA_CHAR_VALUE]; uint8_t flags; int8_t effectivePower; int8_t powerLevels[NUM_POWER_MODES]; From 149a4135732a1d18b5c9d69a247ced7d3790645c Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 10:54:20 +0000 Subject: [PATCH 43/51] some more variable renames. --- services/URIBeacon2Service.h | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 54fdaca..1959352 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -58,12 +58,12 @@ public: * @return * Pointer to the singleton uribeacon service if the initialization goes well; else NULL. */ - static URIBeacon2Service *setup(BLEDevice &bleIn, const char *urlDataIn, uint8_t flagsIn = 0, int8_t effectiveTxPowerIn = 0, uint16_t beaconPeriodIn = 1000) { - if ((urlDataIn == NULL) || (strlen(urlDataIn) == 0)) { + static URIBeacon2Service *setup(BLEDevice &bleIn, const char *uriDataIn, uint8_t flagsIn = 0, int8_t effectiveTxPowerIn = 0, uint16_t beaconPeriodIn = 1000) { + if ((uriDataIn == NULL) || (strlen(uriDataIn) == 0)) { return NULL; } - static URIBeacon2Service service(bleIn, urlDataIn, flagsIn, effectiveTxPowerIn, beaconPeriodIn); + static URIBeacon2Service service(bleIn, uriDataIn, flagsIn, effectiveTxPowerIn, beaconPeriodIn); if (!service.failedToAccomodate) { return &service; } @@ -127,13 +127,13 @@ private: /** * Private constructor. We want a singleton. */ - URIBeacon2Service(BLEDevice &bleIn, const char *urldataIn, uint8_t flagsIn = 0, int8_t effectiveTxPowerIn = 0, uint16_t beaconPeriodIn = 1000) : + URIBeacon2Service(BLEDevice &bleIn, const char *uriDataIn, uint8_t flagsIn = 0, int8_t effectiveTxPowerIn = 0, uint16_t beaconPeriodIn = 1000) : ble(bleIn), payloadIndex(0), serviceDataPayload(), failedToAccomodate(false), lockedState(false), - uriDataLength(strlen(urldataIn)), + uriDataLength(strlen(uriDataIn)), uriData(), flags(flagsIn), effectivePower(effectiveTxPowerIn), @@ -154,9 +154,16 @@ private: beaconPeriodChar(beaconPeriodCharUUID, reinterpret_cast(&beaconPeriod), 2, 2, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE) { - strncpy(reinterpret_cast(uriData), urldataIn, MAX_SIZE_URI_DATA_CHAR_VALUE); + strncpy(reinterpret_cast(uriData), uriDataIn, MAX_SIZE_URI_DATA_CHAR_VALUE); configure(); + if (!failedToAccomodate) { + /* Preserve the originals to be able to reset() upon request. */ + // memcpy(service.originalURIData, urlDataIn, MAX_SIZE_URI_DATA_CHAR_VALUE); + // service.originalFlags = flagsIn; + // service.originalEffectiveTxPower = effectiveTxPowerIn; + // service.originalBeaconPeriod = beaconPeriodIn; + } GattCharacteristic *charTable[] = {&lockedStateChar, &uriDataChar, &flagsChar, &txPowerLevelsChar, &beaconPeriodChar}; GattService beaconControlService(URIBeacon2ControlServiceUUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *)); @@ -347,6 +354,10 @@ private: int8_t powerLevels[NUM_POWER_MODES]; uint16_t beaconPeriod; + uint8_t originalURIData[MAX_SIZE_URI_DATA_CHAR_VALUE]; + uint8_t originalFlags; + int8_t originalEffectivePower; + GattCharacteristic lockedStateChar; GattCharacteristic uriDataChar; GattCharacteristic flagsChar; From 584e14998501442a9f881ef808beae787495f9bd Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 10:57:37 +0000 Subject: [PATCH 44/51] enable resetCharacteristic. --- services/URIBeacon2Service.h | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 1959352..69c75a1 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -29,6 +29,7 @@ const uint8_t uriDataCharUUID[] = UUID_INITIALIZER_LIST(0x20, 0x84) const uint8_t flagsCharUUID[] = UUID_INITIALIZER_LIST(0x20, 0x85); const uint8_t txPowerLevelsCharUUID[] = UUID_INITIALIZER_LIST(0x20, 0x86); const uint8_t beaconPeriodCharUUID[] = UUID_INITIALIZER_LIST(0x20, 0x88); +const uint8_t resetCharUUID[] = UUID_INITIALIZER_LIST(0x20, 0x89); class URIBeacon2Service { public: @@ -152,20 +153,22 @@ private: NUM_POWER_MODES * sizeof(int8_t), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE), beaconPeriodChar(beaconPeriodCharUUID, reinterpret_cast(&beaconPeriod), 2, 2, - GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE) + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE), + resetChar(resetCharUUID, reinterpret_cast(&resetFlag), 1, 1, + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE) { strncpy(reinterpret_cast(uriData), uriDataIn, MAX_SIZE_URI_DATA_CHAR_VALUE); configure(); if (!failedToAccomodate) { /* Preserve the originals to be able to reset() upon request. */ - // memcpy(service.originalURIData, urlDataIn, MAX_SIZE_URI_DATA_CHAR_VALUE); - // service.originalFlags = flagsIn; - // service.originalEffectiveTxPower = effectiveTxPowerIn; - // service.originalBeaconPeriod = beaconPeriodIn; + memcpy(originalURIData, uriDataIn, MAX_SIZE_URI_DATA_CHAR_VALUE); + originalFlags = flagsIn; + originalEffectiveTxPower = effectiveTxPowerIn; + originalBeaconPeriod = beaconPeriodIn; } - GattCharacteristic *charTable[] = {&lockedStateChar, &uriDataChar, &flagsChar, &txPowerLevelsChar, &beaconPeriodChar}; + GattCharacteristic *charTable[] = {&lockedStateChar, &uriDataChar, &flagsChar, &txPowerLevelsChar, &beaconPeriodChar, &resetChar}; GattService beaconControlService(URIBeacon2ControlServiceUUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *)); ble.addService(beaconControlService); @@ -318,11 +321,27 @@ private: } else { beaconPeriod = *((uint16_t *)(params->data)); } + } else if (params->charHandle == resetChar.getValueAttribute().getHandle()) { + resetOriginals(); } configure(); ble.setAdvertisingPayload(); } + void resetOriginals(void) { + memcpy(uriData, originalURIData, MAX_SIZE_URI_DATA_CHAR_VALUE); + memset(powerLevels, 0, sizeof(powerLevels)); + flags = originalFlags; + effectivePower = originalEffectiveTxPower; + beaconPeriod = originalBeaconPeriod; + + ble.updateCharacteristicValue(uriDataChar.getValueAttribute().getHandle(), uriData, uriDataLength); + ble.updateCharacteristicValue(flagsChar.getValueAttribute().getHandle(), &flags, 1 /* size */); + ble.updateCharacteristicValue(beaconPeriodChar.getValueAttribute().getHandle(), reinterpret_cast(&beaconPeriod), sizeof(uint16_t)); + + configure(); + } + private: /** * For debugging only. @@ -353,16 +372,19 @@ private: int8_t effectivePower; int8_t powerLevels[NUM_POWER_MODES]; uint16_t beaconPeriod; + bool resetFlag; uint8_t originalURIData[MAX_SIZE_URI_DATA_CHAR_VALUE]; uint8_t originalFlags; - int8_t originalEffectivePower; + int8_t originalEffectiveTxPower; + uint16_t originalBeaconPeriod; GattCharacteristic lockedStateChar; GattCharacteristic uriDataChar; GattCharacteristic flagsChar; GattCharacteristic txPowerLevelsChar; GattCharacteristic beaconPeriodChar; + GattCharacteristic resetChar; }; #endif /* #ifndef __BLE_URI_BEACON_2_SERVICE_H__*/ From 5cd5f364ea4d257fdcecf2d151e306fa21570d7c Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 10:57:56 +0000 Subject: [PATCH 45/51] minor cosmetic use of reinterpret_cast. --- services/URIBeacon2Service.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 69c75a1..de02161 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -316,7 +316,7 @@ private: } else if (params->charHandle == beaconPeriodChar.getValueAttribute().getHandle()) { if (lockedState) { /* When locked, the device isn't allowed to update the characteristic. */ /* Restore GATT database with previous value. */ - ble.updateCharacteristicValue(beaconPeriodChar.getValueAttribute().getHandle(), (uint8_t *)&beaconPeriod, 2 /* size */); + ble.updateCharacteristicValue(beaconPeriodChar.getValueAttribute().getHandle(), reinterpret_cast(&beaconPeriod), sizeof(uint16_t)); return; } else { beaconPeriod = *((uint16_t *)(params->data)); From 1a0593dc7ca8a473f672661075f9a3b32600fec6 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 11:09:55 +0000 Subject: [PATCH 46/51] switch to useTxPowerLevel() --- services/URIBeacon2Service.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index de02161..95869da 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -109,7 +109,7 @@ public: /** * Set the effective power mode from one of the values in the powerLevels tables. */ - void setPowerMode(TXPowerModes_t mode) { + void useTxPowerMode(TXPowerModes_t mode) { effectivePower = powerLevels[mode]; configure(); } From 3536e5a2b274d7f631519999ccf4e1c428ddf0c2 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 11:57:14 +0000 Subject: [PATCH 47/51] moving back to the constructor. This brings it in line with other services. --- services/URIBeacon2Service.h | 118 +++++++++++++++-------------------- 1 file changed, 52 insertions(+), 66 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 95869da..e80b5cf 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -42,8 +42,6 @@ public: }; /** - * Singleton factory. - * * @param[ref] ble * BLEDevice object for the underlying controller. * @param[in] urldata @@ -56,20 +54,59 @@ public: * The period in milliseconds that a UriBeacon packet is * transmitted. A value of zero disables UriBeacon * transmissions. - * @return - * Pointer to the singleton uribeacon service if the initialization goes well; else NULL. */ - static URIBeacon2Service *setup(BLEDevice &bleIn, const char *uriDataIn, uint8_t flagsIn = 0, int8_t effectiveTxPowerIn = 0, uint16_t beaconPeriodIn = 1000) { - if ((uriDataIn == NULL) || (strlen(uriDataIn) == 0)) { - return NULL; + URIBeacon2Service(BLEDevice &bleIn, const char *uriDataIn, uint8_t flagsIn = 0, int8_t effectiveTxPowerIn = 0, uint16_t beaconPeriodIn = 1000) : + ble(bleIn), + payloadIndex(0), + serviceDataPayload(), + initSucceeded(false), + lockedState(false), + uriDataLength(0), + uriData(), + flags(flagsIn), + effectivePower(effectiveTxPowerIn), + powerLevels(), + beaconPeriod(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(beaconPeriodIn)), + lockedStateChar(lockedStateCharUUID, reinterpret_cast(&lockedState), 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ), + uriDataChar(uriDataCharUUID, + uriData, + MAX_SIZE_URI_DATA_CHAR_VALUE, + MAX_SIZE_URI_DATA_CHAR_VALUE, + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE), + flagsChar(flagsCharUUID, &flags, 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE), + txPowerLevelsChar(txPowerLevelsCharUUID, + reinterpret_cast(powerLevels), + NUM_POWER_MODES * sizeof(int8_t), + NUM_POWER_MODES * sizeof(int8_t), + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE), + beaconPeriodChar(beaconPeriodCharUUID, reinterpret_cast(&beaconPeriod), 2, 2, + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE), + resetChar(resetCharUUID, reinterpret_cast(&resetFlag), 1, 1, + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE) + { + if ((uriDataIn == NULL) || ((uriDataLength = strlen(uriDataIn)) == 0)) { + return; + } + strncpy(reinterpret_cast(uriData), uriDataIn, MAX_SIZE_URI_DATA_CHAR_VALUE); + + configure(); + if (initSucceeded) { + /* Preserve the originals to be able to reset() upon request. */ + memcpy(originalURIData, uriDataIn, MAX_SIZE_URI_DATA_CHAR_VALUE); + originalFlags = flagsIn; + originalEffectiveTxPower = effectiveTxPowerIn; + originalBeaconPeriod = beaconPeriodIn; } - static URIBeacon2Service service(bleIn, uriDataIn, flagsIn, effectiveTxPowerIn, beaconPeriodIn); - if (!service.failedToAccomodate) { - return &service; - } + GattCharacteristic *charTable[] = {&lockedStateChar, &uriDataChar, &flagsChar, &txPowerLevelsChar, &beaconPeriodChar, &resetChar}; + GattService beaconControlService(URIBeacon2ControlServiceUUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *)); - return NULL; /* Oops. Failed to accommodate uridata within the advertising payload. */ + ble.addService(beaconControlService); + ble.onDataWritten(this, &URIBeacon2Service::onDataWritten); + } + + bool initialized(void) const { + return initSucceeded; } /** @@ -124,57 +161,6 @@ public: configure(); } -private: - /** - * Private constructor. We want a singleton. - */ - URIBeacon2Service(BLEDevice &bleIn, const char *uriDataIn, uint8_t flagsIn = 0, int8_t effectiveTxPowerIn = 0, uint16_t beaconPeriodIn = 1000) : - ble(bleIn), - payloadIndex(0), - serviceDataPayload(), - failedToAccomodate(false), - lockedState(false), - uriDataLength(strlen(uriDataIn)), - uriData(), - flags(flagsIn), - effectivePower(effectiveTxPowerIn), - powerLevels(), - beaconPeriod(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(beaconPeriodIn)), - lockedStateChar(lockedStateCharUUID, reinterpret_cast(&lockedState), 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ), - uriDataChar(uriDataCharUUID, - uriData, - MAX_SIZE_URI_DATA_CHAR_VALUE, - MAX_SIZE_URI_DATA_CHAR_VALUE, - GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE), - flagsChar(flagsCharUUID, &flags, 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE), - txPowerLevelsChar(txPowerLevelsCharUUID, - reinterpret_cast(powerLevels), - NUM_POWER_MODES * sizeof(int8_t), - NUM_POWER_MODES * sizeof(int8_t), - GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE), - beaconPeriodChar(beaconPeriodCharUUID, reinterpret_cast(&beaconPeriod), 2, 2, - GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE), - resetChar(resetCharUUID, reinterpret_cast(&resetFlag), 1, 1, - GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE) - { - strncpy(reinterpret_cast(uriData), uriDataIn, MAX_SIZE_URI_DATA_CHAR_VALUE); - - configure(); - if (!failedToAccomodate) { - /* Preserve the originals to be able to reset() upon request. */ - memcpy(originalURIData, uriDataIn, MAX_SIZE_URI_DATA_CHAR_VALUE); - originalFlags = flagsIn; - originalEffectiveTxPower = effectiveTxPowerIn; - originalBeaconPeriod = beaconPeriodIn; - } - - GattCharacteristic *charTable[] = {&lockedStateChar, &uriDataChar, &flagsChar, &txPowerLevelsChar, &beaconPeriodChar, &resetChar}; - GattService beaconControlService(URIBeacon2ControlServiceUUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *)); - - ble.addService(beaconControlService); - ble.onDataWritten(this, &URIBeacon2Service::onDataWritten); - } - /** * Setup the advertisement payload and GAP settings. */ @@ -270,8 +256,8 @@ private: --sizeofURLData; } } - if ((payloadIndex == MAX_SIZEOF_SERVICE_DATA_PAYLOAD) && (sizeofURLData != 0)) { - failedToAccomodate = true; + if (sizeofURLData == 0) { + initSucceeded = true; } return encodedBytes; @@ -363,7 +349,7 @@ private: size_t payloadIndex; uint8_t serviceDataPayload[MAX_SIZEOF_SERVICE_DATA_PAYLOAD]; - bool failedToAccomodate; + bool initSucceeded; bool lockedState; uint16_t uriDataLength; From 617a75408296bf49bd028a7419256d03a65ea0f7 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 12:00:33 +0000 Subject: [PATCH 48/51] rename to configuredSuccessfully() --- services/URIBeacon2Service.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index e80b5cf..a0d3a2f 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -105,7 +105,7 @@ public: ble.onDataWritten(this, &URIBeacon2Service::onDataWritten); } - bool initialized(void) const { + bool configuredSuccessfully(void) const { return initSucceeded; } From 49103aff553818ec6cbc4823946d7ee2c73e0ea0 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 12:03:39 +0000 Subject: [PATCH 49/51] minor change to a check. --- services/URIBeacon2Service.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index a0d3a2f..7eb6c74 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -84,10 +84,10 @@ public: resetChar(resetCharUUID, reinterpret_cast(&resetFlag), 1, 1, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE) { - if ((uriDataIn == NULL) || ((uriDataLength = strlen(uriDataIn)) == 0)) { + if ((uriDataIn == NULL) || ((uriDataLength = strlen(uriDataIn)) == 0) || (uriDataLength > MAX_SIZE_URI_DATA_CHAR_VALUE)) { return; } - strncpy(reinterpret_cast(uriData), uriDataIn, MAX_SIZE_URI_DATA_CHAR_VALUE); + strcpy(reinterpret_cast(uriData), uriDataIn); configure(); if (initSucceeded) { From a4d2a4327cf548b45793ce7fa8731864e63a9bc5 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 12:56:13 +0000 Subject: [PATCH 50/51] fix access privileges for methods of URIBeacon2Service. --- services/URIBeacon2Service.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/services/URIBeacon2Service.h b/services/URIBeacon2Service.h index 7eb6c74..bf5926b 100644 --- a/services/URIBeacon2Service.h +++ b/services/URIBeacon2Service.h @@ -109,6 +109,12 @@ public: return initSucceeded; } + /** + * Please note that the following public APIs are offered to allow modifying + * the service programmatically. It is also possible to do so over BLE GATT + * transactions. + */ +public: /** * Update flags of the URIBeacon dynamically. * @@ -130,12 +136,6 @@ public: configure(); } - /** - * Please note that the following public APIs are offered to allow modifying - * the service programmatically. It is also possible to do so over BLE GATT - * transactions. - */ -public: /** * Update the txPower for a particular mode in the powerLevels table. */ @@ -161,6 +161,7 @@ public: configure(); } +private: /** * Setup the advertisement payload and GAP settings. */ From 959ba7c6db88d09e4b4a135cd39b3658c4d951e8 Mon Sep 17 00:00:00 2001 From: Rohit Grover Date: Fri, 28 Nov 2014 13:38:01 +0000 Subject: [PATCH 51/51] removing Stream as a base class for UARTService. Instantiating Stream was causing a call to initialize the serial console uart; which caused a constant drain of around 1mA. --- services/UARTService.h | 64 ++++++++++++++---------------------------- 1 file changed, 21 insertions(+), 43 deletions(-) diff --git a/services/UARTService.h b/services/UARTService.h index 3248fdb..9a0c6fe 100644 --- a/services/UARTService.h +++ b/services/UARTService.h @@ -33,15 +33,14 @@ extern const uint8_t UARTServiceUUID_reversed[LENGTH_OF_LONG_UUID]; extern const uint8_t UARTServiceTXCharacteristicUUID[LENGTH_OF_LONG_UUID]; extern const uint8_t UARTServiceRXCharacteristicUUID[LENGTH_OF_LONG_UUID]; -class UARTService : public Stream { +class UARTService { public: /**< Maximum length of data (in bytes) that can be transmitted by the UART service module to the peer. */ - static const unsigned GATT_MTU_SIZE_DEFAULT = 23; + static const unsigned GATT_MTU_SIZE_DEFAULT = 23; static const unsigned BLE_UART_SERVICE_MAX_DATA_LEN = (GATT_MTU_SIZE_DEFAULT - 3); public: UARTService(BLEDevice &_ble) : - Stream("bleuart"), ble(_ble), receiveBuffer(), sendBuffer(), @@ -72,41 +71,6 @@ public: return rxCharacteristic.getValueAttribute().getHandle(); } - /** - * Following a call to this function, all writes to stdout (such as from - * printf) get redirected to the outbound characteristic of this service. - * This might be very useful when wanting to receive debug messages over BLE. - * - * @Note: debug messages originating from printf() like calls are buffered - * before being sent out. A '\n' in the printf() triggers the buffer update - * to the underlying characteristic. - * - * @Note: long messages need to be chopped up into 20-byte updates so that - * they flow out completely with notifications. The receiver should be - * prepared to stitch these messages back. - */ - void retargetStdout() { - freopen("/bleuart", "w", stdout); - } - - /** - * This callback allows the UART service to receive updates to the - * txCharacteristic. The application should forward the call to this - * function from the global onDataWritten() callback handler; or if that's - * not used, this method can be used as a callback directly. - */ - virtual void onDataWritten(const GattCharacteristicWriteCBParams *params) { - if (params->charHandle == getTXCharacteristicHandle()) { - uint16_t bytesRead = params->len; - if (bytesRead <= BLE_UART_SERVICE_MAX_DATA_LEN) { - numBytesReceived = bytesRead; - receiveBufferIndex = 0; - memcpy(receiveBuffer, params->data, numBytesReceived); - } - } - } - -protected: /** * Override for Stream::write(). * @@ -126,7 +90,7 @@ protected: * @param length Amount of characters to be appended. * @return Amount of characters appended to the rxCharacteristic. */ - virtual ssize_t write(const void* _buffer, size_t length) { + ssize_t write(const void* _buffer, size_t length) { size_t origLength = length; const uint8_t *buffer = static_cast(_buffer); @@ -162,11 +126,11 @@ protected: * @return * The character written as an unsigned char cast to an int or EOF on error. */ - virtual int _putc(int c) { + int _putc(int c) { return (write(&c, 1) == 1) ? 1 : EOF; } - virtual int _getc() { + int _getc() { if (receiveBufferIndex == numBytesReceived) { return EOF; } @@ -174,8 +138,22 @@ protected: return receiveBuffer[receiveBufferIndex++]; } - virtual int isatty() { - return 1; +private: + /** + * This callback allows the UART service to receive updates to the + * txCharacteristic. The application should forward the call to this + * function from the global onDataWritten() callback handler; or if that's + * not used, this method can be used as a callback directly. + */ + void onDataWritten(const GattCharacteristicWriteCBParams *params) { + if (params->charHandle == getTXCharacteristicHandle()) { + uint16_t bytesRead = params->len; + if (bytesRead <= BLE_UART_SERVICE_MAX_DATA_LEN) { + numBytesReceived = bytesRead; + receiveBufferIndex = 0; + memcpy(receiveBuffer, params->data, numBytesReceived); + } + } } private: