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

Dependencies:   BLE_API GroveEarbudSensor mbed nRF51822 BufferedSerial

Committer:
ansond
Date:
Thu Sep 25 22:19:56 2014 +0000
Revision:
0:aa970fb89a5c
Child:
1:34a767241de5
initial checkin

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ansond 0:aa970fb89a5c 1 /* mbed Microcontroller Library
ansond 0:aa970fb89a5c 2 * Copyright (c) 2006-2013 ARM Limited
ansond 0:aa970fb89a5c 3 *
ansond 0:aa970fb89a5c 4 * Licensed under the Apache License, Version 2.0 (the "License");
ansond 0:aa970fb89a5c 5 * you may not use this file except in compliance with the License.
ansond 0:aa970fb89a5c 6 * You may obtain a copy of the License at
ansond 0:aa970fb89a5c 7 *
ansond 0:aa970fb89a5c 8 * http://www.apache.org/licenses/LICENSE-2.0
ansond 0:aa970fb89a5c 9 *
ansond 0:aa970fb89a5c 10 * Unless required by applicable law or agreed to in writing, software
ansond 0:aa970fb89a5c 11 * distributed under the License is distributed on an "AS IS" BASIS,
ansond 0:aa970fb89a5c 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
ansond 0:aa970fb89a5c 13 * See the License for the specific language governing permissions and
ansond 0:aa970fb89a5c 14 * limitations under the License.
ansond 0:aa970fb89a5c 15 */
ansond 0:aa970fb89a5c 16
ansond 0:aa970fb89a5c 17 #include "mbed.h"
ansond 0:aa970fb89a5c 18 #include "BLEDevice.h"
ansond 0:aa970fb89a5c 19 #include "HeartRateService.h"
ansond 0:aa970fb89a5c 20
ansond 0:aa970fb89a5c 21 // ********************* BEGIN Tunables for TechCon 2014
ansond 0:aa970fb89a5c 22
ansond 0:aa970fb89a5c 23 // !!!!IMPORTANT!!!! CHANGE DEVICE_NAME so that you can find *YOUR* Nordic board in the workshop on your phone!!
ansond 0:aa970fb89a5c 24 const static char DEVICE_NAME[] = "Policeman #1234"; // what we want to appear as in mBED device server
ansond 0:aa970fb89a5c 25
ansond 0:aa970fb89a5c 26 #define HRM_INCREMENT 10 // increment of HRM per button press (+/-)
ansond 0:aa970fb89a5c 27 #define HRM_DEFAULT_INIT 70 // default HRM (button only... earbud defaults to offline status)
ansond 0:aa970fb89a5c 28 #define ENABLE_CONSOLE 1 // 0 - no serial output, 1 - serial output
ansond 0:aa970fb89a5c 29
ansond 0:aa970fb89a5c 30 #define HRM_MIN 10 // min heartrate
ansond 0:aa970fb89a5c 31 #define HRM_MAX 250 // max heartrate
ansond 0:aa970fb89a5c 32 #define HRM_DEFAULT_INIT 70 // initial heartrate (buttons only, earbud will default differently)
ansond 0:aa970fb89a5c 33
ansond 0:aa970fb89a5c 34
ansond 0:aa970fb89a5c 35 // ********************* END Tunables for Techcon 2014
ansond 0:aa970fb89a5c 36
ansond 0:aa970fb89a5c 37 volatile uint16_t hrmCounter = HRM_DEFAULT_INIT; // initial heartrate
ansond 0:aa970fb89a5c 38 int oldhrmCounter = HRM_MAX+1; // tracker so that we only send when things change appropriately
ansond 0:aa970fb89a5c 39
ansond 0:aa970fb89a5c 40 // Support for the Grove Ear-Clip Earbud
ansond 0:aa970fb89a5c 41 #define USE_EARBUD true // true - enable (pin P0_0), false - disable (default)
ansond 0:aa970fb89a5c 42
ansond 0:aa970fb89a5c 43 // Globals
ansond 0:aa970fb89a5c 44 BLEDevice ble;
ansond 0:aa970fb89a5c 45 DigitalOut led1(LED1);
ansond 0:aa970fb89a5c 46 volatile bool connected = false;
ansond 0:aa970fb89a5c 47
ansond 0:aa970fb89a5c 48 // Console allocation
ansond 0:aa970fb89a5c 49 #if ENABLE_CONSOLE
ansond 0:aa970fb89a5c 50 Serial pc(USBTX, USBRX);
ansond 0:aa970fb89a5c 51 #define LOG_CONSOLE(...) { pc.printf(__VA_ARGS__); }
ansond 0:aa970fb89a5c 52 #else
ansond 0:aa970fb89a5c 53 #define LOG_CONSOLE(...)
ansond 0:aa970fb89a5c 54 #endif
ansond 0:aa970fb89a5c 55
ansond 0:aa970fb89a5c 56 // Earbud allocation (or button usage)
ansond 0:aa970fb89a5c 57 #if USE_EARBUD
ansond 0:aa970fb89a5c 58 #include "GroveEarbudSensor.h"
ansond 0:aa970fb89a5c 59 InterruptIn sensor(P0_0);
ansond 0:aa970fb89a5c 60 GroveEarbudSensor earbud(&sensor,&pc);
ansond 0:aa970fb89a5c 61 #else
ansond 0:aa970fb89a5c 62 DigitalIn up(BUTTON1);
ansond 0:aa970fb89a5c 63 DigitalIn down(BUTTON2);
ansond 0:aa970fb89a5c 64 #endif
ansond 0:aa970fb89a5c 65
ansond 0:aa970fb89a5c 66 // BLE Globals
ansond 0:aa970fb89a5c 67 static const uint16_t uuid16_list[] = {GattService::UUID_HEART_RATE_SERVICE};
ansond 0:aa970fb89a5c 68 static volatile bool triggerSensorPolling = false;
ansond 0:aa970fb89a5c 69
ansond 0:aa970fb89a5c 70 // Disconnection callback
ansond 0:aa970fb89a5c 71 void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason) {
ansond 0:aa970fb89a5c 72 LOG_CONSOLE("Disconnected handle %u!\r\n", handle);
ansond 0:aa970fb89a5c 73 LOG_CONSOLE("Restarting the advertising process\r\n");
ansond 0:aa970fb89a5c 74 ble.startAdvertising();
ansond 0:aa970fb89a5c 75 connected = false;
ansond 0:aa970fb89a5c 76 oldhrmCounter = HRM_MAX+1;
ansond 0:aa970fb89a5c 77 #if USE_EARBUD
ansond 0:aa970fb89a5c 78 hrmCounter = HEARTRATE_OFF;
ansond 0:aa970fb89a5c 79 #else
ansond 0:aa970fb89a5c 80 hrmCounter = HRM_DEFAULT_INIT;
ansond 0:aa970fb89a5c 81 #endif
ansond 0:aa970fb89a5c 82 }
ansond 0:aa970fb89a5c 83
ansond 0:aa970fb89a5c 84 // Connection callback
ansond 0:aa970fb89a5c 85 void connectionCallback(Gap::Handle_t handle, const Gap::ConnectionParams_t *parms) {
ansond 0:aa970fb89a5c 86 LOG_CONSOLE("Endpoint is connected!\r\n");
ansond 0:aa970fb89a5c 87 connected = true;
ansond 0:aa970fb89a5c 88 }
ansond 0:aa970fb89a5c 89
ansond 0:aa970fb89a5c 90 // Periodic callback
ansond 0:aa970fb89a5c 91 void periodicCallback(void) {
ansond 0:aa970fb89a5c 92 led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */
ansond 0:aa970fb89a5c 93
ansond 0:aa970fb89a5c 94 /* Note that the periodicCallback() executes in interrupt context, so it is safer to do
ansond 0:aa970fb89a5c 95 * heavy-weight sensor polling from the main thread. */
ansond 0:aa970fb89a5c 96 triggerSensorPolling = true;
ansond 0:aa970fb89a5c 97 }
ansond 0:aa970fb89a5c 98
ansond 0:aa970fb89a5c 99 #if USE_EARBUD
ansond 0:aa970fb89a5c 100 // Heartrate callback (Earbud)
ansond 0:aa970fb89a5c 101 void heartrateCallback(float heartrate,void *data) {
ansond 0:aa970fb89a5c 102 hrmCounter = (int)heartrate;
ansond 0:aa970fb89a5c 103 }
ansond 0:aa970fb89a5c 104 #endif
ansond 0:aa970fb89a5c 105
ansond 0:aa970fb89a5c 106 // main entry point
ansond 0:aa970fb89a5c 107 int main(void) {
ansond 0:aa970fb89a5c 108 bool do_loop = true;
ansond 0:aa970fb89a5c 109 led1 = 1;
ansond 0:aa970fb89a5c 110 Ticker ticker;
ansond 0:aa970fb89a5c 111 ticker.attach(periodicCallback, 1);
ansond 0:aa970fb89a5c 112
ansond 0:aa970fb89a5c 113 #if USE_EARBUD
ansond 0:aa970fb89a5c 114 LOG_CONSOLE("\r\nmbed PoliceHRM (EARBUD) v1.0 (ARM Techcon 2014)\r\n");
ansond 0:aa970fb89a5c 115 #else
ansond 0:aa970fb89a5c 116 LOG_CONSOLE("\r\nmbed PoliceHRM (BUTTON) v1.0 (ARM Techcon 2014)\r\n");
ansond 0:aa970fb89a5c 117 #endif
ansond 0:aa970fb89a5c 118 ble.init();
ansond 0:aa970fb89a5c 119 ble.onDisconnection(disconnectionCallback);
ansond 0:aa970fb89a5c 120 ble.onConnection(connectionCallback);
ansond 0:aa970fb89a5c 121
ansond 0:aa970fb89a5c 122 /* setup advertising */
ansond 0:aa970fb89a5c 123 LOG_CONSOLE("Starting BLE Advertising...\r\n");
ansond 0:aa970fb89a5c 124 ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
ansond 0:aa970fb89a5c 125 ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
ansond 0:aa970fb89a5c 126 ble.accumulateAdvertisingPayload(GapAdvertisingData::HEART_RATE_SENSOR_HEART_RATE_BELT);
ansond 0:aa970fb89a5c 127 ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
ansond 0:aa970fb89a5c 128 ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
ansond 0:aa970fb89a5c 129 ble.setAdvertisingInterval(1600); /* 1000ms; in multiples of 0.625ms. */
ansond 0:aa970fb89a5c 130 ble.startAdvertising();
ansond 0:aa970fb89a5c 131
ansond 0:aa970fb89a5c 132 #if USE_EARBUD
ansond 0:aa970fb89a5c 133 // initialize the earbud
ansond 0:aa970fb89a5c 134 LOG_CONSOLE("Initializing Earbud...\r\n");
ansond 0:aa970fb89a5c 135 hrmCounter = HEARTRATE_OFF;
ansond 0:aa970fb89a5c 136 earbud.registerCallback(heartrateCallback);
ansond 0:aa970fb89a5c 137 #endif
ansond 0:aa970fb89a5c 138
ansond 0:aa970fb89a5c 139 // Start the HRM Service
ansond 0:aa970fb89a5c 140 LOG_CONSOLE("Starting HRM Service...\r\n");
ansond 0:aa970fb89a5c 141 #if !USE_EARBUD
ansond 0:aa970fb89a5c 142 HeartRateService hrService(ble, hrmCounter, HeartRateService::LOCATION_WRIST);
ansond 0:aa970fb89a5c 143 #else
ansond 0:aa970fb89a5c 144 HeartRateService hrService(ble, hrmCounter, HeartRateService::LOCATION_EAR_LOBE);
ansond 0:aa970fb89a5c 145 #endif
ansond 0:aa970fb89a5c 146
ansond 0:aa970fb89a5c 147 // Loop
ansond 0:aa970fb89a5c 148 LOG_CONSOLE("Entering main loop...\r\n");
ansond 0:aa970fb89a5c 149 while (do_loop) {
ansond 0:aa970fb89a5c 150 if (triggerSensorPolling) {
ansond 0:aa970fb89a5c 151 triggerSensorPolling = false;
ansond 0:aa970fb89a5c 152
ansond 0:aa970fb89a5c 153 #if !USE_EARBUD
ansond 0:aa970fb89a5c 154 // see if either button was pressed and adjust the heartrate accordingly
ansond 0:aa970fb89a5c 155 //LOG_CONSOLE("Updating HRM via button...\r\n");
ansond 0:aa970fb89a5c 156 if (up) hrmCounter += HRM_INCREMENT;
ansond 0:aa970fb89a5c 157 if (down) hrmCounter -= HRM_INCREMENT;
ansond 0:aa970fb89a5c 158
ansond 0:aa970fb89a5c 159 // boundary checking
ansond 0:aa970fb89a5c 160 if (hrmCounter < 0) hrmCounter = 0;
ansond 0:aa970fb89a5c 161 else if (hrmCounter < HRM_MIN) hrmCounter = HRM_MIN;
ansond 0:aa970fb89a5c 162 else if (hrmCounter > HRM_MAX) hrmCounter = HRM_MAX;
ansond 0:aa970fb89a5c 163 #endif
ansond 0:aa970fb89a5c 164
ansond 0:aa970fb89a5c 165 // update the heartrate service if it has changed
ansond 0:aa970fb89a5c 166 if (hrmCounter != oldhrmCounter) {
ansond 0:aa970fb89a5c 167 LOG_CONSOLE("Updating HRM values...%d bpm\r\n",hrmCounter);
ansond 0:aa970fb89a5c 168 hrService.updateHeartRate(hrmCounter);
ansond 0:aa970fb89a5c 169 if (connected == true) oldhrmCounter = hrmCounter;
ansond 0:aa970fb89a5c 170 }
ansond 0:aa970fb89a5c 171 } else {
ansond 0:aa970fb89a5c 172 ble.waitForEvent();
ansond 0:aa970fb89a5c 173 }
ansond 0:aa970fb89a5c 174 }
ansond 0:aa970fb89a5c 175
ansond 0:aa970fb89a5c 176 // we have exited
ansond 0:aa970fb89a5c 177 LOG_CONSOLE("Application exiting...\r\n");
ansond 0:aa970fb89a5c 178 }