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

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
         }
     }