BLE EddystoneObserver example
This example is a fork of the following mbed-os example:
https://developer.mbed.org/teams/mbed-os-examples/code/mbed-os-example-ble-EddystoneObserver/
Please read the documentation in this page.
source/main.cpp@0:932f719b42d5, 2016-07-26 (annotated)
- Committer:
- Vincent Coubard
- Date:
- Tue Jul 26 14:38:37 2016 +0100
- Revision:
- 0:932f719b42d5
- Child:
- 1:d839eae15f56
Update example at tag mbed-os-5.0.1-rc1
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Vincent Coubard |
0:932f719b42d5 | 1 | /* mbed Microcontroller Library |
Vincent Coubard |
0:932f719b42d5 | 2 | * Copyright (c) 2006-2013 ARM Limited |
Vincent Coubard |
0:932f719b42d5 | 3 | * |
Vincent Coubard |
0:932f719b42d5 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
Vincent Coubard |
0:932f719b42d5 | 5 | * you may not use this file except in compliance with the License. |
Vincent Coubard |
0:932f719b42d5 | 6 | * You may obtain a copy of the License at |
Vincent Coubard |
0:932f719b42d5 | 7 | * |
Vincent Coubard |
0:932f719b42d5 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
Vincent Coubard |
0:932f719b42d5 | 9 | * |
Vincent Coubard |
0:932f719b42d5 | 10 | * Unless required by applicable law or agreed to in writing, software |
Vincent Coubard |
0:932f719b42d5 | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
Vincent Coubard |
0:932f719b42d5 | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
Vincent Coubard |
0:932f719b42d5 | 13 | * See the License for the specific language governing permissions and |
Vincent Coubard |
0:932f719b42d5 | 14 | * limitations under the License. |
Vincent Coubard |
0:932f719b42d5 | 15 | */ |
Vincent Coubard |
0:932f719b42d5 | 16 | |
Vincent Coubard |
0:932f719b42d5 | 17 | #include <mbed-events/events.h> |
Vincent Coubard |
0:932f719b42d5 | 18 | #include "mbed.h" |
Vincent Coubard |
0:932f719b42d5 | 19 | #include "ble/BLE.h" |
Vincent Coubard |
0:932f719b42d5 | 20 | |
Vincent Coubard |
0:932f719b42d5 | 21 | static const int URI_MAX_LENGTH = 18; // Maximum size of service data in ADV packets |
Vincent Coubard |
0:932f719b42d5 | 22 | |
Vincent Coubard |
0:932f719b42d5 | 23 | static EventQueue eventQueue( |
Vincent Coubard |
0:932f719b42d5 | 24 | /* event count */ 16 * /* event size */ 32 |
Vincent Coubard |
0:932f719b42d5 | 25 | ); |
Vincent Coubard |
0:932f719b42d5 | 26 | |
Vincent Coubard |
0:932f719b42d5 | 27 | DigitalOut led1(LED1, 1); |
Vincent Coubard |
0:932f719b42d5 | 28 | |
Vincent Coubard |
0:932f719b42d5 | 29 | void periodicCallback(void) |
Vincent Coubard |
0:932f719b42d5 | 30 | { |
Vincent Coubard |
0:932f719b42d5 | 31 | led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */ |
Vincent Coubard |
0:932f719b42d5 | 32 | } |
Vincent Coubard |
0:932f719b42d5 | 33 | |
Vincent Coubard |
0:932f719b42d5 | 34 | void decodeURI(const uint8_t* uriData, const size_t uriLen) |
Vincent Coubard |
0:932f719b42d5 | 35 | { |
Vincent Coubard |
0:932f719b42d5 | 36 | const char *prefixes[] = { |
Vincent Coubard |
0:932f719b42d5 | 37 | "http://www.", |
Vincent Coubard |
0:932f719b42d5 | 38 | "https://www.", |
Vincent Coubard |
0:932f719b42d5 | 39 | "http://", |
Vincent Coubard |
0:932f719b42d5 | 40 | "https://", |
Vincent Coubard |
0:932f719b42d5 | 41 | "urn:uuid:" |
Vincent Coubard |
0:932f719b42d5 | 42 | }; |
Vincent Coubard |
0:932f719b42d5 | 43 | const size_t NUM_PREFIXES = sizeof(prefixes) / sizeof(char *); |
Vincent Coubard |
0:932f719b42d5 | 44 | const char *suffixes[] = { |
Vincent Coubard |
0:932f719b42d5 | 45 | ".com/", |
Vincent Coubard |
0:932f719b42d5 | 46 | ".org/", |
Vincent Coubard |
0:932f719b42d5 | 47 | ".edu/", |
Vincent Coubard |
0:932f719b42d5 | 48 | ".net/", |
Vincent Coubard |
0:932f719b42d5 | 49 | ".info/", |
Vincent Coubard |
0:932f719b42d5 | 50 | ".biz/", |
Vincent Coubard |
0:932f719b42d5 | 51 | ".gov/", |
Vincent Coubard |
0:932f719b42d5 | 52 | ".com", |
Vincent Coubard |
0:932f719b42d5 | 53 | ".org", |
Vincent Coubard |
0:932f719b42d5 | 54 | ".edu", |
Vincent Coubard |
0:932f719b42d5 | 55 | ".net", |
Vincent Coubard |
0:932f719b42d5 | 56 | ".info", |
Vincent Coubard |
0:932f719b42d5 | 57 | ".biz", |
Vincent Coubard |
0:932f719b42d5 | 58 | ".gov" |
Vincent Coubard |
0:932f719b42d5 | 59 | }; |
Vincent Coubard |
0:932f719b42d5 | 60 | const size_t NUM_SUFFIXES = sizeof(suffixes) / sizeof(char *); |
Vincent Coubard |
0:932f719b42d5 | 61 | |
Vincent Coubard |
0:932f719b42d5 | 62 | size_t index = 0; |
Vincent Coubard |
0:932f719b42d5 | 63 | |
Vincent Coubard |
0:932f719b42d5 | 64 | /* First byte is the URL Scheme. */ |
Vincent Coubard |
0:932f719b42d5 | 65 | if (uriData[index] < NUM_PREFIXES) { |
Vincent Coubard |
0:932f719b42d5 | 66 | printf("%s", prefixes[uriData[index]]); |
Vincent Coubard |
0:932f719b42d5 | 67 | index++; |
Vincent Coubard |
0:932f719b42d5 | 68 | } else { |
Vincent Coubard |
0:932f719b42d5 | 69 | printf("URL Scheme was not encoded!"); |
Vincent Coubard |
0:932f719b42d5 | 70 | return; |
Vincent Coubard |
0:932f719b42d5 | 71 | } |
Vincent Coubard |
0:932f719b42d5 | 72 | |
Vincent Coubard |
0:932f719b42d5 | 73 | /* From second byte onwards we can have a character or a suffix */ |
Vincent Coubard |
0:932f719b42d5 | 74 | while(index < uriLen) { |
Vincent Coubard |
0:932f719b42d5 | 75 | if (uriData[index] < NUM_SUFFIXES) { |
Vincent Coubard |
0:932f719b42d5 | 76 | printf("%s", suffixes[uriData[index]]); |
Vincent Coubard |
0:932f719b42d5 | 77 | } else { |
Vincent Coubard |
0:932f719b42d5 | 78 | printf("%c", uriData[index]); |
Vincent Coubard |
0:932f719b42d5 | 79 | } |
Vincent Coubard |
0:932f719b42d5 | 80 | index++; |
Vincent Coubard |
0:932f719b42d5 | 81 | } |
Vincent Coubard |
0:932f719b42d5 | 82 | |
Vincent Coubard |
0:932f719b42d5 | 83 | printf("\n\r"); |
Vincent Coubard |
0:932f719b42d5 | 84 | } |
Vincent Coubard |
0:932f719b42d5 | 85 | |
Vincent Coubard |
0:932f719b42d5 | 86 | /* |
Vincent Coubard |
0:932f719b42d5 | 87 | * This function is called every time we scan an advertisement. |
Vincent Coubard |
0:932f719b42d5 | 88 | */ |
Vincent Coubard |
0:932f719b42d5 | 89 | void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params) |
Vincent Coubard |
0:932f719b42d5 | 90 | { |
Vincent Coubard |
0:932f719b42d5 | 91 | struct AdvertisingData_t { |
Vincent Coubard |
0:932f719b42d5 | 92 | uint8_t length; /* doesn't include itself */ |
Vincent Coubard |
0:932f719b42d5 | 93 | GapAdvertisingData::DataType_t dataType; |
Vincent Coubard |
0:932f719b42d5 | 94 | uint8_t data[0]; |
Vincent Coubard |
0:932f719b42d5 | 95 | } AdvDataPacket; |
Vincent Coubard |
0:932f719b42d5 | 96 | |
Vincent Coubard |
0:932f719b42d5 | 97 | struct ApplicationData_t { |
Vincent Coubard |
0:932f719b42d5 | 98 | uint8_t applicationSpecificId[2]; |
Vincent Coubard |
0:932f719b42d5 | 99 | uint8_t frameType; |
Vincent Coubard |
0:932f719b42d5 | 100 | uint8_t advPowerLevels; |
Vincent Coubard |
0:932f719b42d5 | 101 | uint8_t uriData[URI_MAX_LENGTH]; |
Vincent Coubard |
0:932f719b42d5 | 102 | } AppDataPacket; |
Vincent Coubard |
0:932f719b42d5 | 103 | |
Vincent Coubard |
0:932f719b42d5 | 104 | const uint8_t BEACON_UUID[sizeof(UUID::ShortUUIDBytes_t)] = {0xAA, 0xFE}; |
Vincent Coubard |
0:932f719b42d5 | 105 | const uint8_t FRAME_TYPE_URL = 0x10; |
Vincent Coubard |
0:932f719b42d5 | 106 | const uint8_t APPLICATION_DATA_OFFSET = sizeof(ApplicationData_t) + sizeof(AdvDataPacket.dataType) - sizeof(AppDataPacket.uriData); |
Vincent Coubard |
0:932f719b42d5 | 107 | |
Vincent Coubard |
0:932f719b42d5 | 108 | AdvertisingData_t *pAdvData; |
Vincent Coubard |
0:932f719b42d5 | 109 | size_t index = 0; |
Vincent Coubard |
0:932f719b42d5 | 110 | while(index < params->advertisingDataLen) { |
Vincent Coubard |
0:932f719b42d5 | 111 | pAdvData = (AdvertisingData_t *)¶ms->advertisingData[index]; |
Vincent Coubard |
0:932f719b42d5 | 112 | if (pAdvData->dataType == GapAdvertisingData::SERVICE_DATA) { |
Vincent Coubard |
0:932f719b42d5 | 113 | ApplicationData_t *pAppData = (ApplicationData_t *) pAdvData->data; |
Vincent Coubard |
0:932f719b42d5 | 114 | if (!memcmp(pAppData->applicationSpecificId, BEACON_UUID, sizeof(BEACON_UUID)) && (pAppData->frameType == FRAME_TYPE_URL)) { |
Vincent Coubard |
0:932f719b42d5 | 115 | decodeURI(pAppData->uriData, pAdvData->length - APPLICATION_DATA_OFFSET); |
Vincent Coubard |
0:932f719b42d5 | 116 | break; |
Vincent Coubard |
0:932f719b42d5 | 117 | } |
Vincent Coubard |
0:932f719b42d5 | 118 | } |
Vincent Coubard |
0:932f719b42d5 | 119 | index += (pAdvData->length + 1); |
Vincent Coubard |
0:932f719b42d5 | 120 | } |
Vincent Coubard |
0:932f719b42d5 | 121 | } |
Vincent Coubard |
0:932f719b42d5 | 122 | |
Vincent Coubard |
0:932f719b42d5 | 123 | void onBleInitError(BLE &ble, ble_error_t error) |
Vincent Coubard |
0:932f719b42d5 | 124 | { |
Vincent Coubard |
0:932f719b42d5 | 125 | /* Initialization error handling should go here */ |
Vincent Coubard |
0:932f719b42d5 | 126 | } |
Vincent Coubard |
0:932f719b42d5 | 127 | |
Vincent Coubard |
0:932f719b42d5 | 128 | void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) |
Vincent Coubard |
0:932f719b42d5 | 129 | { |
Vincent Coubard |
0:932f719b42d5 | 130 | BLE& ble = params->ble; |
Vincent Coubard |
0:932f719b42d5 | 131 | ble_error_t error = params->error; |
Vincent Coubard |
0:932f719b42d5 | 132 | |
Vincent Coubard |
0:932f719b42d5 | 133 | if (error != BLE_ERROR_NONE) { |
Vincent Coubard |
0:932f719b42d5 | 134 | onBleInitError(ble, error); |
Vincent Coubard |
0:932f719b42d5 | 135 | return; |
Vincent Coubard |
0:932f719b42d5 | 136 | } |
Vincent Coubard |
0:932f719b42d5 | 137 | |
Vincent Coubard |
0:932f719b42d5 | 138 | if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) { |
Vincent Coubard |
0:932f719b42d5 | 139 | return; |
Vincent Coubard |
0:932f719b42d5 | 140 | } |
Vincent Coubard |
0:932f719b42d5 | 141 | |
Vincent Coubard |
0:932f719b42d5 | 142 | ble.gap().setScanParams(1800 /* scan interval */, 1500 /* scan window */); |
Vincent Coubard |
0:932f719b42d5 | 143 | ble.gap().startScan(advertisementCallback); |
Vincent Coubard |
0:932f719b42d5 | 144 | } |
Vincent Coubard |
0:932f719b42d5 | 145 | |
Vincent Coubard |
0:932f719b42d5 | 146 | void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) { |
Vincent Coubard |
0:932f719b42d5 | 147 | BLE &ble = BLE::Instance(); |
Vincent Coubard |
0:932f719b42d5 | 148 | eventQueue.post(Callback<void()>(&ble, &BLE::processEvents)); |
Vincent Coubard |
0:932f719b42d5 | 149 | } |
Vincent Coubard |
0:932f719b42d5 | 150 | |
Vincent Coubard |
0:932f719b42d5 | 151 | int main() |
Vincent Coubard |
0:932f719b42d5 | 152 | { |
Vincent Coubard |
0:932f719b42d5 | 153 | eventQueue.post_every(periodicCallback, 500); |
Vincent Coubard |
0:932f719b42d5 | 154 | |
Vincent Coubard |
0:932f719b42d5 | 155 | BLE &ble = BLE::Instance(); |
Vincent Coubard |
0:932f719b42d5 | 156 | ble.onEventsToProcess(scheduleBleEventsProcessing); |
Vincent Coubard |
0:932f719b42d5 | 157 | ble.init(bleInitComplete); |
Vincent Coubard |
0:932f719b42d5 | 158 | |
Vincent Coubard |
0:932f719b42d5 | 159 | while (true) { |
Vincent Coubard |
0:932f719b42d5 | 160 | eventQueue.dispatch(); |
Vincent Coubard |
0:932f719b42d5 | 161 | } |
Vincent Coubard |
0:932f719b42d5 | 162 | |
Vincent Coubard |
0:932f719b42d5 | 163 | return 0; |
Vincent Coubard |
0:932f719b42d5 | 164 | } |