├── .gitignore ├── BLE_BatteryLevel ├── img │ ├── connection.png │ ├── discovery.png │ ├── notifications.png │ ├── register_to_notifications.png │ ├── scan_result.png │ └── start_scan.png ├── module.json ├── readme.md └── source │ └── main.cpp ├── BLE_Beacon ├── img │ ├── beacon_details.png │ ├── discovery.png │ └── start_scan.png ├── module.json ├── readme.md └── source │ └── main.cpp ├── BLE_Button ├── img │ ├── button_depressed.png │ ├── button_pressed.png │ ├── connection.png │ ├── discovery.png │ ├── register_to_notifications.png │ ├── scan_results.png │ └── start_scan.png ├── module.json ├── readme.md └── source │ ├── ButtonService.h │ └── main.cpp ├── BLE_EddystoneObserver ├── module.json ├── readme.md └── source │ └── main.cpp ├── BLE_EddystoneService ├── config.json ├── img │ ├── app_start.png │ ├── edit_url.png │ ├── open_configuration.png │ ├── result.png │ └── save_url.png ├── module.json ├── readme.md └── source │ ├── EddystoneService.cpp │ ├── EddystoneService.h │ ├── EddystoneTypes.h │ ├── PersistentStorageHelper │ ├── ConfigParamsPersistence.cpp │ ├── ConfigParamsPersistence.h │ └── nrfPersistentStorageHelper │ │ └── nrfConfigParamsPersistence.cpp │ ├── TLMFrame.cpp │ ├── TLMFrame.h │ ├── UIDFrame.cpp │ ├── UIDFrame.h │ ├── URLFrame.cpp │ ├── URLFrame.h │ └── main.cpp ├── BLE_GAPButton ├── README.md ├── img │ ├── discovery.png │ ├── first_press.png │ ├── initial_state.png │ ├── result.png │ └── start_scan.png ├── module.json └── source │ └── main.cpp ├── BLE_HeartRate ├── img │ ├── connection.png │ ├── discovery.png │ ├── notifications.png │ ├── register_to_notifications.png │ ├── scan_result.png │ └── start_scan.png ├── module.json ├── readme.md └── source │ └── main.cpp ├── BLE_LED ├── img │ ├── LED_OFF.png │ ├── LED_ON.png │ ├── connection.png │ ├── discovery.png │ ├── scan_results.png │ ├── start_scan.png │ ├── write_characteristic.png │ └── write_pannel.png ├── module.json ├── readme.md └── source │ ├── LEDService.h │ └── main.cpp ├── BLE_LEDBlinker ├── module.json ├── readme.md └── source │ └── main.cpp ├── BLE_Thermometer ├── img │ ├── connection.png │ ├── discovery.png │ ├── notifications.png │ ├── register_to_notifications.png │ ├── scan_results.png │ └── start_scan.png ├── module.json ├── readme.md └── source │ └── main.cpp ├── BLE_URIBeacon ├── img │ ├── app_start.png │ ├── edit_url.png │ ├── open_configuration.png │ ├── result.png │ ├── save_url.png │ └── start_scan.png ├── module.json ├── readme.md └── source │ ├── ConfigParamsPersistence.h │ ├── main.cpp │ └── nrfConfigParamsPersistence.cpp ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | 30 | .yotta.json 31 | build/ 32 | yotta_modules/ 33 | yotta_targets/ 34 | .DS_Store 35 | -------------------------------------------------------------------------------- /BLE_BatteryLevel/img/connection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_BatteryLevel/img/connection.png -------------------------------------------------------------------------------- /BLE_BatteryLevel/img/discovery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_BatteryLevel/img/discovery.png -------------------------------------------------------------------------------- /BLE_BatteryLevel/img/notifications.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_BatteryLevel/img/notifications.png -------------------------------------------------------------------------------- /BLE_BatteryLevel/img/register_to_notifications.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_BatteryLevel/img/register_to_notifications.png -------------------------------------------------------------------------------- /BLE_BatteryLevel/img/scan_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_BatteryLevel/img/scan_result.png -------------------------------------------------------------------------------- /BLE_BatteryLevel/img/start_scan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_BatteryLevel/img/start_scan.png -------------------------------------------------------------------------------- /BLE_BatteryLevel/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ble-batterylevel", 3 | "version": "0.0.1", 4 | "description": "An example of creating and updating a simple GATT Service using the BLE_API", 5 | "licenses": [ 6 | { 7 | "url": "https://spdx.org/licenses/Apache-2.0", 8 | "type": "Apache-2.0" 9 | } 10 | ], 11 | "dependencies": { 12 | "ble": "^2.0.0" 13 | }, 14 | "targetDependencies": {}, 15 | "bin": "./source" 16 | } 17 | -------------------------------------------------------------------------------- /BLE_BatteryLevel/readme.md: -------------------------------------------------------------------------------- 1 | This example creates and updates a standard Battery Level service containing a single 2 | GATT characteristic. 3 | 4 | The [battery service transmits](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.battery_service.xml) a device's battery level in percentage, with 100% being a fully charged battery and 0% being a fully drained battery. 5 | 6 | Although the sample application runs on a BLE device, it doesn't show the device's real battery level (because that changes very slowly and will make for a dull example). Instead, it transmits a fake battery level that starts at 50% (half charged). Every half second, it increments the battery level, going in single increments until reaching 100% (as if the battery is charging). It then drops down to 20% to start incrementing again. 7 | 8 | # Running the application 9 | 10 | ## Requirements 11 | 12 | The sample application can be seen on any BLE scanner on a smartphone. If you don't have a scanner on your phone, please install : 13 | 14 | - [nRF Master Control Panel](https://play.google.com/store/apps/details?id=no.nordicsemi.android.mcp) for Android. 15 | 16 | - [LightBlue](https://itunes.apple.com/gb/app/lightblue-bluetooth-low-energy/id557428110?mt=8) for iPhone. 17 | 18 | Hardware requirements are in the [main readme](https://github.com/ARMmbed/ble-examples/blob/master/README.md). 19 | 20 | ## Building instructions 21 | 22 | Building instructions for all samples are in the [main readme](https://github.com/ARMmbed/ble-examples/blob/master/README.md). 23 | 24 | ## Checking for success 25 | 26 | **Note:** Screens captures depicted below show what is expected from this example if the scanner used is *nRF Master Control Panel* version 4.0.5. If you encounter any difficulties consider trying another scanner or another version of nRF Master Control Panel. Alternative scanners may require reference to their manuals. 27 | 28 | 1. Build the application and install it on your board as explained in the building instructions. 29 | 1. Open the BLE scanner on your phone. 30 | 1. Start a scan. 31 | 32 | ![](img/start_scan.png) 33 | 34 | **figure 1** How to start scan using nRF Master Control Panel 4.0.5 35 | 36 | 1. Find your device; it should be named `BATTERY`. 37 | 38 | ![](img/scan_result.png) 39 | 40 | **figure 2** Scan results using nRF Master Control Panel 4.0.5 41 | 42 | 1. Establish a connection with your device. 43 | 44 | ![](img/connection.png) 45 | 46 | **figure 3** How to establish a connection using Master Control Panel 4.0.5 47 | 48 | 1. Discover the services and the characteristics on the device. The *Battery service* has the UUID 0x180F and includes the *Battery level* characteristic which has the UUID 0x2A19. 49 | 50 | ![](img/discovery.png) 51 | 52 | **figure 4** Representation of the Battery service using Master Control Panel 4.0.5 53 | 54 | 1. Register for the notifications sent by the *Battery level* characteristic. 55 | 56 | ![](img/register_to_notifications.png) 57 | 58 | **figure 5** How to register to notifications using Master Control Panel 4.0.5 59 | 60 | 61 | 1. You should see the battery level value change every half second. It begins at 50, goes up to 100 (in steps of 1), resets to 20 and so on. 62 | 63 | ![](img/notifications.png) 64 | 65 | **figure 6** Notifications view using Master Control Panel 4.0.5 66 | 67 | If you can see the characteristic, and if its value is incrementing correctly, the application is working properly. 68 | 69 | -------------------------------------------------------------------------------- /BLE_BatteryLevel/source/main.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2014 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "mbed-drivers/mbed.h" 18 | #include "ble/BLE.h" 19 | #include "ble/Gap.h" 20 | #include "ble/services/BatteryService.h" 21 | 22 | DigitalOut led1(LED1, 1); 23 | 24 | const static char DEVICE_NAME[] = "BATTERY"; 25 | static const uint16_t uuid16_list[] = {GattService::UUID_BATTERY_SERVICE}; 26 | 27 | static uint8_t batteryLevel = 50; 28 | static BatteryService* batteryServicePtr; 29 | 30 | void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) 31 | { 32 | BLE::Instance().gap().startAdvertising(); 33 | } 34 | 35 | void updateSensorValue() { 36 | batteryLevel++; 37 | if (batteryLevel > 100) { 38 | batteryLevel = 20; 39 | } 40 | 41 | batteryServicePtr->updateBatteryLevel(batteryLevel); 42 | } 43 | 44 | void blinkCallback(void) 45 | { 46 | led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */ 47 | 48 | BLE &ble = BLE::Instance(); 49 | if (ble.gap().getState().connected) { 50 | minar::Scheduler::postCallback(updateSensorValue); 51 | } 52 | } 53 | 54 | /** 55 | * This function is called when the ble initialization process has failled 56 | */ 57 | void onBleInitError(BLE &ble, ble_error_t error) 58 | { 59 | /* Initialization error handling should go here */ 60 | } 61 | 62 | /** 63 | * Callback triggered when the ble initialization process has finished 64 | */ 65 | void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) 66 | { 67 | BLE& ble = params->ble; 68 | ble_error_t error = params->error; 69 | 70 | if (error != BLE_ERROR_NONE) { 71 | /* In case of error, forward the error handling to onBleInitError */ 72 | onBleInitError(ble, error); 73 | return; 74 | } 75 | 76 | /* Ensure that it is the default instance of BLE */ 77 | if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) { 78 | return; 79 | } 80 | 81 | ble.gap().onDisconnection(disconnectionCallback); 82 | 83 | /* Setup primary service */ 84 | batteryServicePtr = new BatteryService(ble, batteryLevel); 85 | 86 | /* Setup advertising */ 87 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); 88 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *) uuid16_list, sizeof(uuid16_list)); 89 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *) DEVICE_NAME, sizeof(DEVICE_NAME)); 90 | ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); 91 | ble.gap().setAdvertisingInterval(1000); /* 1000ms */ 92 | ble.gap().startAdvertising(); 93 | } 94 | 95 | void app_start(int, char**) 96 | { 97 | minar::Scheduler::postCallback(blinkCallback).period(minar::milliseconds(500)); 98 | 99 | BLE &ble = BLE::Instance(); 100 | ble.init(bleInitComplete); 101 | } 102 | -------------------------------------------------------------------------------- /BLE_Beacon/img/beacon_details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_Beacon/img/beacon_details.png -------------------------------------------------------------------------------- /BLE_Beacon/img/discovery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_Beacon/img/discovery.png -------------------------------------------------------------------------------- /BLE_Beacon/img/start_scan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_Beacon/img/start_scan.png -------------------------------------------------------------------------------- /BLE_Beacon/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ble-beacon", 3 | "version": "0.0.1", 4 | "description": "BLE iBeacon example, building with yotta", 5 | "licenses": [ 6 | { 7 | "url": "https://spdx.org/licenses/Apache-2.0", 8 | "type": "Apache-2.0" 9 | } 10 | ], 11 | "dependencies": { 12 | "ble": "^2.0.0" 13 | }, 14 | "targetDependencies": {}, 15 | "bin": "./source" 16 | } 17 | -------------------------------------------------------------------------------- /BLE_Beacon/readme.md: -------------------------------------------------------------------------------- 1 | This example creates a BLE beacon: a method of advertising a small amount of information to nearby devices. The information doesn't have to be human-readable; it can be in a format that only an application can use. 2 | 3 | Beacons are very easy to set up: the code for all beacons is the same, and only the information you want to advertise - the beacon payload - needs to change. 4 | 5 | This example advertises a UUID, a major and minor number and the transmission strength. The major and minor numbers are an example of information that is not (normally) meaningful to humans, but that an application can use to identify the beacon and display related information. For example, if the major number is a store ID and the minor number is a location in that store, then a matching application can use these numbers to query a database and display location-specific information. 6 | 7 | # Running the application 8 | 9 | ## Requirements 10 | 11 | The sample application can be seen on any BLE scanner on a smartphone. If you don't have a scanner on your phone, please install : 12 | 13 | - [nRF Master Control Panel](https://play.google.com/store/apps/details?id=no.nordicsemi.android.mcp) for Android. 14 | 15 | - [LightBlue](https://itunes.apple.com/gb/app/lightblue-bluetooth-low-energy/id557428110?mt=8) for iPhone. 16 | 17 | Hardware requirements are in the [main readme](https://github.com/ARMmbed/ble-examples/blob/master/README.md). 18 | 19 | ## Building instructions 20 | 21 | Building instructions for all samples are in the [main readme](https://github.com/ARMmbed/ble-examples/blob/master/README.md). 22 | 23 | ## Checking for success 24 | 25 | **Note:** Screens captures depicted below show what is expected from this example if the scanner used is *nRF Master Control Panel* version 4.0.5. If you encounter any difficulties consider trying another scanner or another version of nRF Master Control Panel. Alternative scanners may require reference to their manuals. 26 | 27 | 1. Build the application and install it on your board as explained in the building instructions. 28 | 1. Open the BLE scanner on your phone. 29 | 1. Start a scan. 30 | 31 | ![](img/start_scan.png) 32 | 33 | **figure 1** How to start scan using nRF Master Control Panel 4.0.5 34 | 35 | 1. Find your device; it should be tagged as an `iBeacon` and observe its advertisements (there is no need to connect to the beacon). 36 | 37 | ![](img/discovery.png) 38 | 39 | **figure 2** Scan results using nRF Master Control Panel 4.0.5 40 | 41 | 1. View the beacon's details; the exact steps depend on which scanner you're using. 42 | 43 | ![](img/beacon_details.png) 44 | 45 | **figure 3** Beacon details using nRF Master Control Panel 4.0.5 46 | 47 | 48 | **Tip:** If you are in an area with many BLE devices, it may be difficult to identify your beacon. The simplest solution is to turn your board off and on, initiate a new scan on your BLE scanner every time, and look for the beacon that appears only when your board is on. 49 | 50 | If you can see the beacon and all its information, the application worked properly. 51 | 52 | For more information, see the [mbed Classic version of this application](https://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_iBeacon/). 53 | -------------------------------------------------------------------------------- /BLE_Beacon/source/main.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "mbed-drivers/mbed.h" 18 | #include "ble/BLE.h" 19 | #include "ble/services/iBeacon.h" 20 | 21 | static iBeacon* ibeaconPtr; 22 | 23 | /** 24 | * This function is called when the ble initialization process has failled 25 | */ 26 | void onBleInitError(BLE &ble, ble_error_t error) 27 | { 28 | /* Initialization error handling should go here */ 29 | } 30 | 31 | /** 32 | * Callback triggered when the ble initialization process has finished 33 | */ 34 | void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) 35 | { 36 | BLE& ble = params->ble; 37 | ble_error_t error = params->error; 38 | 39 | if (error != BLE_ERROR_NONE) { 40 | /* In case of error, forward the error handling to onBleInitError */ 41 | onBleInitError(ble, error); 42 | return; 43 | } 44 | 45 | /* Ensure that it is the default instance of BLE */ 46 | if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) { 47 | return; 48 | } 49 | 50 | /** 51 | * The Beacon payload has the following composition: 52 | * 128-Bit / 16byte UUID = E2 0A 39 F4 73 F5 4B C4 A1 2F 17 D1 AD 07 A9 61 53 | * Major/Minor = 0x1122 / 0x3344 54 | * Tx Power = 0xC8 = 200, 2's compliment is 256-200 = (-56dB) 55 | * 56 | * Note: please remember to calibrate your beacons TX Power for more accurate results. 57 | */ 58 | static const uint8_t uuid[] = {0xE2, 0x0A, 0x39, 0xF4, 0x73, 0xF5, 0x4B, 0xC4, 59 | 0xA1, 0x2F, 0x17, 0xD1, 0xAD, 0x07, 0xA9, 0x61}; 60 | uint16_t majorNumber = 1122; 61 | uint16_t minorNumber = 3344; 62 | uint16_t txPower = 0xC8; 63 | ibeaconPtr = new iBeacon(ble, uuid, majorNumber, minorNumber, txPower); 64 | 65 | ble.gap().setAdvertisingInterval(1000); /* 1000ms. */ 66 | ble.gap().startAdvertising(); 67 | } 68 | 69 | void app_start(int, char**) 70 | { 71 | BLE &ble = BLE::Instance(); 72 | ble.init(bleInitComplete); 73 | } 74 | -------------------------------------------------------------------------------- /BLE_Button/img/button_depressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_Button/img/button_depressed.png -------------------------------------------------------------------------------- /BLE_Button/img/button_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_Button/img/button_pressed.png -------------------------------------------------------------------------------- /BLE_Button/img/connection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_Button/img/connection.png -------------------------------------------------------------------------------- /BLE_Button/img/discovery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_Button/img/discovery.png -------------------------------------------------------------------------------- /BLE_Button/img/register_to_notifications.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_Button/img/register_to_notifications.png -------------------------------------------------------------------------------- /BLE_Button/img/scan_results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_Button/img/scan_results.png -------------------------------------------------------------------------------- /BLE_Button/img/start_scan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_Button/img/start_scan.png -------------------------------------------------------------------------------- /BLE_Button/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ble-button", 3 | "version": "0.0.1", 4 | "description": "The *input service template* demonstrates the use of a simple input (boolean values) from a read-only characteristic.", 5 | "licenses": [ 6 | { 7 | "url": "https://spdx.org/licenses/Apache-2.0", 8 | "type": "Apache-2.0" 9 | } 10 | ], 11 | "bin": "./source", 12 | "dependencies": { 13 | "ble": "^2.0.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /BLE_Button/readme.md: -------------------------------------------------------------------------------- 1 | BLE_Button is a BLE service template. It handles a read-only characteristic with a simple input (boolean values). The input's source is the button on the board itself - the characteristic's value changes when the button is pressed or released. 2 | 3 | The template covers: 4 | 5 | 1. Setting up advertising and connection modes. 6 | 7 | 1. Creating an input characteristic: read-only, boolean, with notifications. 8 | 9 | 1. Constructing a service class and adding it to the BLE stack. 10 | 11 | 1. Assigning UUIDs to the service and its characteristic. 12 | 13 | 1. Pushing notifications when the characteristic's value changes. 14 | 15 | # Running the application 16 | 17 | ## Requirements 18 | 19 | The sample application can be seen on any BLE scanner on a smartphone. If you don't have a scanner on your phone, please install : 20 | 21 | - [nRF Master Control Panel](https://play.google.com/store/apps/details?id=no.nordicsemi.android.mcp) for Android. 22 | 23 | - [LightBlue](https://itunes.apple.com/gb/app/lightblue-bluetooth-low-energy/id557428110?mt=8) for iPhone. 24 | 25 | Hardware requirements are in the [main readme](https://github.com/ARMmbed/ble-examples/blob/master/README.md). 26 | 27 | ## Building instructions 28 | 29 | Building instructions for all samples are in the [main readme](https://github.com/ARMmbed/ble-examples/blob/master/README.md). 30 | 31 | ## Checking for success 32 | 33 | **Note:** Screens captures depicted below show what is expected from this example if the scanner used is *nRF Master Control Panel* version 4.0.5. If you encounter any difficulties consider trying another scanner or another version of nRF Master Control Panel. Alternative scanners may require reference to their manuals. 34 | 35 | 1. Build the application and install it on your board as explained in the building instructions. 36 | 1. Open the BLE scanner on your phone. 37 | 1. Start a scan. 38 | 39 | ![](img/start_scan.png) 40 | 41 | **figure 1** How to start scan using nRF Master Control Panel 4.0.5 42 | 43 | 1. Find your device; it should appear with the name `Button` in the scanner. 44 | 45 | ![](img/scan_results.png) 46 | 47 | **figure 2** Scan results using nRF Master Control Panel 4.0.5 48 | 49 | 1. Establish a connection with the device. 50 | 51 | ![](img/connection.png) 52 | 53 | **figure 3** How to establish a connection using Master Control Panel 4.0.5 54 | 55 | 1. Discover the services and the characteristics on the device. The *Button service* has the UUID `0xA000` and includes the *Button state characteristic* which has the UUID `0xA001`. Depending on your scanner, non standard 16-bit UUID's can be displayed as 128-bit UUID's. If it is the case the following format will be used: `0000XXXX-0000-1000-8000-00805F9B34FB` where `XXXX` is the hexadecimal representation of the 16-bit UUID value. 56 | 57 | ![](img/discovery.png) 58 | 59 | **figure 4** Representation of the Button service using Master Control Panel 4.0.5 60 | 61 | 1. Register for the notifications sent by the button state characteristic then the scanner will automatically receive a notification containing the new state of the button every time the state of the button changes. 62 | 63 | ![](img/register_to_notifications.png) 64 | 65 | **figure 5** How to register to notifications using Master Control Panel 4.0.5 66 | 67 | 68 | 1. Pressing Button 1 on your board updates the state of the button and sends a notification to the scanner. The new state of the button characteristic value should be equal to 0x01. 69 | 70 | ![](img/button_pressed.png) 71 | 72 | **figure 6** Notification of button pressed using Master Control Panel 4.0.5 73 | 74 | 1. Releasing Button 1 on your board updates the state of the button and sends a notification to the scanner. The new state of the button characteristic value should be equal to 0x00. 75 | 76 | ![](img/button_depressed.png) 77 | 78 | **figure 7** Notification of button depressed using Master Control Panel 4.0.5 79 | 80 | -------------------------------------------------------------------------------- /BLE_Button/source/ButtonService.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __BLE_BUTTON_SERVICE_H__ 18 | #define __BLE_BUTTON_SERVICE_H__ 19 | 20 | class ButtonService { 21 | public: 22 | const static uint16_t BUTTON_SERVICE_UUID = 0xA000; 23 | const static uint16_t BUTTON_STATE_CHARACTERISTIC_UUID = 0xA001; 24 | 25 | ButtonService(BLE &_ble, bool buttonPressedInitial) : 26 | ble(_ble), buttonState(BUTTON_STATE_CHARACTERISTIC_UUID, &buttonPressedInitial, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) 27 | { 28 | GattCharacteristic *charTable[] = {&buttonState}; 29 | GattService buttonService(ButtonService::BUTTON_SERVICE_UUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *)); 30 | ble.gattServer().addService(buttonService); 31 | } 32 | 33 | void updateButtonState(bool newState) { 34 | ble.gattServer().write(buttonState.getValueHandle(), (uint8_t *)&newState, sizeof(bool)); 35 | } 36 | 37 | private: 38 | BLE &ble; 39 | ReadOnlyGattCharacteristic buttonState; 40 | }; 41 | 42 | #endif /* #ifndef __BLE_BUTTON_SERVICE_H__ */ 43 | -------------------------------------------------------------------------------- /BLE_Button/source/main.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "mbed-drivers/mbed.h" 18 | #include "ble/BLE.h" 19 | #include "ble/Gap.h" 20 | #include "ButtonService.h" 21 | 22 | DigitalOut led1(LED1, 1); 23 | InterruptIn button(BUTTON1); 24 | 25 | const static char DEVICE_NAME[] = "Button"; 26 | static const uint16_t uuid16_list[] = {ButtonService::BUTTON_SERVICE_UUID}; 27 | 28 | ButtonService *buttonServicePtr; 29 | 30 | void buttonPressedCallback(void) 31 | { 32 | minar::Scheduler::postCallback(mbed::util::FunctionPointer1(buttonServicePtr, &ButtonService::updateButtonState).bind(true)); 33 | } 34 | 35 | void buttonReleasedCallback(void) 36 | { 37 | minar::Scheduler::postCallback(mbed::util::FunctionPointer1(buttonServicePtr, &ButtonService::updateButtonState).bind(false)); 38 | } 39 | 40 | void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) 41 | { 42 | BLE::Instance().gap().startAdvertising(); // restart advertising 43 | } 44 | 45 | void blinkCallback(void) 46 | { 47 | led1 = !led1; /* Do blinky on LED1 to indicate system aliveness. */ 48 | } 49 | 50 | void onBleInitError(BLE &ble, ble_error_t error) 51 | { 52 | /* Initialization error handling should go here */ 53 | } 54 | 55 | void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) 56 | { 57 | BLE& ble = params->ble; 58 | ble_error_t error = params->error; 59 | 60 | if (error != BLE_ERROR_NONE) { 61 | /* In case of error, forward the error handling to onBleInitError */ 62 | onBleInitError(ble, error); 63 | return; 64 | } 65 | 66 | /* Ensure that it is the default instance of BLE */ 67 | if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) { 68 | return; 69 | } 70 | 71 | ble.gap().onDisconnection(disconnectionCallback); 72 | 73 | button.fall(buttonPressedCallback); 74 | button.rise(buttonReleasedCallback); 75 | 76 | /* Setup primary service. */ 77 | buttonServicePtr = new ButtonService(ble, false /* initial value for button pressed */); 78 | 79 | /* setup advertising */ 80 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); 81 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); 82 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); 83 | ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); 84 | ble.gap().setAdvertisingInterval(1000); /* 1000ms. */ 85 | ble.gap().startAdvertising(); 86 | } 87 | 88 | void app_start(int, char**) 89 | { 90 | minar::Scheduler::postCallback(blinkCallback).period(minar::milliseconds(500)); 91 | 92 | BLE &ble = BLE::Instance(); 93 | ble.init(bleInitComplete); 94 | } 95 | -------------------------------------------------------------------------------- /BLE_EddystoneObserver/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ble-eddystoneobserver", 3 | "version": "0.0.1", 4 | "description": "BLE EddystoneObserver example, building with yotta", 5 | "licenses": [ 6 | { 7 | "url": "https://spdx.org/licenses/Apache-2.0", 8 | "type": "Apache-2.0" 9 | } 10 | ], 11 | "dependencies": { 12 | "ble": "^2.0.0" 13 | }, 14 | "targetDependencies": {}, 15 | "bin": "./source" 16 | } 17 | -------------------------------------------------------------------------------- /BLE_EddystoneObserver/readme.md: -------------------------------------------------------------------------------- 1 | The Eddystone Observer scans for Eddystone beacons that are running the [Eddystone Service example](https://github.com/ARMmbed/ble-examples/tree/master/BLE_EddystoneService) (see there for general information about Eddystone beacons). It reads the advertising packets broadcast by these beacons, and prints a human-readable version of the advertised URLs to the serial console. 2 | 3 | # Running the application 4 | 5 | ## Requirements 6 | 7 | General hardware information is in the [main readme](https://github.com/ARMmbed/ble-examples/blob/master/README.md). 8 | 9 | This sample requires two devices - one to [broadcast the beacon](https://github.com/ARMmbed/ble-examples/tree/master/BLE_EddystoneService) and one to scan for the broadcast. If you have more devices, you can use them as extra beacons. 10 | 11 | You need a terminal program to listen to the observer's output through a serial port. You can download one, for example: 12 | 13 | * Tera Term for Windows. 14 | 15 | * CoolTerm for Mac OS X. 16 | 17 | * GNU Screen for Linux. 18 | 19 | ## Building instructions 20 | 21 | Building instructions for all samples are in the [main readme](https://github.com/ARMmbed/ble-examples/blob/master/README.md). 22 | 23 | 1. Build and run the [Eddystone beacon](https://github.com/ARMmbed/ble-examples/tree/master/BLE_EddystoneService) on one or more other devices. 24 | 25 | 1. Build the Eddystone Observer application and install it on your board as explained in the building instructions. Leave the board connected to your computer. 26 | 27 | ## Checking console output 28 | 29 | To see the application's output: 30 | 31 | 1. Check which serial port your Eddystone Observer is connected to. 32 | 33 | 1. Run a terminal program with the correct serial port and the baud rate set to 9600. For example, to use GNU Screen, run: ``screen /dev/tty.usbmodem1412 9600``. 34 | 35 | 1. The Eddystone Observer should start printing URLs of nearby Eddystone beacons to the terminal. 36 | -------------------------------------------------------------------------------- /BLE_EddystoneObserver/source/main.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "mbed.h" 18 | #include "ble/BLE.h" 19 | 20 | static const int URI_MAX_LENGTH = 18; // Maximum size of service data in ADV packets 21 | 22 | DigitalOut led1(LED1, 1); 23 | 24 | void periodicCallback(void) 25 | { 26 | led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */ 27 | } 28 | 29 | void decodeURI(const uint8_t* uriData, const size_t uriLen) 30 | { 31 | const char *prefixes[] = { 32 | "http://www.", 33 | "https://www.", 34 | "http://", 35 | "https://", 36 | "urn:uuid:" 37 | }; 38 | const size_t NUM_PREFIXES = sizeof(prefixes) / sizeof(char *); 39 | const char *suffixes[] = { 40 | ".com/", 41 | ".org/", 42 | ".edu/", 43 | ".net/", 44 | ".info/", 45 | ".biz/", 46 | ".gov/", 47 | ".com", 48 | ".org", 49 | ".edu", 50 | ".net", 51 | ".info", 52 | ".biz", 53 | ".gov" 54 | }; 55 | const size_t NUM_SUFFIXES = sizeof(suffixes) / sizeof(char *); 56 | 57 | size_t index = 0; 58 | 59 | /* First byte is the URL Scheme. */ 60 | if (uriData[index] < NUM_PREFIXES) { 61 | printf("%s", prefixes[uriData[index]]); 62 | index++; 63 | } else { 64 | printf("URL Scheme was not encoded!"); 65 | return; 66 | } 67 | 68 | /* From second byte onwards we can have a character or a suffix */ 69 | while(index < uriLen) { 70 | if (uriData[index] < NUM_SUFFIXES) { 71 | printf("%s", suffixes[uriData[index]]); 72 | } else { 73 | printf("%c", uriData[index]); 74 | } 75 | index++; 76 | } 77 | 78 | printf("\n\r"); 79 | } 80 | 81 | /* 82 | * This function is called every time we scan an advertisement. 83 | */ 84 | void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params) 85 | { 86 | struct AdvertisingData_t { 87 | uint8_t length; /* doesn't include itself */ 88 | GapAdvertisingData::DataType_t dataType; 89 | uint8_t data[0]; 90 | } AdvDataPacket; 91 | 92 | struct ApplicationData_t { 93 | uint8_t applicationSpecificId[2]; 94 | uint8_t frameType; 95 | uint8_t advPowerLevels; 96 | uint8_t uriData[URI_MAX_LENGTH]; 97 | } AppDataPacket; 98 | 99 | const uint8_t BEACON_UUID[sizeof(UUID::ShortUUIDBytes_t)] = {0xAA, 0xFE}; 100 | const uint8_t FRAME_TYPE_URL = 0x10; 101 | const uint8_t APPLICATION_DATA_OFFSET = sizeof(ApplicationData_t) + sizeof(AdvDataPacket.dataType) - sizeof(AppDataPacket.uriData); 102 | 103 | AdvertisingData_t *pAdvData; 104 | size_t index = 0; 105 | while(index < params->advertisingDataLen) { 106 | pAdvData = (AdvertisingData_t *)¶ms->advertisingData[index]; 107 | if (pAdvData->dataType == GapAdvertisingData::SERVICE_DATA) { 108 | ApplicationData_t *pAppData = (ApplicationData_t *) pAdvData->data; 109 | if (!memcmp(pAppData->applicationSpecificId, BEACON_UUID, sizeof(BEACON_UUID)) && (pAppData->frameType == FRAME_TYPE_URL)) { 110 | decodeURI(pAppData->uriData, pAdvData->length - APPLICATION_DATA_OFFSET); 111 | break; 112 | } 113 | } 114 | index += (pAdvData->length + 1); 115 | } 116 | } 117 | 118 | void onBleInitError(BLE &ble, ble_error_t error) 119 | { 120 | /* Initialization error handling should go here */ 121 | } 122 | 123 | void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) 124 | { 125 | BLE& ble = params->ble; 126 | ble_error_t error = params->error; 127 | 128 | if (error != BLE_ERROR_NONE) { 129 | onBleInitError(ble, error); 130 | return; 131 | } 132 | 133 | if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) { 134 | return; 135 | } 136 | 137 | ble.gap().setScanParams(1800 /* scan interval */, 1500 /* scan window */); 138 | ble.gap().startScan(advertisementCallback); 139 | } 140 | 141 | void app_start(int, char *[]) 142 | { 143 | minar::Scheduler::postCallback(periodicCallback).period(minar::milliseconds(500)); 144 | 145 | BLE::Instance().init(bleInitComplete); 146 | } 147 | -------------------------------------------------------------------------------- /BLE_EddystoneService/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "nordic": { 3 | "softdevice": "S130" 4 | }, 5 | "mbed": { 6 | "max-filehandles": 4 7 | }, 8 | "eddystone": { 9 | "default-device-name": "\"EDDYSTONE CONFIG\"", 10 | "default-url": "\"https://www.mbed.com/\"", 11 | "default-url-frame-interval": 700, 12 | "default-uid-frame-interval": 300, 13 | "default-tlm-frame-interval": 2000, 14 | "default-eddystone-url-config-adv-interval": 1000 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /BLE_EddystoneService/img/app_start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_EddystoneService/img/app_start.png -------------------------------------------------------------------------------- /BLE_EddystoneService/img/edit_url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_EddystoneService/img/edit_url.png -------------------------------------------------------------------------------- /BLE_EddystoneService/img/open_configuration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_EddystoneService/img/open_configuration.png -------------------------------------------------------------------------------- /BLE_EddystoneService/img/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_EddystoneService/img/result.png -------------------------------------------------------------------------------- /BLE_EddystoneService/img/save_url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_EddystoneService/img/save_url.png -------------------------------------------------------------------------------- /BLE_EddystoneService/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ble-eddystoneservice", 3 | "version": "0.0.1", 4 | "description": "This example demonstrates how to set up and initialize a Eddystone Beacon.", 5 | "licenses": [ 6 | { 7 | "url": "https://spdx.org/licenses/Apache-2.0", 8 | "type": "Apache-2.0" 9 | } 10 | ], 11 | "dependencies": { 12 | "ble": "^2.0.0" 13 | }, 14 | "targetDependencies": {}, 15 | "bin": "./source" 16 | } 17 | -------------------------------------------------------------------------------- /BLE_EddystoneService/readme.md: -------------------------------------------------------------------------------- 1 | Eddystone beacons broadcast a small amount of information, like URLs, to nearby BLE devices. 2 | 3 | The Eddystone Beacon sample application runs in two stages: 4 | 5 | 1. On startup, the Configuration Service (which allows [modification of the beacon](https://github.com/google/eddystone/blob/master/eddystone-url/docs/config-service-spec.md)) runs for a user-defined period (default - 30 seconds). 6 | 7 | 1. When the Configuration Service period ends, the Eddystone Service broadcasts advertisement packets. 8 | 9 | 10 | 11 | # Running the application 12 | 13 | ## Requirements 14 | 15 | You should install the *Physical Web* application on your phone: 16 | 17 | - [Android version](https://play.google.com/store/apps/details?id=physical_web.org.physicalweb) 18 | 19 | - [iOS version](https://itunes.apple.com/us/app/physical-web/id927653608?mt=8) 20 | 21 | 22 | **Note:** It is also possible to use a regular scanner to interract with your Eddystone beacon but it requires 23 | knowledge about BLE and Eddystone beacon specification out of the scope of this document. 24 | 25 | 26 | Hardware requirements are in the [main readme](https://github.com/ARMmbed/ble-examples/blob/master/README.md). 27 | 28 | ## Building instructions 29 | 30 | Building instructions for all samples are in the [main readme](https://github.com/ARMmbed/ble-examples/blob/master/README.md). 31 | 32 | ### Working with nRF51-based 16K targets 33 | 34 | Because of memory constraints, you can't use the SoftDevice 130 (S130) to build for nRF51-based 16K targets. If you are using these targets, then before building: 35 | 36 | 1. Open the ``config.json`` file in this sample. 37 | 1. Change ``soft device`` to ``S110``. 38 | 1. Save. 39 | 40 | You can now build for nRF51-based 16K targets. 41 | 42 | ## Setting up the beacon 43 | 44 | By default, the beacon directs to the url ``http://mbed.org``. You can change this to your own URL in two ways: 45 | 46 | 1. Manually edit the code in ``main.cpp`` in your copy of the sample. 47 | 48 | 1. Build and run the application's default code as explained in the building instructions. When the beacon starts up, the Configuration Service runs for 30 seconds (this is the default value; you can change it in ``main.cpp``). While the Configuration Service runs, you can use a BLE scanner on your phone to edit the values the service presents. 49 | 50 | ## Checking for success 51 | 52 | 1. Build the application and install it on your board as explained in the building instructions. 53 | 54 | 1. Open the *Physical Web* application on your phone. It will start to search for nearby beacons. 55 | 56 | ![](img/app_start.png) 57 | 58 | **figure 1** Start of the *Physical Web* application version 0.1.856 on Android 59 | 60 | 1. When the beacon starts up, the Configuration Service runs for 30 seconds. 61 | During this time it is possible to change the URL advertised by the beacon. 62 | It is also important to note that during these 30 seconds, your device will not advertise any URL. 63 | 64 | ![](img/open_configuration.png) 65 | 66 | **figure 2** How to open the beacon configuration view using the *Physical Web* application version 0.1.856 on Android 67 | 68 | 69 | 1. Edit the URL advertised by your beacon. 70 | 71 | ![](img/edit_url.png) 72 | 73 | **figure 3** How to edit the URL advertised by your beacon using the *Physical Web* application version 0.1.856 on Android 74 | 75 | 76 | 1. Save the URL which will be advertised by your beacon. 77 | 78 | ![](img/save_url.png) 79 | 80 | **figure 4** How to save your beacon configuration and start advertising URL using the *Physical Web* application version 0.1.856 on Android. 81 | 82 | 83 | 1. Find your device; it should advertise the URL you have set. 84 | 85 | ![](img/result.png) 86 | 87 | **figure 5** Display of URL advertised by your beacon using the *Physical Web* application version 0.1.856 on Android. 88 | 89 | 90 | **Note:** You can use the [Eddystone Observer](https://github.com/ARMmbed/ble-examples/tree/master/BLE_EddystoneObserver) sample instead of a phone application. 91 | -------------------------------------------------------------------------------- /BLE_EddystoneService/source/EddystoneService.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __EDDYSTONESERVICE_H__ 18 | #define __EDDYSTONESERVICE_H__ 19 | 20 | #include "ble/BLE.h" 21 | #include "EddystoneTypes.h" 22 | #include "URLFrame.h" 23 | #include "UIDFrame.h" 24 | #include "TLMFrame.h" 25 | #include 26 | #ifdef YOTTA_CFG_MBED_OS 27 | #include "mbed-drivers/mbed.h" 28 | #include "mbed-drivers/CircularBuffer.h" 29 | #else 30 | #include "mbed.h" 31 | #include "CircularBuffer.h" 32 | #endif 33 | 34 | #ifndef YOTTA_CFG_EDDYSTONE_DEFAULT_URL_FRAME_INTERVAL 35 | #define YOTTA_CFG_EDDYSTONE_DEFAULT_URL_FRAME_INTERVAL 700 36 | #endif 37 | 38 | #ifndef YOTTA_CFG_EDDYSTONE_DEFAULT_UID_FRAME_INTERVAL 39 | #define YOTTA_CFG_EDDYSTONE_DEFAULT_UID_FRAME_INTERVAL 300 40 | #endif 41 | 42 | #ifndef YOTTA_CFG_EDDYSTONE_DEFAULT_TLM_FRAME_INTERVAL 43 | #define YOTTA_CFG_EDDYSTONE_DEFAULT_TLM_FRAME_INTERVAL 2000 44 | #endif 45 | 46 | #ifndef YOTTA_CFG_EDDYSTONE_DEFAULT_EDDYSTONE_URL_CONFIG_ADV_INTERVAL 47 | #define YOTTA_CFG_EDDYSTONE_DEFAULT_EDDYSTONE_URL_CONFIG_ADV_INTERVAL 1000 48 | #endif 49 | 50 | /** 51 | * This class implements the Eddystone-URL Config Service and the Eddystone 52 | * Protocol Specification as defined in the publicly available specification at 53 | * https://github.com/google/eddystone/blob/master/protocol-specification.md. 54 | */ 55 | class EddystoneService 56 | { 57 | public: 58 | /** 59 | * Total number of GATT Characteristics in the Eddystonei-URL Configuration 60 | * Service. 61 | */ 62 | static const uint16_t TOTAL_CHARACTERISTICS = 9; 63 | 64 | /** 65 | * Default interval for advertising packets for the Eddystone-URL 66 | * Configuration Service. 67 | */ 68 | static const uint32_t DEFAULT_CONFIG_PERIOD_MSEC = YOTTA_CFG_EDDYSTONE_DEFAULT_EDDYSTONE_URL_CONFIG_ADV_INTERVAL; 69 | /** 70 | * Recommended interval for advertising packets containing Eddystone URL 71 | * frames. 72 | */ 73 | static const uint16_t DEFAULT_URL_FRAME_PERIOD_MSEC = YOTTA_CFG_EDDYSTONE_DEFAULT_URL_FRAME_INTERVAL; 74 | /** 75 | * Recommended interval for advertising packets containing Eddystone UID 76 | * frames. 77 | */ 78 | static const uint16_t DEFAULT_UID_FRAME_PERIOD_MSEC = YOTTA_CFG_EDDYSTONE_DEFAULT_UID_FRAME_INTERVAL; 79 | /** 80 | * Recommended interval for advertising packets containing Eddystone TLM 81 | * frames. 82 | */ 83 | static const uint16_t DEFAULT_TLM_FRAME_PERIOD_MSEC = YOTTA_CFG_EDDYSTONE_DEFAULT_TLM_FRAME_INTERVAL; 84 | 85 | /** 86 | * Enumeration that defines the various operation modes of the 87 | * EddystoneService. 88 | * 89 | * @note The main app can change the mode of EddystoneService at any point 90 | * of time by calling startConfigService() or startBeaconService(). 91 | * Resources from the previous mode will be freed. 92 | * 93 | * @note It is currently NOT possible to force EddystoneService back into 94 | * EDDYSTONE_MODE_NONE. 95 | */ 96 | enum OperationModes { 97 | /** 98 | * NONE: EddystoneService has been initialized but no memory has been 99 | * dynamically allocated. Additionally, no services are running 100 | * nothing is being advertised. 101 | */ 102 | EDDYSTONE_MODE_NONE, 103 | /** 104 | * CONFIG: EddystoneService has been initialized, the configuration 105 | * service started and memory has been allocated for BLE 106 | * characteristics. Memory consumption peaks during CONFIG 107 | * mode. 108 | */ 109 | EDDYSTONE_MODE_CONFIG, 110 | /** 111 | * BEACON: Eddystone service is running as a beacon advertising URL, 112 | * UID and/or TLM frames depending on how it is configured. 113 | */ 114 | EDDYSTONE_MODE_BEACON 115 | }; 116 | 117 | /** 118 | * Structure that encapsulates the Eddystone configuration parameters. This 119 | * structure is particularly useful when storing the parameters to 120 | * persistent storage. 121 | */ 122 | struct EddystoneParams_t { 123 | /** 124 | * The value of the Eddystone-URL Configuration Service Lock State 125 | * characteristic. 126 | */ 127 | bool lockState; 128 | /** 129 | * The value of the Eddystone-URL Configuration Service Lock 130 | * characteristic that can be used to lock the beacon and set the 131 | * single-use lock-code. 132 | */ 133 | Lock_t lock; 134 | /** 135 | * The value of the Eddystone-URL Configuration Service Unlock 136 | * characteristic that can be used to unlock the beacon and clear the 137 | * single-use lock-code. 138 | */ 139 | Lock_t unlock; 140 | /** 141 | * The value of the Eddystone-URL Configuration Service Flags 142 | * characteristic. This value is currently fixed to 0x10. 143 | */ 144 | uint8_t flags; 145 | /** 146 | * The value of the Eddystone-URL Configuration Service Advertised TX 147 | * Power Levels characteristic that is an array of bytes whose values 148 | * are put into the advertising packets when in EDDYSTONE_BEACON_MODE. 149 | * 150 | * @note These are not the same values set internally into the radio tx 151 | * power. 152 | */ 153 | PowerLevels_t advPowerLevels; 154 | /** 155 | * The value of the Eddystone-URL Configuration Service TX Power Mode 156 | * characteristic. This value is an index into the 157 | * EddystoneParams_t::advPowerLevels array. 158 | */ 159 | uint8_t txPowerMode; 160 | /** 161 | * The value of the Eddystone-URL Configuration Service Beacon Period 162 | * characteristic that is the interval (in milliseconds) of the 163 | * Eddystone-URL frames. 164 | * 165 | * @note A value of zero disables Eddystone-URL frame trasmissions. 166 | */ 167 | uint16_t urlFramePeriod; 168 | /** 169 | * The configured interval (in milliseconds) of the Eddystone-UID 170 | * frames. 171 | * 172 | * @note A value of zero disables Eddystone-UID frame transmissions. 173 | * 174 | * @note Currently it is only possible to modify this value by using 175 | * the setUIDFrameAdvertisingInterval() API. 176 | */ 177 | uint16_t uidFramePeriod; 178 | /** 179 | * The configured interval (in milliseconds) of the Eddystone-TLM 180 | * frames. 181 | * 182 | * @note A value of zero disables Eddystone-TLM frame transmissions. 183 | * 184 | * @note Currently it is only possible to modify this value by using 185 | * the setTLMFrameAdvertisingInterval() API. 186 | */ 187 | uint16_t tlmFramePeriod; 188 | /** 189 | * The configured version of the Eddystone-TLM frames. 190 | */ 191 | uint8_t tlmVersion; 192 | /** 193 | * The length of the encoded URL in EddystoneParams_t::urlData used 194 | * within Eddystone-URL frames. 195 | */ 196 | uint8_t urlDataLength; 197 | /** 198 | * The value of the Eddystone-URL Configuration Service URI Data 199 | * characteristic that contains an encoded URL as described in the 200 | * Eddystone Specification at 201 | * https://github.com/google/eddystone/blob/master/eddystone-url/README.md#eddystone-url-http-url-encoding. 202 | */ 203 | UrlData_t urlData; 204 | /** 205 | * The configured 10-byte namespace ID in Eddystone-UID frames that may 206 | * be used to group a particular set of beacons. 207 | */ 208 | UIDNamespaceID_t uidNamespaceID; 209 | /** 210 | * The configured 6-byte instance ID that may be used to uniquely 211 | * identify individual devices in a group. 212 | */ 213 | UIDInstanceID_t uidInstanceID; 214 | }; 215 | 216 | /** 217 | * Enumeration that defines the various error codes for EddystoneService. 218 | */ 219 | enum EddystoneError_t { 220 | /** 221 | * No error occurred. 222 | */ 223 | EDDYSTONE_ERROR_NONE, 224 | /** 225 | * The supplied advertising interval is invalid. The interval may be 226 | * too short/long for the type of advertising packets being broadcast. 227 | * 228 | * @note For the acceptable range of advertising interval refer to the 229 | * following functions in mbed BLE API: 230 | * - Gap::getMinNonConnectableAdvertisingInterval() 231 | * - Gap::getMinAdvertisingInterval() 232 | * - Gap::getMaxAdvertisingInterval() 233 | */ 234 | EDDYSTONE_ERROR_INVALID_ADVERTISING_INTERVAL, 235 | /** 236 | * The result of executing a call when the the EddystoneService is in 237 | * the incorrect operation mode. 238 | */ 239 | EDDYSTONE_ERROR_INVALID_STATE 240 | }; 241 | 242 | /** 243 | * Enumeration that defines the available frame types within Eddystone 244 | * advertising packets. 245 | */ 246 | enum FrameType { 247 | /** 248 | * The Eddystone-URL frame. Refer to 249 | * https://github.com/google/eddystone/tree/master/eddystone-url. 250 | */ 251 | EDDYSTONE_FRAME_URL, 252 | /** 253 | * The Eddystone-URL frame. Refer to 254 | * https://github.com/google/eddystone/tree/master/eddystone-uid. 255 | */ 256 | EDDYSTONE_FRAME_UID, 257 | /** 258 | * The Eddystone-URL frame. Refer to 259 | * https://github.com/google/eddystone/tree/master/eddystone-tlm. 260 | */ 261 | EDDYSTONE_FRAME_TLM, 262 | /** 263 | * The total number Eddystone frame types. 264 | */ 265 | NUM_EDDYSTONE_FRAMES 266 | }; 267 | 268 | /** 269 | * The size of the advertising frame queue. 270 | * 271 | * @note [WARNING] If the advertising rate for any of the frames is higher 272 | * than 100ms then frames will be dropped, this value must be 273 | * increased. 274 | */ 275 | static const uint16_t ADV_FRAME_QUEUE_SIZE = NUM_EDDYSTONE_FRAMES; 276 | 277 | 278 | /** 279 | * Constructor that Initializes the EddystoneService using parameters from 280 | * the supplied EddystoneParams_t. This constructor is particularly useful 281 | * for configuring the EddystoneService with parameters fetched from 282 | * persistent storage. 283 | * 284 | * @param[in] bleIn 285 | * The BLE instance. 286 | * @param[in] paramIn 287 | * The input Eddystone configuration parameters. 288 | * @param[in] radioPowerLevelsIn 289 | * The value set internally into the radion tx power. 290 | * @param[in] advConfigIntervalIn 291 | * The advertising interval for advertising packets of the 292 | * Eddystone-URL Configuration Service. 293 | */ 294 | EddystoneService(BLE &bleIn, 295 | EddystoneParams_t ¶msIn, 296 | const PowerLevels_t &radioPowerLevelsIn, 297 | uint32_t advConfigIntervalIn = DEFAULT_CONFIG_PERIOD_MSEC); 298 | 299 | /** 300 | * Constructor to initialize the EddystoneService to default values. 301 | * 302 | * @param[in] bleIn 303 | * The BLE instance. 304 | * @param[in] advPowerLevelsIn 305 | * The value of the Eddystone-URL Configuration Service TX 306 | * Power Mode characteristic. 307 | * @param[in] radioPowerLevelsIn 308 | * The value set internally into the radion tx power. 309 | * @param[in] advConfigIntervalIn 310 | * The advertising interval for advertising packets of the 311 | * Eddystone-URL Configuration Service. 312 | * 313 | * @note When using this constructor the setURLData(), setTMLData() and 314 | * setUIDData() functions must be called to initialize 315 | * EddystoneService manually. 316 | */ 317 | EddystoneService(BLE &bleIn, 318 | const PowerLevels_t &advPowerLevelsIn, 319 | const PowerLevels_t &radioPowerLevelsIn, 320 | uint32_t advConfigIntervalIn = DEFAULT_CONFIG_PERIOD_MSEC); 321 | 322 | /** 323 | * Setup callback to update BatteryVoltage in Eddystone-TLM frames 324 | * 325 | * @param[in] tlmBatteryVoltageCallbackIn 326 | * The callback being registered. 327 | */ 328 | void onTLMBatteryVoltageUpdate(TlmUpdateCallback_t tlmBatteryVoltageCallbackIn); 329 | 330 | /** 331 | * Setup callback to update BeaconTemperature in Eddystone-TLM frames 332 | * 333 | * @param[in] tlmBeaconTemperatureCallbackIn 334 | * The callback being registered. 335 | */ 336 | void onTLMBeaconTemperatureUpdate(TlmUpdateCallback_t tlmBeaconTemperatureCallbackIn); 337 | 338 | /** 339 | * Set the Eddystone-TLM frame version. The other components of 340 | * Eddystone-TLM frames are updated just before the frame is broadcast 341 | * since information such as beacon temperature and time since boot changes 342 | * relatively quickly. 343 | * 344 | * @param[in] tlmVersionIn 345 | * The Eddyston-TLM version to set. 346 | */ 347 | void setTLMData(uint8_t tlmVersionIn = 0); 348 | 349 | /** 350 | * Set the Eddystone-URL frame URL data. 351 | * 352 | * @param[in] urlDataIn 353 | * A pointer to the plain null terminated string representing 354 | * a URL to be encoded. 355 | */ 356 | void setURLData(const char *urlDataIn); 357 | 358 | /** 359 | * Set the Eddystone-UID namespace and instance IDs. 360 | * 361 | * @param[in] uidNamespaceIDIn 362 | * The new Eddystone-UID namespace ID. 363 | * @param[in] uidInstanceIDIn 364 | * The new Eddystone-UID instance ID. 365 | */ 366 | void setUIDData(const UIDNamespaceID_t &uidNamespaceIDIn, const UIDInstanceID_t &uidInstanceIDIn); 367 | 368 | /** 369 | * Set the interval of the Eddystone-URL frames. 370 | * 371 | * @param[in] urlFrameIntervalIn 372 | * The new frame interval in milliseconds. The default is 373 | * DEFAULT_URL_FRAME_PERIOD_MSEC. 374 | * 375 | * @note A value of zero disables Eddystone-URL frame transmissions. 376 | */ 377 | void setURLFrameAdvertisingInterval(uint16_t urlFrameIntervalIn = DEFAULT_URL_FRAME_PERIOD_MSEC); 378 | 379 | /** 380 | * Set the interval of the Eddystone-UID frames. 381 | * 382 | * @param[in] uidFrameIntervalIn 383 | * The new frame interval in milliseconds. The default is 384 | * DEFAULT_UID_FRAME_PERIOD_MSEC. 385 | * 386 | * @note A value of zero disables Eddystone-UID frame transmissions. 387 | */ 388 | void setUIDFrameAdvertisingInterval(uint16_t uidFrameIntervalIn = DEFAULT_UID_FRAME_PERIOD_MSEC); 389 | 390 | /** 391 | * Set the interval for the Eddystone-TLM frames. 392 | * 393 | * @param[in] tlmFrameIntervalIn 394 | * The new frame interval in milliseconds. The default is 395 | * DEFAULT_TLM_FRAME_PERIOD_MSEC. 396 | * 397 | * @note A value of zero desables Eddystone-TLM frames. 398 | */ 399 | void setTLMFrameAdvertisingInterval(uint16_t tlmFrameIntervalIn = DEFAULT_TLM_FRAME_PERIOD_MSEC); 400 | 401 | /** 402 | * Change the EddystoneService OperationMode to EDDYSTONE_MODE_CONFIG. 403 | * 404 | * @retval EDDYSTONE_ERROR_NONE if the operation succeeded. 405 | * @retval EDDYSONE_ERROR_INVALID_ADVERTISING_INTERVAL if the configured 406 | * advertising interval is zero. 407 | * 408 | * @note If EddystoneService was previously in EDDYSTONE_MODE_BEACON, then 409 | * the resources allocated to that mode of operation such as memory 410 | * are freed and the BLE instance shutdown before the new operation 411 | * mode is configured. 412 | */ 413 | EddystoneError_t startConfigService(void); 414 | 415 | /** 416 | * Change the EddystoneService OperationMode to EDDYSTONE_MODE_BEACON. 417 | * 418 | * @retval EDDYSTONE_ERROR_NONE if the operation succeeded. 419 | * @retval EDDYSONE_ERROR_INVALID_ADVERTISING_INTERVAL if the configured 420 | * advertising interval is zero. 421 | * 422 | * @note If EddystoneService was previously in EDDYSTONE_MODE_CONFIG, then 423 | * the resources allocated to that mode of operation such as memory 424 | * are freed and the BLE instance shutdown before the new operation 425 | * mode is configured. 426 | */ 427 | EddystoneError_t startBeaconService(void); 428 | 429 | /** 430 | * Change the EddystoneService OperationMode to EDDYSTONE_MODE_NONE. 431 | * 432 | * @retval EDDYSTONE_ERROR_NONE if the operation succeeded. 433 | * @retval EDDYSTONE_ERROR_INVALID_STATE if the state of the 434 | * EddystoneService already is EDDYSTONE_MODE_NONE. 435 | * 436 | * @note If EddystoneService was previously in EDDYSTONE_MODE_CONFIG or 437 | * EDDYSTONE_MODE_BEACON, then the resources allocated to that mode 438 | * of operation such as memory are freed and the BLE instance 439 | * shutdown before the new operation mode is configured. 440 | */ 441 | EddystoneError_t stopCurrentService(void); 442 | 443 | /** 444 | * Set the Comple Local Name for the BLE device. This not only updates 445 | * the value of the Device Name Characteristic, it also updates the scan 446 | * response payload if the EddystoneService is currently in 447 | * EDDYSTONE_MODE_CONFIG. 448 | * 449 | * @param[in] deviceNameIn 450 | * A pointer to a null terminated string containing the new 451 | * device name. 452 | * 453 | * @return BLE_ERROR_NONE if the name was successfully set. Otherwise an 454 | * appropriate error. 455 | * 456 | * @note EddystoneService does not make an internal copy of the string 457 | * pointed to by @p deviceNameIn. Therefore, the user is responsible 458 | * for ensuring that the string persists in memory as long as it is 459 | * in use by the EddystoneService. 460 | * 461 | * @note The device name is not considered an Eddystone configuration 462 | * parameter; therefore, it is not contained within the 463 | * EddystoneParams_t structure and must be stored to persistent 464 | * storage separately. 465 | */ 466 | ble_error_t setCompleteDeviceName(const char *deviceNameIn); 467 | 468 | /** 469 | * Get the Eddystone Configuration parameters. This is particularly useful 470 | * for storing the configuration parameters in persistent storage. 471 | * It is not the responsibility of the Eddystone implementation to store 472 | * the configured parameters in persistent storage since this is 473 | * platform-specific. 474 | * 475 | * @param[out] params 476 | * A reference to an EddystoneParams_t structure with the 477 | * configured parameters of the EddystoneService. 478 | */ 479 | void getEddystoneParams(EddystoneParams_t ¶ms); 480 | 481 | private: 482 | /** 483 | * Helper function used only once during construction of an 484 | * EddystoneService object to avoid duplicated code. 485 | * 486 | * @param[in] advPowerLevelsIn 487 | * The value of the Eddystone-URL Configuration Service TX 488 | * Power Mode characteristic. 489 | * @param[in] radioPowerLevelsIn 490 | * The value set internally into the radion tx power. 491 | * @param[in] advConfigIntervalIn 492 | * The advertising interval for advertising packets of the 493 | * Eddystone-URL Configuration Service. 494 | */ 495 | void eddystoneConstructorHelper(const PowerLevels_t &advPowerLevelsIn, 496 | const PowerLevels_t &radioPowerLevelsIn, 497 | uint32_t advConfigIntervalIn); 498 | 499 | /** 500 | * Helper funtion that will be registered as an initialization complete 501 | * callback when BLE::shutdown() is called. This is necessary when changing 502 | * Eddystone OperationModes. Once the BLE initialization is complete, this 503 | * callback will initialize all the necessary resource to operate 504 | * Eddystone service in the selected mode. 505 | * 506 | * @param[in] initContext 507 | * The context provided by BLE API when initialization 508 | * completes. 509 | */ 510 | void bleInitComplete(BLE::InitializationCompleteCallbackContext* initContext); 511 | 512 | /** 513 | * When in EDDYSTONE_MODE_BEACON this function is called to update the 514 | * advertising payload to contain the information related to the specified 515 | * FrameType. 516 | * 517 | * @param[in] frameType 518 | * The frame to populate the advertising payload with. 519 | */ 520 | void swapAdvertisedFrame(FrameType frameType); 521 | 522 | /** 523 | * Helper function that manages the BLE radio that is used to broadcast 524 | * advertising packets. To advertise frames at the configured intervals 525 | * the actual advertising interval of the BLE instance is set to the value 526 | * returned by Gap::getMaxAdvertisingInterval() from the BLE API. When a 527 | * frame needs to be advertised, the enqueueFrame() callbacks add the frame 528 | * type to the advFrameQueue and post a manageRadio() callback. When the 529 | * callback is executed, the frame is dequeued and advertised using the 530 | * radio (by updating the advertising payload). manageRadio() also posts a 531 | * callback to itself Gap::getMinNonConnectableAdvertisingInterval() 532 | * milliseconds later. In this callback, manageRadio() will advertise the 533 | * next frame in the queue, yet if there is none it calls 534 | * Gap::stopAdvertising() and does not post any further callbacks. 535 | */ 536 | void manageRadio(void); 537 | 538 | /** 539 | * Regular callbacks posted at the rate of urlFramePeriod, uidFramePeriod 540 | * and tlmFramePeriod milliseconds enqueue frames to be advertised. If the 541 | * frame queue is currently empty, then this function directly calls 542 | * manageRadio() to broadcast the required FrameType. 543 | * 544 | * @param[in] frameType 545 | * The FrameType to enqueue for broadcasting. 546 | */ 547 | void enqueueFrame(FrameType frameType); 548 | 549 | /** 550 | * Helper function that updates the advertising payload when in 551 | * EDDYSTONE_MODE_BEACON to contain a new frame. 552 | * 553 | * @param[in] rawFrame 554 | * The raw bytes of the frame to advertise. 555 | * @param[in] rawFrameLength 556 | * The length in bytes of the array pointed to by @p rawFrame. 557 | */ 558 | void updateAdvertisementPacket(const uint8_t* rawFrame, size_t rawFrameLength); 559 | 560 | /** 561 | * Helper function that updates the information in the Eddystone-TLM frames 562 | * Internally, this function executes the registered callbacks to update 563 | * beacon Battery Voltage and Temperature (if available). Furthermore, this 564 | * function updates the raw frame data. This operation must be done fairly 565 | * often because the Eddystone-TLM frame Time Since Boot must have a 0.1 566 | * seconds resolution according to the Eddystone specification. 567 | */ 568 | void updateRawTLMFrame(void); 569 | 570 | /** 571 | * Initialize the resources required when switching to 572 | * EDDYSTONE_MODE_BEACON. 573 | */ 574 | void setupBeaconService(void); 575 | 576 | /** 577 | * Initialize the resources required when switching to 578 | * EDDYSTONE_MODE_CONFIG. This includes the GATT services and 579 | * characteristics required by the Eddystone-URL Configuration Service. 580 | */ 581 | void setupConfigService(void); 582 | 583 | /** 584 | * Free the resources acquired by a call to setupConfigService(). 585 | */ 586 | void freeConfigCharacteristics(void); 587 | 588 | /** 589 | * Free the resources acquired by a call to setupBeaconService() and 590 | * cancel all pending callbacks that operate the radio and frame queue. 591 | * 592 | * @note This call will not modify the current state of the BLE device. 593 | * EddystoneService::stopBeaconService should only be called after 594 | * a call to BLE::shutdown(). 595 | */ 596 | void stopBeaconService(void); 597 | 598 | /** 599 | * Helper function used to update the GATT database following any 600 | * change to the internal state of the service object. 601 | */ 602 | void updateCharacteristicValues(void); 603 | 604 | /** 605 | * Setup the payload of advertising packets for Eddystone-URL Configuration 606 | * Service. 607 | */ 608 | void setupEddystoneConfigAdvertisements(void); 609 | 610 | /** 611 | * Helper function to setup the payload of scan response packets for 612 | * Eddystone-URL Configuration Service. 613 | */ 614 | void setupEddystoneConfigScanResponse(void); 615 | 616 | /** 617 | * Callback registered to the BLE API to authorize write operations to the 618 | * Eddystone-URL Configuration Service Lock characteristic. 619 | * 620 | * @param[in] authParams 621 | * Write authentication information. 622 | */ 623 | void lockAuthorizationCallback(GattWriteAuthCallbackParams *authParams); 624 | 625 | /** 626 | * Callback registered to the BLE API to authorize write operations to the 627 | * Eddystone-URL Configuration Service Unlock characteristic. 628 | * 629 | * @param[in] authParams 630 | * Write authentication information. 631 | */ 632 | void unlockAuthorizationCallback(GattWriteAuthCallbackParams *authParams); 633 | 634 | /** 635 | * Callback registered to the BLE API to authorize write operations to the 636 | * Eddystone-URL Configuration Service URI Data characteristic. 637 | * 638 | * @param[in] authParams 639 | * Write authentication information. 640 | */ 641 | void urlDataWriteAuthorizationCallback(GattWriteAuthCallbackParams *authParams); 642 | 643 | void powerModeAuthorizationCallback(GattWriteAuthCallbackParams *authParams); 644 | 645 | /** 646 | * Callback registered to the BLE API to authorize write operations to the 647 | * following Eddystone-URL Configuration Service characteristics: 648 | * - Flags 649 | * - Beacon Period 650 | * - Reset 651 | * 652 | * @param[in] authParams 653 | * Write authentication information. 654 | */ 655 | template 656 | void basicAuthorizationCallback(GattWriteAuthCallbackParams *authParams); 657 | 658 | /** 659 | * This callback is invoked when a GATT client attempts to modify any of the 660 | * characteristics of this service. Attempts to do so are also applied to 661 | * the internal state of this service object. 662 | * 663 | * @param[in] writeParams 664 | * Information about the values that are being written. 665 | */ 666 | void onDataWrittenCallback(const GattWriteCallbackParams *writeParams); 667 | 668 | /** 669 | * Correct the advertising interval for non-connectable packets. 670 | * 671 | * @param[in] beaconPeriodIn 672 | * The input interval in milliseconds. 673 | * 674 | * @return The corrected interval in milliseconds. 675 | * 676 | * @note For the acceptable range of advertising interval refer to the 677 | * following functions in mbed BLE API: 678 | * - Gap::getMinNonConnectableAdvertisingInterval() 679 | * - Gap::getMaxAdvertisingInterval() 680 | */ 681 | uint16_t correctAdvertisementPeriod(uint16_t beaconPeriodIn) const; 682 | 683 | /** 684 | * BLE instance that EddystoneService will operate on. 685 | */ 686 | BLE &ble; 687 | /** 688 | * The advertising interval for Eddystone-URL Config Service advertising 689 | * packets. 690 | */ 691 | uint32_t advConfigInterval; 692 | /** 693 | * Current EddystoneServce operation mode. 694 | */ 695 | uint8_t operationMode; 696 | 697 | /** 698 | * Encapsulation of a URL frame. 699 | */ 700 | URLFrame urlFrame; 701 | /** 702 | * Encapsulation of a UID frame. 703 | */ 704 | UIDFrame uidFrame; 705 | /** 706 | * Encapsulation of a TLM frame. 707 | */ 708 | TLMFrame tlmFrame; 709 | 710 | /** 711 | * The value set internally into the radion tx power. 712 | */ 713 | PowerLevels_t radioPowerLevels; 714 | /** 715 | * An array containing possible values for advertised tx power in Eddystone 716 | * frames. Also, the value of the Eddystone-URL Configuration Service 717 | * Advertised TX Power Levels characteristic. 718 | */ 719 | PowerLevels_t advPowerLevels; 720 | /** 721 | * The value of the Eddystone-URL Configuration Service Lock State 722 | * characteristic. 723 | */ 724 | bool lockState; 725 | /** 726 | * The value of the Eddystone-URL Configuration Service reset 727 | * characteristic. 728 | */ 729 | bool resetFlag; 730 | /** 731 | * The value of the Eddystone-URL Configuration Service Lock 732 | * characteristic. 733 | */ 734 | Lock_t lock; 735 | /** 736 | * The value of the Eddystone-URL Configuration Service Unlock 737 | * characteristic. 738 | */ 739 | Lock_t unlock; 740 | /** 741 | * The value of the Eddystone-URL Configuration Service Flags 742 | * characteristic. 743 | */ 744 | uint8_t flags; 745 | /** 746 | * The value of the Eddystone-URL Configuration Service TX Power Mode 747 | * characteristic. 748 | */ 749 | uint8_t txPowerMode; 750 | /** 751 | * The value of the Eddystone-URL Configuration Service Beacon Period 752 | * characteristic. Also, the advertising interval (in milliseconds) of 753 | * Eddystone-URL frames. 754 | */ 755 | uint16_t urlFramePeriod; 756 | /** 757 | * The advertising interval (in milliseconds) of Eddystone-UID frames. 758 | */ 759 | uint16_t uidFramePeriod; 760 | /** 761 | * The advertising interval (in milliseconds) of Eddystone-TLM frames. 762 | */ 763 | uint16_t tlmFramePeriod; 764 | 765 | /** 766 | * Pointer to the BLE API characteristic encapsulation for the Eddystone-URL 767 | * Configuration Service Lock State characteristic. 768 | */ 769 | ReadOnlyGattCharacteristic *lockStateChar; 770 | /** 771 | * Pointer to the BLE API characteristic encapsulation for the Eddystone-URL 772 | * Configuration Service Lock characteristic. 773 | */ 774 | WriteOnlyArrayGattCharacteristic *lockChar; 775 | /** 776 | * Pointer to the BLE API characteristic encapsulation for the Eddystone-URL 777 | * Configuration Service Unlock characteristic. 778 | */ 779 | WriteOnlyArrayGattCharacteristic *unlockChar; 780 | /** 781 | * Pointer to the BLE API characteristic encapsulation for the Eddystone-URL 782 | * Configuration Service URI Data characteristic. 783 | */ 784 | GattCharacteristic *urlDataChar; 785 | /** 786 | * Pointer to the BLE API characteristic encapsulation for the Eddystone-URL 787 | * Configuration Service Flags characteristic. 788 | */ 789 | ReadWriteGattCharacteristic *flagsChar; 790 | /** 791 | * Pointer to the BLE API characteristic encapsulation for the Eddystone-URL 792 | * Configuration Service Advertised TX Power Levels characteristic. 793 | */ 794 | ReadWriteArrayGattCharacteristic *advPowerLevelsChar; 795 | /** 796 | * Pointer to the BLE API characteristic encapsulation for the Eddystone-URL 797 | * Configuration Service TX Power Mode characteristic. 798 | */ 799 | ReadWriteGattCharacteristic *txPowerModeChar; 800 | /** 801 | * Pointer to the BLE API characteristic encapsulation for the Eddystone-URL 802 | * Configuration Service Beacon Period characteristic. 803 | */ 804 | ReadWriteGattCharacteristic *beaconPeriodChar; 805 | /** 806 | * Pointer to the BLE API characteristic encapsulation for the Eddystone-URL 807 | * Configuration Service Reset characteristic. 808 | */ 809 | WriteOnlyGattCharacteristic *resetChar; 810 | 811 | /** 812 | * Pointer to the raw bytes that will be used to populate Eddystone-URL 813 | * frames. 814 | */ 815 | uint8_t *rawUrlFrame; 816 | /** 817 | * Pointer to the raw bytes that will be used to populate Eddystone-UID 818 | * frames. 819 | */ 820 | uint8_t *rawUidFrame; 821 | /** 822 | * Pointer to the raw bytes that will be used to populate Eddystone-TLM 823 | * frames. 824 | */ 825 | uint8_t *rawTlmFrame; 826 | 827 | /** 828 | * Circular buffer that represents of Eddystone frames to be advertised. 829 | */ 830 | CircularBuffer advFrameQueue; 831 | 832 | /** 833 | * The registered callback to update the Eddystone-TLM frame Battery 834 | * Voltage. 835 | */ 836 | TlmUpdateCallback_t tlmBatteryVoltageCallback; 837 | /** 838 | * The registered callback to update the Eddystone-TLM frame Beacon 839 | * Temperature. 840 | */ 841 | TlmUpdateCallback_t tlmBeaconTemperatureCallback; 842 | 843 | /** 844 | * Timer that keeps track of the time since boot. 845 | */ 846 | Timer timeSinceBootTimer; 847 | 848 | /** 849 | * Minar callback handle to keep track of periodic 850 | * enqueueFrame(EDDYSTONE_FRAME_UID) callbacks that populate the 851 | * advFrameQueue. 852 | */ 853 | minar::callback_handle_t uidFrameCallbackHandle; 854 | /** 855 | * Minar callback handle to keep track of periodic 856 | * enqueueFrame(EDDYSTONE_FRAME_URL) callbacks that populate the 857 | * advFrameQueue. 858 | */ 859 | minar::callback_handle_t urlFrameCallbackHandle; 860 | /** 861 | * Minar callback handle to keep track of periodic 862 | * enqueueFrame(EDDYSTONE_FRAME_TLM) callbacks that populate the 863 | * advFrameQueue. 864 | */ 865 | minar::callback_handle_t tlmFrameCallbackHandle; 866 | /** 867 | * Minar callback handle to keep track of manageRadio() callbacks. 868 | */ 869 | minar::callback_handle_t radioManagerCallbackHandle; 870 | 871 | /** 872 | * GattCharacteristic table used to populate the BLE ATT table in the 873 | * GATT Server. 874 | */ 875 | GattCharacteristic *charTable[TOTAL_CHARACTERISTICS]; 876 | 877 | /** 878 | * Pointer to the device name currently being used. 879 | */ 880 | const char *deviceName; 881 | }; 882 | 883 | #endif /* __EDDYSTONESERVICE_H__ */ 884 | -------------------------------------------------------------------------------- /BLE_EddystoneService/source/EddystoneTypes.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __EDDYSTONETYPES_H__ 18 | #define __EDDYSTONETYPES_H__ 19 | 20 | #include 21 | #include 22 | 23 | #ifndef YOTTA_CFG_EDDYSTONE_DEFAULT_DEVICE_NAME 24 | #define YOTTA_CFG_EDDYSTONE_DEFAULT_DEVICE_NAME "EDDYSTONE CONFIG" 25 | #endif 26 | 27 | #ifndef YOTTA_CFG_EDDYSTONE_DEFAULT_URL 28 | #define YOTTA_CFG_EDDYSTONE_DEFAULT_URL "https://www.mbed.com/" 29 | #endif 30 | 31 | /** 32 | * Macro to expand a 16-bit Eddystone UUID to 128-bit UUID. 33 | */ 34 | #define UUID_URL_BEACON(FIRST, SECOND) { \ 35 | 0xee, 0x0c, FIRST, SECOND, 0x87, 0x86, 0x40, 0xba, \ 36 | 0xab, 0x96, 0x99, 0xb9, 0x1a, 0xc9, 0x81, 0xd8, \ 37 | } 38 | 39 | /** 40 | * Eddystone 16-bit UUID. 41 | */ 42 | const uint8_t EDDYSTONE_UUID[] = {0xAA, 0xFE}; 43 | 44 | /** 45 | * 128-bit UUID for Eddystone-URL Configuration Service. 46 | */ 47 | const uint8_t UUID_URL_BEACON_SERVICE[] = UUID_URL_BEACON(0x20, 0x80); 48 | /** 49 | * 128-bit UUID for Eddystone-URL Configuration Service Lock State 50 | * characteristic. 51 | */ 52 | const uint8_t UUID_LOCK_STATE_CHAR[] = UUID_URL_BEACON(0x20, 0x81); 53 | /** 54 | * 128-bit UUID for Eddystone-URL Configuration Service Lock 55 | * characteristic. 56 | */ 57 | const uint8_t UUID_LOCK_CHAR[] = UUID_URL_BEACON(0x20, 0x82); 58 | /** 59 | * 128-bit UUID for Eddystone-URL Configuration Service Unlock 60 | * characteristic. 61 | */ 62 | const uint8_t UUID_UNLOCK_CHAR[] = UUID_URL_BEACON(0x20, 0x83); 63 | /** 64 | * 128-bit UUID for Eddystone-URL Configuration Service URI Data 65 | * characteristic. 66 | */ 67 | const uint8_t UUID_URL_DATA_CHAR[] = UUID_URL_BEACON(0x20, 0x84); 68 | /** 69 | * 128-bit UUID for Eddystone-URL Configuration Service Flags 70 | * characteristic. 71 | */ 72 | const uint8_t UUID_FLAGS_CHAR[] = UUID_URL_BEACON(0x20, 0x85); 73 | /** 74 | * 128-bit UUID for Eddystone-URL Configuration Service Advertised TX Power 75 | * Levels characteristic. 76 | */ 77 | const uint8_t UUID_ADV_POWER_LEVELS_CHAR[] = UUID_URL_BEACON(0x20, 0x86); 78 | /** 79 | * 128-bit UUID for Eddystone-URL Configuration Service TX Power Mode 80 | * characteristic. 81 | */ 82 | const uint8_t UUID_TX_POWER_MODE_CHAR[] = UUID_URL_BEACON(0x20, 0x87); 83 | /** 84 | * 128-bit UUID for Eddystone-URL Configuration Service Beacon Period 85 | * characteristic. 86 | */ 87 | const uint8_t UUID_BEACON_PERIOD_CHAR[] = UUID_URL_BEACON(0x20, 0x88); 88 | /** 89 | * 128-bit UUID for Eddystone-URL Configuration Service Reset 90 | * characteristic. 91 | */ 92 | const uint8_t UUID_RESET_CHAR[] = UUID_URL_BEACON(0x20, 0x89); 93 | 94 | /** 95 | * Default name for the BLE Device Name characteristic. 96 | */ 97 | const char DEFAULT_DEVICE_NAME[] = YOTTA_CFG_EDDYSTONE_DEFAULT_DEVICE_NAME; 98 | 99 | /** 100 | * Default URL used by EddystoneService. 101 | */ 102 | const char DEFAULT_URL[] = YOTTA_CFG_EDDYSTONE_DEFAULT_URL; 103 | 104 | /** 105 | * Enumeration that defines the Eddystone power levels for the Eddystone-URL 106 | * Configuration Service TX Power Mode characteristic. Refer to 107 | * https://github.com/google/eddystone/blob/master/eddystone-url/docs/config-service-spec.md#37-tx-power-mode. 108 | */ 109 | enum PowerModes { 110 | /** 111 | * Lowest transmit power mode. 112 | */ 113 | TX_POWER_MODE_LOWEST, 114 | /** 115 | * Low transmit power mode. 116 | */ 117 | TX_POWER_MODE_LOW, 118 | /** 119 | * Medium transmit power mode. 120 | */ 121 | TX_POWER_MODE_MEDIUM, 122 | /** 123 | * Highest transmit power mode. 124 | */ 125 | TX_POWER_MODE_HIGH, 126 | /** 127 | * Total number of power modes. 128 | */ 129 | NUM_POWER_MODES 130 | }; 131 | 132 | /** 133 | * Type for the 128-bit for Eddystone-URL Configuration Service Lock and Unlock 134 | * characteristic value. 135 | */ 136 | typedef uint8_t Lock_t[16]; 137 | /** 138 | * Type for the 128-bit for Eddystone-URL Configuration Service Advertised TX 139 | * Power Levels characteristic value. 140 | */ 141 | typedef int8_t PowerLevels_t[NUM_POWER_MODES]; 142 | 143 | /** 144 | * Maximum length of an encoded URL for Eddystone. 145 | */ 146 | const uint16_t URL_DATA_MAX = 18; 147 | /** 148 | * Type for an encoded URL for Eddystone. 149 | */ 150 | typedef uint8_t UrlData_t[URL_DATA_MAX]; 151 | 152 | /** 153 | * Size in bytes of UID namespace ID. 154 | */ 155 | const size_t UID_NAMESPACEID_SIZE = 10; 156 | /** 157 | * Type for the UID namespace ID. 158 | */ 159 | typedef uint8_t UIDNamespaceID_t[UID_NAMESPACEID_SIZE]; 160 | /** 161 | * Size in bytes of UID instance ID. 162 | */ 163 | const size_t UID_INSTANCEID_SIZE = 6; 164 | /** 165 | * Type for the UID instance ID. 166 | */ 167 | typedef uint8_t UIDInstanceID_t[UID_INSTANCEID_SIZE]; 168 | 169 | /** 170 | * Type for callbacks to update Eddystone-TLM frame Batery Voltage and Beacon 171 | * Temperature. 172 | */ 173 | typedef uint16_t (*TlmUpdateCallback_t) (uint16_t); 174 | 175 | /** 176 | * Size of Eddystone UUID. Needed to construct all frames raw bytes. 177 | */ 178 | const uint16_t EDDYSTONE_UUID_SIZE = sizeof(EDDYSTONE_UUID); 179 | 180 | #endif /* __EDDYSTONETYPES_H__ */ 181 | -------------------------------------------------------------------------------- /BLE_EddystoneService/source/PersistentStorageHelper/ConfigParamsPersistence.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "ConfigParamsPersistence.h" 18 | 19 | #ifndef TARGET_NRF51822 /* Persistent storage supported on nrf51 platforms */ 20 | /** 21 | * When not using an nRF51-based target then persistent storage is not available. 22 | */ 23 | #warning "EddystoneService is not configured to store configuration data in non-volatile memory" 24 | 25 | bool loadEddystoneServiceConfigParams(EddystoneService::EddystoneParams_t *paramsP) 26 | { 27 | /* Avoid compiler warnings */ 28 | (void) paramsP; 29 | 30 | /* 31 | * Do nothing and let the main program set Eddystone params to 32 | * defaults 33 | */ 34 | return false; 35 | } 36 | 37 | void saveEddystoneServiceConfigParams(const EddystoneService::EddystoneParams_t *paramsP) 38 | { 39 | /* Avoid compiler warnings */ 40 | (void) paramsP; 41 | 42 | /* Do nothing... */ 43 | return; 44 | } 45 | #endif /* #ifdef TARGET_NRF51822 */ 46 | -------------------------------------------------------------------------------- /BLE_EddystoneService/source/PersistentStorageHelper/ConfigParamsPersistence.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __BLE_CONFIG_PARAMS_PERSISTENCE_H__ 18 | #define __BLE_CONFIG_PARAMS_PERSISTENCE_H__ 19 | 20 | #include "../EddystoneService.h" 21 | 22 | /** 23 | * Generic API to load the Eddystone Service configuration parameters from persistent 24 | * storage. If persistent storage isn't available, the persistenceSignature 25 | * member of params may be left un-initialized to the MAGIC, and this will cause 26 | * a reset to default values. 27 | * 28 | * @param[out] paramsP 29 | * The parameters to be filled in from persistence storage. This 30 | * argument can be NULL if the caller is only interested in 31 | * discovering the persistence status of params. 32 | * 33 | * @return true if params were loaded from persistent storage and have usefully 34 | * initialized fields. 35 | */ 36 | bool loadEddystoneServiceConfigParams(EddystoneService::EddystoneParams_t *paramsP); 37 | 38 | /** 39 | * Generic API to store the Eddystone Service configuration parameters to persistent 40 | * storage. It typically initializes the persistenceSignature member of the 41 | * params to the MAGIC value to indicate persistence. 42 | * 43 | * @param[in,out] paramsP 44 | * The params to be saved; persistenceSignature member gets 45 | * updated if persistence is successful. 46 | * 47 | * @note The save operation may be asynchronous. It may be a short while before 48 | * the request takes affect. Reading back saved configParams may not yield 49 | * correct behaviour if attempted soon after a store. 50 | */ 51 | void saveEddystoneServiceConfigParams(const EddystoneService::EddystoneParams_t *paramsP); 52 | 53 | #endif /* #ifndef __BLE_CONFIG_PARAMS_PERSISTENCE_H__*/ 54 | -------------------------------------------------------------------------------- /BLE_EddystoneService/source/PersistentStorageHelper/nrfPersistentStorageHelper/nrfConfigParamsPersistence.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifdef TARGET_NRF51822 /* Persistent storage supported on nrf51 platforms */ 18 | 19 | extern "C" { 20 | #include "pstorage.h" 21 | } 22 | 23 | #include "nrf_error.h" 24 | #include "../../EddystoneService.h" 25 | 26 | /** 27 | * Nordic specific structure used to store params persistently. 28 | * It extends EddystoneService::EddystoneParams_t with a persistence signature. 29 | */ 30 | struct PersistentParams_t { 31 | EddystoneService::EddystoneParams_t params; 32 | uint32_t persistenceSignature; /* This isn't really a parameter, but having the expected 33 | * magic value in this field indicates persistence. */ 34 | 35 | static const uint32_t MAGIC = 0x1BEAC000; /* Magic that identifies persistence */ 36 | }; 37 | 38 | /** 39 | * The following is a module-local variable to hold configuration parameters for 40 | * short periods during flash access. This is necessary because the pstorage 41 | * APIs don't copy in the memory provided as data source. The memory cannot be 42 | * freed or reused by the application until this flash access is complete. The 43 | * load and store operations in this module initialize persistentParams and then 44 | * pass it on to the 'pstorage' APIs. 45 | */ 46 | static PersistentParams_t persistentParams; 47 | 48 | static pstorage_handle_t pstorageHandle; 49 | 50 | /** 51 | * Dummy callback handler needed by Nordic's pstorage module. This is called 52 | * after every flash access. 53 | */ 54 | static void pstorageNotificationCallback(pstorage_handle_t *p_handle, 55 | uint8_t op_code, 56 | uint32_t result, 57 | uint8_t *p_data, 58 | uint32_t data_len) 59 | { 60 | /* Supress compiler warnings */ 61 | (void) p_handle; 62 | (void) op_code; 63 | (void) result; 64 | (void) p_data; 65 | (void) data_len; 66 | 67 | /* APP_ERROR_CHECK(result); */ 68 | } 69 | 70 | /* Platform-specific implementation for persistence on the nRF5x. Based on the 71 | * pstorage module provided by the Nordic SDK. */ 72 | bool loadEddystoneServiceConfigParams(EddystoneService::EddystoneParams_t *paramsP) 73 | { 74 | static bool pstorageInitied = false; 75 | if (!pstorageInitied) { 76 | pstorage_init(); 77 | 78 | static pstorage_module_param_t pstorageParams = { 79 | .cb = pstorageNotificationCallback, 80 | .block_size = sizeof(PersistentParams_t), 81 | .block_count = 1 82 | }; 83 | pstorage_register(&pstorageParams, &pstorageHandle); 84 | pstorageInitied = true; 85 | } 86 | 87 | if ((pstorage_load(reinterpret_cast(&persistentParams), &pstorageHandle, sizeof(PersistentParams_t), 0) != NRF_SUCCESS) || 88 | (persistentParams.persistenceSignature != PersistentParams_t::MAGIC)) { 89 | // On failure zero out and let the service reset to defaults 90 | memset(paramsP, 0, sizeof(EddystoneService::EddystoneParams_t)); 91 | return false; 92 | } 93 | 94 | memcpy(paramsP, &persistentParams.params, sizeof(EddystoneService::EddystoneParams_t)); 95 | return true; 96 | } 97 | 98 | /* Platform-specific implementation for persistence on the nRF5x. Based on the 99 | * pstorage module provided by the Nordic SDK. */ 100 | void saveEddystoneServiceConfigParams(const EddystoneService::EddystoneParams_t *paramsP) 101 | { 102 | memcpy(&persistentParams.params, paramsP, sizeof(EddystoneService::EddystoneParams_t)); 103 | if (persistentParams.persistenceSignature != PersistentParams_t::MAGIC) { 104 | persistentParams.persistenceSignature = PersistentParams_t::MAGIC; 105 | pstorage_store(&pstorageHandle, 106 | reinterpret_cast(&persistentParams), 107 | sizeof(PersistentParams_t), 108 | 0 /* offset */); 109 | } else { 110 | pstorage_update(&pstorageHandle, 111 | reinterpret_cast(&persistentParams), 112 | sizeof(PersistentParams_t), 113 | 0 /* offset */); 114 | } 115 | } 116 | 117 | #endif /* #ifdef TARGET_NRF51822 */ 118 | -------------------------------------------------------------------------------- /BLE_EddystoneService/source/TLMFrame.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "TLMFrame.h" 18 | 19 | TLMFrame::TLMFrame(uint8_t tlmVersionIn, 20 | uint16_t tlmBatteryVoltageIn, 21 | uint16_t tlmBeaconTemperatureIn, 22 | uint32_t tlmPduCountIn, 23 | uint32_t tlmTimeSinceBootIn) : 24 | tlmVersion(tlmVersionIn), 25 | lastTimeSinceBootRead(0), 26 | tlmBatteryVoltage(tlmBatteryVoltageIn), 27 | tlmBeaconTemperature(tlmBeaconTemperatureIn), 28 | tlmPduCount(tlmPduCountIn), 29 | tlmTimeSinceBoot(tlmTimeSinceBootIn) 30 | { 31 | } 32 | 33 | void TLMFrame::setTLMData(uint8_t tlmVersionIn) 34 | { 35 | /* According to the Eddystone spec BatteryVoltage is 0 and 36 | * BeaconTemperature is 0x8000 if not supported 37 | */ 38 | tlmVersion = tlmVersionIn; 39 | tlmBatteryVoltage = 0; 40 | tlmBeaconTemperature = 0x8000; 41 | tlmPduCount = 0; 42 | tlmTimeSinceBoot = 0; 43 | } 44 | 45 | void TLMFrame::constructTLMFrame(uint8_t *rawFrame) 46 | { 47 | size_t index = 0; 48 | rawFrame[index++] = EDDYSTONE_UUID[0]; // 16-bit Eddystone UUID 49 | rawFrame[index++] = EDDYSTONE_UUID[1]; 50 | rawFrame[index++] = FRAME_TYPE_TLM; // Eddystone frame type = Telemetry 51 | rawFrame[index++] = tlmVersion; // TLM Version Number 52 | rawFrame[index++] = (uint8_t)(tlmBatteryVoltage >> 8); // Battery Voltage[0] 53 | rawFrame[index++] = (uint8_t)(tlmBatteryVoltage >> 0); // Battery Voltage[1] 54 | rawFrame[index++] = (uint8_t)(tlmBeaconTemperature >> 8); // Beacon Temp[0] 55 | rawFrame[index++] = (uint8_t)(tlmBeaconTemperature >> 0); // Beacon Temp[1] 56 | rawFrame[index++] = (uint8_t)(tlmPduCount >> 24); // PDU Count [0] 57 | rawFrame[index++] = (uint8_t)(tlmPduCount >> 16); // PDU Count [1] 58 | rawFrame[index++] = (uint8_t)(tlmPduCount >> 8); // PDU Count [2] 59 | rawFrame[index++] = (uint8_t)(tlmPduCount >> 0); // PDU Count [3] 60 | rawFrame[index++] = (uint8_t)(tlmTimeSinceBoot >> 24); // Time Since Boot [0] 61 | rawFrame[index++] = (uint8_t)(tlmTimeSinceBoot >> 16); // Time Since Boot [1] 62 | rawFrame[index++] = (uint8_t)(tlmTimeSinceBoot >> 8); // Time Since Boot [2] 63 | rawFrame[index++] = (uint8_t)(tlmTimeSinceBoot >> 0); // Time Since Boot [3] 64 | } 65 | 66 | size_t TLMFrame::getRawFrameSize(void) const 67 | { 68 | return FRAME_SIZE_TLM + EDDYSTONE_UUID_SIZE; 69 | } 70 | 71 | void TLMFrame::updateTimeSinceBoot(uint32_t nowInMillis) 72 | { 73 | tlmTimeSinceBoot += (nowInMillis - lastTimeSinceBootRead) / 100; 74 | lastTimeSinceBootRead = nowInMillis; 75 | } 76 | 77 | void TLMFrame::updateBatteryVoltage(uint16_t tlmBatteryVoltageIn) 78 | { 79 | tlmBatteryVoltage = tlmBatteryVoltageIn; 80 | } 81 | 82 | void TLMFrame::updateBeaconTemperature(uint16_t tlmBeaconTemperatureIn) 83 | { 84 | tlmBeaconTemperature = tlmBeaconTemperatureIn; 85 | } 86 | 87 | void TLMFrame::updatePduCount(void) 88 | { 89 | tlmPduCount++; 90 | } 91 | 92 | uint16_t TLMFrame::getBatteryVoltage(void) const 93 | { 94 | return tlmBatteryVoltage; 95 | } 96 | 97 | uint16_t TLMFrame::getBeaconTemperature(void) const 98 | { 99 | return tlmBeaconTemperature; 100 | } 101 | 102 | uint8_t TLMFrame::getTLMVersion(void) const 103 | { 104 | return tlmVersion; 105 | } 106 | -------------------------------------------------------------------------------- /BLE_EddystoneService/source/TLMFrame.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __TLMFRAME_H__ 18 | #define __TLMFRAME_H__ 19 | 20 | #include "EddystoneTypes.h" 21 | 22 | /** 23 | * Class that encapsulates data that belongs to the Eddystone-TLM frame. For 24 | * more information refer to https://github.com/google/eddystone/tree/master/eddystone-tlm. 25 | */ 26 | class TLMFrame 27 | { 28 | public: 29 | /** 30 | * Construct a new instance of this class. 31 | * 32 | * @param[in] tlmVersionIn 33 | * Eddystone-TLM version number to use. 34 | * @param[in] tlmBatteryVoltageIn 35 | * Initial value for the Eddystone-TLM Battery Voltage. 36 | * @param[in] tlmBeaconTemperatureIn 37 | * Initial value for the Eddystone-TLM Beacon Temperature. 38 | * @param[in] tlmPduCountIn 39 | * Initial value for the Eddystone-TLM Advertising PDU Count. 40 | * @param[in] tlmTimeSinceBootIn 41 | * Intitial value for the Eddystone-TLM time since boot timer. 42 | 8 This timer has a 0.1 second resolution. 43 | */ 44 | TLMFrame(uint8_t tlmVersionIn = 0, 45 | uint16_t tlmBatteryVoltageIn = 0, 46 | uint16_t tlmBeaconTemperatureIn = 0x8000, 47 | uint32_t tlmPduCountIn = 0, 48 | uint32_t tlmTimeSinceBootIn = 0); 49 | 50 | /** 51 | * Set the Eddystone-TLM version number. 52 | */ 53 | void setTLMData(uint8_t tlmVersionIn = 0); 54 | 55 | /** 56 | * Construct the raw bytes of the Eddystone-TLM frame that will be directly 57 | * used in the advertising packets. 58 | * 59 | * @param[in] rawFrame 60 | * Pointer to the location where the raw frame will be stored. 61 | */ 62 | void constructTLMFrame(uint8_t *rawFrame); 63 | 64 | /** 65 | * Get the size of the Eddystone-TLM frame constructed with the 66 | * current state of the TLMFrame object. 67 | * 68 | * @return The size in bytes of the Eddystone-TLM frame. 69 | */ 70 | size_t getRawFrameSize(void) const; 71 | 72 | /** 73 | * Update the time since boot. 74 | * 75 | * @param[in] nowInMillis 76 | * The time since boot in milliseconds. 77 | */ 78 | void updateTimeSinceBoot(uint32_t nowInMillis); 79 | 80 | /** 81 | * Update the Battery Voltage. 82 | * 83 | * @param[in] tlmBatteryVoltageIn 84 | * The new Battery Voltage value. 85 | */ 86 | void updateBatteryVoltage(uint16_t tlmBatteryVoltageIn); 87 | 88 | /** 89 | * Update the Beacon Temperature. 90 | * 91 | * @param[in] tlmBeaconTemperatureIn 92 | * The new Beacon Temperature value. 93 | */ 94 | void updateBeaconTemperature(uint16_t tlmBeaconTemperatureIn); 95 | 96 | /** 97 | * Increment the current PDU counter by 1. 98 | */ 99 | void updatePduCount(void); 100 | 101 | /** 102 | * Get the current Battery Voltage. 103 | * 104 | * @return The Battery Voltage. 105 | */ 106 | uint16_t getBatteryVoltage(void) const; 107 | 108 | /** 109 | * Get the current Beacon Temperature. 110 | * 111 | * @return The Beacon Temperature. 112 | */ 113 | uint16_t getBeaconTemperature(void) const; 114 | 115 | /** 116 | * Get the current TLM Version number. 117 | * 118 | * @return The TLM Version number. 119 | */ 120 | uint8_t getTLMVersion(void) const; 121 | 122 | private: 123 | /** 124 | * The byte ID of an Eddystone-TLM frame. 125 | */ 126 | static const uint8_t FRAME_TYPE_TLM = 0x20; 127 | /** 128 | * The size of an Eddystone-TLM frame. 129 | */ 130 | static const uint8_t FRAME_SIZE_TLM = 14; 131 | 132 | /** 133 | * Eddystone-TLM version value. 134 | */ 135 | uint8_t tlmVersion; 136 | /** 137 | * Time since boot in milliseconds. 138 | */ 139 | uint32_t lastTimeSinceBootRead; 140 | /** 141 | * Eddystone-TLM Battery Voltage value. 142 | */ 143 | uint16_t tlmBatteryVoltage; 144 | /** 145 | * Eddystone-TLM Beacon temperature value. 146 | */ 147 | uint16_t tlmBeaconTemperature; 148 | /** 149 | * Eddystone-TLM Advertising PDU Count. 150 | */ 151 | uint32_t tlmPduCount; 152 | /** 153 | * Eddystone-TLM time since boot with 0.1 second resolution. 154 | */ 155 | uint32_t tlmTimeSinceBoot; 156 | }; 157 | 158 | #endif /* __TLMFRAME_H__ */ 159 | -------------------------------------------------------------------------------- /BLE_EddystoneService/source/UIDFrame.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "UIDFrame.h" 18 | 19 | UIDFrame::UIDFrame(void) 20 | { 21 | memset(uidNamespaceID, 0, sizeof(UIDNamespaceID_t)); 22 | memset(uidInstanceID, 0, sizeof(UIDInstanceID_t)); 23 | } 24 | 25 | UIDFrame::UIDFrame(const UIDNamespaceID_t uidNamespaceIDIn, const UIDInstanceID_t uidInstanceIDIn) 26 | { 27 | memcpy(uidNamespaceID, uidNamespaceIDIn, sizeof(UIDNamespaceID_t)); 28 | memcpy(uidInstanceID, uidInstanceIDIn, sizeof(UIDInstanceID_t)); 29 | } 30 | 31 | void UIDFrame::setUIDData(const UIDNamespaceID_t &uidNamespaceIDIn, const UIDInstanceID_t &uidInstanceIDIn) 32 | { 33 | memcpy(uidNamespaceID, uidNamespaceIDIn, sizeof(UIDNamespaceID_t)); 34 | memcpy(uidInstanceID, uidInstanceIDIn, sizeof(UIDInstanceID_t)); 35 | } 36 | 37 | void UIDFrame::constructUIDFrame(uint8_t *rawFrame, int8_t advPowerLevel) 38 | { 39 | size_t index = 0; 40 | 41 | rawFrame[index++] = EDDYSTONE_UUID[0]; // 16-bit Eddystone UUID 42 | rawFrame[index++] = EDDYSTONE_UUID[1]; 43 | rawFrame[index++] = FRAME_TYPE_UID; // 1B Type 44 | rawFrame[index++] = advPowerLevel; // 1B Power @ 0meter 45 | 46 | memcpy(rawFrame + index, uidNamespaceID, sizeof(UIDNamespaceID_t)); // 10B Namespace ID 47 | index += sizeof(UIDNamespaceID_t); 48 | memcpy(rawFrame + index, uidInstanceID, sizeof(UIDInstanceID_t)); // 6B Instance ID 49 | index += sizeof(UIDInstanceID_t); 50 | 51 | memset(rawFrame + index, 0, 2 * sizeof(uint8_t)); // 2B RFU, which are unused 52 | } 53 | 54 | size_t UIDFrame::getRawFrameSize(void) const 55 | { 56 | return FRAME_SIZE_UID + EDDYSTONE_UUID_SIZE; 57 | } 58 | 59 | uint8_t* UIDFrame::getUIDNamespaceID(void) 60 | { 61 | return uidNamespaceID; 62 | } 63 | 64 | uint8_t* UIDFrame::getUIDInstanceID(void) 65 | { 66 | return uidInstanceID; 67 | } 68 | -------------------------------------------------------------------------------- /BLE_EddystoneService/source/UIDFrame.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __UIDFRAME_H__ 18 | #define __UIDFRAME_H__ 19 | 20 | #include 21 | #include "EddystoneTypes.h" 22 | 23 | /** 24 | * Class that encapsulates data that belongs to the Eddystone-UID frame. For 25 | * more information refer to https://github.com/google/eddystone/tree/master/eddystone-uid. 26 | */ 27 | class UIDFrame 28 | { 29 | public: 30 | /** 31 | * Construct a new instance of this class. 32 | */ 33 | UIDFrame(void); 34 | 35 | /** 36 | * Construct a new instance of this class. 37 | * 38 | * @param[in] uidNamespaceIDIn 39 | * The Eddystone-UID namespace ID. 40 | * @param[in] uidInstanceIDIn 41 | * The Eddystone-UID instance ID. 42 | */ 43 | UIDFrame(const UIDNamespaceID_t uidNamespaceIDIn, const UIDInstanceID_t uidInstanceIDIn); 44 | 45 | /** 46 | * Set the instance and namespace ID. 47 | * 48 | * @param[in] uidNamespaceIDIn 49 | * The new Eddystone-UID namespace ID. 50 | * @param[in] uidInstanceIDIn 51 | * The new Eddystone-UID instance ID. 52 | */ 53 | void setUIDData(const UIDNamespaceID_t &uidNamespaceIDIn, const UIDInstanceID_t &uidInstanceIDIn); 54 | 55 | /** 56 | * Construct the raw bytes of the Eddystone-UID frame that will be directly 57 | * used in the advertising packets. 58 | * 59 | * @param[in] rawFrame 60 | * Pointer to the location where the raw frame will be stored. 61 | * @param[in] advPowerLevel 62 | * Power level value included withing the raw frame. 63 | */ 64 | void constructUIDFrame(uint8_t *rawFrame, int8_t advPowerLevel); 65 | 66 | /** 67 | * Get the size of the Eddystone-UID frame constructed with the 68 | * current state of the UIDFrame object. 69 | * 70 | * @return The size in bytes of the Eddystone-UID frame. 71 | */ 72 | size_t getRawFrameSize(void) const; 73 | 74 | /** 75 | * Get the Eddystone-UID namespace ID. 76 | * 77 | * @return A pointer to the namespace ID. 78 | */ 79 | uint8_t* getUIDNamespaceID(void); 80 | 81 | /** 82 | * Get the Eddystone-UID instance ID. 83 | * 84 | * @return A pointer to the instance ID. 85 | */ 86 | uint8_t* getUIDInstanceID(void); 87 | 88 | private: 89 | /** 90 | * The byte ID of an Eddystone-UID frame. 91 | */ 92 | static const uint8_t FRAME_TYPE_UID = 0x00; 93 | /** 94 | * The size (in bytes) of an Eddystone-UID frame. 95 | */ 96 | static const uint8_t FRAME_SIZE_UID = 20; 97 | 98 | /** 99 | * The Eddystone-UID namespace ID. 100 | */ 101 | UIDNamespaceID_t uidNamespaceID; 102 | /** 103 | * The Eddystone-UID instance ID. 104 | */ 105 | UIDInstanceID_t uidInstanceID; 106 | }; 107 | 108 | #endif /* __UIDFRAME_H__ */ 109 | -------------------------------------------------------------------------------- /BLE_EddystoneService/source/URLFrame.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "URLFrame.h" 18 | 19 | URLFrame::URLFrame(void) 20 | { 21 | urlDataLength = 0; 22 | memset(urlData, 0, sizeof(UrlData_t)); 23 | } 24 | 25 | URLFrame::URLFrame(const char *urlDataIn) 26 | { 27 | encodeURL(urlDataIn); 28 | } 29 | 30 | URLFrame::URLFrame(UrlData_t urlDataIn, uint8_t urlDataLengthIn) 31 | { 32 | urlDataLength = (urlDataLengthIn > URL_DATA_MAX) ? URL_DATA_MAX : urlDataLengthIn; 33 | memcpy(urlData, urlDataIn, urlDataLength); 34 | } 35 | 36 | void URLFrame::constructURLFrame(uint8_t* rawFrame, int8_t advPowerLevel) 37 | { 38 | size_t index = 0; 39 | rawFrame[index++] = EDDYSTONE_UUID[0]; // 16-bit Eddystone UUID 40 | rawFrame[index++] = EDDYSTONE_UUID[1]; 41 | rawFrame[index++] = FRAME_TYPE_URL; // 1B Type 42 | rawFrame[index++] = advPowerLevel; // 1B Power @ 0meter 43 | memcpy(rawFrame + index, urlData, urlDataLength); // Encoded URL 44 | } 45 | 46 | size_t URLFrame::getRawFrameSize(void) const 47 | { 48 | return urlDataLength + FRAME_MIN_SIZE_URL + EDDYSTONE_UUID_SIZE; 49 | } 50 | 51 | uint8_t* URLFrame::getEncodedURLData(void) 52 | { 53 | return urlData; 54 | } 55 | 56 | uint8_t URLFrame::getEncodedURLDataLength(void) const 57 | { 58 | return urlDataLength; 59 | } 60 | 61 | void URLFrame::setURLData(const char *urlDataIn) 62 | { 63 | encodeURL(urlDataIn); 64 | } 65 | 66 | void URLFrame::setEncodedURLData(const uint8_t* urlEncodedDataIn, const uint8_t urlEncodedDataLengthIn) 67 | { 68 | urlDataLength = urlEncodedDataLengthIn; 69 | memcpy(urlData, urlEncodedDataIn, urlEncodedDataLengthIn); 70 | } 71 | 72 | void URLFrame::encodeURL(const char *urlDataIn) 73 | { 74 | const char *prefixes[] = { 75 | "http://www.", 76 | "https://www.", 77 | "http://", 78 | "https://", 79 | }; 80 | const size_t NUM_PREFIXES = sizeof(prefixes) / sizeof(char *); 81 | const char *suffixes[] = { 82 | ".com/", 83 | ".org/", 84 | ".edu/", 85 | ".net/", 86 | ".info/", 87 | ".biz/", 88 | ".gov/", 89 | ".com", 90 | ".org", 91 | ".edu", 92 | ".net", 93 | ".info", 94 | ".biz", 95 | ".gov" 96 | }; 97 | const size_t NUM_SUFFIXES = sizeof(suffixes) / sizeof(char *); 98 | 99 | urlDataLength = 0; 100 | memset(urlData, 0, sizeof(UrlData_t)); 101 | 102 | if ((urlDataIn == NULL) || (strlen(urlDataIn) == 0)) { 103 | return; 104 | } 105 | 106 | /* 107 | * handle prefix 108 | */ 109 | for (size_t i = 0; i < NUM_PREFIXES; i++) { 110 | size_t prefixLen = strlen(prefixes[i]); 111 | if (strncmp(urlDataIn, prefixes[i], prefixLen) == 0) { 112 | urlData[urlDataLength++] = i; 113 | urlDataIn += prefixLen; 114 | break; 115 | } 116 | } 117 | 118 | /* 119 | * handle suffixes 120 | */ 121 | while (*urlDataIn && (urlDataLength < URL_DATA_MAX)) { 122 | /* check for suffix match */ 123 | size_t i; 124 | for (i = 0; i < NUM_SUFFIXES; i++) { 125 | size_t suffixLen = strlen(suffixes[i]); 126 | if (strncmp(urlDataIn, suffixes[i], suffixLen) == 0) { 127 | urlData[urlDataLength++] = i; 128 | urlDataIn += suffixLen; 129 | break; /* from the for loop for checking against suffixes */ 130 | } 131 | } 132 | /* This is the default case where we've got an ordinary character which doesn't match a suffix. */ 133 | if (i == NUM_SUFFIXES) { 134 | urlData[urlDataLength++] = *urlDataIn; 135 | ++urlDataIn; 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /BLE_EddystoneService/source/URLFrame.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __URLFRAME_H__ 18 | #define __URLFRAME_H__ 19 | 20 | #include "EddystoneTypes.h" 21 | #include 22 | 23 | /** 24 | * Class that encapsulates data that belongs to the Eddystone-URL frame. For 25 | * more information refer to https://github.com/google/eddystone/tree/master/eddystone-url. 26 | */ 27 | class URLFrame 28 | { 29 | public: 30 | /** 31 | * Construct a new instance of this class. 32 | */ 33 | URLFrame(void); 34 | 35 | /** 36 | * Construct a new instance of this class. 37 | * 38 | * @param[in] urlDataIn 39 | * A null terminated string representing a URL. 40 | */ 41 | URLFrame(const char *urlDataIn); 42 | 43 | /** 44 | * Construct a new instance of this class. 45 | * 46 | * @param[in] urlDataIn 47 | * An encoded URL. 48 | * @param[in] urlDataLengthIn 49 | * The length (in bytes) of the encoded URL. 50 | */ 51 | URLFrame(UrlData_t urlDataIn, uint8_t urlDataLengthIn); 52 | 53 | /** 54 | * Construct the raw bytes of the Eddystone-URL frame that will be directly 55 | * used in the advertising packets. 56 | * 57 | * @param[in] rawFrame 58 | * Pointer to the location where the raw frame will be stored. 59 | * @param[in] advPowerLevel 60 | * Power level value included withing the raw frame. 61 | */ 62 | void constructURLFrame(uint8_t* rawFrame, int8_t advPowerLevel); 63 | 64 | /** 65 | * Get the size of the Eddystone-URL frame constructed with the 66 | * current state of the URLFrame object. 67 | * 68 | * @return The size in bytes of the Eddystone-URL frame. 69 | */ 70 | size_t getRawFrameSize(void) const; 71 | 72 | /** 73 | * Get a pointer to the encoded URL data. 74 | * 75 | * @return A pointer to the encoded URL data. 76 | */ 77 | uint8_t* getEncodedURLData(void); 78 | 79 | /** 80 | * Get the encoded URL data length. 81 | * 82 | * @return The length (in bytes) of the encoded URL data frame. 83 | */ 84 | uint8_t getEncodedURLDataLength(void) const; 85 | 86 | /** 87 | * Set a new URL. 88 | * 89 | * @param[in] urlDataIn 90 | * A null terminated string containing the new URL. 91 | */ 92 | void setURLData(const char *urlDataIn); 93 | 94 | /** 95 | * Set an encoded URL. 96 | * 97 | * @param[in] urlEncodedDataIn 98 | * A pointer to the encoded URL data. 99 | * @param[in] urlEncodedDataLengthIn 100 | * The lenght of the encoded URL data pointed to by @p 101 | * urlEncodedDataIn. 102 | */ 103 | void setEncodedURLData(const uint8_t* urlEncodedDataIn, const uint8_t urlEncodedDataLengthIn); 104 | 105 | private: 106 | /** 107 | * Helper function that encodes a URL null terminated string into the HTTP 108 | * URL Encoding required in Eddystone-URL frames. Refer to 109 | * https://github.com/google/eddystone/blob/master/eddystone-url/README.md#eddystone-url-http-url-encoding. 110 | * 111 | * @param[in] urlDataIn 112 | * The null terminated string containing a URL to encode. 113 | */ 114 | void encodeURL(const char *urlDataIn); 115 | 116 | /** 117 | * The byte ID of an Eddystone-URL frame. 118 | */ 119 | static const uint8_t FRAME_TYPE_URL = 0x10; 120 | /** 121 | * The minimum size (in bytes) of an Eddystone-URL frame. 122 | */ 123 | static const uint8_t FRAME_MIN_SIZE_URL = 2; 124 | 125 | /** 126 | * The length of the encoded URL. 127 | */ 128 | uint8_t urlDataLength; 129 | /** 130 | * The enconded URL data. 131 | */ 132 | UrlData_t urlData; 133 | 134 | }; 135 | 136 | #endif /* __URLFRAME_H__ */ 137 | -------------------------------------------------------------------------------- /BLE_EddystoneService/source/main.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "mbed-drivers/mbed.h" 18 | #include "ble/BLE.h" 19 | #include "EddystoneService.h" 20 | 21 | #include "PersistentStorageHelper/ConfigParamsPersistence.h" 22 | 23 | EddystoneService *eddyServicePtr; 24 | 25 | /* Duration after power-on that config service is available. */ 26 | static const int CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS = 30; 27 | 28 | /* Default UID frame data */ 29 | static const UIDNamespaceID_t uidNamespaceID = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99}; 30 | static const UIDInstanceID_t uidInstanceID = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}; 31 | 32 | /* Default version in TLM frame */ 33 | static const uint8_t tlmVersion = 0x00; 34 | 35 | /* Values for ADV packets related to firmware levels, calibrated based on measured values at 1m */ 36 | static const PowerLevels_t defaultAdvPowerLevels = {-47, -33, -21, -13}; 37 | /* Values for radio power levels, provided by manufacturer. */ 38 | static const PowerLevels_t radioPowerLevels = {-30, -16, -4, 4}; 39 | 40 | DigitalOut led(LED1, 1); 41 | 42 | /** 43 | * Callback triggered upon a disconnection event. 44 | */ 45 | static void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *cbParams) 46 | { 47 | (void) cbParams; 48 | BLE::Instance().gap().startAdvertising(); 49 | } 50 | 51 | /** 52 | * Callback triggered some time after application started to switch to beacon mode. 53 | */ 54 | static void timeout(void) 55 | { 56 | Gap::GapState_t state; 57 | state = BLE::Instance().gap().getState(); 58 | if (!state.connected) { /* don't switch if we're in a connected state. */ 59 | eddyServicePtr->startBeaconService(); 60 | EddystoneService::EddystoneParams_t params; 61 | eddyServicePtr->getEddystoneParams(params); 62 | saveEddystoneServiceConfigParams(¶ms); 63 | } else { 64 | minar::Scheduler::postCallback(timeout).delay(minar::milliseconds(CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS * 1000)); 65 | } 66 | } 67 | 68 | static void blinky(void) 69 | { 70 | led = !led; 71 | } 72 | 73 | static void onBleInitError(BLE::InitializationCompleteCallbackContext* initContext) 74 | { 75 | /* Initialization error handling goes here... */ 76 | (void) initContext; 77 | } 78 | 79 | static void initializeEddystoneToDefaults(BLE &ble) 80 | { 81 | /* Set everything to defaults */ 82 | eddyServicePtr = new EddystoneService(ble, defaultAdvPowerLevels, radioPowerLevels); 83 | 84 | /* Set default URL, UID and TLM frame data if not initialized through the config service */ 85 | const char* url = YOTTA_CFG_EDDYSTONE_DEFAULT_URL; 86 | eddyServicePtr->setURLData(url); 87 | eddyServicePtr->setUIDData(uidNamespaceID, uidInstanceID); 88 | eddyServicePtr->setTLMData(tlmVersion); 89 | } 90 | 91 | static void bleInitComplete(BLE::InitializationCompleteCallbackContext* initContext) 92 | { 93 | BLE &ble = initContext->ble; 94 | ble_error_t error = initContext->error; 95 | 96 | if (error != BLE_ERROR_NONE) { 97 | onBleInitError(initContext); 98 | return; 99 | } 100 | 101 | ble.gap().onDisconnection(disconnectionCallback); 102 | 103 | EddystoneService::EddystoneParams_t params; 104 | if (loadEddystoneServiceConfigParams(¶ms)) { 105 | eddyServicePtr = new EddystoneService(ble, params, radioPowerLevels); 106 | } else { 107 | initializeEddystoneToDefaults(ble); 108 | } 109 | 110 | /* Start Eddystone in config mode */ 111 | eddyServicePtr->startConfigService(); 112 | 113 | minar::Scheduler::postCallback(timeout).delay(minar::milliseconds(CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS * 1000)); 114 | } 115 | 116 | void app_start(int, char *[]) 117 | { 118 | /* Tell standard C library to not allocate large buffers for these streams */ 119 | setbuf(stdout, NULL); 120 | setbuf(stderr, NULL); 121 | setbuf(stdin, NULL); 122 | 123 | minar::Scheduler::postCallback(blinky).period(minar::milliseconds(500)); 124 | 125 | BLE &ble = BLE::Instance(); 126 | ble.init(bleInitComplete); 127 | } 128 | -------------------------------------------------------------------------------- /BLE_GAPButton/README.md: -------------------------------------------------------------------------------- 1 | # Button count over GAP 2 | 3 | This application shows how to use GAP to transmit a simple value to disconnected peer listening for advertisement every time that a value is updated: 4 | 5 | 1. The value is a count of how many times a button on the device was pressed (the code actually monitors the button's releases, not press downs). 6 | 7 | 1. We transmit the value in the SERVICE_DATA field of the advertising payload. 8 | 9 | # Running the application 10 | 11 | ## Requirements 12 | 13 | The sample application can be seen on any BLE scanner on a smartphone. If you don't have a scanner on your phone, please install : 14 | 15 | - [nRF Master Control Panel](https://play.google.com/store/apps/details?id=no.nordicsemi.android.mcp) for Android. 16 | 17 | - [LightBlue](https://itunes.apple.com/gb/app/lightblue-bluetooth-low-energy/id557428110?mt=8) for iPhone. 18 | 19 | Hardware requirements are in the [main readme](https://github.com/ARMmbed/ble-examples/blob/master/README.md). 20 | 21 | ## Building instructions 22 | 23 | Building instructions for all samples are in the [main readme](https://github.com/ARMmbed/ble-examples/blob/master/README.md). 24 | 25 | ## Checking for success 26 | 27 | **Note:** Screens captures depicted below show what is expected from this example if the scanner used is *nRF Master Control Panel* version 4.0.5. If you encounter any difficulties consider trying another scanner or another version of nRF Master Control Panel. Alternative scanners may require reference to their manuals. 28 | 29 | 1. Build the application and install it on your board as explained in the building instructions. 30 | 31 | 1. Open the BLE scanner on your phone. 32 | 33 | 1. Start a scan. 34 | 35 | ![](img/start_scan.png) 36 | 37 | **figure 1** How to start scan using nRF Master Control Panel 4.0.5. 38 | 39 | 1. Find your device; it should be named `GAPButton`; and look at the advertisement broadcasted by your device (there is no need to connect to your device). 40 | 41 | ![](img/discovery.png) 42 | 43 | **figure 2** Scan results using nRF Master Control Panel 4.0.5. 44 | 45 | 1. The Service Data field of the advertisement packet broadcasted by your device reflects the button press count. The starting value is 0. 46 | 47 | ![](img/initial_state.png) 48 | 49 | **figure 3** Initial state of the button using nRF Master Control Panel 4.0.5. 50 | 51 | 1. Press the button on the device. 52 | 53 | ![](img/first_press.png) 54 | 55 | **figure 3** State after 1 button press using nRF Master Control Panel 4.0.5. 56 | 57 | 1. The Service Data field value of the advertisement packet should change every time you press the button. 58 | 59 | ![](img/result.png) 60 | 61 | **figure 3** State after 6 button press using nRF Master Control Panel 4.0.5. 62 | 63 | ## Note 64 | 65 | Since broadcasting is not reliable and your phone may scan intermittently, it is possible that your phone will miss button updates. 66 | -------------------------------------------------------------------------------- /BLE_GAPButton/img/discovery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_GAPButton/img/discovery.png -------------------------------------------------------------------------------- /BLE_GAPButton/img/first_press.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_GAPButton/img/first_press.png -------------------------------------------------------------------------------- /BLE_GAPButton/img/initial_state.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_GAPButton/img/initial_state.png -------------------------------------------------------------------------------- /BLE_GAPButton/img/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_GAPButton/img/result.png -------------------------------------------------------------------------------- /BLE_GAPButton/img/start_scan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_GAPButton/img/start_scan.png -------------------------------------------------------------------------------- /BLE_GAPButton/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ble-gapbutton", 3 | "version": "0.0.1", 4 | "bin": "./source", 5 | "description": "BLE button that uses gap advertisement to broadcast its state.", 6 | "author": "Liyou Zhou", 7 | "license": "Apache-2.0", 8 | "dependencies": { 9 | "mbed-drivers": "*", 10 | "ble": "^2.0.0" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /BLE_GAPButton/source/main.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "mbed-drivers/mbed.h" 18 | #include "ble/BLE.h" 19 | 20 | DigitalOut led1(LED1, 1); 21 | InterruptIn button(BUTTON1); 22 | uint8_t cnt; 23 | 24 | // Change your device name below 25 | const char DEVICE_NAME[] = "GAPButton"; 26 | 27 | /* We can arbiturarily choose the GAPButton service UUID to be 0xAA00 28 | * as long as it does not overlap with the UUIDs defined here: 29 | * https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx */ 30 | #define GAPButtonUUID 0xAA00 31 | const uint16_t uuid16_list[] = {GAPButtonUUID}; 32 | 33 | void print_error(ble_error_t error, const char* msg) 34 | { 35 | printf("%s: ", msg); 36 | switch(error) { 37 | case BLE_ERROR_NONE: 38 | printf("BLE_ERROR_NONE: No error"); 39 | break; 40 | case BLE_ERROR_BUFFER_OVERFLOW: 41 | printf("BLE_ERROR_BUFFER_OVERFLOW: The requested action would cause a buffer overflow and has been aborted"); 42 | break; 43 | case BLE_ERROR_NOT_IMPLEMENTED: 44 | printf("BLE_ERROR_NOT_IMPLEMENTED: Requested a feature that isn't yet implement or isn't supported by the target HW"); 45 | break; 46 | case BLE_ERROR_PARAM_OUT_OF_RANGE: 47 | printf("BLE_ERROR_PARAM_OUT_OF_RANGE: One of the supplied parameters is outside the valid range"); 48 | break; 49 | case BLE_ERROR_INVALID_PARAM: 50 | printf("BLE_ERROR_INVALID_PARAM: One of the supplied parameters is invalid"); 51 | break; 52 | case BLE_STACK_BUSY: 53 | printf("BLE_STACK_BUSY: The stack is busy"); 54 | break; 55 | case BLE_ERROR_INVALID_STATE: 56 | printf("BLE_ERROR_INVALID_STATE: Invalid state"); 57 | break; 58 | case BLE_ERROR_NO_MEM: 59 | printf("BLE_ERROR_NO_MEM: Out of Memory"); 60 | break; 61 | case BLE_ERROR_OPERATION_NOT_PERMITTED: 62 | printf("BLE_ERROR_OPERATION_NOT_PERMITTED"); 63 | break; 64 | case BLE_ERROR_INITIALIZATION_INCOMPLETE: 65 | printf("BLE_ERROR_INITIALIZATION_INCOMPLETE"); 66 | break; 67 | case BLE_ERROR_ALREADY_INITIALIZED: 68 | printf("BLE_ERROR_ALREADY_INITIALIZED"); 69 | break; 70 | case BLE_ERROR_UNSPECIFIED: 71 | printf("BLE_ERROR_UNSPECIFIED: Unknown error"); 72 | break; 73 | } 74 | printf("\r\n"); 75 | } 76 | 77 | void updatePayload(void) 78 | { 79 | // Update the count in the SERVICE_DATA field of the advertising payload 80 | uint8_t service_data[3]; 81 | service_data[0] = GAPButtonUUID & 0xff; 82 | service_data[1] = GAPButtonUUID >> 8; 83 | service_data[2] = cnt; // Put the button click count in the third byte 84 | ble_error_t err = BLE::Instance().gap().updateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, (uint8_t *)service_data, sizeof(service_data)); 85 | if (err != BLE_ERROR_NONE) { 86 | print_error(err, "Updating payload failed"); 87 | } 88 | } 89 | 90 | void buttonPressedCallback(void) 91 | { 92 | ++cnt; 93 | 94 | // Calling BLE api in interrupt context may cause race conditions 95 | // Using minar to schedule calls to BLE api for safety 96 | minar::Scheduler::postCallback(updatePayload); 97 | } 98 | 99 | void blinkCallback(void) 100 | { 101 | led1 = !led1; 102 | } 103 | 104 | void bleInitComplete(BLE::InitializationCompleteCallbackContext *context) 105 | { 106 | BLE& ble = context->ble; 107 | ble_error_t err = context->error; 108 | 109 | if (err != BLE_ERROR_NONE) { 110 | print_error(err, "BLE initialisation failed"); 111 | return; 112 | } 113 | 114 | // Set up the advertising flags. Note: not all combination of flags are valid 115 | // BREDR_NOT_SUPPORTED: Device does not support Basic Rate or Enchanced Data Rate, It is Low Energy only. 116 | // LE_GENERAL_DISCOVERABLE: Peripheral device is discoverable at any moment 117 | err = ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); 118 | if (err != BLE_ERROR_NONE) { 119 | print_error(err, "Setting GAP flags failed"); 120 | return; 121 | } 122 | 123 | // Put the device name in the advertising payload 124 | err = ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); 125 | if (err != BLE_ERROR_NONE) { 126 | print_error(err, "Setting device name failed"); 127 | return; 128 | } 129 | 130 | err = ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); 131 | if (err != BLE_ERROR_NONE) { 132 | print_error(err, "Setting service UUID failed"); 133 | return; 134 | } 135 | 136 | // The Service Data data type consists of a service UUID with the data associated with that service. 137 | // We will encode the number of button clicks in the Service Data field 138 | // First two bytes of SERVICE_DATA field should contain the UUID of the service 139 | uint8_t service_data[3]; 140 | service_data[0] = GAPButtonUUID & 0xff; 141 | service_data[1] = GAPButtonUUID >> 8; 142 | service_data[2] = cnt; // Put the button click count in the third byte 143 | err = ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, (uint8_t *)service_data, sizeof(service_data)); 144 | if (err != BLE_ERROR_NONE) { 145 | print_error(err, "Setting service data failed"); 146 | return; 147 | } 148 | 149 | // It is not connectable as we are just boardcasting 150 | ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED); 151 | 152 | // Send out the advertising payload every 1000ms 153 | ble.gap().setAdvertisingInterval(1000); 154 | 155 | err = ble.gap().startAdvertising(); 156 | if (err != BLE_ERROR_NONE) { 157 | print_error(err, "Sart advertising failed"); 158 | return; 159 | } 160 | } 161 | 162 | void app_start(int, char**) 163 | { 164 | cnt = 0; 165 | ble_error_t err = BLE::Instance().init(bleInitComplete); 166 | if (err != BLE_ERROR_NONE) { 167 | print_error(err, "BLE initialisation failed"); 168 | return; 169 | } 170 | 171 | // Blink LED every 500 ms to indicate system aliveness 172 | minar::Scheduler::postCallback(blinkCallback).period(minar::milliseconds(500)); 173 | 174 | // Register function to be called when button is released 175 | button.rise(buttonPressedCallback); 176 | } 177 | -------------------------------------------------------------------------------- /BLE_HeartRate/img/connection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_HeartRate/img/connection.png -------------------------------------------------------------------------------- /BLE_HeartRate/img/discovery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_HeartRate/img/discovery.png -------------------------------------------------------------------------------- /BLE_HeartRate/img/notifications.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_HeartRate/img/notifications.png -------------------------------------------------------------------------------- /BLE_HeartRate/img/register_to_notifications.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_HeartRate/img/register_to_notifications.png -------------------------------------------------------------------------------- /BLE_HeartRate/img/scan_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_HeartRate/img/scan_result.png -------------------------------------------------------------------------------- /BLE_HeartRate/img/start_scan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_HeartRate/img/start_scan.png -------------------------------------------------------------------------------- /BLE_HeartRate/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ble-heartrate", 3 | "version": "0.0.1", 4 | "description": "BLE Heartreate example, building with yotta", 5 | "licenses": [ 6 | { 7 | "url": "https://spdx.org/licenses/Apache-2.0", 8 | "type": "Apache-2.0" 9 | } 10 | ], 11 | "dependencies": { 12 | "ble": "^2.0.0" 13 | }, 14 | "targetDependencies": {}, 15 | "bin": "./source" 16 | } 17 | -------------------------------------------------------------------------------- /BLE_HeartRate/readme.md: -------------------------------------------------------------------------------- 1 | # BLE Heart Rate Monitor 2 | 3 | This application transmits a heart rate value using the [Bluetooth SIG Heart Rate Profile](https://developer.bluetooth.org/TechnologyOverview/Pages/HRP.aspx). The heart rate value is provided by the application itself, not by a sensor, so that you don't have to get a sensor just to run the example. 4 | 5 | Technical details are better presented [in the mbed Classic equivalent of this example](https://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_HeartRate/). 6 | 7 | # Running the application 8 | 9 | ## Requirements 10 | 11 | To see the heart rate information on your phone, download Panobike for [iOS](https://itunes.apple.com/gb/app/panobike/id567403997?mt=8) or [Android](https://play.google.com/store/apps/details?id=com.topeak.panobike&hl=en). 12 | 13 | You could also use a generic BLE scanners: 14 | 15 | - [nRF Master Control Panel](https://play.google.com/store/apps/details?id=no.nordicsemi.android.mcp) for Android. 16 | 17 | - [LightBlue](https://itunes.apple.com/gb/app/lightblue-bluetooth-low-energy/id557428110?mt=8) for iPhone. 18 | 19 | Hardware requirements are in the [main readme](https://github.com/ARMmbed/ble-examples/blob/master/README.md). 20 | 21 | ## Building instructions 22 | 23 | Building instructions for all samples are in the [main readme](https://github.com/ARMmbed/ble-examples/blob/master/README.md). 24 | 25 | ## Checking for success 26 | 27 | **Note:** Screens captures depicted below show what is expected from this example if the scanner used is *nRF Master Control Panel* version 4.0.5. If you encounter any difficulties consider trying another scanner or another version of nRF Master Control Panel. Alternative scanners may require reference to their manuals. 28 | 29 | 1. Build the application and install it on your board as explained in the building instructions. 30 | 1. Open the BLE scanner on your phone. 31 | 1. Start a scan. 32 | 33 | ![](img/start_scan.png) 34 | 35 | **figure 1** How to start scan using nRF Master Control Panel 4.0.5 36 | 37 | 1. Find your device; it should be named `HRM`. 38 | 39 | ![](img/scan_result.png) 40 | 41 | **figure 2** Scan results using nRF Master Control Panel 4.0.5 42 | 43 | 1. Establish a connection with your device. 44 | 45 | ![](img/connection.png) 46 | 47 | **figure 3** How to establish a connection using Master Control Panel 4.0.5 48 | 49 | 1. Discover the services and the characteristics on the device. The *Heart Rate* service has the UUID `0x180D` and includes the *Heart Rate Measurement* characteristic which has the UUID `0x2A37`. 50 | 51 | ![](img/discovery.png) 52 | 53 | **figure 4** Representation of the Heart Rate service using Master Control Panel 4.0.5 54 | 55 | 1. Register for the notifications sent by the *Heart Rate Measurement* characteristic. 56 | 57 | ![](img/register_to_notifications.png) 58 | 59 | **figure 5** How to register to notifications using Master Control Panel 4.0.5 60 | 61 | 62 | 1. You should see the heart rate value change every half second. It begins at 100, goes up to 175 (in steps of 1), resets to 100 and so on. 63 | 64 | ![](img/notifications.png) 65 | 66 | **figure 6** Notifications view using Master Control Panel 4.0.5 67 | -------------------------------------------------------------------------------- /BLE_HeartRate/source/main.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "mbed-drivers/mbed.h" 18 | #include "ble/BLE.h" 19 | #include "ble/Gap.h" 20 | #include "ble/services/HeartRateService.h" 21 | 22 | DigitalOut led1(LED1, 1); 23 | 24 | const static char DEVICE_NAME[] = "HRM"; 25 | static const uint16_t uuid16_list[] = {GattService::UUID_HEART_RATE_SERVICE}; 26 | 27 | static uint8_t hrmCounter = 100; // init HRM to 100bps 28 | static HeartRateService *hrServicePtr; 29 | 30 | void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) 31 | { 32 | BLE::Instance().gap().startAdvertising(); // restart advertising 33 | } 34 | 35 | void updateSensorValue() { 36 | // Do blocking calls or whatever is necessary for sensor polling. 37 | // In our case, we simply update the HRM measurement. 38 | hrmCounter++; 39 | 40 | // 100 <= HRM bps <=175 41 | if (hrmCounter == 175) { 42 | hrmCounter = 100; 43 | } 44 | 45 | hrServicePtr->updateHeartRate(hrmCounter); 46 | } 47 | 48 | void periodicCallback(void) 49 | { 50 | led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */ 51 | 52 | if (BLE::Instance().getGapState().connected) { 53 | minar::Scheduler::postCallback(updateSensorValue); 54 | } 55 | } 56 | 57 | void onBleInitError(BLE &ble, ble_error_t error) 58 | { 59 | (void)ble; 60 | (void)error; 61 | /* Initialization error handling should go here */ 62 | } 63 | 64 | void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) 65 | { 66 | BLE& ble = params->ble; 67 | ble_error_t error = params->error; 68 | 69 | if (error != BLE_ERROR_NONE) { 70 | onBleInitError(ble, error); 71 | return; 72 | } 73 | 74 | if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) { 75 | return; 76 | } 77 | 78 | ble.gap().onDisconnection(disconnectionCallback); 79 | 80 | /* Setup primary service. */ 81 | hrServicePtr = new HeartRateService(ble, hrmCounter, HeartRateService::LOCATION_FINGER); 82 | 83 | /* Setup advertising. */ 84 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); 85 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); 86 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR); 87 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); 88 | ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); 89 | ble.gap().setAdvertisingInterval(1000); /* 1000ms */ 90 | ble.gap().startAdvertising(); 91 | } 92 | 93 | void app_start(int, char **) 94 | { 95 | minar::Scheduler::postCallback(periodicCallback).period(minar::milliseconds(500)); 96 | 97 | BLE::Instance().init(bleInitComplete); 98 | } 99 | -------------------------------------------------------------------------------- /BLE_LED/img/LED_OFF.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_LED/img/LED_OFF.png -------------------------------------------------------------------------------- /BLE_LED/img/LED_ON.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_LED/img/LED_ON.png -------------------------------------------------------------------------------- /BLE_LED/img/connection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_LED/img/connection.png -------------------------------------------------------------------------------- /BLE_LED/img/discovery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_LED/img/discovery.png -------------------------------------------------------------------------------- /BLE_LED/img/scan_results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_LED/img/scan_results.png -------------------------------------------------------------------------------- /BLE_LED/img/start_scan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_LED/img/start_scan.png -------------------------------------------------------------------------------- /BLE_LED/img/write_characteristic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_LED/img/write_characteristic.png -------------------------------------------------------------------------------- /BLE_LED/img/write_pannel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_LED/img/write_pannel.png -------------------------------------------------------------------------------- /BLE_LED/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ble-led", 3 | "version": "0.0.1", 4 | "description": "A simple service that demonstrates the use of a read-write characteristic to control a LED", 5 | "licenses": [ 6 | { 7 | "url": "https://spdx.org/licenses/Apache-2.0", 8 | "type": "Apache-2.0" 9 | } 10 | ], 11 | "dependencies": { 12 | "ble": "^2.0.0" 13 | }, 14 | "targetDependencies": {}, 15 | "bin": "./source" 16 | } 17 | -------------------------------------------------------------------------------- /BLE_LED/readme.md: -------------------------------------------------------------------------------- 1 | To help you create your own BLE services, we have created this service template. 2 | The LED example demonstrates the use of a read-write characteristic to control a 3 | LED through a phone app. 4 | 5 | The template covers: 6 | 7 | * Setting up advertising and connection states. 8 | * Assigning UUIDs to the service and its characteristic. 9 | * Creating an input characteristic: read-write, boolean. This characteristic offers control of the LED. 10 | * Constructing a service class and adding it to the BLE stack. 11 | 12 | # Running the application 13 | 14 | ## Requirements 15 | 16 | The sample application can be seen on any BLE scanner on a smartphone. If you don't have a scanner on your phone, please install : 17 | 18 | - [nRF Master Control Panel](https://play.google.com/store/apps/details?id=no.nordicsemi.android.mcp) for Android. 19 | 20 | - [LightBlue](https://itunes.apple.com/gb/app/lightblue-bluetooth-low-energy/id557428110?mt=8) for iPhone. 21 | 22 | Hardware requirements are in the [main readme](https://github.com/ARMmbed/ble-examples/blob/master/README.md). 23 | 24 | *NOTE:* If you have more than a single mbed board (e.g. nrf51dk or mkit) you can 25 | run the BLE_LED and BLE_LEDBlinker at the same time. For more information please 26 | refer to the BLE_LEDBlinker demo. 27 | 28 | ## Building instructions 29 | 30 | Building instructions for all samples are in the [main readme](https://github.com/ARMmbed/ble-examples/blob/master/README.md). 31 | 32 | ## Checking for success 33 | 34 | **Note:** Screens captures depicted below show what is expected from this example if the scanner used is *nRF Master Control Panel* version 4.0.5. If you encounter any difficulties consider trying another scanner or another version of nRF Master Control Panel. Alternative scanners may require reference to their manuals. 35 | 36 | 37 | 1. Build the application and install it on your board as explained in the building instructions. 38 | 1. Open the BLE scanner on your phone. 39 | 40 | 1. Start a scan. 41 | 42 | ![](img/start_scan.png) 43 | 44 | **figure 1** How to start scan using nRF Master Control Panel 4.0.5 45 | 46 | 1. Find your device; it should be named `LED`. 47 | 48 | ![](img/scan_results.png) 49 | 50 | **figure 2** Scan results using nRF Master Control Panel 4.0.5 51 | 52 | 1. Establish a connection with your device. 53 | 54 | ![](img/connection.png) 55 | 56 | **figure 3** How to establish a connection using Master Control Panel 4.0.5 57 | 58 | 1. Discover the services and the characteristics on the device. The *LED service* has the UUID `0xA000` and includes the *LED state characteristic* which has the UUID `0xA001`. Depending on your scanner, non standard 16-bit UUID's can be displayed as 128-bit UUID's. If it is the case the following format will be used: `0000XXXX-0000-1000-8000-00805F9B34FB` where `XXXX` is the hexadecimal representation of the 16-bit UUID value. 59 | 60 | ![](img/discovery.png) 61 | 62 | **figure 4** Representation of the Led service using Master Control Panel 4.0.5 63 | 64 | 1. Open the write pannel of the *LED state* characteristic. 65 | 66 | ![](img/write_characteristic.png) 67 | 68 | **figure 5** How to read and write a characteristic value using Master Control Panel 4.0.5 69 | 70 | 71 | 1. The characteristic accept a 1 byte value: 72 | 73 | ![](img/write_pannel.png) 74 | 75 | **figure 6** Write characteristic pannel using Master Control Panel 4.0.5 76 | 77 | * `0x00`: LED ON 78 | 79 | ![](img/LED_ON.png) 80 | 81 | **figure 6** Write characteristic pannel to set the LED on using Master Control Panel 4.0.5 82 | 83 | 84 | * `0x01`: LED OFF 85 | 86 | ![](img/LED_OFF.png) 87 | 88 | **figure 6** Write characteristic pannel to set the LED off using Master Control Panel 4.0.5 89 | 90 | 91 | 1. Toggle the LED characteristic value and see the LED turn ON or turn OFF according to the value you set. 92 | 93 | If you can see the characteristic, and the LED is turned on/off as you toggle its value, the application is working properly. 94 | -------------------------------------------------------------------------------- /BLE_LED/source/LEDService.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __BLE_LED_SERVICE_H__ 18 | #define __BLE_LED_SERVICE_H__ 19 | 20 | class LEDService { 21 | public: 22 | const static uint16_t LED_SERVICE_UUID = 0xA000; 23 | const static uint16_t LED_STATE_CHARACTERISTIC_UUID = 0xA001; 24 | 25 | LEDService(BLEDevice &_ble, bool initialValueForLEDCharacteristic) : 26 | ble(_ble), ledState(LED_STATE_CHARACTERISTIC_UUID, &initialValueForLEDCharacteristic) 27 | { 28 | GattCharacteristic *charTable[] = {&ledState}; 29 | GattService ledService(LED_SERVICE_UUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *)); 30 | ble.addService(ledService); 31 | } 32 | 33 | GattAttribute::Handle_t getValueHandle() const 34 | { 35 | return ledState.getValueHandle(); 36 | } 37 | 38 | private: 39 | BLEDevice &ble; 40 | ReadWriteGattCharacteristic ledState; 41 | }; 42 | 43 | #endif /* #ifndef __BLE_LED_SERVICE_H__ */ 44 | -------------------------------------------------------------------------------- /BLE_LED/source/main.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "mbed-drivers/mbed.h" 18 | #include "ble/BLE.h" 19 | #include "LEDService.h" 20 | 21 | DigitalOut alivenessLED(LED1, 0); 22 | DigitalOut actuatedLED(LED2, 0); 23 | 24 | const static char DEVICE_NAME[] = "LED"; 25 | static const uint16_t uuid16_list[] = {LEDService::LED_SERVICE_UUID}; 26 | 27 | LEDService *ledServicePtr; 28 | 29 | void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) 30 | { 31 | (void) params; 32 | BLE::Instance().gap().startAdvertising(); 33 | } 34 | 35 | void blinkCallback(void) 36 | { 37 | alivenessLED = !alivenessLED; /* Do blinky on LED1 to indicate system aliveness. */ 38 | } 39 | 40 | /** 41 | * This callback allows the LEDService to receive updates to the ledState Characteristic. 42 | * 43 | * @param[in] params 44 | * Information about the characterisitc being updated. 45 | */ 46 | void onDataWrittenCallback(const GattWriteCallbackParams *params) { 47 | if ((params->handle == ledServicePtr->getValueHandle()) && (params->len == 1)) { 48 | actuatedLED = *(params->data); 49 | } 50 | } 51 | 52 | /** 53 | * This function is called when the ble initialization process has failled 54 | */ 55 | void onBleInitError(BLE &ble, ble_error_t error) 56 | { 57 | /* Initialization error handling should go here */ 58 | } 59 | 60 | /** 61 | * Callback triggered when the ble initialization process has finished 62 | */ 63 | void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) 64 | { 65 | BLE& ble = params->ble; 66 | ble_error_t error = params->error; 67 | 68 | if (error != BLE_ERROR_NONE) { 69 | /* In case of error, forward the error handling to onBleInitError */ 70 | onBleInitError(ble, error); 71 | return; 72 | } 73 | 74 | /* Ensure that it is the default instance of BLE */ 75 | if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) { 76 | return; 77 | } 78 | 79 | ble.gap().onDisconnection(disconnectionCallback); 80 | ble.gattServer().onDataWritten(onDataWrittenCallback); 81 | 82 | bool initialValueForLEDCharacteristic = false; 83 | ledServicePtr = new LEDService(ble, initialValueForLEDCharacteristic); 84 | 85 | /* setup advertising */ 86 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); 87 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); 88 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); 89 | ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); 90 | ble.gap().setAdvertisingInterval(1000); /* 1000ms. */ 91 | ble.gap().startAdvertising(); 92 | } 93 | 94 | void app_start(int, char **) 95 | { 96 | minar::Scheduler::postCallback(blinkCallback).period(minar::milliseconds(500)); 97 | 98 | BLE &ble = BLE::Instance(); 99 | ble.init(bleInitComplete); 100 | } 101 | -------------------------------------------------------------------------------- /BLE_LEDBlinker/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ble-ledblinker", 3 | "version": "0.0.1", 4 | "description": "An initial demo showcasing the GattClient APIs. Drives an LED service exported by a BLE_LED peripheral. Shows scanning, connections, service-discovery, and reads/writes.", 5 | "licenses": [ 6 | { 7 | "url": "https://spdx.org/licenses/Apache-2.0", 8 | "type": "Apache-2.0" 9 | } 10 | ], 11 | "dependencies": { 12 | "ble": "^2.0.0" 13 | }, 14 | "bin": "./source" 15 | } 16 | -------------------------------------------------------------------------------- /BLE_LEDBlinker/readme.md: -------------------------------------------------------------------------------- 1 | # BLE LED Blinker 2 | 3 | This example demonstrates using the ``GattClient`` API to control BLE client devices. 4 | 5 | The example uses two applications running on two different devices: 6 | 7 | 1. The first device - the central - runs the application ``BLE_LEDBlinker`` from this repository. This application sends an on/off toggle over BLE. 8 | 9 | 1. The second device - the peripheral - runs the application [``BLE_LED``](https://github.com/ARMmbed/ble-examples/tree/master/BLE_LED) to respond to the toggle. 10 | 11 | The toggle simply turns the LED on the peripheral device on and off. 12 | 13 | # Running the application 14 | 15 | ## Requirements 16 | 17 | Hardware requirements are in the [main readme](https://github.com/ARMmbed/ble-examples/blob/master/README.md). 18 | 19 | This example requires *two* devices. 20 | 21 | ## Building instructions 22 | 23 | You will need to build both applications and flash each one to a different board. 24 | 25 | Please note: The application ``BLE_LEDBlinker`` in this repository initiate a connection to all ble devices which advertise "LED" as complete local name. By default, the application `BLE_LED` advertise "LED" as complete local name. If you change the local name advertised by the application `BLE_LED` you should reflect your change in this application by changing the value of the constant `PEER_NAME` in `main.cpp`. 26 | 27 | **Tip:** You may notice that the application also checks the LED characteristic's UUID; you don't need to change this parameter's value, because it already matches the UUID provided by the second application, ``BLE_LED``. 28 | 29 | Building instructions for all mbed OS samples are in the [main readme](https://github.com/ARMmbed/ble-examples/blob/master/README.md). 30 | 31 | ## Checking for success 32 | 33 | 1. Build both applications and install one on each device, as explained in the building instructions. 34 | 35 | 1. The LED number two of the device running ``BLE_LED`` should blink. 36 | 37 | 38 | ## Monitoring the application through a serial port 39 | 40 | You can run ``BLE_LEDBlinker`` and see that it works properly by monitoring its serial output. 41 | 42 | You need a terminal program to listen to the output through a serial port. You can download one, for example: 43 | 44 | * Tera Term for Windows. 45 | * CoolTerm for Mac OS X. 46 | * GNU Screen for Linux. 47 | 48 | To see the application's output: 49 | 50 | 1. Check which serial port your device is connected to. 51 | 1. Run a terminal program with the correct serial port and set the baud rate to 9600. For example, to use GNU Screen, run: ``screen /dev/tty.usbmodem1412 9600``. 52 | 1. The application should start printing the toggle's value to the terminal. 53 | 54 | **Note:** ``BLE_LEDBlinker`` will not run properly if the ``BLE_LED`` application is not running on a second device. The terminal will show a few print statements, but you will not be able to see the application in full operation. 55 | -------------------------------------------------------------------------------- /BLE_LEDBlinker/source/main.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "mbed-drivers/mbed.h" 18 | #include "ble/BLE.h" 19 | #include "ble/DiscoveredCharacteristic.h" 20 | #include "ble/DiscoveredService.h" 21 | 22 | DigitalOut alivenessLED(LED1, 1); 23 | static DiscoveredCharacteristic ledCharacteristic; 24 | static bool triggerLedCharacteristic; 25 | static const char PEER_NAME[] = "LED"; 26 | 27 | void periodicCallback(void) { 28 | alivenessLED = !alivenessLED; /* Do blinky on LED1 while we're waiting for BLE events */ 29 | } 30 | 31 | void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params) { 32 | // parse the advertising payload, looking for data type COMPLETE_LOCAL_NAME 33 | // The advertising payload is a collection of key/value records where 34 | // byte 0: length of the record excluding this byte 35 | // byte 1: The key, it is the type of the data 36 | // byte [2..N] The value. N is equal to byte0 - 1 37 | for (uint8_t i = 0; i < params->advertisingDataLen; ++i) { 38 | 39 | const uint8_t record_length = params->advertisingData[i]; 40 | if (record_length == 0) { 41 | continue; 42 | } 43 | const uint8_t type = params->advertisingData[i + 1]; 44 | const uint8_t* value = params->advertisingData + i + 2; 45 | const uint8_t value_length = record_length - 1; 46 | 47 | if(type == GapAdvertisingData::COMPLETE_LOCAL_NAME) { 48 | if ((value_length == sizeof(PEER_NAME)) && (memcmp(value, PEER_NAME, value_length) == 0)) { 49 | printf( 50 | "adv peerAddr[%02x %02x %02x %02x %02x %02x] rssi %d, isScanResponse %u, AdvertisementType %u\r\n", 51 | params->peerAddr[5], params->peerAddr[4], params->peerAddr[3], params->peerAddr[2], 52 | params->peerAddr[1], params->peerAddr[0], params->rssi, params->isScanResponse, params->type 53 | ); 54 | BLE::Instance().gap().connect(params->peerAddr, Gap::ADDR_TYPE_RANDOM_STATIC, NULL, NULL); 55 | break; 56 | } 57 | } 58 | i += record_length; 59 | } 60 | } 61 | 62 | void serviceDiscoveryCallback(const DiscoveredService *service) { 63 | if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) { 64 | printf("S UUID-%x attrs[%u %u]\r\n", service->getUUID().getShortUUID(), service->getStartHandle(), service->getEndHandle()); 65 | } else { 66 | printf("S UUID-"); 67 | const uint8_t *longUUIDBytes = service->getUUID().getBaseUUID(); 68 | for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) { 69 | printf("%02x", longUUIDBytes[i]); 70 | } 71 | printf(" attrs[%u %u]\r\n", service->getStartHandle(), service->getEndHandle()); 72 | } 73 | } 74 | 75 | void updateLedCharacteristic(void) { 76 | if (!BLE::Instance().gattClient().isServiceDiscoveryActive()) { 77 | ledCharacteristic.read(); 78 | } 79 | } 80 | 81 | void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP) { 82 | printf(" C UUID-%x valueAttr[%u] props[%x]\r\n", characteristicP->getUUID().getShortUUID(), characteristicP->getValueHandle(), (uint8_t)characteristicP->getProperties().broadcast()); 83 | if (characteristicP->getUUID().getShortUUID() == 0xa001) { /* !ALERT! Alter this filter to suit your device. */ 84 | ledCharacteristic = *characteristicP; 85 | triggerLedCharacteristic = true; 86 | } 87 | } 88 | 89 | void discoveryTerminationCallback(Gap::Handle_t connectionHandle) { 90 | printf("terminated SD for handle %u\r\n", connectionHandle); 91 | if (triggerLedCharacteristic) { 92 | triggerLedCharacteristic = false; 93 | minar::Scheduler::postCallback(updateLedCharacteristic); 94 | } 95 | } 96 | 97 | void connectionCallback(const Gap::ConnectionCallbackParams_t *params) { 98 | if (params->role == Gap::CENTRAL) { 99 | BLE &ble = BLE::Instance(); 100 | ble.gattClient().onServiceDiscoveryTermination(discoveryTerminationCallback); 101 | ble.gattClient().launchServiceDiscovery(params->handle, serviceDiscoveryCallback, characteristicDiscoveryCallback, 0xa000, 0xa001); 102 | } 103 | } 104 | 105 | void triggerToggledWrite(const GattReadCallbackParams *response) { 106 | if (response->handle == ledCharacteristic.getValueHandle()) { 107 | printf("triggerToggledWrite: handle %u, offset %u, len %u\r\n", response->handle, response->offset, response->len); 108 | for (unsigned index = 0; index < response->len; index++) { 109 | printf("%c[%02x]", response->data[index], response->data[index]); 110 | } 111 | printf("\r\n"); 112 | 113 | uint8_t toggledValue = response->data[0] ^ 0x1; 114 | ledCharacteristic.write(1, &toggledValue); 115 | } 116 | } 117 | 118 | void triggerRead(const GattWriteCallbackParams *response) { 119 | if (response->handle == ledCharacteristic.getValueHandle()) { 120 | ledCharacteristic.read(); 121 | } 122 | } 123 | 124 | void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *) { 125 | printf("disconnected\r\n"); 126 | /* Start scanning and try to connect again */ 127 | BLE::Instance().gap().startScan(advertisementCallback); 128 | } 129 | 130 | void onBleInitError(BLE &ble, ble_error_t error) 131 | { 132 | /* Initialization error handling should go here */ 133 | } 134 | 135 | void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) 136 | { 137 | BLE& ble = params->ble; 138 | ble_error_t error = params->error; 139 | 140 | if (error != BLE_ERROR_NONE) { 141 | /* In case of error, forward the error handling to onBleInitError */ 142 | onBleInitError(ble, error); 143 | return; 144 | } 145 | 146 | /* Ensure that it is the default instance of BLE */ 147 | if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) { 148 | return; 149 | } 150 | 151 | ble.gap().onDisconnection(disconnectionCallback); 152 | ble.gap().onConnection(connectionCallback); 153 | 154 | ble.gattClient().onDataRead(triggerToggledWrite); 155 | ble.gattClient().onDataWrite(triggerRead); 156 | 157 | // scan interval: 400ms and scan window: 400ms. 158 | // Every 400ms the device will scan for 400ms 159 | // This means that the device will scan continuously. 160 | ble.gap().setScanParams(400, 400); 161 | ble.gap().startScan(advertisementCallback); 162 | } 163 | 164 | void app_start(int, char**) { 165 | triggerLedCharacteristic = false; 166 | 167 | minar::Scheduler::postCallback(periodicCallback).period(minar::milliseconds(500)); 168 | 169 | BLE::Instance().init(bleInitComplete); 170 | } 171 | -------------------------------------------------------------------------------- /BLE_Thermometer/img/connection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_Thermometer/img/connection.png -------------------------------------------------------------------------------- /BLE_Thermometer/img/discovery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_Thermometer/img/discovery.png -------------------------------------------------------------------------------- /BLE_Thermometer/img/notifications.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_Thermometer/img/notifications.png -------------------------------------------------------------------------------- /BLE_Thermometer/img/register_to_notifications.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_Thermometer/img/register_to_notifications.png -------------------------------------------------------------------------------- /BLE_Thermometer/img/scan_results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_Thermometer/img/scan_results.png -------------------------------------------------------------------------------- /BLE_Thermometer/img/start_scan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_Thermometer/img/start_scan.png -------------------------------------------------------------------------------- /BLE_Thermometer/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ble-thermometer", 3 | "version": "0.0.1", 4 | "description": "This example demonstrates how to use the Health Thermometer Service. The Health Thermometer service reports two pieces of information, Temperature and Sensor Location.", 5 | "licenses": [ 6 | { 7 | "url": "https://spdx.org/licenses/Apache-2.0", 8 | "type": "Apache-2.0" 9 | } 10 | ], 11 | "dependencies": { 12 | "ble": "^2.0.0" 13 | }, 14 | "bin": "./source" 15 | } 16 | -------------------------------------------------------------------------------- /BLE_Thermometer/readme.md: -------------------------------------------------------------------------------- 1 | # Thermometer 2 | 3 | This example uses the [Health Thermometer Profile](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.health_thermometer.xml) to send thermometer information: 4 | 5 | 1. Sensor location: thermometer placement on the body. The default value in this application is the ear (``LOCATION_EAR``). The [characteristic description](https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.temperature_type.xml) shows the other possible values. 6 | 7 | 1. Temperature: the initial temperature is 39.6, and it's incremented by 0.1 every half second. It resets to 39.6 when it reaches 43.0. 8 | 9 | For more information see: 10 | 11 | * [Temperature Service](https://developer.bluetooth.org/gatt/profiles/Pages/ProfileViewer.aspx?u=org.bluetooth.profile.health_thermometer.xml): GATT profile details. 12 | 13 | * [Temperature Measurement](https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.temperature_measurement.xml): GATT characteristic details for temperature measurement. 14 | 15 | * [Temperature Type](https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.temperature_type.xml): GATT characteristic details for temperature type (sensor location). 16 | 17 | # Running the application 18 | 19 | ## Requirements 20 | 21 | The sample application can be seen on any BLE scanner on a smartphone. If you don't have a scanner on your phone, please install : 22 | 23 | - [nRF Master Control Panel](https://play.google.com/store/apps/details?id=no.nordicsemi.android.mcp) for Android. 24 | 25 | - [LightBlue](https://itunes.apple.com/gb/app/lightblue-bluetooth-low-energy/id557428110?mt=8) for iPhone. 26 | 27 | Hardware requirements are in the [main readme](https://github.com/ARMmbed/ble-examples/blob/master/README.md). 28 | 29 | ## Building instructions 30 | 31 | Building instructions for all mbed OS samples are in the [main readme](https://github.com/ARMmbed/ble-examples/blob/master/README.md). 32 | 33 | ## Checking for success 34 | 35 | **Note:** Screens captures depicted below show what is expected from this example if the scanner used is *nRF Master Control Panel* version 4.0.5. If you encounter any difficulties consider trying another scanner or another version of nRF Master Control Panel. Alternative scanners may require reference to their manuals. 36 | 37 | 1. Build the application and install it on your board as explained in the building instructions. 38 | 39 | 1. Open the BLE scanner on your phone. 40 | 41 | 1. Start a scan. 42 | 43 | ![](img/start_scan.png) 44 | 45 | **figure 1** How to start scan using nRF Master Control Panel 4.0.5 46 | 47 | 1. Find your device; it should be named *Therm*. 48 | 49 | ![](img/scan_results.png) 50 | 51 | **figure 2** Scan results using nRF Master Control Panel 4.0.5 52 | 53 | 1. Establish a connection with your device. 54 | 55 | ![](img/connection.png) 56 | 57 | **figure 3** How to establish a connection using Master Control Panel 4.0.5 58 | 59 | 60 | 1. Discover the services and the characteristics on the device. The *Health Thermometer* service has the UUID `0x1809` and includes the *Temperature Measurement* characteristic which has the UUID `0x2A1C`. 61 | 62 | ![](img/discovery.png) 63 | 64 | **figure 4** Representation of the Thermometer service using Master Control Panel 4.0.5 65 | 66 | 67 | 1. Register for the notifications sent by the *Temperature Measurement* characteristic. 68 | 69 | ![](img/register_to_notifications.png) 70 | 71 | **figure 5** How to register to notifications using Master Control Panel 4.0.5 72 | 73 | 74 | 1. You should see the temperature value change every half second. It begins at 39.6, goes up to 43.0 (in steps of 0.1), resets to 39.6 and so on. 75 | 76 | ![](img/notifications.png) 77 | 78 | **figure 6** Notifications view using Master Control Panel 4.0.5 79 | 80 | 81 | -------------------------------------------------------------------------------- /BLE_Thermometer/source/main.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "mbed.h" 18 | #include "ble/BLE.h" 19 | #include "ble/services/HealthThermometerService.h" 20 | 21 | DigitalOut led1(LED1, 1); 22 | 23 | const static char DEVICE_NAME[] = "Therm"; 24 | static const uint16_t uuid16_list[] = {GattService::UUID_HEALTH_THERMOMETER_SERVICE}; 25 | 26 | static float currentTemperature = 39.6; 27 | static HealthThermometerService *thermometerServicePtr; 28 | 29 | /* Restart Advertising on disconnection*/ 30 | void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *) 31 | { 32 | BLE::Instance().gap().startAdvertising(); 33 | } 34 | 35 | void updateSensorValue(void) { 36 | /* Do blocking calls or whatever is necessary for sensor polling. 37 | In our case, we simply update the Temperature measurement. */ 38 | currentTemperature = (currentTemperature + 0.1 > 43.0) ? 39.6 : currentTemperature + 0.1; 39 | thermometerServicePtr->updateTemperature(currentTemperature); 40 | } 41 | 42 | void periodicCallback(void) 43 | { 44 | led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */ 45 | 46 | if (BLE::Instance().gap().getState().connected) { 47 | minar::Scheduler::postCallback(updateSensorValue); 48 | } 49 | } 50 | 51 | void onBleInitError(BLE &ble, ble_error_t error) 52 | { 53 | /* Initialization error handling should go here */ 54 | } 55 | 56 | void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) 57 | { 58 | BLE& ble = params->ble; 59 | ble_error_t error = params->error; 60 | 61 | if (error != BLE_ERROR_NONE) { 62 | onBleInitError(ble, error); 63 | return; 64 | } 65 | 66 | if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) { 67 | return; 68 | } 69 | 70 | ble.gap().onDisconnection(disconnectionCallback); 71 | 72 | /* Setup primary service. */ 73 | thermometerServicePtr = new HealthThermometerService(ble, currentTemperature, HealthThermometerService::LOCATION_EAR); 74 | 75 | /* setup advertising */ 76 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); 77 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); 78 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::THERMOMETER_EAR); 79 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); 80 | ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); 81 | ble.gap().setAdvertisingInterval(1000); /* 1000ms */ 82 | ble.gap().startAdvertising(); 83 | } 84 | 85 | void app_start(int, char**) 86 | { 87 | minar::Scheduler::postCallback(periodicCallback).period(minar::milliseconds(500)); 88 | 89 | BLE::Instance().init(bleInitComplete); 90 | } 91 | -------------------------------------------------------------------------------- /BLE_URIBeacon/img/app_start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_URIBeacon/img/app_start.png -------------------------------------------------------------------------------- /BLE_URIBeacon/img/edit_url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_URIBeacon/img/edit_url.png -------------------------------------------------------------------------------- /BLE_URIBeacon/img/open_configuration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_URIBeacon/img/open_configuration.png -------------------------------------------------------------------------------- /BLE_URIBeacon/img/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_URIBeacon/img/result.png -------------------------------------------------------------------------------- /BLE_URIBeacon/img/save_url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_URIBeacon/img/save_url.png -------------------------------------------------------------------------------- /BLE_URIBeacon/img/start_scan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/ble-examples/HEAD/BLE_URIBeacon/img/start_scan.png -------------------------------------------------------------------------------- /BLE_URIBeacon/module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ble-uribeacon", 3 | "version": "0.0.1", 4 | "description": "BLE URIBeacon example, building with yotta", 5 | "licenses": [ 6 | { 7 | "url": "https://spdx.org/licenses/Apache-2.0", 8 | "type": "Apache-2.0" 9 | } 10 | ], 11 | "dependencies": { 12 | "ble": "^2.0.0" 13 | }, 14 | "targetDependencies": {}, 15 | "bin": "./source" 16 | } 17 | -------------------------------------------------------------------------------- /BLE_URIBeacon/readme.md: -------------------------------------------------------------------------------- 1 | URI-Beacons are handy when there is a need to advertise a small amount of 2 | information (usually a URL) to any nearby device. They’re really easy to set 3 | up: the code is fully available on the mbed website, so all you’ll need to do 4 | is tell the beacon what to broadcast. 5 | 6 | Technical details are better presented [here](https://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_URIBeacon/), 7 | which happens to be the mbed-classic equivalent of this example. Please also refer to [Google's URIBeacon project](https://github.com/google/uribeacon). 8 | 9 | What You’ll Need 10 | ================ 11 | 12 | To get this going, you’ll need: 13 | 14 | - To see URIBeacons get the *Physical Web* app installed on your phone: 15 | 16 | - [Android version](https://play.google.com/store/apps/details?id=physical_web.org.physicalweb) 17 | 18 | - [iOS version](https://itunes.apple.com/us/app/physical-web/id927653608?mt=8) 19 | 20 | - One of the BLE platforms listed in the README.md of this repository, for example a 21 | Nordic DK board. 22 | 23 | Build Instructions 24 | ================== 25 | 26 | After cloning the parent repository, switch to the subfolder BLE_URIBeacon, and 27 | execute the following: 28 | 29 | ```Shell 30 | yotta target 31 | yotta install 32 | yotta build 33 | ``` 34 | Assuming that you're building for the nRF51 DK platform, available targets are 35 | `nrf51dk-armcc` and `nrf51dk-gcc`. You can pick either. 36 | 37 | The other targets you can use are described in the main README.md for this repository. 38 | 39 | The resulting binaries would be under `build//source/`. 40 | 41 | Under that folder, the file called `ble-uribeacon-combined.hex` is the one which 42 | can be flashed to the target using mbed's DAP over USB; the parent README or the 43 | documentation for your yotta target will explain how to choose between the available 44 | binaries and hex files. 45 | 46 | Checking for Success 47 | ==================== 48 | 49 | 50 | 1. Build the application and install it on your board as explained in the building instructions. 51 | 52 | 1. Open the *Physical Web* application on your phone. It will start to search for nearby beacons. 53 | 54 | ![](img/app_start.png) 55 | 56 | **figure 1** Start of the *Physical Web* application version 0.1.856 on Android 57 | 58 | 1. When the beacon starts up, the Configuration Service runs for 60 seconds. 59 | During this time it is possible to change the URL advertised by the beacon. 60 | It is also important to note that during these 60 seconds, your device will not advertise any URL. 61 | 62 | ![](img/open_configuration.png) 63 | 64 | **figure 2** How to open the beacon configuration view using the *Physical Web* application version 0.1.856 on Android 65 | 66 | 67 | 1. Edit the URL advertised by your beacon. 68 | 69 | ![](img/edit_url.png) 70 | 71 | **figure 3** How to edit the URL advertised by your beacon using the *Physical Web* application version 0.1.856 on Android 72 | 73 | 74 | 1. Save the URL which will be advertised by your beacon. 75 | 76 | ![](img/save_url.png) 77 | 78 | **figure 4** How to save your beacon configuration and start advertising URL using the *Physical Web* application version 0.1.856 on Android. 79 | 80 | 81 | 1. Find your device; it should advertise the URL you have set. 82 | 83 | ![](img/result.png) 84 | 85 | **figure 5** Display of URL advertised by your beacon using the *Physical Web* application version 0.1.856 on Android. 86 | 87 | 88 | **Please note that the URIBeacon spec requires the URIBeacon app to remain in 89 | config mode for the first 60 seconds before switching to being a beacon. So if 90 | you're using a physical-web app, you'll only see the beacon after this period; 91 | if you're using one of the generic apps for BLE scanning, you should see a 92 | configurable beacon being advertised for the first 60 seconds.** 93 | 94 | You'll find [links](https://github.com/google/uribeacon/tree/uribeacon-final#contents) on Google's project page to client apps to test URIBeacon. Here's a link that should get you an [Android App](https://github.com/google/uribeacon/releases/tag/v1.2); please browse to `uribeacon-sample-release.apk`. But you should begin with the links to android apps mentioned above. 95 | 96 | -------------------------------------------------------------------------------- /BLE_URIBeacon/source/ConfigParamsPersistence.h: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __BLE_CONFIG_PARAMS_PERSISTENCE_H__ 18 | #define __BLE_CONFIG_PARAMS_PERSISTENCE_H__ 19 | 20 | #include "ble/services/URIBeaconConfigService.h" 21 | 22 | /** 23 | * Generic API to load the URIBeacon configuration parameters from persistent 24 | * storage. If persistent storage isn't available, the persistenceSignature 25 | * member of params may be left un-initialized to the MAGIC, and this will cause 26 | * a reset to default values. 27 | * 28 | * @param[out] paramsP 29 | * The parameters to be filled in from persistence storage. This 30 | argument can be NULL if the caller is only interested in 31 | discovering the persistence status of params. 32 | 33 | * @return true if params were loaded from persistent storage and have usefully 34 | * initialized fields. 35 | */ 36 | bool loadURIBeaconConfigParams(URIBeaconConfigService::Params_t *paramsP); 37 | 38 | /** 39 | * Generic API to store the URIBeacon configuration parameters to persistent 40 | * storage. It typically initializes the persistenceSignature member of the 41 | * params to the MAGIC value to indicate persistence. 42 | * 43 | * @note: the save operation may be asynchronous. It may be a short while before 44 | * the request takes affect. Reading back saved configParams may not yield 45 | * correct behaviour if attempted soon after a store. 46 | * 47 | * @param[in/out] paramsP 48 | * The params to be saved; persistenceSignature member gets 49 | * updated if persistence is successful. 50 | */ 51 | void saveURIBeaconConfigParams(const URIBeaconConfigService::Params_t *paramsP); 52 | 53 | #endif /* #ifndef __BLE_CONFIG_PARAMS_PERSISTENCE_H__*/ 54 | -------------------------------------------------------------------------------- /BLE_URIBeacon/source/main.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2013 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "mbed.h" 18 | #include "ble/BLE.h" 19 | #include "ble/services/URIBeaconConfigService.h" 20 | #include "ble/services/DFUService.h" 21 | #include "ble/services/DeviceInformationService.h" 22 | #include "ConfigParamsPersistence.h" 23 | 24 | /** 25 | * URIBeaconConfig service can operate in two modes: a configuration mode which 26 | * allows a user to update settings over a connection; and normal URIBeacon mode 27 | * which involves advertising a URI. Constructing an object from URIBeaconConfig 28 | * service sets up advertisements for the configuration mode. It is then up to 29 | * the application to switch to URIBeacon mode based on some timeout. 30 | * 31 | * The following help with this switch. 32 | */ 33 | static const int CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS = 60; // Duration after power-on that config service is available. 34 | 35 | /* global static objects */ 36 | BLE ble; 37 | URIBeaconConfigService *uriBeaconConfig; 38 | URIBeaconConfigService::Params_t params; 39 | 40 | /** 41 | * Stop advertising the UriBeaconConfig Service after a delay; and switch to normal URIBeacon. 42 | */ 43 | void timeout(void) 44 | { 45 | Gap::GapState_t state; 46 | state = ble.getGapState(); 47 | if (!state.connected) { /* don't switch if we're in a connected state. */ 48 | uriBeaconConfig->setupURIBeaconAdvertisements(); 49 | ble.startAdvertising(); 50 | } else { 51 | minar::Scheduler::postCallback(timeout).delay(minar::milliseconds(CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS * 1000)); 52 | } 53 | } 54 | 55 | /** 56 | * Callback triggered upon a disconnection event. Needs to re-enable advertisements. 57 | */ 58 | void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *) 59 | { 60 | ble.startAdvertising(); 61 | } 62 | 63 | void app_start(int, char *[]) 64 | { 65 | ble.init(); 66 | ble.onDisconnection(disconnectionCallback); 67 | 68 | /* 69 | * Load parameters from (platform specific) persistent storage. Parameters 70 | * can be set to non-default values while the URIBeacon is in configuration 71 | * mode (within the first 60 seconds of power-up). Thereafter, parameters 72 | * get copied out to persistent storage before switching to normal URIBeacon 73 | * operation. 74 | */ 75 | bool fetchedFromPersistentStorage = loadURIBeaconConfigParams(¶ms); 76 | 77 | /* Initialize a URIBeaconConfig service providing config params, default URI, and power levels. */ 78 | static URIBeaconConfigService::PowerLevels_t defaultAdvPowerLevels = {-20, -4, 0, 10}; // Values for ADV packets related to firmware levels 79 | uriBeaconConfig = new URIBeaconConfigService(ble, params, !fetchedFromPersistentStorage, "http://uribeacon.org", defaultAdvPowerLevels); 80 | if (!uriBeaconConfig->configuredSuccessfully()) { 81 | error("failed to accommodate URI"); 82 | } 83 | 84 | // Setup auxiliary services to allow over-the-air firmware updates, etc 85 | DFUService *dfu = new DFUService(ble); 86 | DeviceInformationService *deviceInfo = new DeviceInformationService(ble, "ARM", "UriBeacon", "SN1", "hw-rev1", "fw-rev1", "soft-rev1"); 87 | 88 | ble.startAdvertising(); /* Set the whole thing in motion. After this call a GAP central can scan the URIBeaconConfig 89 | * service. This can then be switched to the normal URIBeacon functionality after a timeout. */ 90 | 91 | /* Post a timeout callback to be invoked in ADVERTISEMENT_TIMEOUT_SECONDS to affect the switch to beacon mode. */ 92 | minar::Scheduler::postCallback(timeout).delay(minar::milliseconds(CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS * 1000)); 93 | } 94 | -------------------------------------------------------------------------------- /BLE_URIBeacon/source/nrfConfigParamsPersistence.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2006-2015 ARM Limited 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | extern "C" { 18 | #include "pstorage.h" 19 | } 20 | 21 | #include "nrf_error.h" 22 | #include "ConfigParamsPersistence.h" 23 | 24 | /** 25 | * Nordic specific structure used to store params persistently. 26 | * It extends URIBeaconConfigService::Params_t with a persistence signature. 27 | */ 28 | struct PersistentParams_t { 29 | URIBeaconConfigService::Params_t params; 30 | uint32_t persistenceSignature; /* This isn't really a parameter, but having the expected 31 | * magic value in this field indicates persistence. */ 32 | 33 | static const uint32_t MAGIC = 0x1BEAC000; /* Magic that identifies persistence */ 34 | }; 35 | 36 | /** 37 | * The following is a module-local variable to hold configuration parameters for 38 | * short periods during flash access. This is necessary because the pstorage 39 | * APIs don't copy in the memory provided as data source. The memory cannot be 40 | * freed or reused by the application until this flash access is complete. The 41 | * load and store operations in this module initialize persistentParams and then 42 | * pass it on to the 'pstorage' APIs. 43 | */ 44 | static PersistentParams_t persistentParams; 45 | 46 | static pstorage_handle_t pstorageHandle; 47 | 48 | /** 49 | * Dummy callback handler needed by Nordic's pstorage module. This is called 50 | * after every flash access. 51 | */ 52 | static void pstorageNotificationCallback(pstorage_handle_t *p_handle, 53 | uint8_t op_code, 54 | uint32_t result, 55 | uint8_t *p_data, 56 | uint32_t data_len) 57 | { 58 | /* APP_ERROR_CHECK(result); */ 59 | } 60 | 61 | /* Platform-specific implementation for persistence on the nRF5x. Based on the 62 | * pstorage module provided by the Nordic SDK. */ 63 | bool loadURIBeaconConfigParams(URIBeaconConfigService::Params_t *paramsP) 64 | { 65 | static bool pstorageInitied = false; 66 | if (!pstorageInitied) { 67 | pstorage_init(); 68 | 69 | static pstorage_module_param_t pstorageParams = { 70 | .cb = pstorageNotificationCallback, 71 | .block_size = sizeof(PersistentParams_t), 72 | .block_count = 1 73 | }; 74 | pstorage_register(&pstorageParams, &pstorageHandle); 75 | pstorageInitied = true; 76 | } 77 | 78 | if ((pstorage_load(reinterpret_cast(&persistentParams), &pstorageHandle, sizeof(PersistentParams_t), 0) != NRF_SUCCESS) || 79 | (persistentParams.persistenceSignature != PersistentParams_t::MAGIC)) { 80 | // On failure zero out and let the service reset to defaults 81 | memset(paramsP, 0, sizeof(URIBeaconConfigService::Params_t)); 82 | return false; 83 | } 84 | 85 | memcpy(paramsP, &persistentParams.params, sizeof(URIBeaconConfigService::Params_t)); 86 | return true; 87 | } 88 | 89 | /* Platform-specific implementation for persistence on the nRF5x. Based on the 90 | * pstorage module provided by the Nordic SDK. */ 91 | void saveURIBeaconConfigParams(const URIBeaconConfigService::Params_t *paramsP) 92 | { 93 | memcpy(&persistentParams.params, paramsP, sizeof(URIBeaconConfigService::Params_t)); 94 | if (persistentParams.persistenceSignature != PersistentParams_t::MAGIC) { 95 | persistentParams.persistenceSignature = PersistentParams_t::MAGIC; 96 | pstorage_store(&pstorageHandle, 97 | reinterpret_cast(&persistentParams), 98 | sizeof(PersistentParams_t), 99 | 0 /* offset */); 100 | } else { 101 | pstorage_update(&pstorageHandle, 102 | reinterpret_cast(&persistentParams), 103 | sizeof(PersistentParams_t), 104 | 0 /* offset */); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **This repository is superseded by [armmbed/mbed-os-examples-ble](http://github.com/armmbed/mbed-os-example-ble) - which contains BLE example applications for mbed OS 2.0 and mbed OS 5.0.** 2 | 3 | # BLE Examples 4 | 5 | This repo contains a collection of BLE example applications based on 6 | mbed OS 3 and built with [yotta](https://github.com/ARMmbed/yotta). Each example subdirectory contains a separate yotta module meant for building an executable. 7 | 8 | Please browse to subdirectories for specific documentation. 9 | 10 | Getting Started 11 | =============== 12 | 13 | 14 | Pre-Requisites 15 | -------------- 16 | 17 | 18 | To build these examples, you need to have a computer with the following software installed: 19 | 20 | * [CMake](http://www.cmake.org/download/). 21 | * [yotta](https://github.com/ARMmbed/yotta). Please note that **yotta has its own set of dependencies**, listed in the [installation instructions](http://armmbed.github.io/yotta/#installing-on-windows). 22 | * [Python](https://www.python.org/downloads/). 23 | * [ARM GCC toolchain](https://launchpad.net/gcc-arm-embedded). 24 | * A serial terminal emulator (e.g. screen, pySerial, cu). 25 | * If the OS used is Windows, the serial driver of the board has to be correctly installed. 26 | * For boards with mbed interface firmware the installation instructions are located (here)[https://developer.mbed.org/handbook/Windows-serial-configuration] 27 | * For nrf51-based board with a J-Link interface please install the J-Link *software and documentation pack* available (here)[https://www.segger.com/jlink-software.html] 28 | 29 | 30 | In order to use BLE in mbed OS you need one of the following hardware combinations: 31 | 32 | * A Nordic nRF51-based board such as [nrf51dk](https://www.nordicsemi.com/eng/Products/nRF51-DK) or [mkit](https://www.nordicsemi.com/eng/Products/Bluetooth-R-low-energy/nRF51822-mKIT). 33 | * A supported target, such as the [NUCLEO-F411RE](http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF260320), with a BLE shield or an external BLE peripheral, such as an [ST shield](http://www.st.com/web/catalog/tools/FM116/SC1075/PF260517). 34 | 35 | 36 | The [`ble` yotta module](https://github.com/ARMmbed/ble) provides the BLE APIs on mbed OS. The `ble` module uses yotta targets and yotta 37 | target dependencies to provide the appropriate implementation of the BLE API 38 | for your chosen hardware combination. 39 | 40 | A yotta `target` is a supported combination of hardware board and toolchain. This means that, for any of the hardware combinations above, you will need to use or create a 41 | yotta target that describes your configuration. The existing supported configurations 42 | are described below. 43 | 44 | 45 | Targets for BLE 46 | --------------- 47 | 48 | The following targets have been tested and work with these examples: 49 | 50 | Nordic (using the nrf51822-ble module): 51 | 52 | * nrf51dk-armcc 53 | * nrf51dk-gcc 54 | * mkit-gcc 55 | * mkit-armcc 56 | 57 | ST (using the st-ble module): 58 | 59 | * st-nucleo-f401re-st-ble-gcc (a NUCLEO-F411RE board with an ST BLE shield) 60 | 61 | Building and testing the examples 62 | --------------------------------- 63 | 64 | __To build an example:__ 65 | 66 | 1. Clone the repository containing the collection of examples: 67 | 68 | ``` 69 | $ git clone https://github.com/ARMmbed/ble-examples.git 70 | ``` 71 | 72 | 73 | **Tip:** If you don't have GitHub installed, you can [download a zip file](https://github.com/ARMmbed/ble-examples/archive/master.zip) of the repository. 74 | 75 | 1. Using a command-line tool, navigate to any of the example directories, like BLE_Beacon: 76 | 77 | ``` 78 | $ cd ble-examples 79 | $ cd BLE_Beacon 80 | ``` 81 | 82 | 1. Set a yotta target. For example, if you have and Nordic nRF51 and the GCC toolchain: 83 | 84 | ``` 85 | yotta target nrf51dk-gcc 86 | ``` 87 | 88 | 89 | 90 | 1. Run the build: 91 | 92 | ```yotta build``` 93 | 94 | __To run the application on your board:__ 95 | 96 | 1. Connect your mbed board to your computer over USB. It appears as removable storage. 97 | 98 | 1. When you run the ``yotta build`` command, as you did above, yotta creates a BIN or a combined HEX file in a ```build//source``` directory under the example's directory. Drag and drop the file to the removable storage. 99 | 100 | 101 | Exactly which executables are generated depends on the target that you have 102 | chosen. For Nordic Semiconductor targets, the following .hex files will be present: 103 | 104 | * `-combined.hex` is the one which can be flashed to the target. 105 | * `` is an ELF binary containing symbols (useful for debugging). 106 | * `.hex` contains only the application (not the SoftDevice binary) and can be used for Firmware Over the Air. 107 | 108 | 109 | Creating or porting your own BLE applications in mbed OS 110 | ====================================================== 111 | 112 | If you're interested in creating BLE applications for mbed OS, or porting existing applications from mbed Classic to mbed OS, please see our [Introduction to mbed BLE](https://docs.mbed.com/docs/ble-intros/en/latest/mbed_OS/mbed_OS_BLE_Apps/). 113 | --------------------------------------------------------------------------------