ble nano hid over gatt
Dependencies: BLE_API mbed-dev nRF51822
HIDController_BLE.cpp
- Committer:
- cho45
- Date:
- 2016-08-22
- Revision:
- 24:a4dbde033def
- Parent:
- 23:b31957ce64e9
- Child:
- 25:094df0d9e95b
File content as of revision 24:a4dbde033def:
#include "mbed.h" #include "BLE.h" #include "KeyboardService.h" #include "BatteryService.h" #include "DeviceInformationService.h" #include "DFUService.h" #include "HIDController_BLE.h" static const char MODEL_NAME[] = "keyboard"; static const char SERIAL_NUMBER[] = "X00000"; static const char HARDWARE_REVISION[] = "0.1"; static const char FIRMWARE_REVISION[] = "0.1"; static const char SOFTWARE_REVISION[] = "0.0"; static const uint8_t DEVICE_NAME[] = "my keyboard"; static const uint8_t SHORT_DEVICE_NAME[] = "kbd1"; static const bool ENABLE_BONDING = true; static const bool REQUIRE_MITM = true; static const uint8_t PASSKEY[6] = {'1','2','3','4','5','6'}; // must be 6-digits number static const uint16_t uuid16_list[] = { GattService::UUID_HUMAN_INTERFACE_DEVICE_SERVICE, GattService::UUID_DEVICE_INFORMATION_SERVICE, GattService::UUID_BATTERY_SERVICE }; static KeyboardService* keyboardService; static BatteryService* batteryService; static DeviceInformationService* deviceInformationService; static DFUService* dfuService; static BLEProtocol::Address_t peerAddress; static volatile bool connected = false; static void updateBatteryLevel() { if (!batteryService) return; static const float BATTERY_MAX = 2.4; static const float REFERNECE = 1.2; static const float PRESCALE = 3; NRF_ADC->ENABLE = ADC_ENABLE_ENABLE_Enabled; // Use internal 1.2V reference for batteryInput // 1/3 pre-scaled input and 1.2V internal band gap reference // ref. mbed-src/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/analogin_api.c NRF_ADC->CONFIG = (ADC_CONFIG_RES_10bit << ADC_CONFIG_RES_Pos) | // Use VDD 1/3 for input (ADC_CONFIG_INPSEL_SupplyOneThirdPrescaling << ADC_CONFIG_INPSEL_Pos) | // Use internal band gap for reference (ADC_CONFIG_REFSEL_VBG << ADC_CONFIG_REFSEL_Pos) | (ADC_CONFIG_EXTREFSEL_None << ADC_CONFIG_EXTREFSEL_Pos); // Start ADC NRF_ADC->TASKS_START = 1; while (((NRF_ADC->BUSY & ADC_BUSY_BUSY_Msk) >> ADC_BUSY_BUSY_Pos) == ADC_BUSY_BUSY_Busy) { // busy loop } // Read ADC result uint16_t raw10bit = static_cast<uint16_t>(NRF_ADC->RESULT); NRF_ADC->ENABLE = ADC_ENABLE_ENABLE_Disabled; float ratio = raw10bit / static_cast<float>(1<<10); float batteryVoltage = ratio * (REFERNECE * PRESCALE); float percentage = (batteryVoltage / BATTERY_MAX) * 100; if (percentage > 100) { percentage = 100; } printf("updateBatteryLevel %f V : %d/100\r\n", batteryVoltage, static_cast<uint8_t>(percentage)); batteryService->updateBatteryLevel(static_cast<uint8_t>(percentage)); } static void onConnect(const Gap::ConnectionCallbackParams_t *params) { /* printf("onConnect: "); for (unsigned i = 0; i < Gap::ADDR_LEN; i++) { printf("%02x", params->peerAddr[i]); } printf("\r\n"); */ peerAddress.type = params->peerAddrType; memcpy(peerAddress.address, params->peerAddr, Gap::ADDR_LEN); } static void onDisconnect(const Gap::DisconnectionCallbackParams_t *params) { printf("onDisconnect\r\n"); connected = false; BLE::Instance(BLE::DEFAULT_INSTANCE).gap().startAdvertising(); } static void onTimeout(const Gap::TimeoutSource_t source) { printf("onTimeout\r\n"); connected = false; BLE::Instance(BLE::DEFAULT_INSTANCE).gap().startAdvertising(); } static void passkeyDisplayCallback(Gap::Handle_t handle, const SecurityManager::Passkey_t passkey) { printf("Input passKey: "); for (unsigned i = 0; i < Gap::ADDR_LEN; i++) { printf("%c", passkey[i]); } printf("\r\n"); } static void securitySetupCompletedCallback(Gap::Handle_t handle, SecurityManager::SecurityCompletionStatus_t status) { if (status == SecurityManager::SEC_STATUS_SUCCESS) { printf("Security success %d\r\n", status); printf("Set whitelist\r\n"); Gap::Whitelist_t whitelist; whitelist.size = 1; whitelist.capacity = 1; whitelist.addresses = &peerAddress; BLE::Instance(BLE::DEFAULT_INSTANCE).gap().setWhitelist(whitelist); printf("Set Advertising Policy Mode\r\n"); // BLE::Instance(BLE::DEFAULT_INSTANCE).gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_FILTER_SCAN_REQS); // BLE::Instance(BLE::DEFAULT_INSTANCE).gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_FILTER_CONN_REQS); BLE::Instance(BLE::DEFAULT_INSTANCE).gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_FILTER_ALL_REQS); connected = true; } else { printf("Security failed %d\r\n", status); } } static void securitySetupInitiatedCallback(Gap::Handle_t, bool allowBonding, bool requireMITM, SecurityManager::SecurityIOCapabilities_t iocaps) { printf("Security setup initiated\r\n"); } static void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) { // https://developer.mbed.org/compiler/#nav:/keyboard/BLE_API/ble/blecommon.h; ble_error_t error; BLE &ble = params->ble; connected = false; /**< Minimum Connection Interval in 1.25 ms units, see BLE_GAP_CP_LIMITS.*/ uint16_t minConnectionInterval = Gap::MSEC_TO_GAP_DURATION_UNITS(24); /**< Maximum Connection Interval in 1.25 ms units, see BLE_GAP_CP_LIMITS.*/ uint16_t maxConnectionInterval = Gap::MSEC_TO_GAP_DURATION_UNITS(44); /**< Slave Latency in number of connection events, see BLE_GAP_CP_LIMITS.*/ uint16_t slaveLatency = 4; /**< Connection Supervision Timeout in 10 ms units, see BLE_GAP_CP_LIMITS.*/ uint16_t connectionSupervisionTimeout = 32 * 100; Gap::ConnectionParams_t connectionParams = { minConnectionInterval, maxConnectionInterval, slaveLatency, connectionSupervisionTimeout }; error = params->error; if (error != BLE_ERROR_NONE) { printf("error on ble.init() \r\n"); goto return_error; } ble.gap().onDisconnection(onDisconnect); ble.gap().onConnection(onConnect); ble.gap().onTimeout(onTimeout); // printf("setup ble security manager\r\n"); ble.securityManager().onSecuritySetupInitiated(securitySetupInitiatedCallback); ble.securityManager().onPasskeyDisplay(passkeyDisplayCallback); ble.securityManager().onSecuritySetupCompleted(securitySetupCompletedCallback); // bonding with hard-coded passkey. error = ble.securityManager().init(ENABLE_BONDING, REQUIRE_MITM, SecurityManager::IO_CAPS_DISPLAY_ONLY, PASSKEY); if (error != BLE_ERROR_NONE) { printf("error on ble.securityManager().init()"); goto return_error; } // printf("new KeyboardService\r\n"); keyboardService = new KeyboardService(ble); // printf("new DeviceInformationService\r\n"); deviceInformationService = new DeviceInformationService(ble, "lowreal.net", MODEL_NAME, SERIAL_NUMBER, HARDWARE_REVISION, FIRMWARE_REVISION, SOFTWARE_REVISION); // printf("new BatteryService\r\n"); batteryService = new BatteryService(ble, 100); /** TODO STUCK with BLE NANO printf("new DFUService\r\n"); dfuService = new DFUService(ble); */ updateBatteryLevel(); //printf("setup connection params\r\n"); ble.gap().setPreferredConnectionParams(&connectionParams); // printf("general setup\r\n"); error = ble.gap().accumulateAdvertisingPayload( GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE ); // shoud be LE_LIMITED_DISCOVERABLE // error = ble.gap().accumulateAdvertisingPayload( // GapAdvertisingData::BREDR_NOT_SUPPORTED | // GapAdvertisingData::LE_LIMITED_DISCOVERABLE // ); if (error != BLE_ERROR_NONE) goto return_error; // printf("set COMPLETE_LIST_16BIT_SERVICE_IDS\r\n"); error = ble.gap().accumulateAdvertisingPayload( GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t*)uuid16_list, sizeof(uuid16_list) ); if (error != BLE_ERROR_NONE) goto return_error; // printf("set advertising\r\n"); // see 5.1.2: HID over GATT Specification (pg. 25) ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); // printf("set advertising interval\r\n"); ble.gap().setAdvertisingInterval(30); // printf("set advertising timeout\r\n"); ble.gap().setAdvertisingTimeout(180); // printf("set keyboard\r\n"); error = ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::KEYBOARD); if (error != BLE_ERROR_NONE) goto return_error; // printf("set complete local name\r\n"); error = ble.gap().accumulateAdvertisingPayload( GapAdvertisingData::COMPLETE_LOCAL_NAME, DEVICE_NAME, sizeof(DEVICE_NAME) ); if (error != BLE_ERROR_NONE) goto return_error; // printf("set device name\r\n"); error = ble.gap().setDeviceName(DEVICE_NAME); if (error != BLE_ERROR_NONE) goto return_error; /* (Valid values are -40, -20, -16, -12, -8, -4, 0, 4) */ ble.gap().setTxPower(0); // ble.gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST); printf("advertising\r\n"); error = ble.gap().startAdvertising(); if (error != BLE_ERROR_NONE) goto return_error; return; return_error: printf("error with %d\r\n", error); return; } bool HIDController::connected() { return connected; } void HIDController::init() { // https://github.com/jpbrucker/BLE_HID/blob/master/examples/examples_common.cpp printf("ble.init\r\n"); BLE& ble = BLE::Instance(BLE::DEFAULT_INSTANCE); ble.init(bleInitComplete); while (!ble.hasInitialized()) { } printf("ble.hasIntialized\r\n"); } void HIDController::waitForEvent() { BLE& ble = BLE::Instance(BLE::DEFAULT_INSTANCE); keyboardService->stopReportTicker(); ble.waitForEvent(); } void HIDController::appendReportData(uint8_t key) { if (keyboardService) { keyboardService->appendReportData(key); } } void HIDController::deleteReportData(uint8_t key) { if (keyboardService) { keyboardService->deleteReportData(key); } } void HIDController::queueCurrentReportData() { if (!connected) return; if (keyboardService) { printf("queueCurrentReportData\r\n"); keyboardService->queueCurrentReportData(); } }