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

Dependencies:   BLE_API mbed nRF51822 BufferedSerial

Committer:
ansond
Date:
Fri Sep 26 02:36:25 2014 +0000
Revision:
1:e8d3536c7f99
Parent:
0:45e5a1daf7c0
switched to buffered serial

Who changed what in which revision?

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