ble nano hid over gatt
Dependencies: BLE_API mbed-dev nRF51822
main.cpp
00001 /* BLE Keyboard Implementation for mbed 00002 * Copyright (c) 2016 cho45 <cho45@lowreal.net> 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #include <cmath> 00018 #include "mbed.h" 00019 00020 #include "HIDController_BLE.h" 00021 #include "KeyboardMatrixController.h" 00022 #include "BatteryLevel.h" 00023 #include "WatchDog.h" 00024 00025 #include "keymap.h" 00026 #include "config.h" 00027 00028 RawSerial serial(USBTX, USBRX); 00029 00030 static I2C i2c(I2C_SDA0, I2C_SCL0); 00031 static KeyboardMatrixController keyboardMatrixController(i2c); 00032 static Keymap keymap; 00033 00034 // Interrupt from MCP23017 00035 // (pulled-up and two MCP23017 is configured with open drain INT) 00036 static InterruptIn keyboardInterruptIn(P0_5); 00037 00038 #define PIN_STATUS_LED P0_4 00039 static DigitalOut statusLed(PIN_STATUS_LED, 0); 00040 00041 // timeout for status led and wakeup from sleep 00042 static Timeout timeout; 00043 00044 // ROWS=8 00045 // COLS=16 00046 // 列ごとに1バイトにパックしてキーの状態を保持する 00047 static uint8_t keysA[COLS]; 00048 static uint8_t keysB[COLS]; 00049 static bool state = 0; 00050 #define is_pressed(keys, row, col) (!!(keys[col] & (1<<row))) 00051 00052 // delay for interrupt 00053 static volatile int8_t pollCount = 50; 00054 00055 static void keyboardInterrupt() { 00056 // just for wakeup 00057 pollCount = 25; 00058 } 00059 00060 static void powerOff() { 00061 DEBUG_PRINTF("power off\r\n"); 00062 NRF_POWER->SYSTEMOFF = 1; 00063 } 00064 00065 static bool updateStatudLedEnabled = false; 00066 static void updateStatusLed() { 00067 switch (HIDController::status()) { 00068 case TIMEOUT: 00069 case DISCONNECTED: 00070 case CONNECTED: 00071 statusLed = 0; 00072 updateStatudLedEnabled = false; 00073 return; 00074 case ADVERTISING: 00075 case CONNECTING: 00076 statusLed = !statusLed; 00077 updateStatudLedEnabled = true; 00078 timeout.attach(updateStatusLed, statusLed ? 0.1 : 0.5); 00079 break; 00080 } 00081 } 00082 00083 static volatile bool keyIntervalInterrupt = false; 00084 static void wakeupKeyIntervalSleep() { 00085 keyIntervalInterrupt = true; 00086 } 00087 00088 static volatile bool shouldUpdateBatteryLevel = true; 00089 static void wakeupIgnoreLongSleep() { 00090 // just wakeup for reloading WDT 00091 shouldUpdateBatteryLevel = true; 00092 } 00093 00094 void setupIO () { 00095 // mbed's Serial of TARGET_RBLAB_BLENANO sucks 00096 // DO NOT CONNECT RTS/CTS WITHOUT PRIOR CONSENT! 00097 NRF_UART0->PSELRTS = 0xFFFFFFFFUL; 00098 NRF_UART0->PSELCTS = 0xFFFFFFFFUL; 00099 00100 // Set LED Pin as HIGH Current mode 00101 NRF_GPIO->PIN_CNF[PIN_STATUS_LED] = 00102 (NRF_GPIO->PIN_CNF[PIN_STATUS_LED] & ~GPIO_PIN_CNF_DRIVE_Msk) | 00103 (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos); 00104 00105 // Unsed pins. 00106 // Set as PullUp for power consumption 00107 // Use GPIO registers directly for saving ram 00108 // Pad pinouts 00109 /* 00110 DigitalIn unused_p0_7(P0_7, PullUp); 00111 DigitalIn unused_p0_6(P0_6, PullUp); 00112 DigitalIn unused_p0_15(P0_15, PullUp); 00113 DigitalIn unused_p0_29(P0_29, PullUp); 00114 DigitalIn unused_p0_28(P0_28, PullUp); 00115 */ 00116 NRF_GPIO->PIN_CNF[P0_7] = 00117 (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) | 00118 (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) | 00119 (GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) | 00120 (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | 00121 (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos); 00122 NRF_GPIO->PIN_CNF[P0_6] = 00123 (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) | 00124 (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) | 00125 (GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) | 00126 (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | 00127 (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos); 00128 NRF_GPIO->PIN_CNF[P0_15] = 00129 (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) | 00130 (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) | 00131 (GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) | 00132 (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | 00133 (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos); 00134 NRF_GPIO->PIN_CNF[P0_29] = 00135 (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) | 00136 (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) | 00137 (GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) | 00138 (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | 00139 (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos); 00140 NRF_GPIO->PIN_CNF[P0_28] = 00141 (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) | 00142 (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) | 00143 (GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) | 00144 (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | 00145 (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos); 00146 /* 00147 DigitalIn unused_p0_19(P0_19, PullUp); // This is on board LED which connected to VDD 00148 DigitalIn unused_p0_11(P0_11, PullUp); // RXD 00149 */ 00150 NRF_GPIO->PIN_CNF[P0_19] = // This is on board LED which connected to VDD 00151 (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) | 00152 (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) | 00153 (GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) | 00154 (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | 00155 (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos); 00156 NRF_GPIO->PIN_CNF[P0_11] = // RXD 00157 (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) | 00158 (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) | 00159 (GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) | 00160 (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | 00161 (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos); 00162 00163 } 00164 00165 int main(void) { 00166 { 00167 const uint32_t reason = NRF_POWER->RESETREAS; 00168 NRF_POWER->RESETREAS = 0xffffffff; // clear reason 00169 // reset cause should be shown everytime 00170 serial.printf("init [%x] sp:%x\r\n", reason, GET_SP()); 00171 } 00172 00173 float batteryVoltage = BatteryLevel::readBatteryVoltage(); 00174 if (batteryVoltage < BatteryLevel::BATTERY_LOW) { 00175 powerOff(); 00176 } 00177 00178 // Enable Pin-reset on DEBUG mode 00179 // This makes possiable booting without normal mode easily. 00180 NRF_POWER->RESET = 1; 00181 // Disable Internal DC/DC step down converter surely 00182 NRF_POWER->DCDCEN = 0; 00183 00184 setupIO(); 00185 00186 WatchDog::init(); 00187 00188 // only 100kHz/250khz/400khz 00189 i2c.frequency(250000); 00190 00191 keyboardInterruptIn.mode(PullUp); 00192 keyboardInterruptIn.fall(keyboardInterrupt); 00193 00194 keyboardMatrixController.init(); 00195 pollCount = 10; 00196 00197 HIDController::init(); 00198 00199 // STOP UART RX for power consumption 00200 NRF_UART0->TASKS_STOPRX = 1; 00201 00202 // Disable TWI by default. 00203 NRF_TWI0->ENABLE = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos; 00204 00205 { 00206 // init battery level 00207 const uint8_t batteryPercentage = BatteryLevel::readBatteryPercentage(batteryVoltage); 00208 HIDController::updateBatteryLevel(batteryPercentage, batteryVoltage * 1000); 00209 } 00210 00211 while (1) { 00212 if (pollCount > 0) { 00213 DEBUG_PRINTF("scan keys\r\n"); 00214 00215 while (pollCount-- > 0) { 00216 uint8_t (&keysCurr)[COLS] = state ? keysA : keysB; 00217 uint8_t (&keysPrev)[COLS] = state ? keysB : keysA; 00218 00219 NRF_TWI0->ENABLE = TWI_ENABLE_ENABLE_Enabled << TWI_ENABLE_ENABLE_Pos; 00220 keyboardMatrixController.scanKeyboard(keysCurr); 00221 NRF_TWI0->ENABLE = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos; 00222 00223 bool queue = false; 00224 00225 for (int col = 0; col < COLS; col++) { 00226 const uint8_t changed = keysPrev[col] ^ keysCurr[col]; 00227 if (changed) queue = true; 00228 for (int row = 0; row < ROWS; row++) { 00229 if (changed & (1<<row)) { 00230 bool pressed = keysCurr[col] & (1<<row); 00231 // DEBUG_KEYEVENT("changed: col=%d, row=%d / pressed=%d\r\n", col, row, pressed); 00232 keymap.execute(row, col, pressed); 00233 } 00234 } 00235 } 00236 state = !state; 00237 00238 if (HIDController::status() == DISCONNECTED || 00239 HIDController::status() == TIMEOUT) { 00240 00241 if ( 00242 is_pressed(keysCurr, 0, 0) && // left top 1 00243 is_pressed(keysCurr, 1, 0) && // left top 2 00244 is_pressed(keysCurr, 0, 15) // right top 00245 ) { 00246 DEBUG_PRINTF("re-init connection\r\n"); 00247 HIDController::initializeConnection(true); 00248 } else { 00249 if (HIDController::status() == TIMEOUT) { 00250 DEBUG_PRINTF("wakeup\r\n"); 00251 HIDController::initializeConnection(false); 00252 } 00253 } 00254 } 00255 00256 if (queue) HIDController::queueCurrentReportData(); 00257 00258 // use timer to use wait 5ms 00259 timeout.detach(); 00260 keyIntervalInterrupt = false; 00261 timeout.attach_us(wakeupKeyIntervalSleep, 5000); 00262 while (!keyIntervalInterrupt) HIDController::waitForEvent(); 00263 } 00264 } else { 00265 if (!updateStatudLedEnabled) updateStatusLed(); 00266 00267 if (shouldUpdateBatteryLevel) { 00268 shouldUpdateBatteryLevel = false; 00269 float batteryVoltage = BatteryLevel::readBatteryVoltage(); 00270 const uint8_t batteryPercentage = BatteryLevel::readBatteryPercentage(batteryVoltage); 00271 const bool isLowBattery = batteryVoltage < BatteryLevel::BATTERY_LOW; 00272 00273 HIDController::updateBatteryLevel(batteryPercentage, batteryVoltage * 1000); 00274 00275 if (isLowBattery) { 00276 DEBUG_PRINTF("LOWBAT %f %d%%", batteryVoltage, batteryPercentage); 00277 powerOff(); 00278 } 00279 } 00280 00281 if (HIDController::status() == DISCONNECTED) { 00282 HIDController::initializeConnection(false); 00283 } 00284 00285 DEBUG_PRINTF("WFE [%d:%s]\r\n", 00286 HIDController::status(), 00287 HIDController::statusString() 00288 ); 00289 00290 if (!updateStatudLedEnabled) { 00291 timeout.detach(); 00292 timeout.attach(wakeupIgnoreLongSleep, 60); 00293 } 00294 HIDController::waitForEvent(); 00295 } 00296 } 00297 }
Generated on Tue Jul 12 2022 14:16:48 by 1.7.2