ble nano hid over gatt
Dependencies: BLE_API mbed-dev nRF51822
Diff: HIDController_BLE.cpp
- Revision:
- 6:f1c3ea8bc850
- Child:
- 9:d1daefbf1fbd
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HIDController_BLE.cpp Thu Jul 21 01:25:31 2016 +0900 @@ -0,0 +1,212 @@ +#include "mbed.h" +#include "BLE.h" +#include "KeyboardService.h" +#include "BatteryService.h" +#include "DeviceInformationService.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 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); + 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\r\n"); +} + +static void onDisconnect(const Gap::DisconnectionCallbackParams_t *params) { + printf("onDisconnect\r\n"); + BLE::Instance(BLE::DEFAULT_INSTANCE).gap().startAdvertising(); +} + +static void onTimeout(const Gap::TimeoutSource_t source) { + printf("onTimeout\r\n"); + 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); + } 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; + + 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; + } + + keyboardService = new KeyboardService(ble); + deviceInformationService = new DeviceInformationService(ble, "lowreal.net", MODEL_NAME, SERIAL_NUMBER, HARDWARE_REVISION, FIRMWARE_REVISION, SOFTWARE_REVISION); + batteryService = new BatteryService(ble, 100); + updateBatteryLevel(); + + printf("general setup\r\n"); + error = ble.gap().accumulateAdvertisingPayload( + GapAdvertisingData::BREDR_NOT_SUPPORTED | + GapAdvertisingData::LE_GENERAL_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(50); + // XXX + // ble.gap().setAdvertisingTimeout(0); + + 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; + // ble.gap().setTxPower(-12); + + + 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; +} + +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::process() { + BLE& ble = BLE::Instance(BLE::DEFAULT_INSTANCE); + ble.waitForEvent(); +} + +void HIDController::appendReportData(uint8_t key) { + if (keyboardService) { + keyboardService->appendReportData(key); + } +} + +void HIDController::deleteReportData(uint8_t key) { + if (keyboardService) { + keyboardService->deleteReportData(key); + } +}