Techcon 2014 BLE sample Police HRM (earbud-based) for Nordic

Dependencies:   BLE_API GroveEarbudSensor mbed nRF51822 BufferedSerial

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2013 ARM Limited
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 "mbed.h"
00018 #include "BLEDevice.h"
00019 #include "HeartRateService.h"
00020 
00021 // ********************* BEGIN Tunables for TechCon 2014
00022 
00023 // !!!!IMPORTANT!!!!  CHANGE DEVICE_NAME so that you can find *YOUR* Nordic board in the workshop on your phone!!
00024 const static char     DEVICE_NAME[]     = "Policeman #DOUG";                 // what we want to appear as in mBED device server
00025 
00026 #define HRM_INCREMENT                     10                                 // increment of HRM per button press (+/-)
00027 #define HRM_DEFAULT_INIT                  70                                 // default HRM (button only... earbud defaults to offline status)
00028 #define ENABLE_CONSOLE                    1                                  // 0 - no serial output, 1 - serial output
00029 
00030 #define HRM_MIN                           10                                 // min heartrate
00031 #define HRM_MAX                           250                                // max heartrate
00032 #define HRM_DEFAULT_INIT                  70                                 // initial heartrate (buttons only, earbud will default differently)
00033 
00034 
00035 // ********************* END Tunables for Techcon 2014
00036 
00037 volatile uint16_t     hrmCounter        = HRM_DEFAULT_INIT;                  // initial heartrate 
00038 int                   oldhrmCounter     = HRM_MAX+1;                         // tracker so that we only send when things change appropriately
00039 
00040 // Support for the Grove Ear-Clip Earbud 
00041 #define USE_EARBUD                        true                              // true - enable (pin P0_0),  false - disable (default) 
00042 
00043 // Globals
00044 BLEDevice  ble;
00045 DigitalOut led1(LED1);
00046 volatile bool connected = false;
00047 
00048 // Console allocation
00049 #if ENABLE_CONSOLE
00050     #include "BufferedSerial.h"
00051     BufferedSerial  pc(USBTX, USBRX);
00052     #define LOG_CONSOLE(...) { pc.printf(__VA_ARGS__); }
00053 #else
00054     #define LOG_CONSOLE(...)
00055 #endif 
00056 
00057 // Earbud allocation (or button usage)
00058 #if USE_EARBUD
00059     #include "GroveEarbudSensor.h"
00060     InterruptIn sensor(P0_0);
00061     GroveEarbudSensor earbud(&sensor,&pc);
00062 #else
00063     DigitalIn up(BUTTON1);
00064     DigitalIn down(BUTTON2);
00065 #endif
00066 
00067 // BLE Globals
00068 static const uint16_t uuid16_list[]        = {GattService::UUID_HEART_RATE_SERVICE};
00069 static volatile bool  triggerSensorPolling = false;
00070 
00071 // Disconnection callback
00072 void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason) {
00073     LOG_CONSOLE("Disconnected handle %u!\r\n", handle);
00074     LOG_CONSOLE("Restarting the advertising process\r\n");
00075     ble.startAdvertising();
00076     connected = false;
00077     oldhrmCounter = HRM_MAX+1;
00078 #if USE_EARBUD
00079     hrmCounter = HEARTRATE_OFF;
00080 #else
00081     hrmCounter = HRM_DEFAULT_INIT;
00082 #endif
00083 }
00084 
00085 // Connection callback
00086 void connectionCallback(Gap::Handle_t handle, Gap::addr_type_t peerAddrType, const Gap::address_t peerAddr, const Gap::ConnectionParams_t *params) {
00087     LOG_CONSOLE("Endpoint is connected!\r\n");
00088     connected = true;
00089 }
00090 
00091 // Periodic callback
00092 void periodicCallback(void) {
00093     led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */
00094 
00095     /* Note that the periodicCallback() executes in interrupt context, so it is safer to do
00096      * heavy-weight sensor polling from the main thread. */
00097     triggerSensorPolling = true;
00098 }
00099 
00100 #if USE_EARBUD
00101 // Heartrate callback (Earbud)
00102 void heartrateCallback(float heartrate,void *data) {
00103     hrmCounter = (int)heartrate;
00104 }
00105 #endif
00106 
00107 // main entry point
00108 int main(void) {
00109     bool do_loop = true;
00110     led1 = 1;
00111     Ticker ticker;
00112     ticker.attach(periodicCallback, 1);
00113 
00114 #if USE_EARBUD
00115     LOG_CONSOLE("\r\nmbed PoliceHRM (EARBUD) v1.0 (ARM Techcon 2014)\r\n");
00116 #else
00117     LOG_CONSOLE("\r\nmbed PoliceHRM (BUTTON) v1.0 (ARM Techcon 2014)\r\n");
00118 #endif
00119     ble.init();
00120     ble.onDisconnection(disconnectionCallback);
00121     ble.onConnection(connectionCallback);
00122 
00123     /* setup advertising */
00124     LOG_CONSOLE("Starting BLE Advertising...\r\n");
00125     ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
00126     ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
00127     ble.accumulateAdvertisingPayload(GapAdvertisingData::HEART_RATE_SENSOR_HEART_RATE_BELT);
00128     ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
00129     ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
00130     ble.setAdvertisingInterval(1600); /* 1000ms; in multiples of 0.625ms. */
00131     ble.startAdvertising();
00132 
00133 #if USE_EARBUD
00134     // initialize the earbud
00135     LOG_CONSOLE("Initializing Earbud...\r\n");
00136     hrmCounter = HEARTRATE_OFF;
00137     earbud.registerCallback(heartrateCallback);
00138 #endif
00139 
00140     // Start the HRM Service
00141     LOG_CONSOLE("Starting HRM Service...\r\n");
00142 #if !USE_EARBUD
00143     HeartRateService hrService(ble, hrmCounter, HeartRateService::LOCATION_WRIST);
00144 #else
00145     HeartRateService hrService(ble, hrmCounter, HeartRateService::LOCATION_EAR_LOBE);
00146 #endif
00147      
00148     // Loop
00149     LOG_CONSOLE("Entering main loop...\r\n");
00150     while (do_loop) {
00151         if (triggerSensorPolling) {
00152             triggerSensorPolling = false;
00153 
00154 #if !USE_EARBUD
00155             // see if either button was pressed and adjust the heartrate accordingly
00156             //LOG_CONSOLE("Updating HRM via button...\r\n");
00157             if (up) hrmCounter += HRM_INCREMENT;
00158             if (down) hrmCounter -= HRM_INCREMENT;
00159             
00160             // boundary checking
00161             if (hrmCounter <  0) hrmCounter = 0;
00162             else if (hrmCounter < HRM_MIN) hrmCounter = HRM_MIN;
00163             else if (hrmCounter > HRM_MAX) hrmCounter = HRM_MAX;
00164 #endif
00165 
00166             // update the heartrate service if it has changed
00167             if (hrmCounter != oldhrmCounter) {
00168                 LOG_CONSOLE("Updating HRM values...%d bpm\r\n",hrmCounter);
00169                 hrService.updateHeartRate(hrmCounter);
00170                 if (connected == true) oldhrmCounter = hrmCounter;
00171             }
00172         } else {
00173             ble.waitForEvent();
00174         }
00175     }
00176     
00177     // we have exited
00178     LOG_CONSOLE("Application exiting...\r\n");
00179 }