17 #ifndef SERVICES_EDDYSTONEBEACON_H_    18 #define SERVICES_EDDYSTONEBEACON_H_    20 #warning ble/services/EddystoneService.h is deprecated. Please use the example in 'github.com/ARMmbed/ble-examples/tree/master/BLE_EddystoneService'.    23 #include "CircularBuffer.h"    28 #if BLE_FEATURE_GATT_SERVER    30 static const uint8_t BEACON_EDDYSTONE[] = {0xAA, 0xFE};
    34 #define DBG(MSG, ...)  printf("[EddyStone: DBG]" MSG " \t[%s,%d]\r\n", \    38 #define WARN(MSG, ...) printf("[EddyStone: WARN]" MSG " \t[%s,%d]\r\n", \    42 #define ERR(MSG, ...)  printf("[EddyStone: ERR]" MSG " \t[%s,%d]\r\n", \    47 #define DBG(x, ...) //wait_us(10);    48 #define WARN(x, ...) //wait_us(10);    53 #define INFO(x, ...)  printf("[EddyStone: INFO]"x " \t[%s,%d]\r\n", \    77     static const int SERVICE_DATA_MAX = 31;             
    80 #define EDDYSTONE_MAX_FRAMETYPE 3    81     void (*frames[EDDYSTONE_MAX_FRAMETYPE])(uint8_t *, uint32_t);
    82     static const int URI_DATA_MAX = 18;
    83     typedef uint8_t  UriData_t[URI_DATA_MAX];
    87     static const int UID_NAMESPACEID_SIZE = 10;
    88     typedef uint8_t  UIDNamespaceID_t[UID_NAMESPACEID_SIZE];
    89     static const int UID_INSTANCEID_SIZE = 6;
    90     typedef uint8_t  UIDInstanceID_t[UID_INSTANCEID_SIZE];
    93     static const uint8_t FRAME_TYPE_UID = 0x00;
    94     static const uint8_t FRAME_TYPE_URL = 0x10;
    95     static const uint8_t FRAME_TYPE_TLM = 0x20;
    97     static const uint8_t FRAME_SIZE_TLM = 14; 
    98     static const uint8_t FRAME_SIZE_UID = 20; 
   110                          UIDNamespaceID_t namespaceID,
   111                          UIDInstanceID_t  instanceID,
   112                          float            uidAdvPeriodIn,
   113                          uint16_t         RFU = 0x0000) {
   114         if (0.0f == uidAdvPeriodIn) {
   125         defaultUidPower = power;
   126         memcpy(defaultUidNamespaceID, namespaceID, UID_NAMESPACEID_SIZE);
   127         memcpy(defaultUidInstanceID,  instanceID,  UID_INSTANCEID_SIZE);
   128         uidRFU       = (uint16_t)RFU; 
   129         uidAdvPeriod = uidAdvPeriodIn;
   139     unsigned constructUIDFrame(uint8_t *Data, uint8_t maxSize) {
   142         Data[index++] = FRAME_TYPE_UID;                     
   144         if (defaultUidPower > 20) {
   145             defaultUidPower = 20;                           
   147         if (defaultUidPower < -100) {
   148             defaultUidPower = -100;
   150         Data[index++] = defaultUidPower;                    
   152         DBG(
"UID NamespaceID = '0x");
   153         for (
size_t x = 0; x < UID_NAMESPACEID_SIZE; x++) { 
   154             Data[index++] = defaultUidNamespaceID[x];
   155             DBG(
"%x,", defaultUidNamespaceID[x]);
   159         DBG(
"UID InstanceID = '0x");
   160         for (
size_t x = 0; x< UID_INSTANCEID_SIZE; x++) {   
   161             Data[index++] = defaultUidInstanceID[x];
   162             DBG(
"%x,", defaultUidInstanceID[x]);
   167             Data[index++] = (uint8_t)(uidRFU >> 0);
   168             Data[index++] = (uint8_t)(uidRFU >> 8);
   170         DBG(
"construcUIDFrame %d, %d", maxSize, index);
   182         if (0.0f == urlAdvPeriodIn) {
   186         encodeURL(urlIn, defaultUriData, defaultUriDataLength); 
   187         if (defaultUriDataLength > URI_DATA_MAX) {
   190         defaultUrlPower = power;
   191         urlAdvPeriod = urlAdvPeriodIn;
   205         if (0.0f == urlAdvPeriodIn) {
   209         memcpy(defaultUriData, encodedUrlIn, encodedUrlInLength);
   210         if (defaultUriDataLength > URI_DATA_MAX) {
   213         defaultUrlPower      = power;
   214         defaultUriDataLength = encodedUrlInLength;
   215         urlAdvPeriod         = urlAdvPeriodIn;
   226     int constructURLFrame(uint8_t *Data, uint8_t maxSize) {
   228         Data[index++] = FRAME_TYPE_URL;                     
   229         Data[index++] = defaultUrlPower;                    
   230         for (
int x = 0; x < defaultUriDataLength; x++) {    
   231             Data[index++] = defaultUriData[x];
   233         DBG(
"constructURLFrame: %d, %d", maxSize, index);
   245     void setTLMFrameData(uint8_t  version        = 0,
   246                          float    advPeriod      = 60.0f,
   247                          uint16_t batteryVoltage = 0,
   248                          uint16_t beaconTemp     = 0x8000,
   249                          uint32_t pduCount       = 0,
   250                          uint32_t timeSinceBoot  = 0) {
   251         if (0.0f == advPeriod) {
   255         TlmVersion        = version;
   256         TlmBatteryVoltage = batteryVoltage;
   257         TlmBeaconTemp     = beaconTemp;
   258         TlmPduCount       = pduCount;      
   259         TlmTimeSinceBoot  = timeSinceBoot; 
   260         TlmAdvPeriod      = advPeriod;
   270     int constructTLMFrame(uint8_t *Data, uint8_t maxSize) {
   271         uint32_t now = timeSinceBootTimer.read_ms();
   272         TlmTimeSinceBoot += (now - lastBootTimerRead) / 100;
   273         lastBootTimerRead = now;
   276         Data[index++] = FRAME_TYPE_TLM;                    
   277         Data[index++] = TlmVersion;                        
   278         Data[index++] = (uint8_t)(TlmBatteryVoltage >> 8); 
   279         Data[index++] = (uint8_t)(TlmBatteryVoltage >> 0); 
   280         Data[index++] = (uint8_t)(TlmBeaconTemp >> 8);     
   281         Data[index++] = (uint8_t)(TlmBeaconTemp >> 0);     
   282         Data[index++] = (uint8_t)(TlmPduCount >> 24);      
   283         Data[index++] = (uint8_t)(TlmPduCount >> 16);      
   284         Data[index++] = (uint8_t)(TlmPduCount >> 8);       
   285         Data[index++] = (uint8_t)(TlmPduCount >> 0);       
   286         Data[index++] = (uint8_t)(TlmTimeSinceBoot >> 24); 
   287         Data[index++] = (uint8_t)(TlmTimeSinceBoot >> 16); 
   288         Data[index++] = (uint8_t)(TlmTimeSinceBoot >> 8);  
   289         Data[index++] = (uint8_t)(TlmTimeSinceBoot >> 0);  
   290         DBG(
"constructURLFrame: %d, %d", maxSize, index);
   299     void updateTlmBatteryVoltage(uint16_t voltagemv) {
   300         TlmBatteryVoltage = voltagemv;
   308     void updateTlmBeaconTemp(uint16_t temp) {
   309         TlmBeaconTemp = temp;
   317     void updateTlmPduCount(uint32_t pduCount) {
   318         TlmPduCount = pduCount;
   326     void updateTlmTimeSinceBoot(uint32_t timeSinceBoot) {
   327         TlmTimeSinceBoot = timeSinceBoot;
   334     bool updateAdvPacket(uint8_t serviceData[], 
unsigned serviceDataLen) {
   336         DBG(
"Updating AdvFrame: %d", serviceDataLen);
   338         ble.clearAdvertisingPayload();
   340         ble.setAdvertisingInterval(100);
   355     void swapOutFrames(FrameTypes frameType) {
   356         uint8_t  serviceData[SERVICE_DATA_MAX];
   357         unsigned serviceDataLen = 0;
   359         serviceData[serviceDataLen++] = BEACON_EDDYSTONE[0];
   360         serviceData[serviceDataLen++] = BEACON_EDDYSTONE[1];
   367                     DBG(
"Swapping in TLM Frame: version=%x, Batt=%d, Temp = %d, PDUCnt = %d, TimeSinceBoot=%d",
   373                     serviceDataLen += constructTLMFrame(serviceData + serviceDataLen, 20);
   374                     DBG(
"\t Swapping in TLM Frame: len=%d", serviceDataLen);
   375                     updateAdvPacket(serviceData, serviceDataLen);
   381                     DBG(
"Swapping in URL Frame: Power: %d", defaultUrlPower);
   382                     serviceDataLen += constructURLFrame(serviceData + serviceDataLen, 20);
   383                     DBG(
"\t Swapping in URL Frame: len=%d ", serviceDataLen);
   384                     updateAdvPacket(serviceData, serviceDataLen);
   391                     DBG(
"Swapping in UID Frame: Power: %d", defaultUidPower);
   392                     serviceDataLen += constructUIDFrame(serviceData + serviceDataLen, 20);
   393                     DBG(
"\t Swapping in UID Frame: len=%d", serviceDataLen);
   394                     updateAdvPacket(serviceData, serviceDataLen);
   399                 ERR(
"You have not initialized a Frame yet, please initialize one before starting a beacon");
   400                 ERR(
"uidIsSet = %d, urlIsSet = %d, tlmIsSet = %d", uidIsSet, urlIsSet, tlmIsSet);
   407     void urlCallback(
void) {
   409         if (
false == advLock) {
   413             swapOutFrames(frameIndex);
   414             ble.startAdvertising();
   417             INFO(
"URI(%d) cannot complete, %d is currently broadcasting", url, frameIndex);
   426     void uidCallback(
void) {
   428         if (
false == advLock) {
   432             swapOutFrames(frameIndex);
   433             ble.startAdvertising();
   436             INFO(
"UID(%d) cannot complete, %d is currently broadcasting", uid, frameIndex);
   445     void tlmCallback(
void) {
   447         if (
false == advLock) {
   452             swapOutFrames(frameIndex);
   453             ble.startAdvertising();
   456             INFO(
"TLM(%d) cannot complete, %d is currently broadcasting", tlm, frameIndex);
   462     void stopAdvCallback(
void) {
   463         if (overflow.
empty()) {
   465             ble.stopAdvertising();
   471             INFO(
"Re-Transmitting %d", x);
   479 #define EDDYSTONE_SWAPFRAME_DELAYMS 1   480     void radioNotificationCallback(
bool radioActive) {
   488             stopAdv.
attach_us(
this, &EddystoneService::stopAdvCallback, 1);
   502                      uint16_t   beaconPeriodus = 100,
   503                      uint8_t    txPowerIn      = 0) :
   505         advPeriodus(beaconPeriodus),
   518             urlTicker.
attach(
this, &EddystoneService::urlCallback, (
float) advPeriodus / 1000.0f);
   519             DBG(
"attached urlCallback every %d seconds", urlAdvPeriod);
   523             uidTicker.
attach(
this, &EddystoneService::uidCallback, uidAdvPeriod);
   524             DBG(
"attached uidCallback every %d seconds", uidAdvPeriod);
   529             updateTlmPduCount(0);
   530             updateTlmTimeSinceBoot(0);
   531             lastBootTimerRead = 0;
   532             timeSinceBootTimer.start();
   533             tlmTicker.
attach(
this, &EddystoneService::tlmCallback, TlmAdvPeriod);
   534             DBG(
"attached tlmCallback every %d seconds", TlmAdvPeriod);
   536         if (NONE == frameIndex) {
   537             MBED_ERROR(
MBED_MAKE_ERROR(MBED_MODULE_BLE, MBED_ERROR_CODE_BLE_NO_FRAME_INITIALIZED), 
"No Frames were Initialized! Please initialize a frame before starting an eddystone beacon.");
   541         ble.setTxPower(txPower);
   542         ble.gap().onRadioNotification(
this, &EddystoneService::radioNotificationCallback);
   549     uint16_t            advPeriodus;
   551     mbed::Timer               timeSinceBootTimer;
   552     volatile uint32_t   lastBootTimerRead;
   553     volatile bool       advLock;
   554     volatile FrameTypes frameIndex;
   559     uint8_t             defaultUriDataLength;
   560     UriData_t           defaultUriData;
   561     int8_t              defaultUrlPower;
   567     UIDNamespaceID_t    defaultUidNamespaceID;
   568     UIDInstanceID_t     defaultUidInstanceID;
   569     int8_t              defaultUidPower;
   577     volatile uint16_t   TlmBatteryVoltage;
   578     volatile uint16_t   TlmBeaconTemp;
   579     volatile uint32_t   TlmPduCount;
   580     volatile uint32_t   TlmTimeSinceBoot;
   589     static void encodeURL(
const char *uriDataIn, UriData_t uriDataOut, uint8_t &sizeofURIDataOut) {
   590         DBG(
"Encode URL = %s", uriDataIn);
   591         const char  *prefixes[] = {
   597         const size_t NUM_PREFIXES = 
sizeof(prefixes) / 
sizeof(
char *);
   598         const char  *suffixes[]   = {
   614         const size_t NUM_SUFFIXES = 
sizeof(suffixes) / 
sizeof(
char *);
   616         sizeofURIDataOut = 0;
   617         memset(uriDataOut, 0, 
sizeof(UriData_t));
   619         if ((uriDataIn == NULL) || (strlen(uriDataIn) == 0)) {
   626         for (
unsigned i = 0; i < NUM_PREFIXES; i++) {
   627             size_t prefixLen = strlen(prefixes[i]);
   628             if (strncmp(uriDataIn, prefixes[i], prefixLen) == 0) {
   629                 uriDataOut[sizeofURIDataOut++]  = i;
   630                 uriDataIn                      += prefixLen;
   638         while (*uriDataIn && (sizeofURIDataOut < URI_DATA_MAX)) {
   641             for (i = 0; i < NUM_SUFFIXES; i++) {
   642                 size_t suffixLen = strlen(suffixes[i]);
   643                 if (strncmp(uriDataIn, suffixes[i], suffixLen) == 0) {
   644                     uriDataOut[sizeofURIDataOut++]  = i;
   645                     uriDataIn                      += suffixLen;
   650             INFO(
"Encoding URI: No Suffix Found");
   651             if (i == NUM_SUFFIXES) {
   652                 uriDataOut[sizeofURIDataOut++] = *uriDataIn;
   659 #endif // BLE_FEATURE_GATT_SERVER   661 #endif  // SERVICES_EDDYSTONEBEACON_H_ Templated Circular buffer class. 
Abstract away BLE-capable radio transceivers or SOCs. 
Peripheral device is discoverable at any moment. 
Complete list of 16-bit Service IDs. 
bool setURLFrameData(int8_t power, const char *urlIn, float urlAdvPeriodIn)
Set Eddystone URL Frame information. 
void push(const T &data)
Push the transaction to the buffer. 
bool pop(T &data)
Pop the transaction from the buffer. 
Peripheral device is LE only and does not support Bluetooth Enhanced DataRate. 
Device is not connectable and not scannable. 
void attach_us(Callback< void()> func, us_timestamp_t t)
Attach a function to be called by the Ticker, specifying the interval in microseconds. 
A Ticker is used to call a function at a recurring interval. 
bool setURLFrameEncodedData(int8_t power, const char *encodedUrlIn, uint8_t encodedUrlInLength, float urlAdvPeriodIn)
Set Eddystone URL Frame information. 
MBED_FORCEINLINE void attach(F &&func, float t)
Attach a function to be called by the Ticker, specifying the interval in seconds. ...
Entry namespace for all BLE API definitions. 
void setUIDFrameData(int8_t power, UIDNamespaceID_t namespaceID, UIDInstanceID_t instanceID, float uidAdvPeriodIn, uint16_t RFU=0x0000)
Set Eddystone UID Frame information. 
bool empty() const 
Check if the buffer is empty. 
A Timeout is used to call a function at a point in the future.