My fork

Dependencies:   BLE_API mbed-dev-bin nRF51822-bluetooth-mdw

Fork of microbit-dal-bluetooth-mdw by Martin Woolley

Committer:
LancasterUniversity
Date:
Wed Jul 13 12:17:53 2016 +0100
Revision:
21:cab56b701601
Parent:
1:8aa5cdb4ab67
Child:
22:23d7b9a4b082
Synchronized with git rev 87f7233a
Author: Martin Woolley
Added BLE connect/disconnect events and fixed bug in MagnetometerService re: bearing characteristic

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Jonathan Austin 1:8aa5cdb4ab67 1 /*
Jonathan Austin 1:8aa5cdb4ab67 2 The MIT License (MIT)
Jonathan Austin 1:8aa5cdb4ab67 3
Jonathan Austin 1:8aa5cdb4ab67 4 Copyright (c) 2016 British Broadcasting Corporation.
Jonathan Austin 1:8aa5cdb4ab67 5 This software is provided by Lancaster University by arrangement with the BBC.
Jonathan Austin 1:8aa5cdb4ab67 6
Jonathan Austin 1:8aa5cdb4ab67 7 Permission is hereby granted, free of charge, to any person obtaining a
Jonathan Austin 1:8aa5cdb4ab67 8 copy of this software and associated documentation files (the "Software"),
Jonathan Austin 1:8aa5cdb4ab67 9 to deal in the Software without restriction, including without limitation
Jonathan Austin 1:8aa5cdb4ab67 10 the rights to use, copy, modify, merge, publish, distribute, sublicense,
Jonathan Austin 1:8aa5cdb4ab67 11 and/or sell copies of the Software, and to permit persons to whom the
Jonathan Austin 1:8aa5cdb4ab67 12 Software is furnished to do so, subject to the following conditions:
Jonathan Austin 1:8aa5cdb4ab67 13
Jonathan Austin 1:8aa5cdb4ab67 14 The above copyright notice and this permission notice shall be included in
Jonathan Austin 1:8aa5cdb4ab67 15 all copies or substantial portions of the Software.
Jonathan Austin 1:8aa5cdb4ab67 16
Jonathan Austin 1:8aa5cdb4ab67 17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Jonathan Austin 1:8aa5cdb4ab67 18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Jonathan Austin 1:8aa5cdb4ab67 19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
Jonathan Austin 1:8aa5cdb4ab67 20 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Jonathan Austin 1:8aa5cdb4ab67 21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
Jonathan Austin 1:8aa5cdb4ab67 22 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
Jonathan Austin 1:8aa5cdb4ab67 23 DEALINGS IN THE SOFTWARE.
Jonathan Austin 1:8aa5cdb4ab67 24 */
Jonathan Austin 1:8aa5cdb4ab67 25
Jonathan Austin 1:8aa5cdb4ab67 26 #include "MicroBitConfig.h"
Jonathan Austin 1:8aa5cdb4ab67 27 #include "MicroBitBLEManager.h"
Jonathan Austin 1:8aa5cdb4ab67 28 #include "MicroBitStorage.h"
Jonathan Austin 1:8aa5cdb4ab67 29 #include "MicroBitFiber.h"
Jonathan Austin 1:8aa5cdb4ab67 30
Jonathan Austin 1:8aa5cdb4ab67 31
Jonathan Austin 1:8aa5cdb4ab67 32 /* The underlying Nordic libraries that support BLE do not compile cleanly with the stringent GCC settings we employ.
Jonathan Austin 1:8aa5cdb4ab67 33 * If we're compiling under GCC, then we suppress any warnings generated from this code (but not the rest of the DAL)
Jonathan Austin 1:8aa5cdb4ab67 34 * The ARM cc compiler is more tolerant. We don't test __GNUC__ here to detect GCC as ARMCC also typically sets this
Jonathan Austin 1:8aa5cdb4ab67 35 * as a compatability option, but does not support the options used...
Jonathan Austin 1:8aa5cdb4ab67 36 */
Jonathan Austin 1:8aa5cdb4ab67 37 #if !defined(__arm)
Jonathan Austin 1:8aa5cdb4ab67 38 #pragma GCC diagnostic ignored "-Wunused-function"
Jonathan Austin 1:8aa5cdb4ab67 39 #pragma GCC diagnostic push
Jonathan Austin 1:8aa5cdb4ab67 40 #pragma GCC diagnostic ignored "-Wunused-parameter"
Jonathan Austin 1:8aa5cdb4ab67 41 #endif
Jonathan Austin 1:8aa5cdb4ab67 42
Jonathan Austin 1:8aa5cdb4ab67 43 #include "ble.h"
Jonathan Austin 1:8aa5cdb4ab67 44
Jonathan Austin 1:8aa5cdb4ab67 45 extern "C"
Jonathan Austin 1:8aa5cdb4ab67 46 {
Jonathan Austin 1:8aa5cdb4ab67 47 #include "device_manager.h"
Jonathan Austin 1:8aa5cdb4ab67 48 uint32_t btle_set_gatt_table_size(uint32_t size);
Jonathan Austin 1:8aa5cdb4ab67 49 }
Jonathan Austin 1:8aa5cdb4ab67 50
Jonathan Austin 1:8aa5cdb4ab67 51 /*
Jonathan Austin 1:8aa5cdb4ab67 52 * Return to our predefined compiler settings.
Jonathan Austin 1:8aa5cdb4ab67 53 */
Jonathan Austin 1:8aa5cdb4ab67 54 #if !defined(__arm)
Jonathan Austin 1:8aa5cdb4ab67 55 #pragma GCC diagnostic pop
Jonathan Austin 1:8aa5cdb4ab67 56 #endif
Jonathan Austin 1:8aa5cdb4ab67 57
Jonathan Austin 1:8aa5cdb4ab67 58 #define MICROBIT_PAIRING_FADE_SPEED 4
Jonathan Austin 1:8aa5cdb4ab67 59
Jonathan Austin 1:8aa5cdb4ab67 60 const char* MICROBIT_BLE_MANUFACTURER = NULL;
Jonathan Austin 1:8aa5cdb4ab67 61 const char* MICROBIT_BLE_MODEL = "BBC micro:bit";
Jonathan Austin 1:8aa5cdb4ab67 62 const char* MICROBIT_BLE_HARDWARE_VERSION = NULL;
Jonathan Austin 1:8aa5cdb4ab67 63 const char* MICROBIT_BLE_FIRMWARE_VERSION = MICROBIT_DAL_VERSION;
Jonathan Austin 1:8aa5cdb4ab67 64 const char* MICROBIT_BLE_SOFTWARE_VERSION = NULL;
Jonathan Austin 1:8aa5cdb4ab67 65 const int8_t MICROBIT_BLE_POWER_LEVEL[] = {-30, -20, -16, -12, -8, -4, 0, 4};
Jonathan Austin 1:8aa5cdb4ab67 66
Jonathan Austin 1:8aa5cdb4ab67 67 /*
Jonathan Austin 1:8aa5cdb4ab67 68 * Many of the mbed interfaces we need to use only support callbacks to plain C functions, rather than C++ methods.
Jonathan Austin 1:8aa5cdb4ab67 69 * So, we maintain a pointer to the MicroBitBLEManager that's in use. Ths way, we can still access resources on the micro:bit
Jonathan Austin 1:8aa5cdb4ab67 70 * whilst keeping the code modular.
Jonathan Austin 1:8aa5cdb4ab67 71 */
Jonathan Austin 1:8aa5cdb4ab67 72 static MicroBitBLEManager *manager = NULL; // Singleton reference to the BLE manager. many mbed BLE API callbacks still do not support member funcions yet. :-(
Jonathan Austin 1:8aa5cdb4ab67 73 static uint8_t deviceID = 255; // Unique ID for the peer that has connected to us.
Jonathan Austin 1:8aa5cdb4ab67 74 static Gap::Handle_t pairingHandle = 0; // The connection handle used during a pairing process. Used to ensure that connections are dropped elegantly.
Jonathan Austin 1:8aa5cdb4ab67 75
Jonathan Austin 1:8aa5cdb4ab67 76 static void storeSystemAttributes(Gap::Handle_t handle)
Jonathan Austin 1:8aa5cdb4ab67 77 {
Jonathan Austin 1:8aa5cdb4ab67 78 if(manager->storage != NULL && deviceID < MICROBIT_BLE_MAXIMUM_BONDS)
Jonathan Austin 1:8aa5cdb4ab67 79 {
Jonathan Austin 1:8aa5cdb4ab67 80 ManagedString key("bleSysAttrs");
Jonathan Austin 1:8aa5cdb4ab67 81
Jonathan Austin 1:8aa5cdb4ab67 82 KeyValuePair* bleSysAttrs = manager->storage->get(key);
Jonathan Austin 1:8aa5cdb4ab67 83
Jonathan Austin 1:8aa5cdb4ab67 84 BLESysAttribute attrib;
Jonathan Austin 1:8aa5cdb4ab67 85 BLESysAttributeStore attribStore;
Jonathan Austin 1:8aa5cdb4ab67 86
Jonathan Austin 1:8aa5cdb4ab67 87 uint16_t len = sizeof(attrib.sys_attr);
Jonathan Austin 1:8aa5cdb4ab67 88
Jonathan Austin 1:8aa5cdb4ab67 89 sd_ble_gatts_sys_attr_get(handle, attrib.sys_attr, &len, BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS);
Jonathan Austin 1:8aa5cdb4ab67 90
Jonathan Austin 1:8aa5cdb4ab67 91 //copy our stored sysAttrs
Jonathan Austin 1:8aa5cdb4ab67 92 if(bleSysAttrs != NULL)
Jonathan Austin 1:8aa5cdb4ab67 93 {
Jonathan Austin 1:8aa5cdb4ab67 94 memcpy(&attribStore, bleSysAttrs->value, sizeof(BLESysAttributeStore));
Jonathan Austin 1:8aa5cdb4ab67 95 delete bleSysAttrs;
Jonathan Austin 1:8aa5cdb4ab67 96 }
Jonathan Austin 1:8aa5cdb4ab67 97
Jonathan Austin 1:8aa5cdb4ab67 98 //check if we need to update
Jonathan Austin 1:8aa5cdb4ab67 99 if(memcmp(attribStore.sys_attrs[deviceID].sys_attr, attrib.sys_attr, len) != 0)
Jonathan Austin 1:8aa5cdb4ab67 100 {
Jonathan Austin 1:8aa5cdb4ab67 101 attribStore.sys_attrs[deviceID] = attrib;
Jonathan Austin 1:8aa5cdb4ab67 102 manager->storage->put(key, (uint8_t *)&attribStore);
Jonathan Austin 1:8aa5cdb4ab67 103 }
Jonathan Austin 1:8aa5cdb4ab67 104 }
Jonathan Austin 1:8aa5cdb4ab67 105 }
Jonathan Austin 1:8aa5cdb4ab67 106
Jonathan Austin 1:8aa5cdb4ab67 107 /**
Jonathan Austin 1:8aa5cdb4ab67 108 * Callback when a BLE GATT disconnect occurs.
Jonathan Austin 1:8aa5cdb4ab67 109 */
Jonathan Austin 1:8aa5cdb4ab67 110 static void bleDisconnectionCallback(const Gap::DisconnectionCallbackParams_t *reason)
Jonathan Austin 1:8aa5cdb4ab67 111 {
LancasterUniversity 21:cab56b701601 112 MicroBitEvent(MICROBIT_ID_BLE,MICROBIT_BLE_DISCONNECTED);
LancasterUniversity 21:cab56b701601 113
Jonathan Austin 1:8aa5cdb4ab67 114 storeSystemAttributes(reason->handle);
Jonathan Austin 1:8aa5cdb4ab67 115
Jonathan Austin 1:8aa5cdb4ab67 116 if (manager)
Jonathan Austin 1:8aa5cdb4ab67 117 manager->advertise();
Jonathan Austin 1:8aa5cdb4ab67 118 }
Jonathan Austin 1:8aa5cdb4ab67 119
Jonathan Austin 1:8aa5cdb4ab67 120 /**
LancasterUniversity 21:cab56b701601 121 * Callback when a BLE connection is established.
LancasterUniversity 21:cab56b701601 122 */
LancasterUniversity 21:cab56b701601 123 static void bleConnectionCallback(const Gap::ConnectionCallbackParams_t *params)
LancasterUniversity 21:cab56b701601 124 {
LancasterUniversity 21:cab56b701601 125 MicroBitEvent(MICROBIT_ID_BLE,MICROBIT_BLE_CONNECTED);
LancasterUniversity 21:cab56b701601 126 }
LancasterUniversity 21:cab56b701601 127
LancasterUniversity 21:cab56b701601 128 /**
Jonathan Austin 1:8aa5cdb4ab67 129 * Callback when a BLE SYS_ATTR_MISSING.
Jonathan Austin 1:8aa5cdb4ab67 130 */
Jonathan Austin 1:8aa5cdb4ab67 131 static void bleSysAttrMissingCallback(const GattSysAttrMissingCallbackParams *params)
Jonathan Austin 1:8aa5cdb4ab67 132 {
Jonathan Austin 1:8aa5cdb4ab67 133 int complete = 0;
Jonathan Austin 1:8aa5cdb4ab67 134 deviceID = 255;
Jonathan Austin 1:8aa5cdb4ab67 135
Jonathan Austin 1:8aa5cdb4ab67 136 dm_handle_t dm_handle = {0,0,0,0};
Jonathan Austin 1:8aa5cdb4ab67 137
Jonathan Austin 1:8aa5cdb4ab67 138 int ret = dm_handle_get(params->connHandle, &dm_handle);
Jonathan Austin 1:8aa5cdb4ab67 139
Jonathan Austin 1:8aa5cdb4ab67 140 if (ret == 0)
Jonathan Austin 1:8aa5cdb4ab67 141 deviceID = dm_handle.device_id;
Jonathan Austin 1:8aa5cdb4ab67 142
Jonathan Austin 1:8aa5cdb4ab67 143 if(manager->storage != NULL && deviceID < MICROBIT_BLE_MAXIMUM_BONDS)
Jonathan Austin 1:8aa5cdb4ab67 144 {
Jonathan Austin 1:8aa5cdb4ab67 145 ManagedString key("bleSysAttrs");
Jonathan Austin 1:8aa5cdb4ab67 146
Jonathan Austin 1:8aa5cdb4ab67 147 KeyValuePair* bleSysAttrs = manager->storage->get(key);
Jonathan Austin 1:8aa5cdb4ab67 148
Jonathan Austin 1:8aa5cdb4ab67 149 BLESysAttributeStore attribStore;
Jonathan Austin 1:8aa5cdb4ab67 150 BLESysAttribute attrib;
Jonathan Austin 1:8aa5cdb4ab67 151
Jonathan Austin 1:8aa5cdb4ab67 152 if(bleSysAttrs != NULL)
Jonathan Austin 1:8aa5cdb4ab67 153 {
Jonathan Austin 1:8aa5cdb4ab67 154 //restore our sysAttrStore
Jonathan Austin 1:8aa5cdb4ab67 155 memcpy(&attribStore, bleSysAttrs->value, sizeof(BLESysAttributeStore));
Jonathan Austin 1:8aa5cdb4ab67 156 delete bleSysAttrs;
Jonathan Austin 1:8aa5cdb4ab67 157
Jonathan Austin 1:8aa5cdb4ab67 158 attrib = attribStore.sys_attrs[deviceID];
Jonathan Austin 1:8aa5cdb4ab67 159
Jonathan Austin 1:8aa5cdb4ab67 160 ret = sd_ble_gatts_sys_attr_set(params->connHandle, attrib.sys_attr, sizeof(attrib.sys_attr), BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS);
Jonathan Austin 1:8aa5cdb4ab67 161
Jonathan Austin 1:8aa5cdb4ab67 162 complete = 1;
Jonathan Austin 1:8aa5cdb4ab67 163
Jonathan Austin 1:8aa5cdb4ab67 164 if(ret == 0)
Jonathan Austin 1:8aa5cdb4ab67 165 ret = sd_ble_gatts_service_changed(params->connHandle, 0x000c, 0xffff);
Jonathan Austin 1:8aa5cdb4ab67 166 }
Jonathan Austin 1:8aa5cdb4ab67 167 }
Jonathan Austin 1:8aa5cdb4ab67 168
Jonathan Austin 1:8aa5cdb4ab67 169 if (!complete)
Jonathan Austin 1:8aa5cdb4ab67 170 sd_ble_gatts_sys_attr_set(params->connHandle, NULL, 0, 0);
Jonathan Austin 1:8aa5cdb4ab67 171
Jonathan Austin 1:8aa5cdb4ab67 172 }
Jonathan Austin 1:8aa5cdb4ab67 173
Jonathan Austin 1:8aa5cdb4ab67 174 static void passkeyDisplayCallback(Gap::Handle_t handle, const SecurityManager::Passkey_t passkey)
Jonathan Austin 1:8aa5cdb4ab67 175 {
Jonathan Austin 1:8aa5cdb4ab67 176 (void) handle; /* -Wunused-param */
Jonathan Austin 1:8aa5cdb4ab67 177
Jonathan Austin 1:8aa5cdb4ab67 178 ManagedString passKey((const char *)passkey, SecurityManager::PASSKEY_LEN);
Jonathan Austin 1:8aa5cdb4ab67 179
Jonathan Austin 1:8aa5cdb4ab67 180 if (manager)
Jonathan Austin 1:8aa5cdb4ab67 181 manager->pairingRequested(passKey);
Jonathan Austin 1:8aa5cdb4ab67 182 }
Jonathan Austin 1:8aa5cdb4ab67 183
Jonathan Austin 1:8aa5cdb4ab67 184 static void securitySetupCompletedCallback(Gap::Handle_t handle, SecurityManager::SecurityCompletionStatus_t status)
Jonathan Austin 1:8aa5cdb4ab67 185 {
Jonathan Austin 1:8aa5cdb4ab67 186 (void) handle; /* -Wunused-param */
Jonathan Austin 1:8aa5cdb4ab67 187
Jonathan Austin 1:8aa5cdb4ab67 188 dm_handle_t dm_handle = {0,0,0,0};
Jonathan Austin 1:8aa5cdb4ab67 189 int ret = dm_handle_get(handle, &dm_handle);
Jonathan Austin 1:8aa5cdb4ab67 190
Jonathan Austin 1:8aa5cdb4ab67 191 if (ret == 0)
Jonathan Austin 1:8aa5cdb4ab67 192 deviceID = dm_handle.device_id;
Jonathan Austin 1:8aa5cdb4ab67 193
Jonathan Austin 1:8aa5cdb4ab67 194 if (manager)
Jonathan Austin 1:8aa5cdb4ab67 195 {
Jonathan Austin 1:8aa5cdb4ab67 196 pairingHandle = handle;
Jonathan Austin 1:8aa5cdb4ab67 197 manager->pairingComplete(status == SecurityManager::SEC_STATUS_SUCCESS);
Jonathan Austin 1:8aa5cdb4ab67 198 }
Jonathan Austin 1:8aa5cdb4ab67 199 }
Jonathan Austin 1:8aa5cdb4ab67 200
Jonathan Austin 1:8aa5cdb4ab67 201 /**
Jonathan Austin 1:8aa5cdb4ab67 202 * Constructor.
Jonathan Austin 1:8aa5cdb4ab67 203 *
Jonathan Austin 1:8aa5cdb4ab67 204 * Configure and manage the micro:bit's Bluetooth Low Energy (BLE) stack.
Jonathan Austin 1:8aa5cdb4ab67 205 *
Jonathan Austin 1:8aa5cdb4ab67 206 * @param _storage an instance of MicroBitStorage used to persist sys attribute information. (This is required for compatability with iOS).
Jonathan Austin 1:8aa5cdb4ab67 207 *
Jonathan Austin 1:8aa5cdb4ab67 208 * @note The BLE stack *cannot* be brought up in a static context (the software simply hangs or corrupts itself).
Jonathan Austin 1:8aa5cdb4ab67 209 * Hence, the init() member function should be used to initialise the BLE stack.
Jonathan Austin 1:8aa5cdb4ab67 210 */
Jonathan Austin 1:8aa5cdb4ab67 211 MicroBitBLEManager::MicroBitBLEManager(MicroBitStorage& _storage) :
Jonathan Austin 1:8aa5cdb4ab67 212 storage(&_storage)
Jonathan Austin 1:8aa5cdb4ab67 213 {
Jonathan Austin 1:8aa5cdb4ab67 214 manager = this;
Jonathan Austin 1:8aa5cdb4ab67 215 this->ble = NULL;
Jonathan Austin 1:8aa5cdb4ab67 216 this->pairingStatus = 0;
Jonathan Austin 1:8aa5cdb4ab67 217 }
Jonathan Austin 1:8aa5cdb4ab67 218
Jonathan Austin 1:8aa5cdb4ab67 219 /**
Jonathan Austin 1:8aa5cdb4ab67 220 * Constructor.
Jonathan Austin 1:8aa5cdb4ab67 221 *
Jonathan Austin 1:8aa5cdb4ab67 222 * Configure and manage the micro:bit's Bluetooth Low Energy (BLE) stack.
Jonathan Austin 1:8aa5cdb4ab67 223 *
Jonathan Austin 1:8aa5cdb4ab67 224 * @note The BLE stack *cannot* be brought up in a static context (the software simply hangs or corrupts itself).
Jonathan Austin 1:8aa5cdb4ab67 225 * Hence, the init() member function should be used to initialise the BLE stack.
Jonathan Austin 1:8aa5cdb4ab67 226 */
Jonathan Austin 1:8aa5cdb4ab67 227 MicroBitBLEManager::MicroBitBLEManager() :
Jonathan Austin 1:8aa5cdb4ab67 228 storage(NULL)
Jonathan Austin 1:8aa5cdb4ab67 229 {
Jonathan Austin 1:8aa5cdb4ab67 230 manager = this;
Jonathan Austin 1:8aa5cdb4ab67 231 this->ble = NULL;
Jonathan Austin 1:8aa5cdb4ab67 232 this->pairingStatus = 0;
Jonathan Austin 1:8aa5cdb4ab67 233 }
Jonathan Austin 1:8aa5cdb4ab67 234
Jonathan Austin 1:8aa5cdb4ab67 235 /**
Jonathan Austin 1:8aa5cdb4ab67 236 * When called, the micro:bit will begin advertising for a predefined period,
Jonathan Austin 1:8aa5cdb4ab67 237 * MICROBIT_BLE_ADVERTISING_TIMEOUT seconds to bonded devices.
Jonathan Austin 1:8aa5cdb4ab67 238 */
Jonathan Austin 1:8aa5cdb4ab67 239 void MicroBitBLEManager::advertise()
Jonathan Austin 1:8aa5cdb4ab67 240 {
Jonathan Austin 1:8aa5cdb4ab67 241 if(ble)
Jonathan Austin 1:8aa5cdb4ab67 242 ble->gap().startAdvertising();
Jonathan Austin 1:8aa5cdb4ab67 243 }
Jonathan Austin 1:8aa5cdb4ab67 244
Jonathan Austin 1:8aa5cdb4ab67 245 /**
Jonathan Austin 1:8aa5cdb4ab67 246 * Post constructor initialisation method as the BLE stack cannot be brought
Jonathan Austin 1:8aa5cdb4ab67 247 * up in a static context.
Jonathan Austin 1:8aa5cdb4ab67 248 *
Jonathan Austin 1:8aa5cdb4ab67 249 * @param deviceName The name used when advertising
Jonathan Austin 1:8aa5cdb4ab67 250 * @param serialNumber The serial number exposed by the device information service
Jonathan Austin 1:8aa5cdb4ab67 251 * @param messageBus An instance of an EventModel, used during pairing.
Jonathan Austin 1:8aa5cdb4ab67 252 * @param enableBonding If true, the security manager enabled bonding.
Jonathan Austin 1:8aa5cdb4ab67 253 *
Jonathan Austin 1:8aa5cdb4ab67 254 * @code
Jonathan Austin 1:8aa5cdb4ab67 255 * bleManager.init(uBit.getName(), uBit.getSerial(), uBit.messageBus, true);
Jonathan Austin 1:8aa5cdb4ab67 256 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 257 */
Jonathan Austin 1:8aa5cdb4ab67 258 void MicroBitBLEManager::init(ManagedString deviceName, ManagedString serialNumber, EventModel& messageBus, bool enableBonding)
Jonathan Austin 1:8aa5cdb4ab67 259 {
Jonathan Austin 1:8aa5cdb4ab67 260 ManagedString BLEName("BBC micro:bit");
Jonathan Austin 1:8aa5cdb4ab67 261 this->deviceName = deviceName;
Jonathan Austin 1:8aa5cdb4ab67 262
Jonathan Austin 1:8aa5cdb4ab67 263 #if !(CONFIG_ENABLED(MICROBIT_BLE_WHITELIST))
Jonathan Austin 1:8aa5cdb4ab67 264 ManagedString namePrefix(" [");
Jonathan Austin 1:8aa5cdb4ab67 265 ManagedString namePostfix("]");
Jonathan Austin 1:8aa5cdb4ab67 266 BLEName = BLEName + namePrefix + deviceName + namePostfix;
Jonathan Austin 1:8aa5cdb4ab67 267 #endif
Jonathan Austin 1:8aa5cdb4ab67 268
Jonathan Austin 1:8aa5cdb4ab67 269 // Start the BLE stack.
Jonathan Austin 1:8aa5cdb4ab67 270 #if CONFIG_ENABLED(MICROBIT_HEAP_REUSE_SD)
Jonathan Austin 1:8aa5cdb4ab67 271 btle_set_gatt_table_size(MICROBIT_SD_GATT_TABLE_SIZE);
Jonathan Austin 1:8aa5cdb4ab67 272 #endif
Jonathan Austin 1:8aa5cdb4ab67 273
Jonathan Austin 1:8aa5cdb4ab67 274 ble = new BLEDevice();
Jonathan Austin 1:8aa5cdb4ab67 275 ble->init();
Jonathan Austin 1:8aa5cdb4ab67 276
Jonathan Austin 1:8aa5cdb4ab67 277 // automatically restart advertising after a device disconnects.
Jonathan Austin 1:8aa5cdb4ab67 278 ble->gap().onDisconnection(bleDisconnectionCallback);
Jonathan Austin 1:8aa5cdb4ab67 279 ble->gattServer().onSysAttrMissing(bleSysAttrMissingCallback);
LancasterUniversity 21:cab56b701601 280
LancasterUniversity 21:cab56b701601 281 // generate an event when a Bluetooth connection is lost
LancasterUniversity 21:cab56b701601 282 ble->gap().onConnection(bleConnectionCallback);
Jonathan Austin 1:8aa5cdb4ab67 283
Jonathan Austin 1:8aa5cdb4ab67 284 // Configure the stack to hold onto the CPU during critical timing events.
Jonathan Austin 1:8aa5cdb4ab67 285 // mbed-classic performs __disable_irq() calls in its timers that can cause
Jonathan Austin 1:8aa5cdb4ab67 286 // MIC failures on secure BLE channels...
Jonathan Austin 1:8aa5cdb4ab67 287 ble_common_opt_radio_cpu_mutex_t opt;
Jonathan Austin 1:8aa5cdb4ab67 288 opt.enable = 1;
Jonathan Austin 1:8aa5cdb4ab67 289 sd_ble_opt_set(BLE_COMMON_OPT_RADIO_CPU_MUTEX, (const ble_opt_t *)&opt);
Jonathan Austin 1:8aa5cdb4ab67 290
Jonathan Austin 1:8aa5cdb4ab67 291 #if CONFIG_ENABLED(MICROBIT_BLE_PRIVATE_ADDRESSES)
Jonathan Austin 1:8aa5cdb4ab67 292 // Configure for private addresses, so kids' behaviour can't be easily tracked.
Jonathan Austin 1:8aa5cdb4ab67 293 ble->gap().setAddress(BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE, {0});
Jonathan Austin 1:8aa5cdb4ab67 294 #endif
Jonathan Austin 1:8aa5cdb4ab67 295
Jonathan Austin 1:8aa5cdb4ab67 296 // Setup our security requirements.
Jonathan Austin 1:8aa5cdb4ab67 297 ble->securityManager().onPasskeyDisplay(passkeyDisplayCallback);
Jonathan Austin 1:8aa5cdb4ab67 298 ble->securityManager().onSecuritySetupCompleted(securitySetupCompletedCallback);
Jonathan Austin 1:8aa5cdb4ab67 299 ble->securityManager().init(enableBonding, (SecurityManager::MICROBIT_BLE_SECURITY_LEVEL == SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM), SecurityManager::IO_CAPS_DISPLAY_ONLY);
Jonathan Austin 1:8aa5cdb4ab67 300
Jonathan Austin 1:8aa5cdb4ab67 301 if (enableBonding)
Jonathan Austin 1:8aa5cdb4ab67 302 {
Jonathan Austin 1:8aa5cdb4ab67 303 // If we're in pairing mode, review the size of the bond table.
Jonathan Austin 1:8aa5cdb4ab67 304 int bonds = getBondCount();
Jonathan Austin 1:8aa5cdb4ab67 305
Jonathan Austin 1:8aa5cdb4ab67 306 // TODO: It would be much better to implement some sort of LRU/NFU policy here,
Jonathan Austin 1:8aa5cdb4ab67 307 // but this isn't currently supported in mbed, so we'd need to layer break...
Jonathan Austin 1:8aa5cdb4ab67 308
Jonathan Austin 1:8aa5cdb4ab67 309 // If we're full, empty the bond table.
Jonathan Austin 1:8aa5cdb4ab67 310 if (bonds >= MICROBIT_BLE_MAXIMUM_BONDS)
Jonathan Austin 1:8aa5cdb4ab67 311 ble->securityManager().purgeAllBondingState();
Jonathan Austin 1:8aa5cdb4ab67 312 }
Jonathan Austin 1:8aa5cdb4ab67 313
Jonathan Austin 1:8aa5cdb4ab67 314 #if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST)
Jonathan Austin 1:8aa5cdb4ab67 315 // Configure a whitelist to filter all connection requetss from unbonded devices.
Jonathan Austin 1:8aa5cdb4ab67 316 // Most BLE stacks only permit one connection at a time, so this prevents denial of service attacks.
Jonathan Austin 1:8aa5cdb4ab67 317 BLEProtocol::Address_t bondedAddresses[MICROBIT_BLE_MAXIMUM_BONDS];
Jonathan Austin 1:8aa5cdb4ab67 318 Gap::Whitelist_t whitelist;
Jonathan Austin 1:8aa5cdb4ab67 319 whitelist.addresses = bondedAddresses;
Jonathan Austin 1:8aa5cdb4ab67 320 whitelist.capacity = MICROBIT_BLE_MAXIMUM_BONDS;
Jonathan Austin 1:8aa5cdb4ab67 321
Jonathan Austin 1:8aa5cdb4ab67 322 ble->securityManager().getAddressesFromBondTable(whitelist);
Jonathan Austin 1:8aa5cdb4ab67 323
Jonathan Austin 1:8aa5cdb4ab67 324 ble->gap().setWhitelist(whitelist);
Jonathan Austin 1:8aa5cdb4ab67 325 ble->gap().setScanningPolicyMode(Gap::SCAN_POLICY_IGNORE_WHITELIST);
Jonathan Austin 1:8aa5cdb4ab67 326 ble->gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_FILTER_CONN_REQS);
Jonathan Austin 1:8aa5cdb4ab67 327 #endif
Jonathan Austin 1:8aa5cdb4ab67 328
Jonathan Austin 1:8aa5cdb4ab67 329 // Configure the radio at our default power level
Jonathan Austin 1:8aa5cdb4ab67 330 setTransmitPower(MICROBIT_BLE_DEFAULT_TX_POWER);
Jonathan Austin 1:8aa5cdb4ab67 331
Jonathan Austin 1:8aa5cdb4ab67 332 // Bring up core BLE services.
Jonathan Austin 1:8aa5cdb4ab67 333 new MicroBitDFUService(*ble);
Jonathan Austin 1:8aa5cdb4ab67 334 DeviceInformationService ble_device_information_service (*ble, MICROBIT_BLE_MANUFACTURER, MICROBIT_BLE_MODEL, serialNumber.toCharArray(), MICROBIT_BLE_HARDWARE_VERSION, MICROBIT_BLE_FIRMWARE_VERSION, MICROBIT_BLE_SOFTWARE_VERSION);
Jonathan Austin 1:8aa5cdb4ab67 335 new MicroBitEventService(*ble, messageBus);
Jonathan Austin 1:8aa5cdb4ab67 336
Jonathan Austin 1:8aa5cdb4ab67 337
Jonathan Austin 1:8aa5cdb4ab67 338 // Configure for high speed mode where possible.
Jonathan Austin 1:8aa5cdb4ab67 339 Gap::ConnectionParams_t fast;
Jonathan Austin 1:8aa5cdb4ab67 340 ble->getPreferredConnectionParams(&fast);
Jonathan Austin 1:8aa5cdb4ab67 341 fast.minConnectionInterval = 8; // 10 ms
Jonathan Austin 1:8aa5cdb4ab67 342 fast.maxConnectionInterval = 16; // 20 ms
Jonathan Austin 1:8aa5cdb4ab67 343 fast.slaveLatency = 0;
Jonathan Austin 1:8aa5cdb4ab67 344 ble->setPreferredConnectionParams(&fast);
Jonathan Austin 1:8aa5cdb4ab67 345
Jonathan Austin 1:8aa5cdb4ab67 346 // Setup advertising.
Jonathan Austin 1:8aa5cdb4ab67 347 #if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST)
Jonathan Austin 1:8aa5cdb4ab67 348 ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
Jonathan Austin 1:8aa5cdb4ab67 349 #else
Jonathan Austin 1:8aa5cdb4ab67 350 ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
Jonathan Austin 1:8aa5cdb4ab67 351 #endif
Jonathan Austin 1:8aa5cdb4ab67 352
Jonathan Austin 1:8aa5cdb4ab67 353 ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)BLEName.toCharArray(), BLEName.length());
Jonathan Austin 1:8aa5cdb4ab67 354 ble->setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
Jonathan Austin 1:8aa5cdb4ab67 355 ble->setAdvertisingInterval(200);
Jonathan Austin 1:8aa5cdb4ab67 356
Jonathan Austin 1:8aa5cdb4ab67 357 #if (MICROBIT_BLE_ADVERTISING_TIMEOUT > 0)
Jonathan Austin 1:8aa5cdb4ab67 358 ble->gap().setAdvertisingTimeout(MICROBIT_BLE_ADVERTISING_TIMEOUT);
Jonathan Austin 1:8aa5cdb4ab67 359 #endif
Jonathan Austin 1:8aa5cdb4ab67 360
Jonathan Austin 1:8aa5cdb4ab67 361 // If we have whitelisting enabled, then prevent only enable advertising of we have any binded devices...
Jonathan Austin 1:8aa5cdb4ab67 362 // This is to further protect kids' privacy. If no-one initiates BLE, then the device is unreachable.
Jonathan Austin 1:8aa5cdb4ab67 363 // If whiltelisting is disabled, then we always advertise.
Jonathan Austin 1:8aa5cdb4ab67 364 #if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST)
Jonathan Austin 1:8aa5cdb4ab67 365 if (whitelist.size > 0)
Jonathan Austin 1:8aa5cdb4ab67 366 #endif
Jonathan Austin 1:8aa5cdb4ab67 367 ble->startAdvertising();
Jonathan Austin 1:8aa5cdb4ab67 368 }
Jonathan Austin 1:8aa5cdb4ab67 369
Jonathan Austin 1:8aa5cdb4ab67 370 /**
Jonathan Austin 1:8aa5cdb4ab67 371 * Change the output power level of the transmitter to the given value.
Jonathan Austin 1:8aa5cdb4ab67 372 *
Jonathan Austin 1:8aa5cdb4ab67 373 * @param power a value in the range 0..7, where 0 is the lowest power and 7 is the highest.
Jonathan Austin 1:8aa5cdb4ab67 374 *
Jonathan Austin 1:8aa5cdb4ab67 375 * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the value is out of range.
Jonathan Austin 1:8aa5cdb4ab67 376 *
Jonathan Austin 1:8aa5cdb4ab67 377 * @code
Jonathan Austin 1:8aa5cdb4ab67 378 * // maximum transmission power.
Jonathan Austin 1:8aa5cdb4ab67 379 * bleManager.setTransmitPower(7);
Jonathan Austin 1:8aa5cdb4ab67 380 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 381 */
Jonathan Austin 1:8aa5cdb4ab67 382 int MicroBitBLEManager::setTransmitPower(int power)
Jonathan Austin 1:8aa5cdb4ab67 383 {
Jonathan Austin 1:8aa5cdb4ab67 384 if (power < 0 || power >= MICROBIT_BLE_POWER_LEVELS)
Jonathan Austin 1:8aa5cdb4ab67 385 return MICROBIT_INVALID_PARAMETER;
Jonathan Austin 1:8aa5cdb4ab67 386
Jonathan Austin 1:8aa5cdb4ab67 387 if (ble->gap().setTxPower(MICROBIT_BLE_POWER_LEVEL[power]) != NRF_SUCCESS)
Jonathan Austin 1:8aa5cdb4ab67 388 return MICROBIT_NOT_SUPPORTED;
Jonathan Austin 1:8aa5cdb4ab67 389
Jonathan Austin 1:8aa5cdb4ab67 390 return MICROBIT_OK;
Jonathan Austin 1:8aa5cdb4ab67 391 }
Jonathan Austin 1:8aa5cdb4ab67 392
Jonathan Austin 1:8aa5cdb4ab67 393 /**
Jonathan Austin 1:8aa5cdb4ab67 394 * Determines the number of devices currently bonded with this micro:bit.
Jonathan Austin 1:8aa5cdb4ab67 395 * @return The number of active bonds.
Jonathan Austin 1:8aa5cdb4ab67 396 */
Jonathan Austin 1:8aa5cdb4ab67 397 int MicroBitBLEManager::getBondCount()
Jonathan Austin 1:8aa5cdb4ab67 398 {
Jonathan Austin 1:8aa5cdb4ab67 399 BLEProtocol::Address_t bondedAddresses[MICROBIT_BLE_MAXIMUM_BONDS];
Jonathan Austin 1:8aa5cdb4ab67 400 Gap::Whitelist_t whitelist;
Jonathan Austin 1:8aa5cdb4ab67 401 whitelist.addresses = bondedAddresses;
Jonathan Austin 1:8aa5cdb4ab67 402 whitelist.capacity = MICROBIT_BLE_MAXIMUM_BONDS;
Jonathan Austin 1:8aa5cdb4ab67 403 ble->securityManager().getAddressesFromBondTable(whitelist);
Jonathan Austin 1:8aa5cdb4ab67 404
Jonathan Austin 1:8aa5cdb4ab67 405 return whitelist.bonds;
Jonathan Austin 1:8aa5cdb4ab67 406 }
Jonathan Austin 1:8aa5cdb4ab67 407
Jonathan Austin 1:8aa5cdb4ab67 408 /**
Jonathan Austin 1:8aa5cdb4ab67 409 * A request to pair has been received from a BLE device.
Jonathan Austin 1:8aa5cdb4ab67 410 * If we're in pairing mode, display the passkey to the user.
Jonathan Austin 1:8aa5cdb4ab67 411 * Also, purge the bonding table if it has reached capacity.
Jonathan Austin 1:8aa5cdb4ab67 412 *
Jonathan Austin 1:8aa5cdb4ab67 413 * @note for internal use only.
Jonathan Austin 1:8aa5cdb4ab67 414 */
Jonathan Austin 1:8aa5cdb4ab67 415 void MicroBitBLEManager::pairingRequested(ManagedString passKey)
Jonathan Austin 1:8aa5cdb4ab67 416 {
Jonathan Austin 1:8aa5cdb4ab67 417 // Update our mode to display the passkey.
Jonathan Austin 1:8aa5cdb4ab67 418 this->passKey = passKey;
Jonathan Austin 1:8aa5cdb4ab67 419 this->pairingStatus = MICROBIT_BLE_PAIR_REQUEST;
Jonathan Austin 1:8aa5cdb4ab67 420 }
Jonathan Austin 1:8aa5cdb4ab67 421
Jonathan Austin 1:8aa5cdb4ab67 422 /**
Jonathan Austin 1:8aa5cdb4ab67 423 * A pairing request has been sucessfully completed.
Jonathan Austin 1:8aa5cdb4ab67 424 * If we're in pairing mode, display a success or failure message.
Jonathan Austin 1:8aa5cdb4ab67 425 *
Jonathan Austin 1:8aa5cdb4ab67 426 * @note for internal use only.
Jonathan Austin 1:8aa5cdb4ab67 427 */
Jonathan Austin 1:8aa5cdb4ab67 428 void MicroBitBLEManager::pairingComplete(bool success)
Jonathan Austin 1:8aa5cdb4ab67 429 {
Jonathan Austin 1:8aa5cdb4ab67 430 this->pairingStatus = MICROBIT_BLE_PAIR_COMPLETE;
Jonathan Austin 1:8aa5cdb4ab67 431
Jonathan Austin 1:8aa5cdb4ab67 432 if(success)
Jonathan Austin 1:8aa5cdb4ab67 433 {
Jonathan Austin 1:8aa5cdb4ab67 434 this->pairingStatus |= MICROBIT_BLE_PAIR_SUCCESSFUL;
Jonathan Austin 1:8aa5cdb4ab67 435 fiber_add_idle_component(this);
Jonathan Austin 1:8aa5cdb4ab67 436 }
Jonathan Austin 1:8aa5cdb4ab67 437 }
Jonathan Austin 1:8aa5cdb4ab67 438
Jonathan Austin 1:8aa5cdb4ab67 439 /**
Jonathan Austin 1:8aa5cdb4ab67 440 * Periodic callback in thread context.
Jonathan Austin 1:8aa5cdb4ab67 441 * We use this here purely to safely issue a disconnect operation after a pairing operation is complete.
Jonathan Austin 1:8aa5cdb4ab67 442 */
Jonathan Austin 1:8aa5cdb4ab67 443 void MicroBitBLEManager::idleTick()
Jonathan Austin 1:8aa5cdb4ab67 444 {
Jonathan Austin 1:8aa5cdb4ab67 445 if (ble)
Jonathan Austin 1:8aa5cdb4ab67 446 ble->disconnect(pairingHandle, Gap::REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF);
Jonathan Austin 1:8aa5cdb4ab67 447
Jonathan Austin 1:8aa5cdb4ab67 448 fiber_remove_idle_component(this);
Jonathan Austin 1:8aa5cdb4ab67 449 }
Jonathan Austin 1:8aa5cdb4ab67 450
Jonathan Austin 1:8aa5cdb4ab67 451 /**
Jonathan Austin 1:8aa5cdb4ab67 452 * Enter pairing mode. This is mode is called to initiate pairing, and to enable FOTA programming
Jonathan Austin 1:8aa5cdb4ab67 453 * of the micro:bit in cases where BLE is disabled during normal operation.
Jonathan Austin 1:8aa5cdb4ab67 454 *
Jonathan Austin 1:8aa5cdb4ab67 455 * @param display An instance of MicroBitDisplay used when displaying pairing information.
Jonathan Austin 1:8aa5cdb4ab67 456 * @param authorizationButton The button to use to authorise a pairing request.
Jonathan Austin 1:8aa5cdb4ab67 457 *
Jonathan Austin 1:8aa5cdb4ab67 458 * @code
Jonathan Austin 1:8aa5cdb4ab67 459 * // initiate pairing mode
Jonathan Austin 1:8aa5cdb4ab67 460 * bleManager.pairingMode(uBit.display, uBit.buttonA);
Jonathan Austin 1:8aa5cdb4ab67 461 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 462 */
Jonathan Austin 1:8aa5cdb4ab67 463 void MicroBitBLEManager::pairingMode(MicroBitDisplay& display, MicroBitButton& authorisationButton)
Jonathan Austin 1:8aa5cdb4ab67 464 {
Jonathan Austin 1:8aa5cdb4ab67 465 ManagedString namePrefix("BBC micro:bit [");
Jonathan Austin 1:8aa5cdb4ab67 466 ManagedString namePostfix("]");
Jonathan Austin 1:8aa5cdb4ab67 467 ManagedString BLEName = namePrefix + deviceName + namePostfix;
Jonathan Austin 1:8aa5cdb4ab67 468
Jonathan Austin 1:8aa5cdb4ab67 469 ManagedString msg("PAIRING MODE!");
Jonathan Austin 1:8aa5cdb4ab67 470
Jonathan Austin 1:8aa5cdb4ab67 471 int timeInPairingMode = 0;
Jonathan Austin 1:8aa5cdb4ab67 472 int brightness = 255;
Jonathan Austin 1:8aa5cdb4ab67 473 int fadeDirection = 0;
Jonathan Austin 1:8aa5cdb4ab67 474
Jonathan Austin 1:8aa5cdb4ab67 475 ble->gap().stopAdvertising();
Jonathan Austin 1:8aa5cdb4ab67 476
Jonathan Austin 1:8aa5cdb4ab67 477 // Clear the whitelist (if we have one), so that we're discoverable by all BLE devices.
Jonathan Austin 1:8aa5cdb4ab67 478 #if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST)
Jonathan Austin 1:8aa5cdb4ab67 479 BLEProtocol::Address_t addresses[MICROBIT_BLE_MAXIMUM_BONDS];
Jonathan Austin 1:8aa5cdb4ab67 480 Gap::Whitelist_t whitelist;
Jonathan Austin 1:8aa5cdb4ab67 481 whitelist.addresses = addresses;
Jonathan Austin 1:8aa5cdb4ab67 482 whitelist.capacity = MICROBIT_BLE_MAXIMUM_BONDS;
Jonathan Austin 1:8aa5cdb4ab67 483 whitelist.size = 0;
Jonathan Austin 1:8aa5cdb4ab67 484 ble->gap().setWhitelist(whitelist);
Jonathan Austin 1:8aa5cdb4ab67 485 ble->gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST);
Jonathan Austin 1:8aa5cdb4ab67 486 #endif
Jonathan Austin 1:8aa5cdb4ab67 487
Jonathan Austin 1:8aa5cdb4ab67 488 // Update the advertised name of this micro:bit to include the device name
Jonathan Austin 1:8aa5cdb4ab67 489 ble->clearAdvertisingPayload();
Jonathan Austin 1:8aa5cdb4ab67 490
Jonathan Austin 1:8aa5cdb4ab67 491 ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
Jonathan Austin 1:8aa5cdb4ab67 492 ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)BLEName.toCharArray(), BLEName.length());
Jonathan Austin 1:8aa5cdb4ab67 493 ble->setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
Jonathan Austin 1:8aa5cdb4ab67 494 ble->setAdvertisingInterval(200);
Jonathan Austin 1:8aa5cdb4ab67 495
Jonathan Austin 1:8aa5cdb4ab67 496 ble->gap().setAdvertisingTimeout(0);
Jonathan Austin 1:8aa5cdb4ab67 497 ble->gap().startAdvertising();
Jonathan Austin 1:8aa5cdb4ab67 498
Jonathan Austin 1:8aa5cdb4ab67 499 // Stop any running animations on the display
Jonathan Austin 1:8aa5cdb4ab67 500 display.stopAnimation();
Jonathan Austin 1:8aa5cdb4ab67 501 display.scroll(msg);
Jonathan Austin 1:8aa5cdb4ab67 502
Jonathan Austin 1:8aa5cdb4ab67 503 // Display our name, visualised as a histogram in the display to aid identification.
Jonathan Austin 1:8aa5cdb4ab67 504 showNameHistogram(display);
Jonathan Austin 1:8aa5cdb4ab67 505
Jonathan Austin 1:8aa5cdb4ab67 506 while(1)
Jonathan Austin 1:8aa5cdb4ab67 507 {
Jonathan Austin 1:8aa5cdb4ab67 508 if (pairingStatus & MICROBIT_BLE_PAIR_REQUEST)
Jonathan Austin 1:8aa5cdb4ab67 509 {
Jonathan Austin 1:8aa5cdb4ab67 510 timeInPairingMode = 0;
Jonathan Austin 1:8aa5cdb4ab67 511 MicroBitImage arrow("0,0,255,0,0\n0,255,0,0,0\n255,255,255,255,255\n0,255,0,0,0\n0,0,255,0,0\n");
Jonathan Austin 1:8aa5cdb4ab67 512 display.print(arrow,0,0,0);
Jonathan Austin 1:8aa5cdb4ab67 513
Jonathan Austin 1:8aa5cdb4ab67 514 if (fadeDirection == 0)
Jonathan Austin 1:8aa5cdb4ab67 515 brightness -= MICROBIT_PAIRING_FADE_SPEED;
Jonathan Austin 1:8aa5cdb4ab67 516 else
Jonathan Austin 1:8aa5cdb4ab67 517 brightness += MICROBIT_PAIRING_FADE_SPEED;
Jonathan Austin 1:8aa5cdb4ab67 518
Jonathan Austin 1:8aa5cdb4ab67 519 if (brightness <= 40)
Jonathan Austin 1:8aa5cdb4ab67 520 display.clear();
Jonathan Austin 1:8aa5cdb4ab67 521
Jonathan Austin 1:8aa5cdb4ab67 522 if (brightness <= 0)
Jonathan Austin 1:8aa5cdb4ab67 523 fadeDirection = 1;
Jonathan Austin 1:8aa5cdb4ab67 524
Jonathan Austin 1:8aa5cdb4ab67 525 if (brightness >= 255)
Jonathan Austin 1:8aa5cdb4ab67 526 fadeDirection = 0;
Jonathan Austin 1:8aa5cdb4ab67 527
Jonathan Austin 1:8aa5cdb4ab67 528 if (authorisationButton.isPressed())
Jonathan Austin 1:8aa5cdb4ab67 529 {
Jonathan Austin 1:8aa5cdb4ab67 530 pairingStatus &= ~MICROBIT_BLE_PAIR_REQUEST;
Jonathan Austin 1:8aa5cdb4ab67 531 pairingStatus |= MICROBIT_BLE_PAIR_PASSCODE;
Jonathan Austin 1:8aa5cdb4ab67 532 }
Jonathan Austin 1:8aa5cdb4ab67 533 }
Jonathan Austin 1:8aa5cdb4ab67 534
Jonathan Austin 1:8aa5cdb4ab67 535 if (pairingStatus & MICROBIT_BLE_PAIR_PASSCODE)
Jonathan Austin 1:8aa5cdb4ab67 536 {
Jonathan Austin 1:8aa5cdb4ab67 537 timeInPairingMode = 0;
Jonathan Austin 1:8aa5cdb4ab67 538 display.setBrightness(255);
Jonathan Austin 1:8aa5cdb4ab67 539 for (int i=0; i<passKey.length(); i++)
Jonathan Austin 1:8aa5cdb4ab67 540 {
Jonathan Austin 1:8aa5cdb4ab67 541 display.image.print(passKey.charAt(i),0,0);
Jonathan Austin 1:8aa5cdb4ab67 542 fiber_sleep(800);
Jonathan Austin 1:8aa5cdb4ab67 543 display.clear();
Jonathan Austin 1:8aa5cdb4ab67 544 fiber_sleep(200);
Jonathan Austin 1:8aa5cdb4ab67 545
Jonathan Austin 1:8aa5cdb4ab67 546 if (pairingStatus & MICROBIT_BLE_PAIR_COMPLETE)
Jonathan Austin 1:8aa5cdb4ab67 547 break;
Jonathan Austin 1:8aa5cdb4ab67 548 }
Jonathan Austin 1:8aa5cdb4ab67 549
Jonathan Austin 1:8aa5cdb4ab67 550 fiber_sleep(1000);
Jonathan Austin 1:8aa5cdb4ab67 551 }
Jonathan Austin 1:8aa5cdb4ab67 552
Jonathan Austin 1:8aa5cdb4ab67 553 if (pairingStatus & MICROBIT_BLE_PAIR_COMPLETE)
Jonathan Austin 1:8aa5cdb4ab67 554 {
Jonathan Austin 1:8aa5cdb4ab67 555 if (pairingStatus & MICROBIT_BLE_PAIR_SUCCESSFUL)
Jonathan Austin 1:8aa5cdb4ab67 556 {
Jonathan Austin 1:8aa5cdb4ab67 557 MicroBitImage tick("0,0,0,0,0\n0,0,0,0,255\n0,0,0,255,0\n255,0,255,0,0\n0,255,0,0,0\n");
Jonathan Austin 1:8aa5cdb4ab67 558 display.print(tick,0,0,0);
Jonathan Austin 1:8aa5cdb4ab67 559 fiber_sleep(15000);
Jonathan Austin 1:8aa5cdb4ab67 560 timeInPairingMode = MICROBIT_BLE_PAIRING_TIMEOUT * 30;
Jonathan Austin 1:8aa5cdb4ab67 561
Jonathan Austin 1:8aa5cdb4ab67 562 /*
Jonathan Austin 1:8aa5cdb4ab67 563 * Disabled, as the API to return the number of active bonds is not reliable at present...
Jonathan Austin 1:8aa5cdb4ab67 564 *
Jonathan Austin 1:8aa5cdb4ab67 565 display.clear();
Jonathan Austin 1:8aa5cdb4ab67 566 ManagedString c(getBondCount());
Jonathan Austin 1:8aa5cdb4ab67 567 ManagedString c2("/");
Jonathan Austin 1:8aa5cdb4ab67 568 ManagedString c3(MICROBIT_BLE_MAXIMUM_BONDS);
Jonathan Austin 1:8aa5cdb4ab67 569 ManagedString c4("USED");
Jonathan Austin 1:8aa5cdb4ab67 570
Jonathan Austin 1:8aa5cdb4ab67 571 display.scroll(c+c2+c3+c4);
Jonathan Austin 1:8aa5cdb4ab67 572 *
Jonathan Austin 1:8aa5cdb4ab67 573 *
Jonathan Austin 1:8aa5cdb4ab67 574 */
Jonathan Austin 1:8aa5cdb4ab67 575 }
Jonathan Austin 1:8aa5cdb4ab67 576 else
Jonathan Austin 1:8aa5cdb4ab67 577 {
Jonathan Austin 1:8aa5cdb4ab67 578 MicroBitImage cross("255,0,0,0,255\n0,255,0,255,0\n0,0,255,0,0\n0,255,0,255,0\n255,0,0,0,255\n");
Jonathan Austin 1:8aa5cdb4ab67 579 display.print(cross,0,0,0);
Jonathan Austin 1:8aa5cdb4ab67 580 }
Jonathan Austin 1:8aa5cdb4ab67 581 }
Jonathan Austin 1:8aa5cdb4ab67 582
Jonathan Austin 1:8aa5cdb4ab67 583 fiber_sleep(100);
Jonathan Austin 1:8aa5cdb4ab67 584 timeInPairingMode++;
Jonathan Austin 1:8aa5cdb4ab67 585
Jonathan Austin 1:8aa5cdb4ab67 586 if (timeInPairingMode >= MICROBIT_BLE_PAIRING_TIMEOUT * 30)
Jonathan Austin 1:8aa5cdb4ab67 587 microbit_reset();
Jonathan Austin 1:8aa5cdb4ab67 588 }
Jonathan Austin 1:8aa5cdb4ab67 589 }
Jonathan Austin 1:8aa5cdb4ab67 590
Jonathan Austin 1:8aa5cdb4ab67 591 /**
Jonathan Austin 1:8aa5cdb4ab67 592 * Displays the device's ID code as a histogram on the provided MicroBitDisplay instance.
Jonathan Austin 1:8aa5cdb4ab67 593 *
Jonathan Austin 1:8aa5cdb4ab67 594 * @param display The display instance used for displaying the histogram.
Jonathan Austin 1:8aa5cdb4ab67 595 */
Jonathan Austin 1:8aa5cdb4ab67 596 void MicroBitBLEManager::showNameHistogram(MicroBitDisplay &display)
Jonathan Austin 1:8aa5cdb4ab67 597 {
Jonathan Austin 1:8aa5cdb4ab67 598 uint32_t n = NRF_FICR->DEVICEID[1];
Jonathan Austin 1:8aa5cdb4ab67 599 int ld = 1;
Jonathan Austin 1:8aa5cdb4ab67 600 int d = MICROBIT_DFU_HISTOGRAM_HEIGHT;
Jonathan Austin 1:8aa5cdb4ab67 601 int h;
Jonathan Austin 1:8aa5cdb4ab67 602
Jonathan Austin 1:8aa5cdb4ab67 603 display.clear();
Jonathan Austin 1:8aa5cdb4ab67 604 for (int i=0; i<MICROBIT_DFU_HISTOGRAM_WIDTH;i++)
Jonathan Austin 1:8aa5cdb4ab67 605 {
Jonathan Austin 1:8aa5cdb4ab67 606 h = (n % d) / ld;
Jonathan Austin 1:8aa5cdb4ab67 607
Jonathan Austin 1:8aa5cdb4ab67 608 n -= h;
Jonathan Austin 1:8aa5cdb4ab67 609 d *= MICROBIT_DFU_HISTOGRAM_HEIGHT;
Jonathan Austin 1:8aa5cdb4ab67 610 ld *= MICROBIT_DFU_HISTOGRAM_HEIGHT;
Jonathan Austin 1:8aa5cdb4ab67 611
Jonathan Austin 1:8aa5cdb4ab67 612 for (int j=0; j<h+1; j++)
Jonathan Austin 1:8aa5cdb4ab67 613 display.image.setPixelValue(MICROBIT_DFU_HISTOGRAM_WIDTH-i-1, MICROBIT_DFU_HISTOGRAM_HEIGHT-j-1, 255);
Jonathan Austin 1:8aa5cdb4ab67 614 }
LancasterUniversity 21:cab56b701601 615 }