Shervin Emami / Mbed 2 deprecated Shervs_TestMouse_TinyBLE

Dependencies:   BLE_API BLE_HID mbed nRF51822

Fork of BLENano_HID by Yuuichi Akagawa

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /**
00002  * Handheld BLE finger input device based on Seeed Studio Tiny BLE (TinyBLE).
00003  * By Shervin Emami (http://shervinemami.info/), 25th Aug 2018.
00004  * If the analog voltage on a "finger" pin is below a threshold voltage,
00005  * then it sends a mouse command using Bluetooth BLE, 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 
00031 const float FINGER1_PRESS = 0.42f;   // Set how much the person needs to press their finger in to trigger a keypress.
00032 const float FINGER2_PRESS = 0.41f;   // Note that each finger is slightly different strength, due to the mechanical design.
00033 const float FINGER3_PRESS = 0.38f;   //
00034 const float FINGER4_PRESS = 0.37f;   //
00035 
00036 const float FINGER1_RELEASE = 0.35f;   // Set how much the person needs to release their finger to finish a keypress.
00037 const float FINGER2_RELEASE = 0.35f;   // Note that each finger is slightly different strength, due to the mechanical design.
00038 const float FINGER3_RELEASE = 0.34f;   //
00039 const float FINGER4_RELEASE = 0.34f;   //
00040 
00041 const float BATTERY_NEEDS_CHARGE = 0.198f;  // 0.20 means >= 3.4V, 0.19 means >= 2.4V.
00042 
00043  
00044 /* mbed Microcontroller Library
00045  * Copyright (c) 2015 ARM Limited
00046  *
00047  * Licensed under the Apache License, Version 2.0 (the "License");
00048  * you may not use this file except in compliance with the License.
00049  * You may obtain a copy of the License at
00050  *
00051  *     http://www.apache.org/licenses/LICENSE-2.0
00052  *
00053  * Unless required by applicable law or agreed to in writing, software
00054  * distributed under the License is distributed on an "AS IS" BASIS,
00055  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00056  * See the License for the specific language governing permissions and
00057  * limitations under the License.
00058  */
00059  
00060 #include "mbed.h"
00061  
00062 #include "ble/BLE.h"
00063 //#include "KeyboardService.h"
00064 #include "MouseService.h"
00065 
00066  
00067 #include "examples_common.h"
00068 
00069 
00070 
00071 #undef HID_DEBUG
00072 #undef LOG
00073 #ifdef LOG_MESSAGES
00074     #define LOG(...)    { pc.printf(__VA_ARGS__); }
00075     Serial pc(UART_TX, UART_RX);
00076 #else
00077     #define LOG(...)
00078 #endif
00079 #define HID_DEBUG   LOG
00080 
00081 
00082 AnalogIn    battery(BATTERY_PIN);   // For measuring the battery level
00083 AnalogIn    finger1(FINGER1_PIN);   // For measuring a finger level
00084 AnalogIn    finger2(FINGER2_PIN);   //
00085 AnalogIn    finger3(FINGER3_PIN);   //
00086 AnalogIn    finger4(FINGER4_PIN);   //
00087 DigitalOut waiting_led(LED_RED);      // For showing BLE is trying to connect
00088 DigitalOut connected_led(LED_GREEN);  // For showing BLE is connected
00089 DigitalOut status_led(LED_BLUE);      // For showing BLE is busy
00090 DigitalOut enable_out3v3(OUT3V3_PIN); // For using OUT_3V3 pin of TinyBLE
00091 
00092 #define LED_ON   0      // LEDs on Tiny BLE need 0V to light up.
00093 #define LED_OFF  1      //
00094 
00095 
00096 bool haveAskedForRecharge = false;  // Only ask for a recharge once per poweron. Requires user to turn device off once per day!
00097 
00098 
00099 InterruptIn button1(BUTTON_PIN);    // For sending a BLE command
00100  
00101 BLE ble;
00102 //KeyboardService *kbdServicePtr;
00103 MouseService *mouseServicePtr;
00104  
00105 static const char DEVICE_NAME[] = "ShervMouse";
00106 static const char SHORT_DEVICE_NAME[] = "ShMouse";
00107 
00108 
00109 // Status flags that are updated in ISR callback functions.
00110 volatile bool check_fingers = false;
00111 volatile bool press_keyup[5] = {false};
00112 
00113 
00114 
00115 static void onDisconnect(const Gap::DisconnectionCallbackParams_t *params)
00116 {
00117     HID_DEBUG("discon\n\r");
00118     waiting_led = LED_ON;
00119     connected_led = LED_OFF;
00120  
00121     ble.gap().startAdvertising(); // restart advertising
00122 }
00123  
00124 static void onConnect(const Gap::ConnectionCallbackParams_t *params)
00125 {
00126     HID_DEBUG("conn\n\r");
00127     waiting_led = LED_OFF;
00128     connected_led = LED_ON;
00129 }
00130 
00131 
00132 
00133 
00134 
00135 // ISR callback function that is automatically called every 0.1 seconds or so.
00136 // Make sure there isn't anything slow like printf in this ISR!
00137 static void heartbeat_ISR() {
00138     if (!mouseServicePtr->isConnected())
00139         waiting_led = !waiting_led;
00140     else {
00141         //connected_led = !connected_led;
00142         //waiting_led = 0;
00143     }
00144 
00145     // Signal that we should check the finger sensors soon.
00146     check_fingers = true;
00147 }
00148  
00149  
00150 int main()
00151 {
00152 #ifdef LOG_MESSAGES
00153     pc.baud(115200);  // Use fast UART for log messages instead of default 9600 bps.
00154 #endif
00155     
00156     waiting_led = LED_OFF;    // Set LEDs to blue, until ready.
00157     connected_led = LED_OFF;
00158     status_led = LED_ON;
00159     
00160     wait(1);    
00161     LOG("---- Shervin's Mouse Input device, using TinyBLE + BLE HID mouse service ----\n\r");
00162 
00163     // Call the button1_ISR function whenever the pushbutton is pressed.
00164     //button1.rise(button1_ISR);
00165  
00166     HID_DEBUG("initialising ticker\n\r");
00167 
00168     // Call the heartbeat_ISR function every 0.1 seconds 
00169     Ticker heartbeat;
00170     heartbeat.attach(heartbeat_ISR, 0.1f);
00171 
00172     HID_DEBUG("enabling finger sensors\n\r");
00173     enable_out3v3 = 1;
00174  
00175     HID_DEBUG("initialising ble\n\r");
00176     ble.init();
00177  
00178     ble.gap().onDisconnection(onDisconnect);
00179     ble.gap().onConnection(onConnect);
00180  
00181     initializeSecurity(ble);
00182  
00183     HID_DEBUG("adding hid mouse service\n\r");
00184     MouseService mouseService(ble);
00185     mouseServicePtr = &mouseService;
00186  
00187     HID_DEBUG("adding device info and battery service\n\r");
00188     initializeHOGP(ble);
00189  
00190     HID_DEBUG("setting up gap\n\r");
00191     ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::MOUSE);
00192     ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME,
00193                                            (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
00194     ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,
00195                                            (uint8_t *)SHORT_DEVICE_NAME, sizeof(SHORT_DEVICE_NAME));
00196  
00197     HID_DEBUG("advertising\n\r");
00198     ble.gap().startAdvertising();
00199 
00200     // Turn LEDs to green connected.
00201     connected_led = LED_ON;
00202     waiting_led = LED_OFF;
00203     status_led = LED_OFF;
00204 
00205     // Run forever ...
00206     LOG("Ready to run forever ...\n\r");
00207     int counter1 = 0; 
00208     int counter2 = 0; 
00209     while (true) {
00210         ble.waitForEvent();
00211         
00212         // Signal that we should check the finger sensors soon.
00213         if (check_fingers) {
00214             check_fingers = false;
00215 
00216             // Measure all the finger sensors and battery level.
00217             float fing1 = finger1.read();
00218             float fing2 = finger2.read();
00219             float fing3 = finger3.read();
00220             float fing4 = finger4.read();
00221             float batt = battery.read();
00222             
00223             // If a finger was pressed and now has been released, possibly send another event.
00224             if (press_keyup[1] && fing1 < FINGER1_RELEASE) {
00225                 press_keyup[1] = false;    // Clear the flag
00226                 LOG("key up for 1.\n\r");
00227                 
00228                 // Nothing needs to be done for releasing a mouse click.
00229             }
00230             if (press_keyup[2] && fing2 < FINGER2_RELEASE) {
00231                 press_keyup[2] = false;    // Clear the flag
00232                 LOG("key up for 2.\n\r");
00233 
00234                 // Nothing needs to be done for releasing a mouse click.
00235             }
00236             if (press_keyup[3] && fing3 < FINGER3_RELEASE) {
00237                 press_keyup[3] = false;    // Clear the flag
00238                 LOG("key up for 3.\n\r");
00239 
00240                 // Stop the scrolling.
00241                 mouseServicePtr->setSpeed(0, 0, 0);
00242             }
00243             if (press_keyup[4] && fing4 < FINGER4_RELEASE) {
00244                 press_keyup[4] = false;    // Clear the flag
00245                 LOG("key up for 4.\n\r");
00246 
00247                 // Stop the scrolling.
00248                 mouseServicePtr->setSpeed(0, 0, 0);
00249             }
00250             
00251 
00252             // Very occasionally, show the connected LED
00253             counter1++;
00254             if (counter1 == 1) {
00255                 if (mouseServicePtr->isConnected()) {
00256                     connected_led = LED_ON;
00257                     waiting_led = LED_OFF;
00258                 }
00259             }
00260             if (counter1 == 2) {
00261                 //counter2 = 0;
00262                 connected_led = LED_OFF;
00263                 waiting_led = LED_OFF;
00264             }
00265             
00266 
00267             // Occasionally show some debug info
00268             if (counter1 > 15) {
00269                 //counter2++;
00270                 LOG("%.2f%. F1=%.2f, F2=%.2f, F3=%.2f, F4=%.2f\n\r", batt, fing1, fing2, fing3, fing4);
00271 
00272                 // Check for low battery
00273                 if (batt < BATTERY_NEEDS_CHARGE) {
00274                     // Toggle blue LED
00275                     waiting_led = LED_OFF;
00276                     connected_led = LED_OFF;
00277                     status_led = !status_led;
00278                     if (!haveAskedForRecharge) {
00279                         //send_string("RECHARGE BATTERY!");
00280                         haveAskedForRecharge = true;
00281                     }
00282                     LOG("RECHARGE BATTERY!\n\r");
00283                 }
00284                 //else {
00285                 //}
00286                 counter1 = 0;
00287             }
00288             
00289             // Check if a finger was pressed
00290             if (fing1 > FINGER1_PRESS && !press_keyup[1]) {
00291                 LOG("finger 1.\n\r");
00292                 press_keyup[1] = true; // Don't trigger this event again until the finger has been released.
00293                 
00294                 mouseServicePtr->setButton(MOUSE_BUTTON_LEFT, BUTTON_DOWN);
00295                 wait(0.05);         // Add a slight delay
00296                 ble.waitForEvent(); // Add a slight delay
00297                 mouseServicePtr->setButton(MOUSE_BUTTON_LEFT, BUTTON_UP);
00298             }
00299             if (fing2 > FINGER2_PRESS && !press_keyup[2]) {
00300                 LOG("finger 2.\n\r");
00301                 press_keyup[2] = true; // Don't trigger this event again until the finger has been released.
00302                 
00303                 mouseServicePtr->setButton(MOUSE_BUTTON_RIGHT, BUTTON_DOWN);
00304                 wait(0.05);         // Add a slight delay
00305                 ble.waitForEvent(); // Add a slight delay
00306                 mouseServicePtr->setButton(MOUSE_BUTTON_RIGHT, BUTTON_UP);
00307             }
00308             if (fing3 > FINGER3_PRESS && !press_keyup[3]) {
00309                 LOG("finger 3.\n\r");
00310                 press_keyup[3] = true; // Don't trigger this event again until the finger has been released.
00311 
00312                 // Start scrolling down, until the user releases this finger.
00313                 mouseServicePtr->setSpeed(0, 0, 1);
00314             }
00315             if (fing4 > FINGER4_PRESS && !press_keyup[4]) {
00316                 LOG("finger 4.\n\r");
00317                 press_keyup[4] = true; // Don't trigger this event again until the finger has been released.
00318 
00319                 // Start scrolling up, until the user releases this finger.
00320                 mouseServicePtr->setSpeed(0, 0, -1);                
00321             }
00322         }
00323     }
00324 }