17 #ifndef SERVICES_EDDYSTONE_BEACON_CONFIG_SERVICE_H_ 18 #define SERVICES_EDDYSTONE_BEACON_CONFIG_SERVICE_H_ 20 #warning ble/services/EddystoneConfigService.h is deprecated. Please use the example in 'github.com/ARMmbed/ble-examples/tree/master/BLE_EddystoneService'. 22 #if BLE_FEATURE_GATT_SERVER 25 #include "ble/services/EddystoneService.h" 29 #define UUID_URI_BEACON(FIRST, SECOND) { \ 30 0xee, 0x0c, FIRST, SECOND, 0x87, 0x86, 0x40, 0xba, \ 31 0xab, 0x96, 0x99, 0xb9, 0x1a, 0xc9, 0x81, 0xd8, \ 34 static const uint8_t UUID_URI_BEACON_SERVICE[] = UUID_URI_BEACON(0x20, 0x80);
35 static const uint8_t UUID_LOCK_STATE_CHAR[] = UUID_URI_BEACON(0x20, 0x81);
36 static const uint8_t UUID_LOCK_CHAR[] = UUID_URI_BEACON(0x20, 0x82);
37 static const uint8_t UUID_UNLOCK_CHAR[] = UUID_URI_BEACON(0x20, 0x83);
38 static const uint8_t UUID_URI_DATA_CHAR[] = UUID_URI_BEACON(0x20, 0x84);
39 static const uint8_t UUID_FLAGS_CHAR[] = UUID_URI_BEACON(0x20, 0x85);
40 static const uint8_t UUID_ADV_POWER_LEVELS_CHAR[] = UUID_URI_BEACON(0x20, 0x86);
41 static const uint8_t UUID_TX_POWER_MODE_CHAR[] = UUID_URI_BEACON(0x20, 0x87);
42 static const uint8_t UUID_BEACON_PERIOD_CHAR[] = UUID_URI_BEACON(0x20, 0x88);
43 static const uint8_t UUID_RESET_CHAR[] = UUID_URI_BEACON(0x20, 0x89);
44 extern const uint8_t BEACON_EDDYSTONE[2];
66 static const unsigned ADVERTISING_INTERVAL_MSEC = 1000;
67 static const unsigned SERVICE_DATA_MAX = 31;
69 typedef uint8_t Lock_t[16];
70 typedef int8_t PowerLevels_t[NUM_POWER_MODES];
73 #define EDDYSTONE_MAX_FRAMETYPE 3 74 static const unsigned URI_DATA_MAX = 18;
75 typedef uint8_t UriData_t[URI_DATA_MAX];
78 static const size_t UID_NAMESPACEID_SIZE = 10;
79 typedef uint8_t UIDNamespaceID_t[UID_NAMESPACEID_SIZE];
80 static const size_t UID_INSTANCEID_SIZE = 6;
81 typedef uint8_t UIDInstanceID_t[UID_INSTANCEID_SIZE];
84 static const uint8_t FRAME_TYPE_UID = 0x00;
85 static const uint8_t FRAME_TYPE_URL = 0x10;
86 static const uint8_t FRAME_TYPE_TLM = 0x20;
88 static const uint8_t FRAME_SIZE_TLM = 14;
89 static const uint8_t FRAME_SIZE_UID = 20;
98 PowerLevels_t advPowerLevels;
100 uint16_t beaconPeriod;
104 float tlmBeaconPeriod;
106 uint8_t uriDataLength;
109 float uriBeaconPeriod;
111 UIDNamespaceID_t uidNamespaceID;
112 UIDInstanceID_t uidInstanceID;
114 float uidBeaconPeriod;
131 PowerLevels_t &defaultAdvPowerLevelsIn,
132 PowerLevels_t &radioPowerLevelsIn) :
135 defaultAdvPowerLevels(defaultAdvPowerLevelsIn),
136 radioPowerLevels(radioPowerLevelsIn),
137 initSucceeded(false),
139 defaultUidNamespaceID(),
140 defaultUidInstanceID(),
141 defaultUidPower(defaultAdvPowerLevelsIn[params.txPowerMode]),
143 defaultUriDataLength(),
145 defaultUrlPower(defaultAdvPowerLevelsIn[params.txPowerMode]),
148 lockedStateChar(UUID_LOCK_STATE_CHAR, ¶ms.lockedState),
149 lockChar(UUID_LOCK_CHAR, ¶ms.lock),
150 uriDataChar(UUID_URI_DATA_CHAR, params.uriData, 0, URI_DATA_MAX,
152 unlockChar(UUID_UNLOCK_CHAR, ¶ms.lock),
153 flagsChar(UUID_FLAGS_CHAR, ¶ms.flags),
154 advPowerLevelsChar(UUID_ADV_POWER_LEVELS_CHAR, ¶ms.advPowerLevels),
155 txPowerModeChar(UUID_TX_POWER_MODE_CHAR, ¶ms.txPowerMode),
156 beaconPeriodChar(UUID_BEACON_PERIOD_CHAR, ¶ms.beaconPeriod),
157 resetChar(UUID_RESET_CHAR, &resetFlag) {
159 params.isConfigured =
false;
161 lockChar.setWriteAuthorizationCallback(
this, &EddystoneConfigService::lockAuthorizationCallback);
162 unlockChar.setWriteAuthorizationCallback(
this, &EddystoneConfigService::unlockAuthorizationCallback);
163 uriDataChar.setWriteAuthorizationCallback(
this, &EddystoneConfigService::uriDataWriteAuthorizationCallback);
164 flagsChar.setWriteAuthorizationCallback(
this, &EddystoneConfigService::basicAuthorizationCallback<uint8_t>);
165 advPowerLevelsChar.setWriteAuthorizationCallback(
this, &EddystoneConfigService::basicAuthorizationCallback<PowerLevels_t>);
166 txPowerModeChar.setWriteAuthorizationCallback(
this, &EddystoneConfigService::powerModeAuthorizationCallback);
167 beaconPeriodChar.setWriteAuthorizationCallback(
this, &EddystoneConfigService::basicAuthorizationCallback<uint16_t>);
168 resetChar.setWriteAuthorizationCallback(
this, &EddystoneConfigService::basicAuthorizationCallback<uint8_t>);
171 &lockedStateChar, &lockChar, &unlockChar, &uriDataChar,
172 &flagsChar, &advPowerLevelsChar, &txPowerModeChar, &beaconPeriodChar, &resetChar
177 ble.addService(configService);
178 ble.onDataWritten(
this, &EddystoneConfigService::onDataWrittenCallback);
191 void start(
bool resetToDefaultsFlag){
192 INFO(
"reset to defaults flag = %d", resetToDefaultsFlag);
193 if (!resetToDefaultsFlag && (params.uriDataLength > URI_DATA_MAX)) {
194 INFO(
"Reset to Defaults triggered");
195 resetToDefaultsFlag =
true;
198 if (resetToDefaultsFlag) {
201 updateCharacteristicValues();
204 setupEddystoneConfigAdvertisements();
205 initSucceeded =
true;
211 bool initSuccessfully(
void)
const {
212 return initSucceeded;
222 void setDefaultTLMFrameData(uint8_t tlmVersionIn = 0,
float advPeriodInSec = 60){
223 DBG(
"Setting Default TLM Data, version = %d, advPeriodInMind= %f", tlmVersionIn, advPeriodInSec);
224 defaultTlmVersion = tlmVersionIn;
225 TlmBatteryVoltage = 0;
226 TlmBeaconTemp = 0x8000;
228 TlmTimeSinceBoot = 0;
229 defaultTlmAdvPeriod = advPeriodInSec;
240 void setDefaultURIFrameData(
const char *uriIn,
float advPeriod = 1){
241 DBG(
"Setting Default URI Data");
243 EddystoneService::encodeURL(uriIn, defaultUriData, defaultUriDataLength);
244 if (defaultUriDataLength > URI_DATA_MAX) {
247 INFO(
"\t URI input = %s : %d", uriIn, defaultUriDataLength);
248 INFO(
"\t default URI = %s : %d ", defaultUriData, defaultUriDataLength );
249 defaultUriAdvPeriod = advPeriod;
261 void setDefaultUIDFrameData(UIDNamespaceID_t *namespaceID, UIDInstanceID_t *instanceID,
float advPeriod = 10){
263 DBG(
"Setting default UID Data");
264 memcpy(defaultUidNamespaceID, namespaceID, UID_NAMESPACEID_SIZE);
265 memcpy(defaultUidInstanceID, instanceID, UID_INSTANCEID_SIZE);
266 defaultUidAdvPeriod = advPeriod;
273 void setupEddystoneConfigAdvertisements() {
274 const char DEVICE_NAME[] =
"eddystone Config";
276 ble.clearAdvertisingPayload();
281 uint8_t reversedServiceUUID[
sizeof(UUID_URI_BEACON_SERVICE)];
282 for (
unsigned int i = 0; i <
sizeof(UUID_URI_BEACON_SERVICE); i++) {
283 reversedServiceUUID[i] = UUID_URI_BEACON_SERVICE[
sizeof(UUID_URI_BEACON_SERVICE) - i - 1];
288 ble.accumulateScanResponse(
290 reinterpret_cast<uint8_t *>(&defaultAdvPowerLevels[EddystoneConfigService::TX_POWER_MODE_LOW]),
293 ble.setTxPower(radioPowerLevels[params.txPowerMode]);
294 ble.setDeviceName(reinterpret_cast<const uint8_t *>(&DEVICE_NAME));
296 ble.setAdvertisingInterval(ADVERTISING_INTERVAL_MSEC);
304 void setupEddystoneAdvertisements() {
305 DBG(
"Switching Config -> adv");
307 extern void saveURIBeaconConfigParams(
const Params_t *paramsP);
308 saveURIBeaconConfigParams(¶ms);
309 INFO(
"Saved Params to Memory.")
311 static EddystoneService eddyServ(
ble, params.beaconPeriod, radioPowerLevels[params.txPowerMode]);
313 if (params.tlmEnabled) {
314 eddyServ.setTLMFrameData(params.tlmVersion, params.tlmBeaconPeriod);
316 if (params.uriEnabled) {
317 eddyServ.
setURLFrameEncodedData(params.advPowerLevels[params.txPowerMode], (
const char *) params.uriData, params.uriDataLength, params.uriBeaconPeriod);
319 if (params.uidEnabled) {
321 (uint8_t *)params.uidNamespaceID,
322 (uint8_t *)params.uidInstanceID,
323 params.uidBeaconPeriod);
336 uint16_t handle = writeParams->
handle;
338 if (handle == lockChar.getValueHandle()) {
340 memcpy(params.lock, writeParams->
data,
sizeof(Lock_t));
342 params.lockedState =
true;
343 INFO(
"Device Locked");
344 }
else if (handle == unlockChar.getValueHandle()) {
346 params.lockedState =
false;
347 INFO(
"Device Unlocked");
348 }
else if (handle == uriDataChar.getValueHandle()) {
349 params.uriDataLength = writeParams->
len;
350 memset(params.uriData, 0x00, URI_DATA_MAX);
351 memcpy(params.uriData, writeParams->
data, writeParams->
len);
352 params.uriEnabled =
true;
353 INFO(
"URI = %s, URILen = %d", writeParams->
data, writeParams->
len);
354 }
else if (handle == flagsChar.getValueHandle()) {
355 params.flags = *(writeParams->
data);
356 INFO(
"flagsChar = 0x%x", params.flags);
357 }
else if (handle == advPowerLevelsChar.getValueHandle()) {
358 memcpy(params.advPowerLevels, writeParams->
data,
sizeof(PowerLevels_t));
359 INFO(
"PowerLevelsChar = %4x", params.advPowerLevels);
360 }
else if (handle == txPowerModeChar.getValueHandle()) {
361 params.txPowerMode = *(writeParams->
data);
362 INFO(
"TxPowerModeChar = %d", params.txPowerMode);
363 }
else if (handle == beaconPeriodChar.getValueHandle()) {
364 params.beaconPeriod = *((uint16_t *)(writeParams->
data));
365 INFO(
"BeaconPeriod = %d", params.beaconPeriod);
368 if (params.beaconPeriod != 0) {
369 bool paramsUpdated =
false;
370 if (params.beaconPeriod <
ble.getMinAdvertisingInterval()) {
371 params.beaconPeriod =
ble.getMinAdvertisingInterval();
372 paramsUpdated =
true;
373 }
else if (params.beaconPeriod >
ble.getMaxAdvertisingInterval()) {
374 params.beaconPeriod =
ble.getMaxAdvertisingInterval();
375 paramsUpdated =
true;
378 ble.updateCharacteristicValue(beaconPeriodChar.getValueHandle(),
reinterpret_cast<uint8_t *
>(¶ms.beaconPeriod),
sizeof(uint16_t));
381 }
else if (handle == resetChar.getValueHandle()) {
382 INFO(
"Reset triggered from Config Service, resetting to defaults");
385 updateCharacteristicValues();
386 params.isConfigured =
true;
392 void resetToDefaults(
void) {
393 INFO(
"Resetting to defaults");
395 params.lockedState =
false;
396 memset(params.lock, 0,
sizeof(Lock_t));
398 memcpy(params.advPowerLevels, defaultAdvPowerLevels,
sizeof(PowerLevels_t));
399 params.txPowerMode = TX_POWER_MODE_LOW;
400 params.beaconPeriod = (uint16_t) defaultUriAdvPeriod * 1000;
403 params.tlmVersion = defaultTlmVersion;
404 params.tlmBeaconPeriod = defaultTlmAdvPeriod;
405 params.tlmEnabled = tlmIsSet;
408 memcpy(params.uriData, defaultUriData, URI_DATA_MAX);
409 params.uriDataLength = defaultUriDataLength;
410 params.uriBeaconPeriod = defaultUriAdvPeriod;
411 params.uriEnabled = urlIsSet;
414 memcpy(params.uidNamespaceID, defaultUidNamespaceID, UID_NAMESPACEID_SIZE);
415 memcpy(params.uidInstanceID, defaultUidInstanceID, UID_INSTANCEID_SIZE);
416 params.uidBeaconPeriod = defaultUidAdvPeriod;
417 params.uidEnabled = uidIsSet;
419 updateCharacteristicValues();
426 void updateCharacteristicValues(
void) {
427 ble.updateCharacteristicValue(lockedStateChar.getValueHandle(), ¶ms.lockedState, 1);
428 ble.updateCharacteristicValue(uriDataChar.getValueHandle(), params.uriData, params.uriDataLength);
429 ble.updateCharacteristicValue(flagsChar.getValueHandle(), ¶ms.flags, 1);
430 ble.updateCharacteristicValue(beaconPeriodChar.getValueHandle(),
431 reinterpret_cast<uint8_t *
>(¶ms.beaconPeriod),
sizeof(uint16_t));
432 ble.updateCharacteristicValue(txPowerModeChar.getValueHandle(), ¶ms.txPowerMode, 1);
433 ble.updateCharacteristicValue(advPowerLevelsChar.getValueHandle(),
434 reinterpret_cast<uint8_t *
>(params.advPowerLevels),
sizeof(PowerLevels_t));
439 if (params.lockedState) {
441 }
else if (authParams->
len !=
sizeof(Lock_t)) {
443 }
else if (authParams->
offset != 0) {
451 if ((!params.lockedState) && (authParams->
len ==
sizeof(Lock_t))) {
453 }
else if (authParams->
len !=
sizeof(Lock_t)) {
455 }
else if (authParams->
offset != 0) {
457 }
else if (memcmp(authParams->
data, params.lock,
sizeof(Lock_t)) != 0) {
465 if (params.lockedState) {
467 }
else if (authParams->
offset != 0) {
475 if (params.lockedState) {
477 }
else if (authParams->
len !=
sizeof(uint8_t)) {
479 }
else if (authParams->
offset != 0) {
481 }
else if (*((uint8_t *)authParams->
data) >= NUM_POWER_MODES) {
488 template <
typename T>
490 if (params.lockedState) {
492 }
else if (authParams->
len !=
sizeof(T)) {
494 }
else if (authParams->
offset != 0) {
506 PowerLevels_t &defaultAdvPowerLevels;
507 PowerLevels_t &radioPowerLevels;
514 UIDNamespaceID_t defaultUidNamespaceID;
515 UIDInstanceID_t defaultUidInstanceID;
516 float defaultUidAdvPeriod;
517 int8_t defaultUidPower;
522 uint8_t defaultUriDataLength;
523 UriData_t defaultUriData;
524 int8_t defaultUrlPower;
525 float defaultUriAdvPeriod;
529 uint8_t defaultTlmVersion;
530 float defaultTlmAdvPeriod;
531 volatile uint16_t TlmBatteryVoltage;
532 volatile uint16_t TlmBeaconTemp;
533 volatile uint32_t TlmPduCount;
534 volatile uint32_t TlmTimeSinceBoot;
548 #endif // BLE_FEATURE_GATT_SERVER 550 #endif // SERVICES_EDDYSTONE_BEACON_CONFIG_SERVICE_H_
GattAuthCallbackReply_t authorizationReply
Authorization result.
const uint8_t * data
Incoming data.
const uint8_t * data
Pointer to the data to write.
Abstract away BLE-capable radio transceivers or SOCs.
GATT write authorization request event.
Peripheral device is discoverable at any moment.
Complete list of 128-bit Service IDs.
ATT Error: Write not permitted.
ATT Error: The specified offset was past the end of the attribute.
GATT Write event definition.
uint16_t len
Length (in bytes) of the data to write.
Peripheral device is LE only and does not support Bluetooth Enhanced DataRate.
EddystoneConfigService(BLEDevice &bleIn, Params_t ¶msIn, PowerLevels_t &defaultAdvPowerLevelsIn, PowerLevels_t &radioPowerLevelsIn)
Representation of a GattServer characteristic.
void start(bool resetToDefaultsFlag)
Start EddystoneConfig advertising.
uint16_t offset
Offset for the write operation.
uint16_t len
Length of the incoming data.
GattAttribute::Handle_t handle
Handle of the attribute to which the write operation applies.
A Ticker is used to call a function at a recurring interval.
Eddystone Configuration Service.
Representation of a GattServer service.
Device is connectable, scannable and doesn't expect connection from a specific peer.
bool setURLFrameEncodedData(int8_t power, const char *encodedUrlIn, uint8_t encodedUrlInLength, float urlAdvPeriodIn)
Set Eddystone URL Frame information.
Entry namespace for all BLE API definitions.
ATT Error: Invalid value size.
void setUIDFrameData(int8_t power, UIDNamespaceID_t namespaceID, UIDInstanceID_t instanceID, float uidAdvPeriodIn, uint16_t RFU=0x0000)
Set Eddystone UID Frame information.
ATT Error: Used in ATT as "insufficient authorization".
A Timeout is used to call a function at a point in the future.