Bluetooth BLE HID Keyboard for the AlterErgo device, based on Seeed Studio Tiny BLE.
Dependencies: BLE_API BLE_HID mbed nRF51822
Fork of BLENano_HID by
main.cpp
00001 /** 00002 * Handheld BLE finger input device based on Seeed Studio Tiny BLE (TinyBLE). 00003 * By Shervin Emami (http://shervinemami.info/), Apr 2018. 00004 * If the analog voltage on a "finger" pin is below a threshold voltage, 00005 * then it sends a rare keypress using Bluetooth, so that any computer or 00006 * smartphone can be configured to perform a desired function due to this input event. 00007 * 00008 * 00009 * This program implements a complete HID-over-Gatt Profile: 00010 * - HID is provided by KeyboardService 00011 * - Battery Service 00012 * - Device Information Service 00013 * 00014 * Complete strings can be sent over BLE using printf. Please note, however, than a 12char string 00015 * will take about 500ms to transmit, principally because of the limited notification rate in BLE. 00016 * KeyboardService uses a circular buffer to store the strings to send, and calls to putc will fail 00017 * once this buffer is full. This will result in partial strings being sent to the client. 00018 00019 * Tested with mbed libraries for April 2nd, 2018. If you use a newer version of mbed or other 00020 * libs and you have problems, try rolling back to April 2nd, 2018. 00021 */ 00022 00023 // Configure the settings of my board. 00024 #include "tiny_ble.h" // Seeed Studio Tiny BLE 00025 00026 00027 // Define LOG_MESSAGES if you want various debug messages to be sent to the PC via a UART cable. 00028 #define LOG_MESSAGES 00029 00030 // Various USB Keyboard keycodes that we can send. 00031 #define KEYCODE_F4 131 00032 #define KEYCODE_F5 132 00033 #define KEYCODE_F6 133 00034 #define KEYCODE_F7 134 00035 #define KEYCODE_F8 135 00036 #define KEYCODE_F9 136 00037 #define KEYCODE_F10 137 00038 #define KEYCODE_F11 138 00039 #define KEYCODE_F12 139 00040 #define KEYCODE_HOME 145 00041 #define KEYCODE_PAGEUP 146 00042 #define KEYCODE_PAGEDOWN 147 00043 #define KEYCODE_RIGHT 148 00044 #define KEYCODE_LEFT 149 00045 #define KEYCODE_DOWN 150 00046 #define KEYCODE_UP 151 00047 #define KEYCODE_ESCAPE 157 00048 #define KEYCODE_RIGHTCLK 188 00049 #define KEYCODE_ACCENT 96 00050 #define KEYCODE_NUMLOCK 193 00051 00052 00053 00054 00055 const int FING1_KEYCODE = KEYCODE_F8; // Set the keypress that will be sent over bluetooth. 00056 const int FING2DOWN_KEYCODE = KEYCODE_F4; // 00057 const int FING2UP_KEYCODE = KEYCODE_NUMLOCK; 00058 const int FING3_KEYCODE = KEYCODE_UP; // 00059 const int FING4_KEYCODE = KEYCODE_DOWN; // 00060 00061 const float FINGER1_PRESS = 0.42f; // Set how much the person needs to press their finger in to trigger a keypress. 00062 const float FINGER2_PRESS = 0.41f; // Note that each finger is slightly different strength, due to the mechanical design. 00063 const float FINGER3_PRESS = 0.38f; // 00064 const float FINGER4_PRESS = 0.37f; // 00065 00066 const float FINGER1_RELEASE = 0.35f; // Set how much the person needs to release their finger to finish a keypress. 00067 const float FINGER2_RELEASE = 0.35f; // Note that each finger is slightly different strength, due to the mechanical design. 00068 const float FINGER3_RELEASE = 0.34f; // 00069 const float FINGER4_RELEASE = 0.34f; // 00070 00071 const float BATTERY_NEEDS_CHARGE = 0.198f; // 0.20 means >= 3.4V, 0.19 means >= 2.4V. 00072 00073 00074 /* mbed Microcontroller Library 00075 * Copyright (c) 2015 ARM Limited 00076 * 00077 * Licensed under the Apache License, Version 2.0 (the "License"); 00078 * you may not use this file except in compliance with the License. 00079 * You may obtain a copy of the License at 00080 * 00081 * http://www.apache.org/licenses/LICENSE-2.0 00082 * 00083 * Unless required by applicable law or agreed to in writing, software 00084 * distributed under the License is distributed on an "AS IS" BASIS, 00085 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00086 * See the License for the specific language governing permissions and 00087 * limitations under the License. 00088 */ 00089 00090 #include "mbed.h" 00091 00092 #include "ble/BLE.h" 00093 #include "KeyboardService.h" 00094 00095 #include "examples_common.h" 00096 00097 00098 00099 #undef HID_DEBUG 00100 #undef LOG 00101 #ifdef LOG_MESSAGES 00102 #define LOG(...) { pc.printf(__VA_ARGS__); } 00103 Serial pc(UART_TX, UART_RX); 00104 #else 00105 #define LOG(...) 00106 #endif 00107 #define HID_DEBUG LOG 00108 00109 00110 AnalogIn battery(BATTERY_PIN); // For measuring the battery level 00111 AnalogIn finger1(FINGER1_PIN); // For measuring a finger level 00112 AnalogIn finger2(FINGER2_PIN); // 00113 AnalogIn finger3(FINGER3_PIN); // 00114 AnalogIn finger4(FINGER4_PIN); // 00115 DigitalOut waiting_led(LED_RED); // For showing BLE is trying to connect 00116 DigitalOut connected_led(LED_GREEN); // For showing BLE is connected 00117 DigitalOut status_led(LED_BLUE); // For showing BLE is busy 00118 DigitalOut enable_out3v3(OUT3V3_PIN); // For using OUT_3V3 pin of TinyBLE 00119 00120 #define LED_ON 0 // LEDs on Tiny BLE need 0V to light up. 00121 #define LED_OFF 1 // 00122 00123 00124 bool haveAskedForRecharge = false; // Only ask for a recharge once per poweron. Requires user to turn device off once per day! 00125 00126 00127 InterruptIn button1(BUTTON_PIN); // For sending a BLE command 00128 00129 BLE ble; 00130 KeyboardService *kbdServicePtr; 00131 00132 static const char DEVICE_NAME[] = "ShervFingerControl"; 00133 static const char SHORT_DEVICE_NAME[] = "ShFingerCtl"; 00134 00135 00136 // Status flags that are updated in ISR callback functions. 00137 volatile bool check_fingers = false; 00138 volatile bool press_keyup[5] = {false}; 00139 00140 00141 00142 static void onDisconnect(const Gap::DisconnectionCallbackParams_t *params) 00143 { 00144 HID_DEBUG("discon\n\r"); 00145 waiting_led = LED_ON; 00146 connected_led = LED_OFF; 00147 00148 ble.gap().startAdvertising(); // restart advertising 00149 } 00150 00151 static void onConnect(const Gap::ConnectionCallbackParams_t *params) 00152 { 00153 HID_DEBUG("conn\n\r"); 00154 waiting_led = LED_OFF; 00155 connected_led = LED_ON; 00156 } 00157 00158 00159 00160 void send_keypress(int keycode, int finger) { 00161 if (!kbdServicePtr) 00162 return; 00163 00164 if (!kbdServicePtr->isConnected()) { 00165 HID_DEBUG("no conn yet\n\r"); 00166 } else { 00167 //LOG("send_keypress(%d, %d)\n\r", keycode, finger); 00168 kbdServicePtr->keyDownCode(keycode, 0); 00169 press_keyup[finger] = true; 00170 00171 } 00172 } 00173 00174 void send_string(const char * c) { 00175 if (!kbdServicePtr) 00176 return; 00177 00178 if (!kbdServicePtr->isConnected()) { 00179 HID_DEBUG("no conn yet\n\r"); 00180 } else { 00181 int len = strlen(c); 00182 kbdServicePtr->printf(c); 00183 HID_DEBUG("sending %d chars\n\r", len); 00184 } 00185 } 00186 00187 00188 // Call the button1_ISR function whenever the pushbutton is pressed. 00189 // Make sure there isn't anything slow like printf in this ISR! 00190 void button1_ISR() { 00191 send_string("x\n"); 00192 } 00193 00194 00195 // ISR callback function that is automatically called every 0.1 seconds or so. 00196 // Make sure there isn't anything slow like printf in this ISR! 00197 static void heartbeat_ISR() { 00198 if (!kbdServicePtr->isConnected()) 00199 waiting_led = !waiting_led; 00200 else { 00201 //connected_led = !connected_led; 00202 //waiting_led = 0; 00203 } 00204 00205 // Signal that we should check the finger sensors soon. 00206 check_fingers = true; 00207 } 00208 00209 00210 int main() 00211 { 00212 #ifdef LOG_MESSAGES 00213 pc.baud(115200); // Use fast UART for log messages instead of default 9600 bps. 00214 #endif 00215 00216 waiting_led = LED_OFF; // Set LEDs to blue, until ready. 00217 connected_led = LED_OFF; 00218 status_led = LED_ON; 00219 00220 wait(1); 00221 LOG("---- Shervin's Finger Input device, using TinyBLE + BLE HID keyboard service ----\n\r"); 00222 00223 // Call the button1_ISR function whenever the pushbutton is pressed. 00224 button1.rise(button1_ISR); 00225 00226 HID_DEBUG("initialising ticker\n\r"); 00227 00228 // Call the heartbeat_ISR function every 0.1 seconds 00229 Ticker heartbeat; 00230 heartbeat.attach(heartbeat_ISR, 0.1f); 00231 00232 HID_DEBUG("enabling finger sensors\n\r"); 00233 enable_out3v3 = 1; 00234 00235 HID_DEBUG("initialising ble\n\r"); 00236 ble.init(); 00237 00238 ble.gap().onDisconnection(onDisconnect); 00239 ble.gap().onConnection(onConnect); 00240 00241 initializeSecurity(ble); 00242 00243 HID_DEBUG("adding hid service\n\r"); 00244 KeyboardService kbdService(ble); 00245 kbdServicePtr = &kbdService; 00246 00247 HID_DEBUG("adding device info and battery service\n\r"); 00248 initializeHOGP(ble); 00249 00250 HID_DEBUG("setting up gap\n\r"); 00251 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::KEYBOARD); 00252 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, 00253 (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); 00254 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME, 00255 (uint8_t *)SHORT_DEVICE_NAME, sizeof(SHORT_DEVICE_NAME)); 00256 00257 HID_DEBUG("advertising\n\r"); 00258 ble.gap().startAdvertising(); 00259 00260 // Turn LEDs to green connected. 00261 connected_led = LED_ON; 00262 waiting_led = LED_OFF; 00263 status_led = LED_OFF; 00264 00265 // Run forever ... 00266 int counter1 = 0; 00267 int counter2 = 0; 00268 while (true) { 00269 ble.waitForEvent(); 00270 00271 // Signal that we should check the finger sensors soon. 00272 if (check_fingers) { 00273 check_fingers = false; 00274 00275 // Measure all the finger sensors and battery level. 00276 float fing1 = finger1.read(); 00277 float fing2 = finger2.read(); 00278 float fing3 = finger3.read(); 00279 float fing4 = finger4.read(); 00280 float batt = battery.read(); 00281 00282 // If a finger was pressed and now has been released, send the keyUp event soon after. 00283 if (press_keyup[1] && fing1 < FINGER1_RELEASE) { 00284 press_keyup[1] = false; // Clear the flag 00285 kbdServicePtr->keyUpCode(); 00286 HID_DEBUG("sent key up for 1.\n\r"); 00287 } 00288 if (press_keyup[2] && fing2 < FINGER2_RELEASE) { 00289 press_keyup[2] = false; // Clear the flag 00290 send_keypress(FING2UP_KEYCODE, 2); 00291 HID_DEBUG("sent final key down for 2.\n\r"); 00292 ble.waitForEvent(); // Add a slight delay 00293 //wait(0.1); // Add a slight delay 00294 //ble.waitForEvent(); // Add a slight delay 00295 kbdServicePtr->keyUpCode(); 00296 HID_DEBUG("sent final key up for 2.\n\r"); 00297 press_keyup[2] = false; // Clear the flag 00298 } 00299 if (press_keyup[3] && fing3 < FINGER3_RELEASE) { 00300 press_keyup[3] = false; // Clear the flag 00301 kbdServicePtr->keyUpCode(); 00302 HID_DEBUG("sent key up for 3.\n\r"); 00303 } 00304 if (press_keyup[4] && fing4 < FINGER4_RELEASE) { 00305 press_keyup[4] = false; // Clear the flag 00306 kbdServicePtr->keyUpCode(); 00307 HID_DEBUG("sent key up for 4.\n\r"); 00308 } 00309 00310 00311 // Very occasionally, show the connected LED 00312 counter1++; 00313 if (counter1 == 1) { 00314 if (kbdServicePtr->isConnected()) { 00315 connected_led = LED_ON; 00316 waiting_led = LED_OFF; 00317 } 00318 } 00319 if (counter1 == 2) { 00320 //counter2 = 0; 00321 connected_led = LED_OFF; 00322 waiting_led = LED_OFF; 00323 } 00324 00325 00326 // Occasionally show some debug info 00327 if (counter1 > 15) { 00328 //counter2++; 00329 LOG("%.2f%. F1=%.2f, F2=%.2f, F3=%.2f, F4=%.2f\n\r", batt, fing1, fing2, fing3, fing4); 00330 00331 // Check for low battery 00332 if (batt < BATTERY_NEEDS_CHARGE) { 00333 // Toggle blue LED 00334 waiting_led = LED_OFF; 00335 connected_led = LED_OFF; 00336 status_led = !status_led; 00337 if (!haveAskedForRecharge) { 00338 send_string("RECHARGE BATTERY!"); 00339 haveAskedForRecharge = true; 00340 } 00341 LOG("RECHARGE BATTERY!\n\r"); 00342 } 00343 //else { 00344 //} 00345 counter1 = 0; 00346 } 00347 00348 // Check if a finger was pressed 00349 if (fing1 > FINGER1_PRESS && !press_keyup[1]) { 00350 send_keypress(FING1_KEYCODE, 1); 00351 HID_DEBUG("sent keypress %d for 1.\n\r", FING1_KEYCODE); 00352 //counter2+=20; 00353 //LOG("%d\n\r", counter2); 00354 } 00355 if (fing2 > FINGER2_PRESS && !press_keyup[2]) { 00356 send_keypress(FING2DOWN_KEYCODE, 2); 00357 HID_DEBUG("sent keypress %d for 2.\n\r", FING2DOWN_KEYCODE); 00358 // Finger 2 is treated differently. We want to be able to hold down finger 2 00359 // Without causing repeated keystrokes, so we will send an up press straight after the down press, 00360 // and a different key down and up when the fingure is released, so the client software can 00361 // figure out the duration that it was held for. 00362 ble.waitForEvent(); // Add a slight delay 00363 //wait(0.1); // Add a slight delay 00364 //ble.waitForEvent(); // Add a slight delay 00365 kbdServicePtr->keyUpCode(); 00366 HID_DEBUG("sent initial key up for 2.\n\r"); 00367 } 00368 if (fing3 > FINGER3_PRESS && !press_keyup[3]) { 00369 send_keypress(FING3_KEYCODE, 3); 00370 HID_DEBUG("sent keypress %d for 3.\n\r", FING3_KEYCODE); 00371 //counter2++; 00372 //send_keypress(counter2, 3); 00373 //LOG("%d\n\r", counter2); 00374 } 00375 if (fing4 > FINGER4_PRESS && !press_keyup[4]) { 00376 send_keypress(FING4_KEYCODE, 4); 00377 HID_DEBUG("sent keypress %d for 4.\n\r", FING4_KEYCODE); 00378 //counter2--; 00379 //send_keypress(counter2, 4); 00380 //LOG("%d\n\r", counter2); 00381 00382 } 00383 } 00384 } 00385 }
Generated on Sun Jul 17 2022 01:10:54 by 1.7.2