I've got some basic filter code setup (but not yet tested).

Dependencies:   BLE_API Queue mbed nRF51822

Fork of BLE_HeartRate by Bluetooth Low Energy

Committer:
roysandberg
Date:
Sun Jun 28 03:06:00 2015 +0000
Revision:
62:8e2fbe131b53
Parent:
61:1de72bdab0ef
Working Beat Detection and Analysis

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ktownsend 0:87a7fc231fae 1 /* mbed Microcontroller Library
ktownsend 0:87a7fc231fae 2 * Copyright (c) 2006-2013 ARM Limited
ktownsend 0:87a7fc231fae 3 *
ktownsend 0:87a7fc231fae 4 * Licensed under the Apache License, Version 2.0 (the "License");
ktownsend 0:87a7fc231fae 5 * you may not use this file except in compliance with the License.
ktownsend 0:87a7fc231fae 6 * You may obtain a copy of the License at
ktownsend 0:87a7fc231fae 7 *
ktownsend 0:87a7fc231fae 8 * http://www.apache.org/licenses/LICENSE-2.0
ktownsend 0:87a7fc231fae 9 *
ktownsend 0:87a7fc231fae 10 * Unless required by applicable law or agreed to in writing, software
ktownsend 0:87a7fc231fae 11 * distributed under the License is distributed on an "AS IS" BASIS,
ktownsend 0:87a7fc231fae 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
ktownsend 0:87a7fc231fae 13 * See the License for the specific language governing permissions and
ktownsend 0:87a7fc231fae 14 * limitations under the License.
ktownsend 0:87a7fc231fae 15 */
ktownsend 0:87a7fc231fae 16
ktownsend 0:87a7fc231fae 17 #include "mbed.h"
roysandberg 62:8e2fbe131b53 18 #include <qrsdet.h>
roysandberg 62:8e2fbe131b53 19 #include "queue.h"
roysandberg 62:8e2fbe131b53 20
Rohit Grover 10:2436164b692e 21 #include "BLEDevice.h"
rgrover1 39:6390604f904c 22 #include "HeartRateService.h"
rgrover1 42:06ebef2e0e44 23 #include "DeviceInformationService.h"
ktownsend 0:87a7fc231fae 24
rgrover1 52:6bbf62943106 25 /* Enable the following if you need to throttle the connection interval. This has
rgrover1 52:6bbf62943106 26 * the effect of reducing energy consumption after a connection is made;
rgrover1 52:6bbf62943106 27 * particularly for applications where the central may want a fast connection
rgrover1 52:6bbf62943106 28 * interval.*/
rgrover1 52:6bbf62943106 29 #define UPDATE_PARAMS_FOR_LONGER_CONNECTION_INTERVAL 0
rgrover1 52:6bbf62943106 30
roysandberg 62:8e2fbe131b53 31 // SAMPLE_RATE is defined in qrsdet.h
roysandberg 62:8e2fbe131b53 32 #define MS_PER_SAMPLE (1000/SAMPLE_RATE)
roysandberg 62:8e2fbe131b53 33
roysandberg 61:1de72bdab0ef 34 extern void setup_sampler(void (*function)(uint32_t));
roysandberg 62:8e2fbe131b53 35 extern int BeatDetectAndClassify(int ecgSample, int *beatType, int *beatMatch); // defined in bdac.cpp
roysandberg 62:8e2fbe131b53 36 extern void ResetBDAC(void);
roysandberg 62:8e2fbe131b53 37
Rohit Grover 10:2436164b692e 38 BLEDevice ble;
rgrover1 47:430545f41113 39 DigitalOut led1(LED1);
roysandberg 62:8e2fbe131b53 40 PwmOut LRA(P0_15);
roysandberg 62:8e2fbe131b53 41 InterruptIn button1(P0_17); // button 1
roysandberg 62:8e2fbe131b53 42 InterruptIn button2(P0_18); // button 2
roysandberg 62:8e2fbe131b53 43 InterruptIn button3(P0_19); // button 3
roysandberg 62:8e2fbe131b53 44 InterruptIn button4(P0_20); // button 4
ktownsend 0:87a7fc231fae 45
roysandberg 62:8e2fbe131b53 46
roysandberg 62:8e2fbe131b53 47 //Serial pc (P0_9, P0_11); // TX, RX
roysandberg 62:8e2fbe131b53 48
roysandberg 62:8e2fbe131b53 49 volatile uint8_t hrmCounter = 128;
roysandberg 62:8e2fbe131b53 50 volatile uint16_t ecgSample = 0;
roysandberg 62:8e2fbe131b53 51 volatile int sampleCounter=0;
roysandberg 62:8e2fbe131b53 52
roysandberg 62:8e2fbe131b53 53 #define ITEMS_IN_QUEUE 50
roysandberg 62:8e2fbe131b53 54 Queue ecgQueue ( sizeof(int), ITEMS_IN_QUEUE ); // queue of hrmCounter values
roysandberg 62:8e2fbe131b53 55 bool itemAddedToQueue = true;
roysandberg 62:8e2fbe131b53 56
roysandberg 61:1de72bdab0ef 57
mbedAustin 55:3a7d497a3e03 58 const static char DEVICE_NAME[] = "HRM1";
rgrover1 42:06ebef2e0e44 59 static const uint16_t uuid16_list[] = {GattService::UUID_HEART_RATE_SERVICE,
roysandberg 61:1de72bdab0ef 60 GattService::UUID_DEVICE_INFORMATION_SERVICE
roysandberg 61:1de72bdab0ef 61 };
Rohit Grover 36:ea2a1b4f51c1 62
rgrover1 41:9cef0129da5f 63 void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
ktownsend 0:87a7fc231fae 64 {
rgrover1 46:ee7c55907f36 65 ble.startAdvertising(); // restart advertising
rgrover1 7:daab8ba5139e 66 }
Rohit Grover 3:24e2b056d229 67
roysandberg 62:8e2fbe131b53 68
roysandberg 62:8e2fbe131b53 69 void power0() {
roysandberg 62:8e2fbe131b53 70 LRA.write(0.0);
roysandberg 62:8e2fbe131b53 71 }
roysandberg 62:8e2fbe131b53 72 void power1() {
roysandberg 62:8e2fbe131b53 73 LRA.write(0.55);
roysandberg 62:8e2fbe131b53 74 }
roysandberg 62:8e2fbe131b53 75 void power2() {
roysandberg 62:8e2fbe131b53 76 LRA.write(0.85);
roysandberg 62:8e2fbe131b53 77 }
roysandberg 62:8e2fbe131b53 78 void power3() {
roysandberg 62:8e2fbe131b53 79 LRA.write(1.0);
roysandberg 62:8e2fbe131b53 80 }
roysandberg 61:1de72bdab0ef 81
roysandberg 61:1de72bdab0ef 82 void sampler_callback(uint32_t value)
Rohit Grover 11:1d9aafee4984 83 {
roysandberg 62:8e2fbe131b53 84 //hrmCounter = (uint8_t) ((value+127) % 255);
roysandberg 62:8e2fbe131b53 85 ecgSample = (uint16_t) value;
roysandberg 62:8e2fbe131b53 86 itemAddedToQueue = ecgQueue.PutIrq((void*)&ecgSample);
Rohit Grover 11:1d9aafee4984 87 }
Rohit Grover 11:1d9aafee4984 88
roysandberg 62:8e2fbe131b53 89
ktownsend 0:87a7fc231fae 90 int main(void)
ktownsend 0:87a7fc231fae 91 {
roysandberg 62:8e2fbe131b53 92 uint16_t value;
roysandberg 62:8e2fbe131b53 93 int beatType;
roysandberg 62:8e2fbe131b53 94 int beatMatch;
roysandberg 62:8e2fbe131b53 95 int samplesSinceLastR;
roysandberg 62:8e2fbe131b53 96 int lastSamplesSinceLastR=0;
roysandberg 62:8e2fbe131b53 97 int sampleOffset=0;
roysandberg 62:8e2fbe131b53 98 char* beatName;
roysandberg 62:8e2fbe131b53 99
rgrover1 47:430545f41113 100 led1 = 1;
roysandberg 62:8e2fbe131b53 101
roysandberg 61:1de72bdab0ef 102 // Ticker ticker;
roysandberg 61:1de72bdab0ef 103 //ticker.attach(periodicCallback, 0.1); // blink LED every second
roysandberg 61:1de72bdab0ef 104
roysandberg 62:8e2fbe131b53 105 button1.rise(&power0);
roysandberg 62:8e2fbe131b53 106 button2.rise(&power1);
roysandberg 62:8e2fbe131b53 107 button3.rise(&power2);
roysandberg 62:8e2fbe131b53 108 button4.rise(&power3);
ktownsend 0:87a7fc231fae 109
roysandberg 62:8e2fbe131b53 110 LRA.period_us(50); // 50 uS -> 20 Khz (needs to be between 10Khz and 250Khz)
roysandberg 62:8e2fbe131b53 111 LRA.write(0.0); // Off. < 50% = 0ff
roysandberg 62:8e2fbe131b53 112
roysandberg 62:8e2fbe131b53 113 printf("Initializing BLE...\r\n");
roysandberg 62:8e2fbe131b53 114
Rohit Grover 15:7ba28817e31e 115 ble.init();
rgrover1 7:daab8ba5139e 116 ble.onDisconnection(disconnectionCallback);
ktownsend 0:87a7fc231fae 117
rgrover1 45:98c5a34b07a4 118 /* Setup primary service. */
roysandberg 61:1de72bdab0ef 119 //uint8_t hrmCounter = 100; // init HRM to 100bps
rgrover1 45:98c5a34b07a4 120 HeartRateService hrService(ble, hrmCounter, HeartRateService::LOCATION_FINGER);
rgrover1 45:98c5a34b07a4 121
mbedAustin 55:3a7d497a3e03 122 /* Setup auxiliary service. */
rgrover1 45:98c5a34b07a4 123 DeviceInformationService deviceInfo(ble, "ARM", "Model1", "SN1", "hw-rev1", "fw-rev1", "soft-rev1");
rgrover1 45:98c5a34b07a4 124
rgrover1 45:98c5a34b07a4 125 /* Setup advertising. */
roysandberg 62:8e2fbe131b53 126 printf("Setting up advertising...\r\n");
Rohit Grover 29:76d865c718a6 127 ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
rgrover1 40:e73130c6f2bb 128 ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
rgrover1 42:06ebef2e0e44 129 ble.accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR);
Rohit Grover 29:76d865c718a6 130 ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
rgrover1 7:daab8ba5139e 131 ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
rgrover1 56:83623419d5e4 132 ble.setAdvertisingInterval(1000);
rgrover1 7:daab8ba5139e 133 ble.startAdvertising();
Rohit Grover 3:24e2b056d229 134
roysandberg 62:8e2fbe131b53 135 setup_sampler(&sampler_callback);
roysandberg 62:8e2fbe131b53 136
roysandberg 62:8e2fbe131b53 137 ResetBDAC(); // reset the beat detector and classifier
roysandberg 62:8e2fbe131b53 138
roysandberg 62:8e2fbe131b53 139 printf("Starting...\r\n");
roysandberg 62:8e2fbe131b53 140
mbedAustin 55:3a7d497a3e03 141 // infinite loop
mbedAustin 55:3a7d497a3e03 142 while (1) {
mbedAustin 55:3a7d497a3e03 143 // check for trigger from periodicCallback()
roysandberg 62:8e2fbe131b53 144 if (ble.getGapState().connected) {
roysandberg 62:8e2fbe131b53 145 while (ecgQueue.GetNumberOfItems()>0) {
roysandberg 62:8e2fbe131b53 146 ecgQueue.Get(&value);
roysandberg 62:8e2fbe131b53 147 samplesSinceLastR = BeatDetectAndClassify(value, &beatType, &beatMatch);
roysandberg 62:8e2fbe131b53 148 if (samplesSinceLastR != 0) {
roysandberg 62:8e2fbe131b53 149 printf("[C] samplesSinceLastR=%d, type=%d\r\n", value, beatType);
roysandberg 62:8e2fbe131b53 150 }
roysandberg 62:8e2fbe131b53 151 //hrService.updateHeartRate(value);
roysandberg 62:8e2fbe131b53 152 led1 = !led1;
roysandberg 62:8e2fbe131b53 153 }
Rohit Grover 36:ea2a1b4f51c1 154 } else {
roysandberg 62:8e2fbe131b53 155 if (!itemAddedToQueue) {
roysandberg 62:8e2fbe131b53 156 printf("Queue overflow.\n\r");
roysandberg 62:8e2fbe131b53 157 itemAddedToQueue = true;
roysandberg 62:8e2fbe131b53 158 }
roysandberg 62:8e2fbe131b53 159 while (ecgQueue.GetNumberOfItems()>0) {
roysandberg 62:8e2fbe131b53 160 sampleCounter++;
roysandberg 62:8e2fbe131b53 161 ecgQueue.Get(&value);
roysandberg 62:8e2fbe131b53 162 samplesSinceLastR = BeatDetectAndClassify(value, &beatType, &beatMatch);
roysandberg 62:8e2fbe131b53 163 if (samplesSinceLastR != 0) {
roysandberg 62:8e2fbe131b53 164 sampleOffset = lastSamplesSinceLastR - samplesSinceLastR;
roysandberg 62:8e2fbe131b53 165
roysandberg 62:8e2fbe131b53 166 if (beatType == 1) {
roysandberg 62:8e2fbe131b53 167 beatName = "Normal";
roysandberg 62:8e2fbe131b53 168 } else if (beatType == 5) {
roysandberg 62:8e2fbe131b53 169 beatName = "Ectopic";
roysandberg 62:8e2fbe131b53 170 } else {
roysandberg 62:8e2fbe131b53 171 beatName = "Unknown";
roysandberg 62:8e2fbe131b53 172 }
roysandberg 62:8e2fbe131b53 173 printf("[NC] interval_ms=%d, bpm=%d, samplesSinceLastR=%d (%s)\r\n", ((sampleCounter-sampleOffset)*MS_PER_SAMPLE), (60000/((sampleCounter-sampleOffset)*MS_PER_SAMPLE)), value, beatName);
roysandberg 62:8e2fbe131b53 174 sampleCounter=0;
roysandberg 62:8e2fbe131b53 175 lastSamplesSinceLastR = samplesSinceLastR;
roysandberg 62:8e2fbe131b53 176 }
roysandberg 62:8e2fbe131b53 177 }
mbedAustin 55:3a7d497a3e03 178 ble.waitForEvent(); // low power wait for event
Rohit Grover 36:ea2a1b4f51c1 179 }
ktownsend 0:87a7fc231fae 180 }
ktownsend 0:87a7fc231fae 181 }