ble nano hid over gatt
Dependencies: BLE_API mbed-dev nRF51822
HIDController_BLE.cpp
00001 #include "mbed.h" 00002 #include "BLE.h" 00003 00004 #include "config.h" 00005 #include "WatchDog.h" 00006 #include "KeyboardService.h" 00007 #include "BatteryService.h" 00008 #include "DeviceInformationService.h" 00009 #include "ScanParametersService.h" 00010 #include "DFUService.h" 00011 #include "HIDController_BLE.h" 00012 00013 static const char MANUFACTURERERS_NAME[] = "lowreal.net"; 00014 static const char MODEL_NAME[] = "keble"; 00015 static const char SERIAL_NUMBER[] = "X00000"; 00016 static const char HARDWARE_REVISION[] = "0.1"; 00017 static const char FIRMWARE_REVISION[] = "0.1"; 00018 static const char SOFTWARE_REVISION[] = "0.0"; 00019 static PnPID_t PNP_ID = { 00020 0x01, // From Bluetooth SIG 00021 0xFFFE, 00022 0x0001, 00023 0x01, 00024 }; 00025 00026 static const uint8_t DEVICE_NAME[] = "Keble"; 00027 00028 static const bool ENABLE_BONDING = true; 00029 static const bool REQUIRE_MITM = true; 00030 static const uint8_t PASSKEY[6] = {'1','2','3','4','5','6'}; // must be 6-digits number 00031 00032 static const uint16_t uuid16_list[] = { 00033 GattService::UUID_HUMAN_INTERFACE_DEVICE_SERVICE 00034 }; 00035 00036 static KeyboardService* keyboardService; 00037 static BatteryService* batteryService; 00038 static DeviceInformationService* deviceInformationService; 00039 static ScanParametersService* scanParametersService; 00040 // static DFUService* dfuService; 00041 00042 00043 static BLEProtocol::Address_t peerAddress; 00044 00045 static volatile Status_t controllerStatus; 00046 00047 static void onConnect(const Gap::ConnectionCallbackParams_t *params) { 00048 peerAddress.type = params->peerAddrType; 00049 memcpy(peerAddress.address, params->peerAddr, Gap::ADDR_LEN); 00050 00051 BLEProtocol::Address_t peerAddresses[2]; 00052 Gap::Whitelist_t whitelist; 00053 whitelist.size = 0; 00054 whitelist.capacity = 2; 00055 whitelist.addresses = peerAddresses; 00056 BLE::Instance(BLE::DEFAULT_INSTANCE).gap().getWhitelist(whitelist); 00057 DEBUG_PRINTF_BLE_INTERRUPT("getWhitelist %d\r\n", whitelist.size); 00058 for (int i = 0; i < whitelist.size; i++) { 00059 if (whitelist.addresses[i].type == params->peerAddrType && 00060 memcmp(whitelist.addresses[i].address, params->peerAddr, Gap::ADDR_LEN) == 0) { 00061 00062 BLE::Instance(BLE::DEFAULT_INSTANCE).gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_FILTER_ALL_REQS); 00063 controllerStatus = CONNECTED; 00064 DEBUG_PRINTF_BLE_INTERRUPT("peer is found in whitelist\r\n"); 00065 return; 00066 } 00067 } 00068 00069 controllerStatus = CONNECTING; 00070 DEBUG_PRINTF_BLE_INTERRUPT("peer is not found in whitelist\r\n"); 00071 } 00072 00073 static void onDisconnect(const Gap::DisconnectionCallbackParams_t *params) { 00074 controllerStatus = DISCONNECTED; 00075 DEBUG_PRINTF_BLE_INTERRUPT("onDisconnect\r\n"); 00076 } 00077 00078 static void onTimeout(const Gap::TimeoutSource_t source) { 00079 DEBUG_PRINTF_BLE_INTERRUPT("onTimeout %d\r\n", source); 00080 switch (source) { 00081 case Gap::TIMEOUT_SRC_ADVERTISING: 00082 controllerStatus = TIMEOUT; 00083 return; 00084 00085 // treat following timeout as DISCONNECT (retry advertising) 00086 case Gap::TIMEOUT_SRC_SECURITY_REQUEST: 00087 case Gap::TIMEOUT_SRC_SCAN: 00088 case Gap::TIMEOUT_SRC_CONN: 00089 controllerStatus = DISCONNECTED; 00090 return; 00091 } 00092 } 00093 00094 static void passkeyDisplayCallback(Gap::Handle_t handle, const SecurityManager::Passkey_t passkey) { 00095 DEBUG_PRINTF_BLE_INTERRUPT("Input passKey: "); 00096 for (unsigned i = 0; i < Gap::ADDR_LEN; i++) { 00097 DEBUG_PRINTF_BLE_INTERRUPT("%c", passkey[i]); 00098 } 00099 DEBUG_PRINTF_BLE_INTERRUPT("\r\n"); 00100 } 00101 00102 static void securitySetupCompletedCallback(Gap::Handle_t handle, SecurityManager::SecurityCompletionStatus_t status) { 00103 if (status == SecurityManager::SEC_STATUS_SUCCESS) { 00104 DEBUG_PRINTF_BLE_INTERRUPT("Security success %d\r\n", status); 00105 DEBUG_PRINTF_BLE_INTERRUPT("Set whitelist\r\n"); 00106 Gap::Whitelist_t whitelist; 00107 whitelist.size = 1; 00108 whitelist.capacity = 1; 00109 whitelist.addresses = &peerAddress; 00110 00111 BLE::Instance(BLE::DEFAULT_INSTANCE).gap().setWhitelist(whitelist); 00112 DEBUG_PRINTF_BLE_INTERRUPT("Set Advertising Policy Mode\r\n"); 00113 // BLE::Instance(BLE::DEFAULT_INSTANCE).gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_FILTER_SCAN_REQS); 00114 // BLE::Instance(BLE::DEFAULT_INSTANCE).gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_FILTER_CONN_REQS); 00115 BLE::Instance(BLE::DEFAULT_INSTANCE).gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_FILTER_ALL_REQS); 00116 controllerStatus = CONNECTED; 00117 } else { 00118 DEBUG_PRINTF_BLE_INTERRUPT("Security failed %d\r\n", status); 00119 } 00120 } 00121 00122 static void securitySetupInitiatedCallback(Gap::Handle_t, bool allowBonding, bool requireMITM, SecurityManager::SecurityIOCapabilities_t iocaps) { 00123 DEBUG_PRINTF_BLE_INTERRUPT("Security setup initiated\r\n"); 00124 } 00125 00126 static void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) { 00127 // https://developer.mbed.org/compiler/#nav:/keyboard/BLE_API/ble/blecommon.h; 00128 ble_error_t error; 00129 BLE &ble = params->ble; 00130 00131 controllerStatus = DISCONNECTED; 00132 00133 /**< Minimum Connection Interval in 1.25 ms units, see BLE_GAP_CP_LIMITS.*/ 00134 uint16_t minConnectionInterval = Gap::MSEC_TO_GAP_DURATION_UNITS(15); 00135 /**< Maximum Connection Interval in 1.25 ms units, see BLE_GAP_CP_LIMITS.*/ 00136 uint16_t maxConnectionInterval = Gap::MSEC_TO_GAP_DURATION_UNITS(20); 00137 /**< Slave Latency in number of connection events, see BLE_GAP_CP_LIMITS.*/ 00138 uint16_t slaveLatency = 50; 00139 /**< Connection Supervision Timeout in 10 ms units, see BLE_GAP_CP_LIMITS.*/ 00140 uint16_t connectionSupervisionTimeout = 32 * 100; 00141 Gap::ConnectionParams_t connectionParams = { 00142 minConnectionInterval, 00143 maxConnectionInterval, 00144 slaveLatency, 00145 connectionSupervisionTimeout 00146 }; 00147 00148 error = params->error; 00149 if (error != BLE_ERROR_NONE) { 00150 DEBUG_PRINTF_BLE("error on ble.init() \r\n"); 00151 goto return_error; 00152 } 00153 00154 ble.gap().onDisconnection(onDisconnect); 00155 ble.gap().onConnection(onConnect); 00156 ble.gap().onTimeout(onTimeout); 00157 00158 // DEBUG_PRINTF_BLE("setup ble security manager\r\n"); 00159 ble.securityManager().onSecuritySetupInitiated(securitySetupInitiatedCallback); 00160 ble.securityManager().onPasskeyDisplay(passkeyDisplayCallback); 00161 ble.securityManager().onSecuritySetupCompleted(securitySetupCompletedCallback); 00162 // bonding with hard-coded passkey. 00163 error = ble.securityManager().init(ENABLE_BONDING, REQUIRE_MITM, SecurityManager::IO_CAPS_DISPLAY_ONLY, PASSKEY); 00164 if (error != BLE_ERROR_NONE) { 00165 DEBUG_PRINTF_BLE("error on ble.securityManager().init()"); 00166 goto return_error; 00167 } 00168 00169 // DEBUG_PRINTF_BLE("new KeyboardService\r\n"); 00170 keyboardService = new KeyboardService(ble); 00171 keyboardService->init(); 00172 DEBUG_PRINTF_BLE("new DeviceInformationService\r\n"); 00173 deviceInformationService = new DeviceInformationService(ble, MANUFACTURERERS_NAME, MODEL_NAME, SERIAL_NUMBER, HARDWARE_REVISION, FIRMWARE_REVISION, SOFTWARE_REVISION, &PNP_ID); 00174 DEBUG_PRINTF_BLE("new BatteryService\r\n"); 00175 batteryService = new BatteryService(ble, 100); 00176 DEBUG_PRINTF_BLE("new ScanParametersService\r\n"); 00177 scanParametersService = new ScanParametersService(ble); 00178 /** TODO 00179 DEBUG_PRINTF_BLE("new DFUService\r\n"); 00180 dfuService = new DFUService(ble); 00181 */ 00182 00183 //DEBUG_PRINTF_BLE("setup connection params\r\n"); 00184 00185 ble.gap().setPreferredConnectionParams(&connectionParams); 00186 00187 // DEBUG_PRINTF_BLE("general setup\r\n"); 00188 // error = ble.gap().accumulateAdvertisingPayload( 00189 // GapAdvertisingData::BREDR_NOT_SUPPORTED | 00190 // GapAdvertisingData::LE_GENERAL_DISCOVERABLE 00191 // ); 00192 // shoud be LE_LIMITED_DISCOVERABLE 00193 error = ble.gap().accumulateAdvertisingPayload( 00194 GapAdvertisingData::BREDR_NOT_SUPPORTED | 00195 GapAdvertisingData::LE_LIMITED_DISCOVERABLE 00196 ); 00197 if (error != BLE_ERROR_NONE) goto return_error; 00198 00199 // DEBUG_PRINTF_BLE("set COMPLETE_LIST_16BIT_SERVICE_IDS\r\n"); 00200 error = ble.gap().accumulateAdvertisingPayload( 00201 GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, 00202 (uint8_t*)uuid16_list, sizeof(uuid16_list) 00203 ); 00204 if (error != BLE_ERROR_NONE) goto return_error; 00205 00206 // DEBUG_PRINTF_BLE("set advertising\r\n"); 00207 // see 5.1.2: HID over GATT Specification (pg. 25) 00208 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); 00209 00210 // DEBUG_PRINTF_BLE("set advertising interval\r\n"); 00211 ble.gap().setAdvertisingInterval(20); 00212 // DEBUG_PRINTF_BLE("set advertising timeout\r\n"); 00213 ble.gap().setAdvertisingTimeout(30); 00214 00215 /* 00216 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED); 00217 ble.gap().setAdvertisingTimeout(1.28); 00218 */ 00219 00220 // DEBUG_PRINTF_BLE("set keyboard\r\n"); 00221 error = ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::KEYBOARD); 00222 if (error != BLE_ERROR_NONE) goto return_error; 00223 00224 // DEBUG_PRINTF_BLE("set complete local name\r\n"); 00225 error = ble.gap().accumulateAdvertisingPayload( 00226 GapAdvertisingData::COMPLETE_LOCAL_NAME, 00227 DEVICE_NAME, sizeof(DEVICE_NAME) 00228 ); 00229 if (error != BLE_ERROR_NONE) goto return_error; 00230 00231 // DEBUG_PRINTF_BLE("set device name\r\n"); 00232 error = ble.gap().setDeviceName(DEVICE_NAME); 00233 if (error != BLE_ERROR_NONE) goto return_error; 00234 /* (Valid values are -40, -20, -16, -12, -8, -4, 0, 4) */ 00235 ble.gap().setTxPower(0); 00236 00237 { 00238 BLEProtocol::Address_t peerAddresses[2]; 00239 Gap::Whitelist_t whitelist; 00240 whitelist.size = 0; 00241 whitelist.capacity = 2; 00242 whitelist.addresses = peerAddresses; 00243 error = ble.securityManager().getAddressesFromBondTable(whitelist); 00244 DEBUG_PRINTF_BLE("getAddressesFromBondTable %d\r\n", whitelist.size); 00245 BLE::Instance(BLE::DEFAULT_INSTANCE).gap().setWhitelist(whitelist); 00246 // for (int i = 0; i < whitelist.size; i++) { 00247 // whitelist.addresses[i] 00248 // } 00249 } 00250 00251 ble.gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST); 00252 ble.gap().setScanningPolicyMode(Gap::SCAN_POLICY_FILTER_ALL_ADV); 00253 ble.gap().setInitiatorPolicyMode(Gap::INIT_POLICY_FILTER_ALL_ADV); 00254 00255 // DEBUG_PRINTF_BLE("advertising\r\n"); 00256 error = ble.gap().startAdvertising(); 00257 if (error != BLE_ERROR_NONE) goto return_error; 00258 controllerStatus = ADVERTISING; 00259 return; 00260 00261 return_error: 00262 DEBUG_PRINTF_BLE("error with %d\r\n", error); 00263 return; 00264 } 00265 00266 bool HIDController::connected() { 00267 return controllerStatus == CONNECTED; 00268 } 00269 00270 Status_t HIDController::status() { 00271 return controllerStatus; 00272 } 00273 00274 const char* HIDController::statusString() { 00275 static const char* const disconnected = "disconnected"; 00276 static const char* const connecting = "connecting"; 00277 static const char* const connected = "connected"; 00278 static const char* const timeout = "timeout"; 00279 static const char* const advertising = "advertising"; 00280 static const char* const unknown = "unknown"; 00281 00282 return controllerStatus == DISCONNECTED ? disconnected: 00283 controllerStatus == CONNECTING ? connecting: 00284 controllerStatus == CONNECTED ? connected: 00285 controllerStatus == TIMEOUT ? timeout: 00286 controllerStatus == ADVERTISING ? advertising: 00287 unknown; 00288 } 00289 00290 void HIDController::init() { 00291 // https://github.com/jpbrucker/BLE_HID/blob/master/examples/examples_common.cpp 00292 DEBUG_PRINTF_BLE("ble.init\r\n"); 00293 00294 BLE& ble = BLE::Instance(BLE::DEFAULT_INSTANCE); 00295 ble.init(bleInitComplete); 00296 00297 // copied from https://github.com/lancaster-university/microbit-dal/commit/3c314794f07e5ac91331c9e9849475375708ec89 00298 // configure the stack to hold on to CPU during critical timing events. 00299 // mbed-classic performs __disabe_irq calls in its timers, which can cause MIC failures 00300 // on secure BLE channels. 00301 ble_common_opt_radio_cpu_mutex_t opt; 00302 opt.enable = 1; 00303 sd_ble_opt_set(BLE_COMMON_OPT_RADIO_CPU_MUTEX, (const ble_opt_t *)&opt); 00304 00305 while (!ble.hasInitialized()) { } 00306 DEBUG_PRINTF_BLE("ble.hasIntialized\r\n"); 00307 } 00308 00309 00310 void HIDController::waitForEvent() { 00311 BLE& ble = BLE::Instance(BLE::DEFAULT_INSTANCE); 00312 00313 WatchDog::reload(); 00314 00315 keyboardService->processSend(); 00316 if (DEBUG_BLE_INTERRUPT) { 00317 ble.waitForEvent(); 00318 } else { 00319 // disable internal HFCLK RC Clock surely. It consume 1mA constantly 00320 // TWI / SPI / UART must be disabled and boot without debug mode 00321 while (NRF_UART0->EVENTS_TXDRDY != 1); 00322 00323 const uint32_t tx = NRF_UART0->PSELTXD; 00324 00325 NRF_UART0->TASKS_STOPTX = 1; 00326 NRF_UART0->ENABLE = (UART_ENABLE_ENABLE_Disabled << UART_ENABLE_ENABLE_Pos); 00327 00328 ble.waitForEvent(); 00329 00330 NRF_UART0->ENABLE = (UART_ENABLE_ENABLE_Enabled << UART_ENABLE_ENABLE_Pos); 00331 NRF_UART0->TASKS_STARTTX = 1; 00332 // dummy send to wakeup... 00333 NRF_UART0->PSELTXD = 0xFFFFFFFF; 00334 NRF_UART0->EVENTS_TXDRDY = 0; 00335 NRF_UART0->TXD = 0; 00336 while (NRF_UART0->EVENTS_TXDRDY != 1); 00337 NRF_UART0->PSELTXD = tx; 00338 } 00339 } 00340 00341 void HIDController::appendReportData(const uint8_t key) { 00342 if (keyboardService) { 00343 keyboardService->appendReportData(key); 00344 } 00345 } 00346 00347 void HIDController::deleteReportData(const uint8_t key) { 00348 if (keyboardService) { 00349 keyboardService->deleteReportData(key); 00350 } 00351 } 00352 00353 void HIDController::pressConsumerKey(const uint16_t key) { 00354 if (keyboardService) { 00355 keyboardService->pressConsumerKey(key); 00356 } 00357 } 00358 00359 void HIDController::releaseConsumerKey() { 00360 if (keyboardService) { 00361 keyboardService->releaseConsumerKey(); 00362 } 00363 } 00364 00365 void HIDController::queueCurrentReportData() { 00366 if (!connected()) return; 00367 if (keyboardService) { 00368 keyboardService->queueCurrentReportData(); 00369 } 00370 } 00371 00372 void HIDController::updateBatteryLevel(const uint8_t percentage, const uint16_t voltage) { 00373 if (!batteryService) return; 00374 DEBUG_PRINTF_BLE("updateBatteryLevel\r\n"); 00375 batteryService->updateBatteryLevel(percentage, voltage); 00376 } 00377 00378 void HIDController::initializeConnection(const bool ignoreWhiteList = false) { 00379 ble_error_t error; 00380 00381 DEBUG_PRINTF_BLE("initializeConnection(%d)\r\n", ignoreWhiteList); 00382 00383 BLE& ble = BLE::Instance(BLE::DEFAULT_INSTANCE); 00384 ble.gap().setAdvertisingInterval(20); 00385 ble.gap().setAdvertisingTimeout(30); 00386 if (ignoreWhiteList) { 00387 ble.gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST); 00388 } else { 00389 // XXX : startAdvertising returns BLE_ERROR_PARAM_OUT_OF_RANGE 00390 // ble.gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_FILTER_ALL_REQS); 00391 ble.gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST); 00392 } 00393 00394 // DEBUG_PRINTF_BLE("advertising\r\n"); 00395 error = ble.gap().startAdvertising(); 00396 if (error != BLE_ERROR_NONE) goto return_error; 00397 controllerStatus = ADVERTISING; 00398 return; 00399 00400 return_error: 00401 DEBUG_PRINTF_BLE("error with %d\r\n", error); 00402 return; 00403 }
Generated on Tue Jul 12 2022 14:16:48 by 1.7.2