Hiroh Satoh / keyboard Featured

Dependencies:   BLE_API mbed-dev nRF51822

Committer:
cho45
Date:
Thu Jul 21 21:40:44 2016 +0900
Revision:
10:1aed2481a743
Parent:
9:d1daefbf1fbd
Child:
13:b0ffdf2012b9
rename

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 6:f1c3ea8bc850 3 #include "KeyboardService.h"
cho45 6:f1c3ea8bc850 4 #include "BatteryService.h"
cho45 6:f1c3ea8bc850 5 #include "DeviceInformationService.h"
cho45 6:f1c3ea8bc850 6 #include "HIDController_BLE.h"
cho45 6:f1c3ea8bc850 7
cho45 6:f1c3ea8bc850 8 static const char MODEL_NAME[] = "keyboard";
cho45 6:f1c3ea8bc850 9 static const char SERIAL_NUMBER[] = "X00000";
cho45 6:f1c3ea8bc850 10 static const char HARDWARE_REVISION[] = "0.1";
cho45 6:f1c3ea8bc850 11 static const char FIRMWARE_REVISION[] = "0.1";
cho45 6:f1c3ea8bc850 12 static const char SOFTWARE_REVISION[] = "0.0";
cho45 6:f1c3ea8bc850 13
cho45 6:f1c3ea8bc850 14 static const uint8_t DEVICE_NAME[] = "my keyboard";
cho45 6:f1c3ea8bc850 15 static const uint8_t SHORT_DEVICE_NAME[] = "kbd1";
cho45 6:f1c3ea8bc850 16
cho45 6:f1c3ea8bc850 17 static const bool ENABLE_BONDING = true;
cho45 6:f1c3ea8bc850 18 static const bool REQUIRE_MITM = true;
cho45 6:f1c3ea8bc850 19 static const uint8_t PASSKEY[6] = {'1','2','3','4','5','6'}; // must be 6-digits number
cho45 6:f1c3ea8bc850 20
cho45 6:f1c3ea8bc850 21 static const uint16_t uuid16_list[] = {
cho45 6:f1c3ea8bc850 22 GattService::UUID_HUMAN_INTERFACE_DEVICE_SERVICE,
cho45 6:f1c3ea8bc850 23 GattService::UUID_DEVICE_INFORMATION_SERVICE,
cho45 6:f1c3ea8bc850 24 GattService::UUID_BATTERY_SERVICE
cho45 6:f1c3ea8bc850 25 };
cho45 6:f1c3ea8bc850 26
cho45 6:f1c3ea8bc850 27 static KeyboardService* keyboardService;
cho45 6:f1c3ea8bc850 28 static BatteryService* batteryService;
cho45 6:f1c3ea8bc850 29 static DeviceInformationService* deviceInformationService;
cho45 6:f1c3ea8bc850 30
cho45 6:f1c3ea8bc850 31 static void updateBatteryLevel() {
cho45 6:f1c3ea8bc850 32 if (!batteryService) return;
cho45 6:f1c3ea8bc850 33 static const float BATTERY_MAX = 2.4;
cho45 6:f1c3ea8bc850 34 static const float REFERNECE = 1.2;
cho45 6:f1c3ea8bc850 35 static const float PRESCALE = 3;
cho45 6:f1c3ea8bc850 36
cho45 6:f1c3ea8bc850 37 NRF_ADC->ENABLE = ADC_ENABLE_ENABLE_Enabled;
cho45 6:f1c3ea8bc850 38
cho45 6:f1c3ea8bc850 39 // Use internal 1.2V reference for batteryInput
cho45 6:f1c3ea8bc850 40 // 1/3 pre-scaled input and 1.2V internal band gap reference
cho45 6:f1c3ea8bc850 41 // ref. mbed-src/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/analogin_api.c
cho45 6:f1c3ea8bc850 42 NRF_ADC->CONFIG =
cho45 6:f1c3ea8bc850 43 (ADC_CONFIG_RES_10bit << ADC_CONFIG_RES_Pos) |
cho45 6:f1c3ea8bc850 44 // Use VDD 1/3 for input
cho45 6:f1c3ea8bc850 45 (ADC_CONFIG_INPSEL_SupplyOneThirdPrescaling << ADC_CONFIG_INPSEL_Pos) |
cho45 6:f1c3ea8bc850 46 // Use internal band gap for reference
cho45 6:f1c3ea8bc850 47 (ADC_CONFIG_REFSEL_VBG << ADC_CONFIG_REFSEL_Pos) |
cho45 6:f1c3ea8bc850 48 (ADC_CONFIG_EXTREFSEL_None << ADC_CONFIG_EXTREFSEL_Pos);
cho45 6:f1c3ea8bc850 49
cho45 6:f1c3ea8bc850 50 // Start ADC
cho45 6:f1c3ea8bc850 51 NRF_ADC->TASKS_START = 1;
cho45 6:f1c3ea8bc850 52 while (((NRF_ADC->BUSY & ADC_BUSY_BUSY_Msk) >> ADC_BUSY_BUSY_Pos) == ADC_BUSY_BUSY_Busy) {
cho45 6:f1c3ea8bc850 53 // busy loop
cho45 6:f1c3ea8bc850 54 }
cho45 6:f1c3ea8bc850 55
cho45 6:f1c3ea8bc850 56 // Read ADC result
cho45 6:f1c3ea8bc850 57 uint16_t raw10bit = static_cast<uint16_t>(NRF_ADC->RESULT);
cho45 6:f1c3ea8bc850 58 float ratio = raw10bit / static_cast<float>(1<<10);
cho45 6:f1c3ea8bc850 59
cho45 6:f1c3ea8bc850 60 float batteryVoltage = ratio * (REFERNECE * PRESCALE);
cho45 6:f1c3ea8bc850 61 float percentage = (batteryVoltage / BATTERY_MAX) * 100;
cho45 6:f1c3ea8bc850 62 if (percentage > 100) {
cho45 6:f1c3ea8bc850 63 percentage = 100;
cho45 6:f1c3ea8bc850 64 }
cho45 6:f1c3ea8bc850 65 printf("updateBatteryLevel %f V : %d/100\r\n", batteryVoltage, static_cast<uint8_t>(percentage));
cho45 6:f1c3ea8bc850 66 batteryService->updateBatteryLevel(static_cast<uint8_t>(percentage));
cho45 6:f1c3ea8bc850 67 }
cho45 6:f1c3ea8bc850 68
cho45 6:f1c3ea8bc850 69
cho45 6:f1c3ea8bc850 70 static void onConnect(const Gap::ConnectionCallbackParams_t *params) {
cho45 6:f1c3ea8bc850 71 printf("onConnect\r\n");
cho45 9:d1daefbf1fbd 72 // If a bond is created, the HID Device should write the address of the HID Host in the HID Device controller’s white list and set the HID Device controller’s advertising filter policy to ‘process scan and connection requests only from devices in the White List’.
cho45 6:f1c3ea8bc850 73 }
cho45 6:f1c3ea8bc850 74
cho45 6:f1c3ea8bc850 75 static void onDisconnect(const Gap::DisconnectionCallbackParams_t *params) {
cho45 6:f1c3ea8bc850 76 printf("onDisconnect\r\n");
cho45 6:f1c3ea8bc850 77 BLE::Instance(BLE::DEFAULT_INSTANCE).gap().startAdvertising();
cho45 6:f1c3ea8bc850 78 }
cho45 6:f1c3ea8bc850 79
cho45 6:f1c3ea8bc850 80 static void onTimeout(const Gap::TimeoutSource_t source) {
cho45 6:f1c3ea8bc850 81 printf("onTimeout\r\n");
cho45 6:f1c3ea8bc850 82 BLE::Instance(BLE::DEFAULT_INSTANCE).gap().startAdvertising();
cho45 6:f1c3ea8bc850 83 }
cho45 6:f1c3ea8bc850 84
cho45 6:f1c3ea8bc850 85 static void passkeyDisplayCallback(Gap::Handle_t handle, const SecurityManager::Passkey_t passkey) {
cho45 6:f1c3ea8bc850 86 printf("Input passKey: ");
cho45 6:f1c3ea8bc850 87 for (unsigned i = 0; i < Gap::ADDR_LEN; i++) {
cho45 6:f1c3ea8bc850 88 printf("%c", passkey[i]);
cho45 6:f1c3ea8bc850 89 }
cho45 6:f1c3ea8bc850 90 printf("\r\n");
cho45 6:f1c3ea8bc850 91 }
cho45 6:f1c3ea8bc850 92
cho45 6:f1c3ea8bc850 93 static void securitySetupCompletedCallback(Gap::Handle_t handle, SecurityManager::SecurityCompletionStatus_t status) {
cho45 6:f1c3ea8bc850 94 if (status == SecurityManager::SEC_STATUS_SUCCESS) {
cho45 6:f1c3ea8bc850 95 printf("Security success %d\r\n", status);
cho45 6:f1c3ea8bc850 96 } else {
cho45 6:f1c3ea8bc850 97 printf("Security failed %d\r\n", status);
cho45 6:f1c3ea8bc850 98 }
cho45 6:f1c3ea8bc850 99 }
cho45 6:f1c3ea8bc850 100
cho45 6:f1c3ea8bc850 101 static void securitySetupInitiatedCallback(Gap::Handle_t, bool allowBonding, bool requireMITM, SecurityManager::SecurityIOCapabilities_t iocaps) {
cho45 6:f1c3ea8bc850 102 printf("Security setup initiated\r\n");
cho45 6:f1c3ea8bc850 103 }
cho45 6:f1c3ea8bc850 104
cho45 6:f1c3ea8bc850 105 static void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) {
cho45 6:f1c3ea8bc850 106 // https://developer.mbed.org/compiler/#nav:/keyboard/BLE_API/ble/blecommon.h;
cho45 6:f1c3ea8bc850 107 ble_error_t error;
cho45 6:f1c3ea8bc850 108 BLE &ble = params->ble;
cho45 6:f1c3ea8bc850 109
cho45 6:f1c3ea8bc850 110 error = params->error;
cho45 6:f1c3ea8bc850 111 if (error != BLE_ERROR_NONE) {
cho45 6:f1c3ea8bc850 112 printf("error on ble.init() \r\n");
cho45 6:f1c3ea8bc850 113 goto return_error;
cho45 6:f1c3ea8bc850 114 }
cho45 6:f1c3ea8bc850 115
cho45 6:f1c3ea8bc850 116 ble.gap().onDisconnection(onDisconnect);
cho45 6:f1c3ea8bc850 117 ble.gap().onConnection(onConnect);
cho45 6:f1c3ea8bc850 118 ble.gap().onTimeout(onTimeout);
cho45 6:f1c3ea8bc850 119
cho45 6:f1c3ea8bc850 120 printf("setup ble security manager\r\n");
cho45 6:f1c3ea8bc850 121 ble.securityManager().onSecuritySetupInitiated(securitySetupInitiatedCallback);
cho45 6:f1c3ea8bc850 122 ble.securityManager().onPasskeyDisplay(passkeyDisplayCallback);
cho45 6:f1c3ea8bc850 123 ble.securityManager().onSecuritySetupCompleted(securitySetupCompletedCallback);
cho45 6:f1c3ea8bc850 124 // bonding with hard-coded passkey.
cho45 6:f1c3ea8bc850 125 error = ble.securityManager().init(ENABLE_BONDING, REQUIRE_MITM, SecurityManager::IO_CAPS_DISPLAY_ONLY, PASSKEY);
cho45 6:f1c3ea8bc850 126 if (error != BLE_ERROR_NONE) {
cho45 6:f1c3ea8bc850 127 printf("error on ble.securityManager().init()");
cho45 6:f1c3ea8bc850 128 goto return_error;
cho45 6:f1c3ea8bc850 129 }
cho45 6:f1c3ea8bc850 130
cho45 6:f1c3ea8bc850 131 keyboardService = new KeyboardService(ble);
cho45 6:f1c3ea8bc850 132 deviceInformationService = new DeviceInformationService(ble, "lowreal.net", MODEL_NAME, SERIAL_NUMBER, HARDWARE_REVISION, FIRMWARE_REVISION, SOFTWARE_REVISION);
cho45 6:f1c3ea8bc850 133 batteryService = new BatteryService(ble, 100);
cho45 6:f1c3ea8bc850 134 updateBatteryLevel();
cho45 6:f1c3ea8bc850 135
cho45 6:f1c3ea8bc850 136 printf("general setup\r\n");
cho45 6:f1c3ea8bc850 137 error = ble.gap().accumulateAdvertisingPayload(
cho45 6:f1c3ea8bc850 138 GapAdvertisingData::BREDR_NOT_SUPPORTED |
cho45 6:f1c3ea8bc850 139 GapAdvertisingData::LE_GENERAL_DISCOVERABLE
cho45 6:f1c3ea8bc850 140 );
cho45 9:d1daefbf1fbd 141 // shoud be LE_LIMITED_DISCOVERABLE
cho45 9:d1daefbf1fbd 142 // error = ble.gap().accumulateAdvertisingPayload(
cho45 9:d1daefbf1fbd 143 // GapAdvertisingData::BREDR_NOT_SUPPORTED |
cho45 9:d1daefbf1fbd 144 // GapAdvertisingData::LE_LIMITED_DISCOVERABLE
cho45 9:d1daefbf1fbd 145 // );
cho45 6:f1c3ea8bc850 146 if (error != BLE_ERROR_NONE) goto return_error;
cho45 6:f1c3ea8bc850 147
cho45 6:f1c3ea8bc850 148 printf("set COMPLETE_LIST_16BIT_SERVICE_IDS\r\n");
cho45 6:f1c3ea8bc850 149 error = ble.gap().accumulateAdvertisingPayload(
cho45 6:f1c3ea8bc850 150 GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS,
cho45 6:f1c3ea8bc850 151 (uint8_t*)uuid16_list, sizeof(uuid16_list)
cho45 6:f1c3ea8bc850 152 );
cho45 6:f1c3ea8bc850 153 if (error != BLE_ERROR_NONE) goto return_error;
cho45 6:f1c3ea8bc850 154
cho45 6:f1c3ea8bc850 155 printf("set advertising\r\n");
cho45 6:f1c3ea8bc850 156 // see 5.1.2: HID over GATT Specification (pg. 25)
cho45 6:f1c3ea8bc850 157 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
cho45 6:f1c3ea8bc850 158
cho45 6:f1c3ea8bc850 159 printf("set advertising interval\r\n");
cho45 9:d1daefbf1fbd 160 ble.gap().setAdvertisingInterval(30);
cho45 9:d1daefbf1fbd 161 printf("set advertising timeout\r\n");
cho45 9:d1daefbf1fbd 162 ble.gap().setAdvertisingTimeout(180);
cho45 6:f1c3ea8bc850 163
cho45 6:f1c3ea8bc850 164 printf("set keyboard\r\n");
cho45 6:f1c3ea8bc850 165 error = ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::KEYBOARD);
cho45 6:f1c3ea8bc850 166 if (error != BLE_ERROR_NONE) goto return_error;
cho45 6:f1c3ea8bc850 167
cho45 6:f1c3ea8bc850 168 printf("set complete local name\r\n");
cho45 6:f1c3ea8bc850 169 error = ble.gap().accumulateAdvertisingPayload(
cho45 6:f1c3ea8bc850 170 GapAdvertisingData::COMPLETE_LOCAL_NAME,
cho45 6:f1c3ea8bc850 171 DEVICE_NAME, sizeof(DEVICE_NAME)
cho45 6:f1c3ea8bc850 172 );
cho45 6:f1c3ea8bc850 173 if (error != BLE_ERROR_NONE) goto return_error;
cho45 6:f1c3ea8bc850 174
cho45 6:f1c3ea8bc850 175 printf("set device name\r\n");
cho45 6:f1c3ea8bc850 176 error = ble.gap().setDeviceName(DEVICE_NAME);
cho45 6:f1c3ea8bc850 177 if (error != BLE_ERROR_NONE) goto return_error;
cho45 6:f1c3ea8bc850 178 // ble.gap().setTxPower(-12);
cho45 6:f1c3ea8bc850 179
cho45 6:f1c3ea8bc850 180
cho45 6:f1c3ea8bc850 181 printf("advertising\r\n");
cho45 6:f1c3ea8bc850 182 error = ble.gap().startAdvertising();
cho45 6:f1c3ea8bc850 183 if (error != BLE_ERROR_NONE) goto return_error;
cho45 6:f1c3ea8bc850 184 return;
cho45 6:f1c3ea8bc850 185
cho45 6:f1c3ea8bc850 186 return_error:
cho45 6:f1c3ea8bc850 187 printf("error with %d\r\n", error);
cho45 6:f1c3ea8bc850 188 return;
cho45 6:f1c3ea8bc850 189 }
cho45 6:f1c3ea8bc850 190
cho45 6:f1c3ea8bc850 191 void HIDController::init() {
cho45 6:f1c3ea8bc850 192 // https://github.com/jpbrucker/BLE_HID/blob/master/examples/examples_common.cpp
cho45 6:f1c3ea8bc850 193 printf("ble.init\r\n");
cho45 6:f1c3ea8bc850 194
cho45 6:f1c3ea8bc850 195 BLE& ble = BLE::Instance(BLE::DEFAULT_INSTANCE);
cho45 6:f1c3ea8bc850 196 ble.init(bleInitComplete);
cho45 6:f1c3ea8bc850 197
cho45 6:f1c3ea8bc850 198 while (!ble.hasInitialized()) { }
cho45 6:f1c3ea8bc850 199
cho45 6:f1c3ea8bc850 200 printf("ble.hasIntialized\r\n");
cho45 6:f1c3ea8bc850 201 }
cho45 6:f1c3ea8bc850 202
cho45 10:1aed2481a743 203 void HIDController::waitForEvent() {
cho45 6:f1c3ea8bc850 204 BLE& ble = BLE::Instance(BLE::DEFAULT_INSTANCE);
cho45 6:f1c3ea8bc850 205 ble.waitForEvent();
cho45 6:f1c3ea8bc850 206 }
cho45 6:f1c3ea8bc850 207
cho45 6:f1c3ea8bc850 208 void HIDController::appendReportData(uint8_t key) {
cho45 6:f1c3ea8bc850 209 if (keyboardService) {
cho45 6:f1c3ea8bc850 210 keyboardService->appendReportData(key);
cho45 6:f1c3ea8bc850 211 }
cho45 6:f1c3ea8bc850 212 }
cho45 6:f1c3ea8bc850 213
cho45 6:f1c3ea8bc850 214 void HIDController::deleteReportData(uint8_t key) {
cho45 6:f1c3ea8bc850 215 if (keyboardService) {
cho45 6:f1c3ea8bc850 216 keyboardService->deleteReportData(key);
cho45 6:f1c3ea8bc850 217 }
cho45 6:f1c3ea8bc850 218 }
cho45 9:d1daefbf1fbd 219
cho45 9:d1daefbf1fbd 220 void HIDController::queueCurrentReportData() {
cho45 9:d1daefbf1fbd 221 if (keyboardService) {
cho45 9:d1daefbf1fbd 222 keyboardService->queueCurrentReportData();
cho45 9:d1daefbf1fbd 223 }
cho45 9:d1daefbf1fbd 224 }