Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: BLE_API mbed-dev nRF51822
main.cpp@5:65d4e94735b6, 2016-07-21 (annotated)
- Committer:
- cho45
- Date:
- Thu Jul 21 00:38:09 2016 +0900
- Revision:
- 5:65d4e94735b6
- Parent:
- 4:54cb552e50c4
- Child:
- 6:f1c3ea8bc850
keyboard controller
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| cho45 | 0:be89b5fdea09 | 1 | /* mbed Microcontroller Library |
| cho45 | 0:be89b5fdea09 | 2 | * Copyright (c) 2015 ARM Limited |
| cho45 | 0:be89b5fdea09 | 3 | * |
| cho45 | 0:be89b5fdea09 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| cho45 | 0:be89b5fdea09 | 5 | * you may not use this file except in compliance with the License. |
| cho45 | 0:be89b5fdea09 | 6 | * You may obtain a copy of the License at |
| cho45 | 0:be89b5fdea09 | 7 | * |
| cho45 | 0:be89b5fdea09 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| cho45 | 0:be89b5fdea09 | 9 | * |
| cho45 | 0:be89b5fdea09 | 10 | * Unless required by applicable law or agreed to in writing, software |
| cho45 | 0:be89b5fdea09 | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| cho45 | 0:be89b5fdea09 | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| cho45 | 0:be89b5fdea09 | 13 | * See the License for the specific language governing permissions and |
| cho45 | 0:be89b5fdea09 | 14 | * limitations under the License. |
| cho45 | 0:be89b5fdea09 | 15 | */ |
| cho45 | 0:be89b5fdea09 | 16 | |
| cho45 | 0:be89b5fdea09 | 17 | #include "mbed.h" |
| cho45 | 0:be89b5fdea09 | 18 | #include "BLE.h" |
| cho45 | 0:be89b5fdea09 | 19 | #include "KeyboardService.h" |
| cho45 | 0:be89b5fdea09 | 20 | #include "BatteryService.h" |
| cho45 | 0:be89b5fdea09 | 21 | #include "DeviceInformationService.h" |
| cho45 |
4:54cb552e50c4 | 22 | #include "mcp23017.h" |
| cho45 |
5:65d4e94735b6 | 23 | #include "keymap.h" |
| cho45 | 0:be89b5fdea09 | 24 | |
| cho45 | 0:be89b5fdea09 | 25 | static const char MODEL_NAME[] = "keyboard"; |
| cho45 | 0:be89b5fdea09 | 26 | static const char SERIAL_NUMBER[] = "X00000"; |
| cho45 | 0:be89b5fdea09 | 27 | static const char HARDWARE_REVISION[] = "0.1"; |
| cho45 | 0:be89b5fdea09 | 28 | static const char FIRMWARE_REVISION[] = "0.1"; |
| cho45 | 0:be89b5fdea09 | 29 | static const char SOFTWARE_REVISION[] = "0.0"; |
| cho45 | 0:be89b5fdea09 | 30 | |
| cho45 | 0:be89b5fdea09 | 31 | static const uint8_t DEVICE_NAME[] = "my keyboard"; |
| cho45 | 0:be89b5fdea09 | 32 | static const uint8_t SHORT_DEVICE_NAME[] = "kbd1"; |
| cho45 | 0:be89b5fdea09 | 33 | |
| cho45 |
2:c2e3f240640c | 34 | static const bool ENABLE_BONDING = true; |
| cho45 |
2:c2e3f240640c | 35 | static const bool REQUIRE_MITM = true; |
| cho45 |
2:c2e3f240640c | 36 | static const uint8_t PASSKEY[6] = {'1','2','3','4','5','6'}; // must be 6-digits number |
| cho45 |
2:c2e3f240640c | 37 | |
| cho45 | 0:be89b5fdea09 | 38 | static const uint16_t uuid16_list[] = { |
| cho45 |
2:c2e3f240640c | 39 | GattService::UUID_HUMAN_INTERFACE_DEVICE_SERVICE, |
| cho45 |
2:c2e3f240640c | 40 | GattService::UUID_DEVICE_INFORMATION_SERVICE, |
| cho45 |
2:c2e3f240640c | 41 | GattService::UUID_BATTERY_SERVICE |
| cho45 | 0:be89b5fdea09 | 42 | }; |
| cho45 | 0:be89b5fdea09 | 43 | |
| cho45 | 0:be89b5fdea09 | 44 | KeyboardService* keyboardService; |
| cho45 | 0:be89b5fdea09 | 45 | BatteryService* batteryService; |
| cho45 | 0:be89b5fdea09 | 46 | DeviceInformationService* deviceInformationService; |
| cho45 | 0:be89b5fdea09 | 47 | |
| cho45 |
3:266dfa9f8709 | 48 | void updateBatteryLevel() { |
| cho45 |
3:266dfa9f8709 | 49 | if (!batteryService) return; |
| cho45 |
3:266dfa9f8709 | 50 | static const float BATTERY_MAX = 2.4; |
| cho45 |
4:54cb552e50c4 | 51 | static const float REFERNECE = 1.2; |
| cho45 |
4:54cb552e50c4 | 52 | static const float PRESCALE = 3; |
| cho45 |
3:266dfa9f8709 | 53 | |
| cho45 |
4:54cb552e50c4 | 54 | NRF_ADC->ENABLE = ADC_ENABLE_ENABLE_Enabled; |
| cho45 |
4:54cb552e50c4 | 55 | |
| cho45 |
4:54cb552e50c4 | 56 | // Use internal 1.2V reference for batteryInput |
| cho45 |
4:54cb552e50c4 | 57 | // 1/3 pre-scaled input and 1.2V internal band gap reference |
| cho45 |
4:54cb552e50c4 | 58 | // ref. mbed-src/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/analogin_api.c |
| cho45 |
4:54cb552e50c4 | 59 | NRF_ADC->CONFIG = |
| cho45 |
4:54cb552e50c4 | 60 | (ADC_CONFIG_RES_10bit << ADC_CONFIG_RES_Pos) | |
| cho45 |
4:54cb552e50c4 | 61 | // Use VDD 1/3 for input |
| cho45 |
4:54cb552e50c4 | 62 | (ADC_CONFIG_INPSEL_SupplyOneThirdPrescaling << ADC_CONFIG_INPSEL_Pos) | |
| cho45 |
4:54cb552e50c4 | 63 | // Use internal band gap for reference |
| cho45 |
4:54cb552e50c4 | 64 | (ADC_CONFIG_REFSEL_VBG << ADC_CONFIG_REFSEL_Pos) | |
| cho45 |
4:54cb552e50c4 | 65 | (ADC_CONFIG_EXTREFSEL_None << ADC_CONFIG_EXTREFSEL_Pos); |
| cho45 |
4:54cb552e50c4 | 66 | |
| cho45 |
4:54cb552e50c4 | 67 | // Start ADC |
| cho45 |
4:54cb552e50c4 | 68 | NRF_ADC->TASKS_START = 1; |
| cho45 |
4:54cb552e50c4 | 69 | while (((NRF_ADC->BUSY & ADC_BUSY_BUSY_Msk) >> ADC_BUSY_BUSY_Pos) == ADC_BUSY_BUSY_Busy) { |
| cho45 |
4:54cb552e50c4 | 70 | // busy loop |
| cho45 |
4:54cb552e50c4 | 71 | } |
| cho45 |
4:54cb552e50c4 | 72 | |
| cho45 |
4:54cb552e50c4 | 73 | // Read ADC result |
| cho45 |
4:54cb552e50c4 | 74 | uint16_t raw10bit = static_cast<uint16_t>(NRF_ADC->RESULT); |
| cho45 |
4:54cb552e50c4 | 75 | float ratio = raw10bit / static_cast<float>(1<<10); |
| cho45 |
4:54cb552e50c4 | 76 | |
| cho45 |
4:54cb552e50c4 | 77 | float batteryVoltage = ratio * (REFERNECE * PRESCALE); |
| cho45 |
3:266dfa9f8709 | 78 | float percentage = (batteryVoltage / BATTERY_MAX) * 100; |
| cho45 |
3:266dfa9f8709 | 79 | if (percentage > 100) { |
| cho45 |
3:266dfa9f8709 | 80 | percentage = 100; |
| cho45 |
3:266dfa9f8709 | 81 | } |
| cho45 |
4:54cb552e50c4 | 82 | printf("updateBatteryLevel %f V : %d/100\r\n", batteryVoltage, static_cast<uint8_t>(percentage)); |
| cho45 |
3:266dfa9f8709 | 83 | batteryService->updateBatteryLevel(static_cast<uint8_t>(percentage)); |
| cho45 |
3:266dfa9f8709 | 84 | } |
| cho45 |
3:266dfa9f8709 | 85 | |
| cho45 |
3:266dfa9f8709 | 86 | |
| cho45 | 0:be89b5fdea09 | 87 | static void onConnect(const Gap::ConnectionCallbackParams_t *params) { |
| cho45 |
2:c2e3f240640c | 88 | printf("onConnect\r\n"); |
| cho45 | 0:be89b5fdea09 | 89 | } |
| cho45 | 0:be89b5fdea09 | 90 | |
| cho45 |
2:c2e3f240640c | 91 | static void onDisconnect(const Gap::DisconnectionCallbackParams_t *params) { |
| cho45 |
2:c2e3f240640c | 92 | printf("onDisconnect\r\n"); |
| cho45 |
2:c2e3f240640c | 93 | BLE::Instance(BLE::DEFAULT_INSTANCE).gap().startAdvertising(); |
| cho45 |
2:c2e3f240640c | 94 | } |
| cho45 |
2:c2e3f240640c | 95 | |
| cho45 |
2:c2e3f240640c | 96 | static void onTimeout(const Gap::TimeoutSource_t source) { |
| cho45 |
2:c2e3f240640c | 97 | printf("onTimeout\r\n"); |
| cho45 |
2:c2e3f240640c | 98 | BLE::Instance(BLE::DEFAULT_INSTANCE).gap().startAdvertising(); |
| cho45 |
2:c2e3f240640c | 99 | } |
| cho45 | 0:be89b5fdea09 | 100 | |
| cho45 | 0:be89b5fdea09 | 101 | static void passkeyDisplayCallback(Gap::Handle_t handle, const SecurityManager::Passkey_t passkey) { |
| cho45 |
2:c2e3f240640c | 102 | printf("Input passKey: "); |
| cho45 |
2:c2e3f240640c | 103 | for (unsigned i = 0; i < Gap::ADDR_LEN; i++) { |
| cho45 |
2:c2e3f240640c | 104 | printf("%c", passkey[i]); |
| cho45 |
2:c2e3f240640c | 105 | } |
| cho45 |
2:c2e3f240640c | 106 | printf("\r\n"); |
| cho45 |
2:c2e3f240640c | 107 | } |
| cho45 |
2:c2e3f240640c | 108 | |
| cho45 |
2:c2e3f240640c | 109 | static void securitySetupCompletedCallback(Gap::Handle_t handle, SecurityManager::SecurityCompletionStatus_t status) { |
| cho45 |
2:c2e3f240640c | 110 | if (status == SecurityManager::SEC_STATUS_SUCCESS) { |
| cho45 |
2:c2e3f240640c | 111 | printf("Security success %d\r\n", status); |
| cho45 |
2:c2e3f240640c | 112 | } else { |
| cho45 |
2:c2e3f240640c | 113 | printf("Security failed %d\r\n", status); |
| cho45 |
2:c2e3f240640c | 114 | } |
| cho45 |
2:c2e3f240640c | 115 | } |
| cho45 |
2:c2e3f240640c | 116 | |
| cho45 |
2:c2e3f240640c | 117 | static void securitySetupInitiatedCallback(Gap::Handle_t, bool allowBonding, bool requireMITM, SecurityManager::SecurityIOCapabilities_t iocaps) { |
| cho45 |
2:c2e3f240640c | 118 | printf("Security setup initiated\r\n"); |
| cho45 | 0:be89b5fdea09 | 119 | } |
| cho45 | 0:be89b5fdea09 | 120 | |
| cho45 |
2:c2e3f240640c | 121 | static void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) { |
| cho45 |
2:c2e3f240640c | 122 | // https://developer.mbed.org/compiler/#nav:/keyboard/BLE_API/ble/blecommon.h; |
| cho45 |
2:c2e3f240640c | 123 | ble_error_t error; |
| cho45 |
2:c2e3f240640c | 124 | BLE &ble = params->ble; |
| cho45 |
2:c2e3f240640c | 125 | |
| cho45 |
2:c2e3f240640c | 126 | error = params->error; |
| cho45 |
2:c2e3f240640c | 127 | if (error != BLE_ERROR_NONE) { |
| cho45 |
2:c2e3f240640c | 128 | printf("error on ble.init() \r\n"); |
| cho45 |
2:c2e3f240640c | 129 | goto return_error; |
| cho45 |
2:c2e3f240640c | 130 | } |
| cho45 |
2:c2e3f240640c | 131 | |
| cho45 |
2:c2e3f240640c | 132 | ble.gap().onDisconnection(onDisconnect); |
| cho45 |
2:c2e3f240640c | 133 | ble.gap().onConnection(onConnect); |
| cho45 |
2:c2e3f240640c | 134 | ble.gap().onTimeout(onTimeout); |
| cho45 |
2:c2e3f240640c | 135 | |
| cho45 |
2:c2e3f240640c | 136 | printf("setup ble security manager\r\n"); |
| cho45 |
2:c2e3f240640c | 137 | ble.securityManager().onSecuritySetupInitiated(securitySetupInitiatedCallback); |
| cho45 |
2:c2e3f240640c | 138 | ble.securityManager().onPasskeyDisplay(passkeyDisplayCallback); |
| cho45 |
2:c2e3f240640c | 139 | ble.securityManager().onSecuritySetupCompleted(securitySetupCompletedCallback); |
| cho45 |
2:c2e3f240640c | 140 | // bonding with hard-coded passkey. |
| cho45 |
2:c2e3f240640c | 141 | error = ble.securityManager().init(ENABLE_BONDING, REQUIRE_MITM, SecurityManager::IO_CAPS_DISPLAY_ONLY, PASSKEY); |
| cho45 |
2:c2e3f240640c | 142 | if (error != BLE_ERROR_NONE) { |
| cho45 |
2:c2e3f240640c | 143 | printf("error on ble.securityManager().init()"); |
| cho45 |
2:c2e3f240640c | 144 | goto return_error; |
| cho45 |
2:c2e3f240640c | 145 | } |
| cho45 |
2:c2e3f240640c | 146 | |
| cho45 |
2:c2e3f240640c | 147 | keyboardService = new KeyboardService(ble); |
| cho45 |
2:c2e3f240640c | 148 | deviceInformationService = new DeviceInformationService(ble, "lowreal.net", MODEL_NAME, SERIAL_NUMBER, HARDWARE_REVISION, FIRMWARE_REVISION, SOFTWARE_REVISION); |
| cho45 |
3:266dfa9f8709 | 149 | batteryService = new BatteryService(ble, 100); |
| cho45 |
3:266dfa9f8709 | 150 | updateBatteryLevel(); |
| cho45 | 0:be89b5fdea09 | 151 | |
| cho45 |
2:c2e3f240640c | 152 | printf("general setup\r\n"); |
| cho45 |
2:c2e3f240640c | 153 | error = ble.gap().accumulateAdvertisingPayload( |
| cho45 |
2:c2e3f240640c | 154 | GapAdvertisingData::BREDR_NOT_SUPPORTED | |
| cho45 |
2:c2e3f240640c | 155 | GapAdvertisingData::LE_GENERAL_DISCOVERABLE |
| cho45 |
2:c2e3f240640c | 156 | ); |
| cho45 |
2:c2e3f240640c | 157 | if (error != BLE_ERROR_NONE) goto return_error; |
| cho45 |
2:c2e3f240640c | 158 | |
| cho45 |
2:c2e3f240640c | 159 | printf("set COMPLETE_LIST_16BIT_SERVICE_IDS\r\n"); |
| cho45 |
2:c2e3f240640c | 160 | error = ble.gap().accumulateAdvertisingPayload( |
| cho45 |
2:c2e3f240640c | 161 | GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, |
| cho45 |
2:c2e3f240640c | 162 | (uint8_t*)uuid16_list, sizeof(uuid16_list) |
| cho45 |
2:c2e3f240640c | 163 | ); |
| cho45 |
2:c2e3f240640c | 164 | if (error != BLE_ERROR_NONE) goto return_error; |
| cho45 |
2:c2e3f240640c | 165 | |
| cho45 |
2:c2e3f240640c | 166 | printf("set advertising\r\n"); |
| cho45 |
2:c2e3f240640c | 167 | // see 5.1.2: HID over GATT Specification (pg. 25) |
| cho45 |
2:c2e3f240640c | 168 | ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); |
| cho45 | 0:be89b5fdea09 | 169 | |
| cho45 |
2:c2e3f240640c | 170 | printf("set advertising interval\r\n"); |
| cho45 |
2:c2e3f240640c | 171 | ble.gap().setAdvertisingInterval(50); |
| cho45 |
2:c2e3f240640c | 172 | // XXX |
| cho45 |
2:c2e3f240640c | 173 | // ble.gap().setAdvertisingTimeout(0); |
| cho45 |
2:c2e3f240640c | 174 | |
| cho45 |
2:c2e3f240640c | 175 | printf("set keyboard\r\n"); |
| cho45 |
2:c2e3f240640c | 176 | error = ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::KEYBOARD); |
| cho45 |
2:c2e3f240640c | 177 | if (error != BLE_ERROR_NONE) goto return_error; |
| cho45 |
2:c2e3f240640c | 178 | |
| cho45 |
2:c2e3f240640c | 179 | printf("set complete local name\r\n"); |
| cho45 |
2:c2e3f240640c | 180 | error = ble.gap().accumulateAdvertisingPayload( |
| cho45 |
2:c2e3f240640c | 181 | GapAdvertisingData::COMPLETE_LOCAL_NAME, |
| cho45 |
2:c2e3f240640c | 182 | DEVICE_NAME, sizeof(DEVICE_NAME) |
| cho45 |
2:c2e3f240640c | 183 | ); |
| cho45 |
2:c2e3f240640c | 184 | if (error != BLE_ERROR_NONE) goto return_error; |
| cho45 |
2:c2e3f240640c | 185 | |
| cho45 |
2:c2e3f240640c | 186 | printf("set device name\r\n"); |
| cho45 |
2:c2e3f240640c | 187 | error = ble.gap().setDeviceName(DEVICE_NAME); |
| cho45 |
2:c2e3f240640c | 188 | if (error != BLE_ERROR_NONE) goto return_error; |
| cho45 |
2:c2e3f240640c | 189 | // ble.gap().setTxPower(-12); |
| cho45 | 0:be89b5fdea09 | 190 | |
| cho45 | 0:be89b5fdea09 | 191 | |
| cho45 |
2:c2e3f240640c | 192 | printf("advertising\r\n"); |
| cho45 |
2:c2e3f240640c | 193 | error = ble.gap().startAdvertising(); |
| cho45 |
2:c2e3f240640c | 194 | if (error != BLE_ERROR_NONE) goto return_error; |
| cho45 |
2:c2e3f240640c | 195 | return; |
| cho45 | 0:be89b5fdea09 | 196 | |
| cho45 |
2:c2e3f240640c | 197 | return_error: |
| cho45 |
2:c2e3f240640c | 198 | printf("error with %d\r\n", error); |
| cho45 |
2:c2e3f240640c | 199 | return; |
| cho45 | 0:be89b5fdea09 | 200 | } |
| cho45 | 0:be89b5fdea09 | 201 | |
| cho45 |
5:65d4e94735b6 | 202 | class KeyboardMatrixController { |
| cho45 |
5:65d4e94735b6 | 203 | I2C& i2c; |
| cho45 |
5:65d4e94735b6 | 204 | MCP23017 gpio1; |
| cho45 |
5:65d4e94735b6 | 205 | MCP23017 gpio2; |
| cho45 |
5:65d4e94735b6 | 206 | |
| cho45 |
5:65d4e94735b6 | 207 | static const uint8_t GPIO1_SLAVE_ADDRESS = 0b0100000; |
| cho45 |
5:65d4e94735b6 | 208 | static const uint8_t GPIO2_SLAVE_ADDRESS = 0b0100001; |
| cho45 |
5:65d4e94735b6 | 209 | |
| cho45 |
5:65d4e94735b6 | 210 | /** |
| cho45 |
5:65d4e94735b6 | 211 | * COL=GPIOA (output normaly positive) |
| cho45 |
5:65d4e94735b6 | 212 | * ROW=GPIOB (input pulled-up) |
| cho45 |
5:65d4e94735b6 | 213 | */ |
| cho45 |
5:65d4e94735b6 | 214 | |
| cho45 |
5:65d4e94735b6 | 215 | int setupGpio(MCP23017& gpio) { |
| cho45 |
5:65d4e94735b6 | 216 | int ok; |
| cho45 |
5:65d4e94735b6 | 217 | ok = gpio.write8( |
| cho45 |
5:65d4e94735b6 | 218 | MCP23017::IOCON, |
| cho45 |
5:65d4e94735b6 | 219 | 0<<MCP23017::BANK | |
| cho45 |
5:65d4e94735b6 | 220 | 1<<MCP23017::MIRROR | |
| cho45 |
5:65d4e94735b6 | 221 | 1<<MCP23017::SEQOP | |
| cho45 |
5:65d4e94735b6 | 222 | 0<<MCP23017::DISSLW | |
| cho45 |
5:65d4e94735b6 | 223 | 1<<MCP23017::ODR // int pin is open drain |
| cho45 |
5:65d4e94735b6 | 224 | ); |
| cho45 |
5:65d4e94735b6 | 225 | |
| cho45 |
5:65d4e94735b6 | 226 | // IODIR |
| cho45 |
5:65d4e94735b6 | 227 | // 1: input |
| cho45 |
5:65d4e94735b6 | 228 | // 0: output |
| cho45 |
5:65d4e94735b6 | 229 | ok = gpio.write16( |
| cho45 |
5:65d4e94735b6 | 230 | MCP23017::IODIRA, |
| cho45 |
5:65d4e94735b6 | 231 | 0b0000000011111111 |
| cho45 |
5:65d4e94735b6 | 232 | ); |
| cho45 |
4:54cb552e50c4 | 233 | |
| cho45 |
5:65d4e94735b6 | 234 | // INPUT POLARITY |
| cho45 |
5:65d4e94735b6 | 235 | // 1: inverse polarity |
| cho45 |
5:65d4e94735b6 | 236 | // 0: raw |
| cho45 |
5:65d4e94735b6 | 237 | ok = gpio.write8( |
| cho45 |
5:65d4e94735b6 | 238 | MCP23017::IPOLB, |
| cho45 |
5:65d4e94735b6 | 239 | 0b11111111 |
| cho45 |
5:65d4e94735b6 | 240 | ); |
| cho45 |
5:65d4e94735b6 | 241 | |
| cho45 |
5:65d4e94735b6 | 242 | // INTERRUPT-ON-CHANGE Enable |
| cho45 |
5:65d4e94735b6 | 243 | ok = gpio.write8( |
| cho45 |
5:65d4e94735b6 | 244 | MCP23017::GPINTENB, |
| cho45 |
5:65d4e94735b6 | 245 | 0b11111111 |
| cho45 |
5:65d4e94735b6 | 246 | ); |
| cho45 |
5:65d4e94735b6 | 247 | // INTERRUPT-ON-CHANGE Control |
| cho45 |
5:65d4e94735b6 | 248 | // 1: compared with DEFVAL |
| cho45 |
5:65d4e94735b6 | 249 | // 0: compared to previous value |
| cho45 |
5:65d4e94735b6 | 250 | ok = gpio.write8( |
| cho45 |
5:65d4e94735b6 | 251 | MCP23017::INTCONB, |
| cho45 |
5:65d4e94735b6 | 252 | 0b00000000 |
| cho45 |
5:65d4e94735b6 | 253 | ); |
| cho45 |
5:65d4e94735b6 | 254 | // PULL-UP (for input pin) |
| cho45 |
5:65d4e94735b6 | 255 | // 1: pull-up enabled |
| cho45 |
5:65d4e94735b6 | 256 | // 0: pull-up disabled |
| cho45 |
5:65d4e94735b6 | 257 | ok = gpio.write8( |
| cho45 |
5:65d4e94735b6 | 258 | MCP23017::GPPUB, |
| cho45 |
5:65d4e94735b6 | 259 | 0b11111111 |
| cho45 |
5:65d4e94735b6 | 260 | ); |
| cho45 |
5:65d4e94735b6 | 261 | |
| cho45 |
5:65d4e94735b6 | 262 | ok = gpio1.write8( |
| cho45 |
5:65d4e94735b6 | 263 | MCP23017::GPIOA, |
| cho45 |
5:65d4e94735b6 | 264 | 0b00000000 |
| cho45 |
5:65d4e94735b6 | 265 | ); |
| cho45 |
5:65d4e94735b6 | 266 | |
| cho45 |
5:65d4e94735b6 | 267 | return ok; |
| cho45 |
5:65d4e94735b6 | 268 | } |
| cho45 |
5:65d4e94735b6 | 269 | |
| cho45 |
4:54cb552e50c4 | 270 | public: |
| cho45 |
5:65d4e94735b6 | 271 | KeyboardMatrixController(I2C& _i2c) : |
| cho45 |
5:65d4e94735b6 | 272 | i2c(_i2c), |
| cho45 |
5:65d4e94735b6 | 273 | gpio1(i2c, GPIO1_SLAVE_ADDRESS), |
| cho45 |
5:65d4e94735b6 | 274 | gpio2(i2c, GPIO2_SLAVE_ADDRESS) |
| cho45 |
4:54cb552e50c4 | 275 | { |
| cho45 |
4:54cb552e50c4 | 276 | } |
| cho45 |
4:54cb552e50c4 | 277 | |
| cho45 |
5:65d4e94735b6 | 278 | void init() { |
| cho45 |
5:65d4e94735b6 | 279 | setupGpio(gpio1); |
| cho45 |
5:65d4e94735b6 | 280 | // setupGpio(gpio2); |
| cho45 |
5:65d4e94735b6 | 281 | } |
| cho45 |
5:65d4e94735b6 | 282 | |
| cho45 |
5:65d4e94735b6 | 283 | void scanKeyboard(uint8_t* keys) { |
| cho45 |
5:65d4e94735b6 | 284 | int ok; |
| cho45 |
5:65d4e94735b6 | 285 | |
| cho45 |
5:65d4e94735b6 | 286 | // Disable interrupt |
| cho45 |
5:65d4e94735b6 | 287 | ok = gpio1.write8( |
| cho45 |
5:65d4e94735b6 | 288 | MCP23017::GPINTENB, |
| cho45 |
5:65d4e94735b6 | 289 | 0b00000000 |
| cho45 |
5:65d4e94735b6 | 290 | ); |
| cho45 |
5:65d4e94735b6 | 291 | |
| cho45 |
5:65d4e94735b6 | 292 | for (int i = 0; i < 8; i++) { |
| cho45 |
5:65d4e94735b6 | 293 | ok = gpio1.write8( |
| cho45 |
5:65d4e94735b6 | 294 | MCP23017::GPIOA, |
| cho45 |
5:65d4e94735b6 | 295 | ~(1<<i) |
| cho45 |
5:65d4e94735b6 | 296 | ); |
| cho45 |
5:65d4e94735b6 | 297 | keys[i] = gpio1.read8(MCP23017::GPIOB, ok); |
| cho45 |
4:54cb552e50c4 | 298 | } |
| cho45 |
2:c2e3f240640c | 299 | |
| cho45 |
5:65d4e94735b6 | 300 | // set all output to negative for interrupt |
| cho45 |
5:65d4e94735b6 | 301 | ok = gpio1.write8( |
| cho45 |
5:65d4e94735b6 | 302 | MCP23017::GPIOA, |
| cho45 |
5:65d4e94735b6 | 303 | 0b00000000 |
| cho45 |
5:65d4e94735b6 | 304 | ); |
| cho45 |
5:65d4e94735b6 | 305 | |
| cho45 |
5:65d4e94735b6 | 306 | // Enable interrupt |
| cho45 |
5:65d4e94735b6 | 307 | ok = gpio1.write8( |
| cho45 |
5:65d4e94735b6 | 308 | MCP23017::GPINTENB, |
| cho45 |
5:65d4e94735b6 | 309 | 0b11111111 |
| cho45 |
5:65d4e94735b6 | 310 | ); |
| cho45 |
5:65d4e94735b6 | 311 | |
| cho45 |
5:65d4e94735b6 | 312 | // Clear interrupt |
| cho45 |
5:65d4e94735b6 | 313 | gpio1.read8(MCP23017::GPIOB, ok); |
| cho45 |
5:65d4e94735b6 | 314 | |
| cho45 |
5:65d4e94735b6 | 315 | // TODO gpio2 |
| cho45 |
4:54cb552e50c4 | 316 | } |
| cho45 |
5:65d4e94735b6 | 317 | }; |
| cho45 |
4:54cb552e50c4 | 318 | |
| cho45 |
5:65d4e94735b6 | 319 | I2C i2c(I2C_SDA0, I2C_SCL0); |
| cho45 |
5:65d4e94735b6 | 320 | KeyboardMatrixController keyboardMatrixController(i2c); |
| cho45 |
5:65d4e94735b6 | 321 | Keymap keymap(keyboardService); |
| cho45 |
5:65d4e94735b6 | 322 | InterruptIn buttonInt(P0_5); |
| cho45 |
5:65d4e94735b6 | 323 | DigitalIn buttonIntIn(P0_5); |
| cho45 |
5:65d4e94735b6 | 324 | |
| cho45 |
5:65d4e94735b6 | 325 | // ROWS=8 |
| cho45 |
5:65d4e94735b6 | 326 | // COLS=16 |
| cho45 |
5:65d4e94735b6 | 327 | // 列ごとに1バイトにパックしてキーの状態を保持する |
| cho45 |
5:65d4e94735b6 | 328 | static uint8_t keysA[COLS]; |
| cho45 |
5:65d4e94735b6 | 329 | static uint8_t keysB[COLS]; |
| cho45 |
5:65d4e94735b6 | 330 | static bool state = 0; |
| cho45 |
5:65d4e94735b6 | 331 | |
| cho45 |
5:65d4e94735b6 | 332 | void buttonIntCallback() { |
| cho45 |
5:65d4e94735b6 | 333 | printf("pinChanged!!!\r\n"); |
| cho45 |
5:65d4e94735b6 | 334 | uint8_t (&keysCurr)[COLS] = state ? keysA : keysB; |
| cho45 |
5:65d4e94735b6 | 335 | uint8_t (&keysPrev)[COLS] = state ? keysB : keysA; |
| cho45 |
5:65d4e94735b6 | 336 | |
| cho45 |
5:65d4e94735b6 | 337 | printf("scanKeyboard\r\n"); |
| cho45 |
5:65d4e94735b6 | 338 | keyboardMatrixController.scanKeyboard(keysCurr); |
| cho45 |
5:65d4e94735b6 | 339 | |
| cho45 |
5:65d4e94735b6 | 340 | for (int col = 0; col < COLS; col++) { |
| cho45 |
5:65d4e94735b6 | 341 | uint8_t changed = keysPrev[col] ^ keysCurr[col]; |
| cho45 |
5:65d4e94735b6 | 342 | if (changed) printf("changed: %x\r\n", changed); |
| cho45 |
5:65d4e94735b6 | 343 | for (int row = 0; row < ROWS; row++) { |
| cho45 |
5:65d4e94735b6 | 344 | if (changed & (1<<row)) { |
| cho45 |
5:65d4e94735b6 | 345 | bool pressed = keysCurr[col] & (1<<row); |
| cho45 |
5:65d4e94735b6 | 346 | printf("changed: col=%d, row=%d / pressed=%d\r\n", col, row, pressed); |
| cho45 |
5:65d4e94735b6 | 347 | // keymap.execute(col, row, pressed); |
| cho45 |
4:54cb552e50c4 | 348 | } |
| cho45 |
4:54cb552e50c4 | 349 | } |
| cho45 |
2:c2e3f240640c | 350 | } |
| cho45 |
5:65d4e94735b6 | 351 | state = !state; |
| cho45 |
2:c2e3f240640c | 352 | } |
| cho45 |
2:c2e3f240640c | 353 | |
| cho45 | 0:be89b5fdea09 | 354 | int main(void) { |
| cho45 |
5:65d4e94735b6 | 355 | printf("init\r\n"); |
| cho45 |
4:54cb552e50c4 | 356 | |
| cho45 |
4:54cb552e50c4 | 357 | // mbed's Serial of TARGET_RBLAB_BLENANO sucks |
| cho45 |
4:54cb552e50c4 | 358 | // DO NOT CONNECT RTS/CTS AUTOMATICALY! |
| cho45 |
4:54cb552e50c4 | 359 | NRF_UART0->PSELRTS = 0xFFFFFFFFUL; |
| cho45 |
4:54cb552e50c4 | 360 | NRF_UART0->PSELCTS = 0xFFFFFFFFUL; |
| cho45 |
4:54cb552e50c4 | 361 | |
| cho45 |
4:54cb552e50c4 | 362 | int ok; |
| cho45 |
4:54cb552e50c4 | 363 | |
| cho45 |
4:54cb552e50c4 | 364 | // 100kHz |
| cho45 |
4:54cb552e50c4 | 365 | i2c.frequency(100000); |
| cho45 |
4:54cb552e50c4 | 366 | |
| cho45 |
5:65d4e94735b6 | 367 | buttonInt.mode(PullUp); |
| cho45 |
5:65d4e94735b6 | 368 | buttonInt.fall(buttonIntCallback); |
| cho45 |
4:54cb552e50c4 | 369 | |
| cho45 |
5:65d4e94735b6 | 370 | keyboardMatrixController.init(); |
| cho45 |
5:65d4e94735b6 | 371 | buttonIntCallback(); |
| cho45 |
4:54cb552e50c4 | 372 | |
| cho45 |
5:65d4e94735b6 | 373 | while (1) { |
| cho45 |
5:65d4e94735b6 | 374 | wait_ms(1000); |
| cho45 |
4:54cb552e50c4 | 375 | } |
| cho45 |
4:54cb552e50c4 | 376 | |
| cho45 |
4:54cb552e50c4 | 377 | return; |
| cho45 | 0:be89b5fdea09 | 378 | |
| cho45 |
2:c2e3f240640c | 379 | // https://github.com/jpbrucker/BLE_HID/blob/master/examples/examples_common.cpp |
| cho45 | 0:be89b5fdea09 | 380 | |
| cho45 |
2:c2e3f240640c | 381 | printf("ble.init\r\n"); |
| cho45 |
2:c2e3f240640c | 382 | BLE& ble = BLE::Instance(BLE::DEFAULT_INSTANCE); |
| cho45 |
2:c2e3f240640c | 383 | ble.init(bleInitComplete); |
| cho45 | 0:be89b5fdea09 | 384 | |
| cho45 |
2:c2e3f240640c | 385 | while (!ble.hasInitialized()) { } |
| cho45 | 0:be89b5fdea09 | 386 | |
| cho45 |
2:c2e3f240640c | 387 | printf("ble.hasIntialized\r\n"); |
| cho45 | 0:be89b5fdea09 | 388 | |
| cho45 |
2:c2e3f240640c | 389 | while (1) { |
| cho45 |
2:c2e3f240640c | 390 | ble.waitForEvent(); |
| cho45 |
2:c2e3f240640c | 391 | } |
| cho45 |
2:c2e3f240640c | 392 | } |