I've got some basic filter code setup (but not yet tested).
Dependencies: BLE_API Queue mbed nRF51822
Fork of BLE_HeartRate by
Diff: main.cpp
- Revision:
- 62:8e2fbe131b53
- Parent:
- 61:1de72bdab0ef
--- a/main.cpp Sun May 17 00:27:16 2015 +0000 +++ b/main.cpp Sun Jun 28 03:06:00 2015 +0000 @@ -15,6 +15,9 @@ */ #include "mbed.h" +#include <qrsdet.h> +#include "queue.h" + #include "BLEDevice.h" #include "HeartRateService.h" #include "DeviceInformationService.h" @@ -25,50 +28,90 @@ * interval.*/ #define UPDATE_PARAMS_FOR_LONGER_CONNECTION_INTERVAL 0 +// SAMPLE_RATE is defined in qrsdet.h +#define MS_PER_SAMPLE (1000/SAMPLE_RATE) + extern void setup_sampler(void (*function)(uint32_t)); - +extern int BeatDetectAndClassify(int ecgSample, int *beatType, int *beatMatch); // defined in bdac.cpp +extern void ResetBDAC(void); + BLEDevice ble; DigitalOut led1(LED1); +PwmOut LRA(P0_15); +InterruptIn button1(P0_17); // button 1 +InterruptIn button2(P0_18); // button 2 +InterruptIn button3(P0_19); // button 3 +InterruptIn button4(P0_20); // button 4 -volatile uint8_t hrmCounter = 100; // init HRM to 100bps + +//Serial pc (P0_9, P0_11); // TX, RX + +volatile uint8_t hrmCounter = 128; +volatile uint16_t ecgSample = 0; +volatile int sampleCounter=0; + +#define ITEMS_IN_QUEUE 50 +Queue ecgQueue ( sizeof(int), ITEMS_IN_QUEUE ); // queue of hrmCounter values +bool itemAddedToQueue = true; + const static char DEVICE_NAME[] = "HRM1"; static const uint16_t uuid16_list[] = {GattService::UUID_HEART_RATE_SERVICE, GattService::UUID_DEVICE_INFORMATION_SERVICE }; -static volatile bool triggerSensorPolling = false; void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason) { ble.startAdvertising(); // restart advertising } -//void periodicCallback(void) -//{ -// led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */ -// -// /* Note that the periodicCallback() executes in interrupt context, so it is safer to do -// * heavy-weight sensor polling from the main thread. */ -// triggerSensorPolling = true; -//} + +void power0() { + LRA.write(0.0); +} +void power1() { + LRA.write(0.55); +} +void power2() { + LRA.write(0.85); +} +void power3() { + LRA.write(1.0); +} void sampler_callback(uint32_t value) { - hrmCounter = (uint8_t) (value); -// led1 = !led1; - triggerSensorPolling = true; + //hrmCounter = (uint8_t) ((value+127) % 255); + ecgSample = (uint16_t) value; + itemAddedToQueue = ecgQueue.PutIrq((void*)&ecgSample); } + int main(void) { + uint16_t value; + int beatType; + int beatMatch; + int samplesSinceLastR; + int lastSamplesSinceLastR=0; + int sampleOffset=0; + char* beatName; + led1 = 1; + // Ticker ticker; //ticker.attach(periodicCallback, 0.1); // blink LED every second - printf("Executing code...\n"); - - setup_sampler(&sampler_callback); + button1.rise(&power0); + button2.rise(&power1); + button3.rise(&power2); + button4.rise(&power3); + LRA.period_us(50); // 50 uS -> 20 Khz (needs to be between 10Khz and 250Khz) + LRA.write(0.0); // Off. < 50% = 0ff + + printf("Initializing BLE...\r\n"); + ble.init(); ble.onDisconnection(disconnectionCallback); @@ -80,6 +123,7 @@ DeviceInformationService deviceInfo(ble, "ARM", "Model1", "SN1", "hw-rev1", "fw-rev1", "soft-rev1"); /* Setup advertising. */ + printf("Setting up advertising...\r\n"); ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); ble.accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR); @@ -88,27 +132,49 @@ ble.setAdvertisingInterval(1000); ble.startAdvertising(); + setup_sampler(&sampler_callback); + + ResetBDAC(); // reset the beat detector and classifier + + printf("Starting...\r\n"); + // infinite loop while (1) { // check for trigger from periodicCallback() - if (triggerSensorPolling && ble.getGapState().connected) { - triggerSensorPolling = false; - - led1 = !led1; - - printf("v=%d\n", hrmCounter); -// // Do blocking calls or whatever is necessary for sensor polling. -// // In our case, we simply update the HRM measurement. -// hrmCounter++; -// -// // 100 <= HRM bps <=175 -// if (hrmCounter == 175) { -// hrmCounter = 100; -// } - - // update bps - hrService.updateHeartRate(hrmCounter); + if (ble.getGapState().connected) { + while (ecgQueue.GetNumberOfItems()>0) { + ecgQueue.Get(&value); + samplesSinceLastR = BeatDetectAndClassify(value, &beatType, &beatMatch); + if (samplesSinceLastR != 0) { + printf("[C] samplesSinceLastR=%d, type=%d\r\n", value, beatType); + } + //hrService.updateHeartRate(value); + led1 = !led1; + } } else { + if (!itemAddedToQueue) { + printf("Queue overflow.\n\r"); + itemAddedToQueue = true; + } + while (ecgQueue.GetNumberOfItems()>0) { + sampleCounter++; + ecgQueue.Get(&value); + samplesSinceLastR = BeatDetectAndClassify(value, &beatType, &beatMatch); + if (samplesSinceLastR != 0) { + sampleOffset = lastSamplesSinceLastR - samplesSinceLastR; + + if (beatType == 1) { + beatName = "Normal"; + } else if (beatType == 5) { + beatName = "Ectopic"; + } else { + beatName = "Unknown"; + } + 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); + sampleCounter=0; + lastSamplesSinceLastR = samplesSinceLastR; + } + } ble.waitForEvent(); // low power wait for event } }