ST / Mbed OS mbed-os-example-ble-EddystoneObserver
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2013 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *      http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include <events/mbed_events.h>
00018 #include "mbed.h"
00019 #include "ble/BLE.h"
00020 
00021 static const int URI_MAX_LENGTH = 18;             // Maximum size of service data in ADV packets
00022 
00023 static EventQueue eventQueue(/* event count */ 16 * EVENTS_EVENT_SIZE);
00024 
00025 DigitalOut led1(LED1, 1);
00026 
00027 void periodicCallback(void)
00028 {
00029     led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */
00030 }
00031 
00032 void decodeURI(const uint8_t* uriData, const size_t uriLen)
00033 {
00034     const char *prefixes[] = {
00035         "http://www.",
00036         "https://www.",
00037         "http://",
00038         "https://",
00039         "urn:uuid:"
00040     };
00041     const size_t NUM_PREFIXES = sizeof(prefixes) / sizeof(char *);
00042     const char *suffixes[] = {
00043         ".com/",
00044         ".org/",
00045         ".edu/",
00046         ".net/",
00047         ".info/",
00048         ".biz/",
00049         ".gov/",
00050         ".com",
00051         ".org",
00052         ".edu",
00053         ".net",
00054         ".info",
00055         ".biz",
00056         ".gov"
00057     };
00058     const size_t NUM_SUFFIXES = sizeof(suffixes) / sizeof(char *);
00059 
00060     size_t index = 0;
00061 
00062     /* First byte is the URL Scheme. */
00063     if (uriData[index] < NUM_PREFIXES) {
00064         printf("%s", prefixes[uriData[index]]);
00065         index++;
00066     } else {
00067         printf("URL Scheme was not encoded!");
00068         return;
00069     }
00070 
00071     /* From second byte onwards we can have a character or a suffix */
00072     while(index < uriLen) {
00073         if (uriData[index] < NUM_SUFFIXES) {
00074             printf("%s", suffixes[uriData[index]]);
00075         } else {
00076             printf("%c", uriData[index]);
00077         }
00078         index++;
00079     }
00080 
00081     printf("\n\r");
00082 }
00083 
00084 /*
00085  * This function is called every time we scan an advertisement.
00086  */
00087 void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params)
00088 {
00089     struct AdvertisingData_t {
00090         uint8_t                        length; /* doesn't include itself */
00091         GapAdvertisingData::DataType_t dataType;
00092         uint8_t                        data[1];
00093     } AdvDataPacket;
00094 
00095     struct ApplicationData_t {
00096         uint8_t applicationSpecificId[2];
00097         uint8_t frameType;
00098         uint8_t advPowerLevels;
00099         uint8_t uriData[URI_MAX_LENGTH];
00100     } AppDataPacket;
00101 
00102     const uint8_t BEACON_UUID[sizeof(UUID::ShortUUIDBytes_t)] = {0xAA, 0xFE};
00103     const uint8_t FRAME_TYPE_URL                              = 0x10;
00104     const uint8_t APPLICATION_DATA_OFFSET                     = sizeof(ApplicationData_t) + sizeof(AdvDataPacket.dataType) - sizeof(AppDataPacket.uriData);
00105 
00106     AdvertisingData_t *pAdvData;
00107     size_t index = 0;
00108     while(index < params->advertisingDataLen) {
00109         pAdvData = (AdvertisingData_t *)&params->advertisingData[index];
00110         if (pAdvData->dataType == GapAdvertisingData::SERVICE_DATA) {
00111             ApplicationData_t *pAppData = (ApplicationData_t *) pAdvData->data;
00112             if (!memcmp(pAppData->applicationSpecificId, BEACON_UUID, sizeof(BEACON_UUID)) && (pAppData->frameType == FRAME_TYPE_URL)) {
00113                 decodeURI(pAppData->uriData, pAdvData->length - APPLICATION_DATA_OFFSET);
00114                 break;
00115             }
00116         }
00117         index += (pAdvData->length + 1);
00118     }
00119 }
00120 
00121 void onBleInitError(BLE &ble, ble_error_t error)
00122 {
00123    /* Initialization error handling should go here */
00124 }
00125 
00126 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
00127 {
00128     BLE&        ble   = params->ble;
00129     ble_error_t error = params->error;
00130 
00131     if (error != BLE_ERROR_NONE) {
00132         onBleInitError(ble, error);
00133         return;
00134     }
00135 
00136     if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
00137         return;
00138     }
00139 
00140     ble.gap().setScanParams(1800 /* scan interval */, 1500 /* scan window */);
00141     ble.gap().startScan(advertisementCallback);
00142 }
00143 
00144 void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) {
00145     BLE &ble = BLE::Instance();
00146     eventQueue.call(Callback<void()>(&ble, &BLE::processEvents));
00147 }
00148 
00149 int main()
00150 {
00151     eventQueue.call_every(500, periodicCallback);
00152 
00153     BLE &ble = BLE::Instance();
00154     ble.onEventsToProcess(scheduleBleEventsProcessing);
00155     ble.init(bleInitComplete);
00156 
00157     eventQueue.dispatch_forever();
00158 
00159     return 0;
00160 }