ble nano hid over gatt

Dependencies:   BLE_API mbed-dev nRF51822

Committer:
cho45
Date:
Thu Sep 15 09:31:05 2016 +0900
Revision:
86:e0fab77e669d
Parent:
85:e526a89a0674
support consumer keys

Who changed what in which revision?

UserRevisionLine numberNew contents of line
cho45 6:f1c3ea8bc850 1 #include "mbed.h"
cho45 6:f1c3ea8bc850 2 #include "BLE.h"
cho45 42:2c3be8694896 3
cho45 42:2c3be8694896 4 #include "config.h"
cho45 67:81a545a4963c 5 #include "WatchDog.h"
cho45 6:f1c3ea8bc850 6 #include "KeyboardService.h"
cho45 6:f1c3ea8bc850 7 #include "BatteryService.h"
cho45 6:f1c3ea8bc850 8 #include "DeviceInformationService.h"
cho45 85:e526a89a0674 9 #include "ScanParametersService.h"
cho45 15:70bf079d3ee1 10 #include "DFUService.h"
cho45 6:f1c3ea8bc850 11 #include "HIDController_BLE.h"
cho45 6:f1c3ea8bc850 12
cho45 59:2d6c0bff2151 13 static const char MANUFACTURERERS_NAME[] = "lowreal.net";
cho45 47:5bf2ae8cc710 14 static const char MODEL_NAME[] = "keble";
cho45 6:f1c3ea8bc850 15 static const char SERIAL_NUMBER[] = "X00000";
cho45 6:f1c3ea8bc850 16 static const char HARDWARE_REVISION[] = "0.1";
cho45 6:f1c3ea8bc850 17 static const char FIRMWARE_REVISION[] = "0.1";
cho45 6:f1c3ea8bc850 18 static const char SOFTWARE_REVISION[] = "0.0";
cho45 75:351d7ffe81d1 19 static PnPID_t PNP_ID = {
cho45 84:b917922bb5f1 20 0x01, // From Bluetooth SIG
cho45 84:b917922bb5f1 21 0xFFFE,
cho45 84:b917922bb5f1 22 0x0001,
cho45 84:b917922bb5f1 23 0x01,
cho45 75:351d7ffe81d1 24 };
cho45 6:f1c3ea8bc850 25
cho45 83:2e940d154f8b 26 static const uint8_t DEVICE_NAME[] = "Keble";
cho45 6:f1c3ea8bc850 27
cho45 6:f1c3ea8bc850 28 static const bool ENABLE_BONDING = true;
cho45 6:f1c3ea8bc850 29 static const bool REQUIRE_MITM = true;
cho45 6:f1c3ea8bc850 30 static const uint8_t PASSKEY[6] = {'1','2','3','4','5','6'}; // must be 6-digits number
cho45 6:f1c3ea8bc850 31
cho45 6:f1c3ea8bc850 32 static const uint16_t uuid16_list[] = {
cho45 85:e526a89a0674 33 GattService::UUID_HUMAN_INTERFACE_DEVICE_SERVICE
cho45 6:f1c3ea8bc850 34 };
cho45 6:f1c3ea8bc850 35
cho45 6:f1c3ea8bc850 36 static KeyboardService* keyboardService;
cho45 6:f1c3ea8bc850 37 static BatteryService* batteryService;
cho45 6:f1c3ea8bc850 38 static DeviceInformationService* deviceInformationService;
cho45 85:e526a89a0674 39 static ScanParametersService* scanParametersService;
cho45 48:d6938de02f62 40 // static DFUService* dfuService;
cho45 6:f1c3ea8bc850 41
cho45 59:2d6c0bff2151 42
cho45 13:b0ffdf2012b9 43 static BLEProtocol::Address_t peerAddress;
cho45 27:7370b8994603 44
cho45 27:7370b8994603 45 static volatile Status_t controllerStatus;
cho45 13:b0ffdf2012b9 46
cho45 6:f1c3ea8bc850 47 static void onConnect(const Gap::ConnectionCallbackParams_t *params) {
cho45 42:2c3be8694896 48 peerAddress.type = params->peerAddrType;
cho45 42:2c3be8694896 49 memcpy(peerAddress.address, params->peerAddr, Gap::ADDR_LEN);
cho45 73:d36e0b817ebf 50
cho45 73:d36e0b817ebf 51 BLEProtocol::Address_t peerAddresses[2];
cho45 73:d36e0b817ebf 52 Gap::Whitelist_t whitelist;
cho45 73:d36e0b817ebf 53 whitelist.size = 0;
cho45 73:d36e0b817ebf 54 whitelist.capacity = 2;
cho45 73:d36e0b817ebf 55 whitelist.addresses = peerAddresses;
cho45 73:d36e0b817ebf 56 BLE::Instance(BLE::DEFAULT_INSTANCE).gap().getWhitelist(whitelist);
cho45 73:d36e0b817ebf 57 DEBUG_PRINTF_BLE_INTERRUPT("getWhitelist %d\r\n", whitelist.size);
cho45 73:d36e0b817ebf 58 for (int i = 0; i < whitelist.size; i++) {
cho45 73:d36e0b817ebf 59 if (whitelist.addresses[i].type == params->peerAddrType &&
cho45 73:d36e0b817ebf 60 memcmp(whitelist.addresses[i].address, params->peerAddr, Gap::ADDR_LEN) == 0) {
cho45 73:d36e0b817ebf 61
cho45 73:d36e0b817ebf 62 BLE::Instance(BLE::DEFAULT_INSTANCE).gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_FILTER_ALL_REQS);
cho45 73:d36e0b817ebf 63 controllerStatus = CONNECTED;
cho45 73:d36e0b817ebf 64 DEBUG_PRINTF_BLE_INTERRUPT("peer is found in whitelist\r\n");
cho45 73:d36e0b817ebf 65 return;
cho45 73:d36e0b817ebf 66 }
cho45 73:d36e0b817ebf 67 }
cho45 73:d36e0b817ebf 68
cho45 75:351d7ffe81d1 69 controllerStatus = CONNECTING;
cho45 73:d36e0b817ebf 70 DEBUG_PRINTF_BLE_INTERRUPT("peer is not found in whitelist\r\n");
cho45 6:f1c3ea8bc850 71 }
cho45 6:f1c3ea8bc850 72
cho45 6:f1c3ea8bc850 73 static void onDisconnect(const Gap::DisconnectionCallbackParams_t *params) {
cho45 27:7370b8994603 74 controllerStatus = DISCONNECTED;
cho45 42:2c3be8694896 75 DEBUG_PRINTF_BLE_INTERRUPT("onDisconnect\r\n");
cho45 6:f1c3ea8bc850 76 }
cho45 6:f1c3ea8bc850 77
cho45 6:f1c3ea8bc850 78 static void onTimeout(const Gap::TimeoutSource_t source) {
cho45 61:17e9a3afc4f4 79 DEBUG_PRINTF_BLE_INTERRUPT("onTimeout %d\r\n", source);
cho45 61:17e9a3afc4f4 80 switch (source) {
cho45 61:17e9a3afc4f4 81 case Gap::TIMEOUT_SRC_ADVERTISING:
cho45 61:17e9a3afc4f4 82 controllerStatus = TIMEOUT;
cho45 61:17e9a3afc4f4 83 return;
cho45 61:17e9a3afc4f4 84
cho45 61:17e9a3afc4f4 85 // treat following timeout as DISCONNECT (retry advertising)
cho45 61:17e9a3afc4f4 86 case Gap::TIMEOUT_SRC_SECURITY_REQUEST:
cho45 61:17e9a3afc4f4 87 case Gap::TIMEOUT_SRC_SCAN:
cho45 61:17e9a3afc4f4 88 case Gap::TIMEOUT_SRC_CONN:
cho45 61:17e9a3afc4f4 89 controllerStatus = DISCONNECTED;
cho45 61:17e9a3afc4f4 90 return;
cho45 61:17e9a3afc4f4 91 }
cho45 6:f1c3ea8bc850 92 }
cho45 6:f1c3ea8bc850 93
cho45 6:f1c3ea8bc850 94 static void passkeyDisplayCallback(Gap::Handle_t handle, const SecurityManager::Passkey_t passkey) {
cho45 42:2c3be8694896 95 DEBUG_PRINTF_BLE_INTERRUPT("Input passKey: ");
cho45 6:f1c3ea8bc850 96 for (unsigned i = 0; i < Gap::ADDR_LEN; i++) {
cho45 42:2c3be8694896 97 DEBUG_PRINTF_BLE_INTERRUPT("%c", passkey[i]);
cho45 6:f1c3ea8bc850 98 }
cho45 42:2c3be8694896 99 DEBUG_PRINTF_BLE_INTERRUPT("\r\n");
cho45 6:f1c3ea8bc850 100 }
cho45 6:f1c3ea8bc850 101
cho45 6:f1c3ea8bc850 102 static void securitySetupCompletedCallback(Gap::Handle_t handle, SecurityManager::SecurityCompletionStatus_t status) {
cho45 6:f1c3ea8bc850 103 if (status == SecurityManager::SEC_STATUS_SUCCESS) {
cho45 42:2c3be8694896 104 DEBUG_PRINTF_BLE_INTERRUPT("Security success %d\r\n", status);
cho45 42:2c3be8694896 105 DEBUG_PRINTF_BLE_INTERRUPT("Set whitelist\r\n");
cho45 13:b0ffdf2012b9 106 Gap::Whitelist_t whitelist;
cho45 13:b0ffdf2012b9 107 whitelist.size = 1;
cho45 13:b0ffdf2012b9 108 whitelist.capacity = 1;
cho45 13:b0ffdf2012b9 109 whitelist.addresses = &peerAddress;
cho45 13:b0ffdf2012b9 110
cho45 13:b0ffdf2012b9 111 BLE::Instance(BLE::DEFAULT_INSTANCE).gap().setWhitelist(whitelist);
cho45 42:2c3be8694896 112 DEBUG_PRINTF_BLE_INTERRUPT("Set Advertising Policy Mode\r\n");
cho45 13:b0ffdf2012b9 113 // BLE::Instance(BLE::DEFAULT_INSTANCE).gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_FILTER_SCAN_REQS);
cho45 13:b0ffdf2012b9 114 // BLE::Instance(BLE::DEFAULT_INSTANCE).gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_FILTER_CONN_REQS);
cho45 13:b0ffdf2012b9 115 BLE::Instance(BLE::DEFAULT_INSTANCE).gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_FILTER_ALL_REQS);
cho45 73:d36e0b817ebf 116 controllerStatus = CONNECTED;
cho45 6:f1c3ea8bc850 117 } else {
cho45 42:2c3be8694896 118 DEBUG_PRINTF_BLE_INTERRUPT("Security failed %d\r\n", status);
cho45 6:f1c3ea8bc850 119 }
cho45 6:f1c3ea8bc850 120 }
cho45 6:f1c3ea8bc850 121
cho45 6:f1c3ea8bc850 122 static void securitySetupInitiatedCallback(Gap::Handle_t, bool allowBonding, bool requireMITM, SecurityManager::SecurityIOCapabilities_t iocaps) {
cho45 42:2c3be8694896 123 DEBUG_PRINTF_BLE_INTERRUPT("Security setup initiated\r\n");
cho45 6:f1c3ea8bc850 124 }
cho45 6:f1c3ea8bc850 125
cho45 6:f1c3ea8bc850 126 static void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) {
cho45 6:f1c3ea8bc850 127 // https://developer.mbed.org/compiler/#nav:/keyboard/BLE_API/ble/blecommon.h;
cho45 6:f1c3ea8bc850 128 ble_error_t error;
cho45 6:f1c3ea8bc850 129 BLE &ble = params->ble;
cho45 23:b31957ce64e9 130
cho45 27:7370b8994603 131 controllerStatus = DISCONNECTED;
cho45 16:345eebc4f259 132
cho45 16:345eebc4f259 133 /**< Minimum Connection Interval in 1.25 ms units, see BLE_GAP_CP_LIMITS.*/
cho45 66:a7c6fbe45cf5 134 uint16_t minConnectionInterval = Gap::MSEC_TO_GAP_DURATION_UNITS(15);
cho45 65:391ce51e37cc 135 /**< Maximum Connection Interval in 1.25 ms units, see BLE_GAP_CP_LIMITS.*/
cho45 66:a7c6fbe45cf5 136 uint16_t maxConnectionInterval = Gap::MSEC_TO_GAP_DURATION_UNITS(20);
cho45 65:391ce51e37cc 137 /**< Slave Latency in number of connection events, see BLE_GAP_CP_LIMITS.*/
cho45 83:2e940d154f8b 138 uint16_t slaveLatency = 50;
cho45 65:391ce51e37cc 139 /**< Connection Supervision Timeout in 10 ms units, see BLE_GAP_CP_LIMITS.*/
cho45 65:391ce51e37cc 140 uint16_t connectionSupervisionTimeout = 32 * 100;
cho45 65:391ce51e37cc 141 Gap::ConnectionParams_t connectionParams = {
cho45 65:391ce51e37cc 142 minConnectionInterval,
cho45 65:391ce51e37cc 143 maxConnectionInterval,
cho45 65:391ce51e37cc 144 slaveLatency,
cho45 65:391ce51e37cc 145 connectionSupervisionTimeout
cho45 65:391ce51e37cc 146 };
cho45 65:391ce51e37cc 147
cho45 6:f1c3ea8bc850 148 error = params->error;
cho45 6:f1c3ea8bc850 149 if (error != BLE_ERROR_NONE) {
cho45 42:2c3be8694896 150 DEBUG_PRINTF_BLE("error on ble.init() \r\n");
cho45 6:f1c3ea8bc850 151 goto return_error;
cho45 6:f1c3ea8bc850 152 }
cho45 6:f1c3ea8bc850 153
cho45 6:f1c3ea8bc850 154 ble.gap().onDisconnection(onDisconnect);
cho45 6:f1c3ea8bc850 155 ble.gap().onConnection(onConnect);
cho45 6:f1c3ea8bc850 156 ble.gap().onTimeout(onTimeout);
cho45 6:f1c3ea8bc850 157
cho45 42:2c3be8694896 158 // DEBUG_PRINTF_BLE("setup ble security manager\r\n");
cho45 6:f1c3ea8bc850 159 ble.securityManager().onSecuritySetupInitiated(securitySetupInitiatedCallback);
cho45 6:f1c3ea8bc850 160 ble.securityManager().onPasskeyDisplay(passkeyDisplayCallback);
cho45 6:f1c3ea8bc850 161 ble.securityManager().onSecuritySetupCompleted(securitySetupCompletedCallback);
cho45 6:f1c3ea8bc850 162 // bonding with hard-coded passkey.
cho45 57:ae521136842c 163 error = ble.securityManager().init(ENABLE_BONDING, REQUIRE_MITM, SecurityManager::IO_CAPS_DISPLAY_ONLY, PASSKEY);
cho45 6:f1c3ea8bc850 164 if (error != BLE_ERROR_NONE) {
cho45 42:2c3be8694896 165 DEBUG_PRINTF_BLE("error on ble.securityManager().init()");
cho45 6:f1c3ea8bc850 166 goto return_error;
cho45 6:f1c3ea8bc850 167 }
cho45 16:345eebc4f259 168
cho45 42:2c3be8694896 169 // DEBUG_PRINTF_BLE("new KeyboardService\r\n");
cho45 6:f1c3ea8bc850 170 keyboardService = new KeyboardService(ble);
cho45 79:0095bfb18c57 171 keyboardService->init();
cho45 79:0095bfb18c57 172 DEBUG_PRINTF_BLE("new DeviceInformationService\r\n");
cho45 75:351d7ffe81d1 173 deviceInformationService = new DeviceInformationService(ble, MANUFACTURERERS_NAME, MODEL_NAME, SERIAL_NUMBER, HARDWARE_REVISION, FIRMWARE_REVISION, SOFTWARE_REVISION, &PNP_ID);
cho45 79:0095bfb18c57 174 DEBUG_PRINTF_BLE("new BatteryService\r\n");
cho45 6:f1c3ea8bc850 175 batteryService = new BatteryService(ble, 100);
cho45 85:e526a89a0674 176 DEBUG_PRINTF_BLE("new ScanParametersService\r\n");
cho45 85:e526a89a0674 177 scanParametersService = new ScanParametersService(ble);
cho45 37:4ce71fa47fc3 178 /** TODO
cho45 42:2c3be8694896 179 DEBUG_PRINTF_BLE("new DFUService\r\n");
cho45 16:345eebc4f259 180 dfuService = new DFUService(ble);
cho45 16:345eebc4f259 181 */
cho45 16:345eebc4f259 182
cho45 42:2c3be8694896 183 //DEBUG_PRINTF_BLE("setup connection params\r\n");
cho45 16:345eebc4f259 184
cho45 65:391ce51e37cc 185 ble.gap().setPreferredConnectionParams(&connectionParams);
cho45 6:f1c3ea8bc850 186
cho45 42:2c3be8694896 187 // DEBUG_PRINTF_BLE("general setup\r\n");
cho45 65:391ce51e37cc 188 // error = ble.gap().accumulateAdvertisingPayload(
cho45 65:391ce51e37cc 189 // GapAdvertisingData::BREDR_NOT_SUPPORTED |
cho45 65:391ce51e37cc 190 // GapAdvertisingData::LE_GENERAL_DISCOVERABLE
cho45 65:391ce51e37cc 191 // );
cho45 65:391ce51e37cc 192 // shoud be LE_LIMITED_DISCOVERABLE
cho45 6:f1c3ea8bc850 193 error = ble.gap().accumulateAdvertisingPayload(
cho45 6:f1c3ea8bc850 194 GapAdvertisingData::BREDR_NOT_SUPPORTED |
cho45 65:391ce51e37cc 195 GapAdvertisingData::LE_LIMITED_DISCOVERABLE
cho45 6:f1c3ea8bc850 196 );
cho45 6:f1c3ea8bc850 197 if (error != BLE_ERROR_NONE) goto return_error;
cho45 6:f1c3ea8bc850 198
cho45 42:2c3be8694896 199 // DEBUG_PRINTF_BLE("set COMPLETE_LIST_16BIT_SERVICE_IDS\r\n");
cho45 6:f1c3ea8bc850 200 error = ble.gap().accumulateAdvertisingPayload(
cho45 6:f1c3ea8bc850 201 GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS,
cho45 6:f1c3ea8bc850 202 (uint8_t*)uuid16_list, sizeof(uuid16_list)
cho45 6:f1c3ea8bc850 203 );
cho45 6:f1c3ea8bc850 204 if (error != BLE_ERROR_NONE) goto return_error;
cho45 6:f1c3ea8bc850 205
cho45 42:2c3be8694896 206 // DEBUG_PRINTF_BLE("set advertising\r\n");
cho45 6:f1c3ea8bc850 207 // see 5.1.2: HID over GATT Specification (pg. 25)
cho45 6:f1c3ea8bc850 208 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
cho45 6:f1c3ea8bc850 209
cho45 42:2c3be8694896 210 // DEBUG_PRINTF_BLE("set advertising interval\r\n");
cho45 28:1f843a3daab0 211 ble.gap().setAdvertisingInterval(20);
cho45 42:2c3be8694896 212 // DEBUG_PRINTF_BLE("set advertising timeout\r\n");
cho45 38:115875b8cb6c 213 ble.gap().setAdvertisingTimeout(30);
cho45 28:1f843a3daab0 214
cho45 28:1f843a3daab0 215 /*
cho45 28:1f843a3daab0 216 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED);
cho45 28:1f843a3daab0 217 ble.gap().setAdvertisingTimeout(1.28);
cho45 28:1f843a3daab0 218 */
cho45 6:f1c3ea8bc850 219
cho45 42:2c3be8694896 220 // DEBUG_PRINTF_BLE("set keyboard\r\n");
cho45 6:f1c3ea8bc850 221 error = ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::KEYBOARD);
cho45 6:f1c3ea8bc850 222 if (error != BLE_ERROR_NONE) goto return_error;
cho45 6:f1c3ea8bc850 223
cho45 42:2c3be8694896 224 // DEBUG_PRINTF_BLE("set complete local name\r\n");
cho45 6:f1c3ea8bc850 225 error = ble.gap().accumulateAdvertisingPayload(
cho45 6:f1c3ea8bc850 226 GapAdvertisingData::COMPLETE_LOCAL_NAME,
cho45 6:f1c3ea8bc850 227 DEVICE_NAME, sizeof(DEVICE_NAME)
cho45 6:f1c3ea8bc850 228 );
cho45 6:f1c3ea8bc850 229 if (error != BLE_ERROR_NONE) goto return_error;
cho45 6:f1c3ea8bc850 230
cho45 42:2c3be8694896 231 // DEBUG_PRINTF_BLE("set device name\r\n");
cho45 6:f1c3ea8bc850 232 error = ble.gap().setDeviceName(DEVICE_NAME);
cho45 6:f1c3ea8bc850 233 if (error != BLE_ERROR_NONE) goto return_error;
cho45 22:a78f0a91280a 234 /* (Valid values are -40, -20, -16, -12, -8, -4, 0, 4) */
cho45 19:cd7f2fe05ae4 235 ble.gap().setTxPower(0);
cho45 6:f1c3ea8bc850 236
cho45 73:d36e0b817ebf 237 {
cho45 73:d36e0b817ebf 238 BLEProtocol::Address_t peerAddresses[2];
cho45 73:d36e0b817ebf 239 Gap::Whitelist_t whitelist;
cho45 73:d36e0b817ebf 240 whitelist.size = 0;
cho45 73:d36e0b817ebf 241 whitelist.capacity = 2;
cho45 73:d36e0b817ebf 242 whitelist.addresses = peerAddresses;
cho45 73:d36e0b817ebf 243 error = ble.securityManager().getAddressesFromBondTable(whitelist);
cho45 73:d36e0b817ebf 244 DEBUG_PRINTF_BLE("getAddressesFromBondTable %d\r\n", whitelist.size);
cho45 73:d36e0b817ebf 245 BLE::Instance(BLE::DEFAULT_INSTANCE).gap().setWhitelist(whitelist);
cho45 73:d36e0b817ebf 246 // for (int i = 0; i < whitelist.size; i++) {
cho45 73:d36e0b817ebf 247 // whitelist.addresses[i]
cho45 73:d36e0b817ebf 248 // }
cho45 73:d36e0b817ebf 249 }
cho45 73:d36e0b817ebf 250
cho45 32:6c0f43fda460 251 ble.gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST);
cho45 84:b917922bb5f1 252 ble.gap().setScanningPolicyMode(Gap::SCAN_POLICY_FILTER_ALL_ADV);
cho45 84:b917922bb5f1 253 ble.gap().setInitiatorPolicyMode(Gap::INIT_POLICY_FILTER_ALL_ADV);
cho45 23:b31957ce64e9 254
cho45 42:2c3be8694896 255 // DEBUG_PRINTF_BLE("advertising\r\n");
cho45 6:f1c3ea8bc850 256 error = ble.gap().startAdvertising();
cho45 6:f1c3ea8bc850 257 if (error != BLE_ERROR_NONE) goto return_error;
cho45 32:6c0f43fda460 258 controllerStatus = ADVERTISING;
cho45 6:f1c3ea8bc850 259 return;
cho45 6:f1c3ea8bc850 260
cho45 6:f1c3ea8bc850 261 return_error:
cho45 42:2c3be8694896 262 DEBUG_PRINTF_BLE("error with %d\r\n", error);
cho45 6:f1c3ea8bc850 263 return;
cho45 6:f1c3ea8bc850 264 }
cho45 6:f1c3ea8bc850 265
cho45 20:d8840ac38434 266 bool HIDController::connected() {
cho45 27:7370b8994603 267 return controllerStatus == CONNECTED;
cho45 27:7370b8994603 268 }
cho45 27:7370b8994603 269
cho45 27:7370b8994603 270 Status_t HIDController::status() {
cho45 27:7370b8994603 271 return controllerStatus;
cho45 20:d8840ac38434 272 }
cho45 20:d8840ac38434 273
cho45 32:6c0f43fda460 274 const char* HIDController::statusString() {
cho45 59:2d6c0bff2151 275 static const char* const disconnected = "disconnected";
cho45 59:2d6c0bff2151 276 static const char* const connecting = "connecting";
cho45 59:2d6c0bff2151 277 static const char* const connected = "connected";
cho45 59:2d6c0bff2151 278 static const char* const timeout = "timeout";
cho45 59:2d6c0bff2151 279 static const char* const advertising = "advertising";
cho45 59:2d6c0bff2151 280 static const char* const unknown = "unknown";
cho45 32:6c0f43fda460 281
cho45 32:6c0f43fda460 282 return controllerStatus == DISCONNECTED ? disconnected:
cho45 32:6c0f43fda460 283 controllerStatus == CONNECTING ? connecting:
cho45 32:6c0f43fda460 284 controllerStatus == CONNECTED ? connected:
cho45 32:6c0f43fda460 285 controllerStatus == TIMEOUT ? timeout:
cho45 32:6c0f43fda460 286 controllerStatus == ADVERTISING ? advertising:
cho45 32:6c0f43fda460 287 unknown;
cho45 32:6c0f43fda460 288 }
cho45 32:6c0f43fda460 289
cho45 6:f1c3ea8bc850 290 void HIDController::init() {
cho45 6:f1c3ea8bc850 291 // https://github.com/jpbrucker/BLE_HID/blob/master/examples/examples_common.cpp
cho45 42:2c3be8694896 292 DEBUG_PRINTF_BLE("ble.init\r\n");
cho45 6:f1c3ea8bc850 293
cho45 6:f1c3ea8bc850 294 BLE& ble = BLE::Instance(BLE::DEFAULT_INSTANCE);
cho45 6:f1c3ea8bc850 295 ble.init(bleInitComplete);
cho45 46:b8f4c050739a 296
cho45 46:b8f4c050739a 297 // copied from https://github.com/lancaster-university/microbit-dal/commit/3c314794f07e5ac91331c9e9849475375708ec89
cho45 46:b8f4c050739a 298 // configure the stack to hold on to CPU during critical timing events.
cho45 46:b8f4c050739a 299 // mbed-classic performs __disabe_irq calls in its timers, which can cause MIC failures
cho45 46:b8f4c050739a 300 // on secure BLE channels.
cho45 65:391ce51e37cc 301 ble_common_opt_radio_cpu_mutex_t opt;
cho45 65:391ce51e37cc 302 opt.enable = 1;
cho45 65:391ce51e37cc 303 sd_ble_opt_set(BLE_COMMON_OPT_RADIO_CPU_MUTEX, (const ble_opt_t *)&opt);
cho45 46:b8f4c050739a 304
cho45 6:f1c3ea8bc850 305 while (!ble.hasInitialized()) { }
cho45 42:2c3be8694896 306 DEBUG_PRINTF_BLE("ble.hasIntialized\r\n");
cho45 6:f1c3ea8bc850 307 }
cho45 6:f1c3ea8bc850 308
cho45 22:a78f0a91280a 309
cho45 10:1aed2481a743 310 void HIDController::waitForEvent() {
cho45 6:f1c3ea8bc850 311 BLE& ble = BLE::Instance(BLE::DEFAULT_INSTANCE);
cho45 68:13e2343452d5 312
cho45 69:9d6ecd584a0c 313 WatchDog::reload();
cho45 69:9d6ecd584a0c 314
cho45 45:f4be69c936f6 315 keyboardService->processSend();
cho45 58:64df960619ce 316 if (DEBUG_BLE_INTERRUPT) {
cho45 58:64df960619ce 317 ble.waitForEvent();
cho45 58:64df960619ce 318 } else {
cho45 58:64df960619ce 319 // disable internal HFCLK RC Clock surely. It consume 1mA constantly
cho45 58:64df960619ce 320 // TWI / SPI / UART must be disabled and boot without debug mode
cho45 58:64df960619ce 321 while (NRF_UART0->EVENTS_TXDRDY != 1);
cho45 58:64df960619ce 322
cho45 58:64df960619ce 323 const uint32_t tx = NRF_UART0->PSELTXD;
cho45 58:64df960619ce 324
cho45 58:64df960619ce 325 NRF_UART0->TASKS_STOPTX = 1;
cho45 58:64df960619ce 326 NRF_UART0->ENABLE = (UART_ENABLE_ENABLE_Disabled << UART_ENABLE_ENABLE_Pos);
cho45 58:64df960619ce 327
cho45 58:64df960619ce 328 ble.waitForEvent();
cho45 58:64df960619ce 329
cho45 58:64df960619ce 330 NRF_UART0->ENABLE = (UART_ENABLE_ENABLE_Enabled << UART_ENABLE_ENABLE_Pos);
cho45 58:64df960619ce 331 NRF_UART0->TASKS_STARTTX = 1;
cho45 58:64df960619ce 332 // dummy send to wakeup...
cho45 58:64df960619ce 333 NRF_UART0->PSELTXD = 0xFFFFFFFF;
cho45 58:64df960619ce 334 NRF_UART0->EVENTS_TXDRDY = 0;
cho45 58:64df960619ce 335 NRF_UART0->TXD = 0;
cho45 58:64df960619ce 336 while (NRF_UART0->EVENTS_TXDRDY != 1);
cho45 58:64df960619ce 337 NRF_UART0->PSELTXD = tx;
cho45 58:64df960619ce 338 }
cho45 6:f1c3ea8bc850 339 }
cho45 6:f1c3ea8bc850 340
cho45 48:d6938de02f62 341 void HIDController::appendReportData(const uint8_t key) {
cho45 6:f1c3ea8bc850 342 if (keyboardService) {
cho45 6:f1c3ea8bc850 343 keyboardService->appendReportData(key);
cho45 6:f1c3ea8bc850 344 }
cho45 6:f1c3ea8bc850 345 }
cho45 6:f1c3ea8bc850 346
cho45 48:d6938de02f62 347 void HIDController::deleteReportData(const uint8_t key) {
cho45 6:f1c3ea8bc850 348 if (keyboardService) {
cho45 6:f1c3ea8bc850 349 keyboardService->deleteReportData(key);
cho45 6:f1c3ea8bc850 350 }
cho45 6:f1c3ea8bc850 351 }
cho45 9:d1daefbf1fbd 352
cho45 86:e0fab77e669d 353 void HIDController::pressConsumerKey(const uint16_t key) {
cho45 86:e0fab77e669d 354 if (keyboardService) {
cho45 86:e0fab77e669d 355 keyboardService->pressConsumerKey(key);
cho45 86:e0fab77e669d 356 }
cho45 86:e0fab77e669d 357 }
cho45 86:e0fab77e669d 358
cho45 86:e0fab77e669d 359 void HIDController::releaseConsumerKey() {
cho45 86:e0fab77e669d 360 if (keyboardService) {
cho45 86:e0fab77e669d 361 keyboardService->releaseConsumerKey();
cho45 86:e0fab77e669d 362 }
cho45 86:e0fab77e669d 363 }
cho45 86:e0fab77e669d 364
cho45 9:d1daefbf1fbd 365 void HIDController::queueCurrentReportData() {
cho45 29:ec548c473d50 366 if (!connected()) return;
cho45 9:d1daefbf1fbd 367 if (keyboardService) {
cho45 9:d1daefbf1fbd 368 keyboardService->queueCurrentReportData();
cho45 9:d1daefbf1fbd 369 }
cho45 9:d1daefbf1fbd 370 }
cho45 37:4ce71fa47fc3 371
cho45 58:64df960619ce 372 void HIDController::updateBatteryLevel(const uint8_t percentage, const uint16_t voltage) {
cho45 37:4ce71fa47fc3 373 if (!batteryService) return;
cho45 68:13e2343452d5 374 DEBUG_PRINTF_BLE("updateBatteryLevel\r\n");
cho45 58:64df960619ce 375 batteryService->updateBatteryLevel(percentage, voltage);
cho45 37:4ce71fa47fc3 376 }
cho45 37:4ce71fa47fc3 377
cho45 48:d6938de02f62 378 void HIDController::initializeConnection(const bool ignoreWhiteList = false) {
cho45 38:115875b8cb6c 379 ble_error_t error;
cho45 76:8c5b07462dad 380
cho45 76:8c5b07462dad 381 DEBUG_PRINTF_BLE("initializeConnection(%d)\r\n", ignoreWhiteList);
cho45 76:8c5b07462dad 382
cho45 38:115875b8cb6c 383 BLE& ble = BLE::Instance(BLE::DEFAULT_INSTANCE);
cho45 39:b7889285c9ef 384 ble.gap().setAdvertisingInterval(20);
cho45 39:b7889285c9ef 385 ble.gap().setAdvertisingTimeout(30);
cho45 40:364deaa190fe 386 if (ignoreWhiteList) {
cho45 40:364deaa190fe 387 ble.gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST);
cho45 76:8c5b07462dad 388 } else {
cho45 76:8c5b07462dad 389 // XXX : startAdvertising returns BLE_ERROR_PARAM_OUT_OF_RANGE
cho45 76:8c5b07462dad 390 // ble.gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_FILTER_ALL_REQS);
cho45 76:8c5b07462dad 391 ble.gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST);
cho45 40:364deaa190fe 392 }
cho45 38:115875b8cb6c 393
cho45 42:2c3be8694896 394 // DEBUG_PRINTF_BLE("advertising\r\n");
cho45 38:115875b8cb6c 395 error = ble.gap().startAdvertising();
cho45 38:115875b8cb6c 396 if (error != BLE_ERROR_NONE) goto return_error;
cho45 38:115875b8cb6c 397 controllerStatus = ADVERTISING;
cho45 38:115875b8cb6c 398 return;
cho45 38:115875b8cb6c 399
cho45 38:115875b8cb6c 400 return_error:
cho45 42:2c3be8694896 401 DEBUG_PRINTF_BLE("error with %d\r\n", error);
cho45 38:115875b8cb6c 402 return;
cho45 65:391ce51e37cc 403 }