Pacemaker models

Dependencies:   MQTT

main.cpp

Committer:
ncshy
Date:
2018-12-12
Revision:
9:9d028e2a7c61
Parent:
8:1c786926bb66

File content as of revision 9:9d028e2a7c61:

#define MQTTCLIENT_QOS2 1

#include "ESP8266Interface.h"
#include "MQTTNetwork.h"
#include "MQTTmbed.h"
#include "MQTTClient.h"
#include "TextLCD.h"
#include "mbed.h"
#include "time.h"

#include <string.h>
#include <stdlib.h>
#include <deque>

#define IAP_LOCATION 0x1FFF1FF1

// Serial port for debug
Serial pc(USBTX, USBRX);
TextLCD LcdControl(p15,p16,p17,p18,p14,p20, TextLCD::LCD16x2);
int LRI = 1100;
int HRI = 1500;
unsigned int case_count = 0;

// Heart monitor window averaging variables
#define AVG_WINDOW      20 // Can be 20, 40, or 60 seconds
#define AVG_INTERVAL    5 // Can be 5, 10, 15, or 20 seconds


DigitalOut led_slow_alarm(LED3);
DigitalOut led_fast_alarm(LED4);

DigitalOut senseBeatLED(LED1);
DigitalOut sendPaceLED(LED2);


DigitalOut pace_signal(p19);
InterruptIn receive_sense(p5);
InterruptIn case1_sense(p21);
InterruptIn case2_sense(p22);
InterruptIn case3_sense(p23);


ESP8266Interface wifi(p28, p27);

// Defines for monitor
#define URL             100 //This is in bpm, not ms
#define RATE_ALARM      1
#define PACE_ALARM      2
#define PACE_THRESH     10  // Pretty arbitrary number

int RI = 1500; 
int VRP = 240;
bool hp_enable, hp;   
bool sense_received = 0;
bool sense_flag = 0;
bool pace_sent = 0;
time_t start_time;
Timer timer;
Ticker indicator;
Ticker paceIndicator;

/* pace_times is a subest of beat_times. I need all beats and paces to
 * calculate the average heartrate, but only the number of paces to determine 
 * if the too slow alarm needs to go off. 
 */
deque<time_t> beat_times;
deque<time_t> pace_times;

// The number of times each alarm has occured
unsigned int rate_alarm_count = 0;
unsigned int pace_alarm_count = 0;

// Threads
Thread pacemaker_thread;
Thread monitor_observe;
Thread monitor_calculate;


const char* hostname = "broker.hivemq.com";
int port = 1883;
char* topic = "sectopic";
char* rTopic = "sectopic";
MQTTNetwork network(&wifi);
MQTTNetwork mqttNetwork(network);
MQTT::Client<MQTTNetwork, Countdown> client(mqttNetwork);
MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
MQTT::Message message;
char buf[100];

// This looks at the time difference in each element
// of both the pace and heartbeat queues and removes
// any which are too old, i.e. outside the averaging window time
void prune_lists(time_t new_time) 
{
    
    // Only look at the front of the queues because elements are added
    // already sorted
    while (difftime(new_time, beat_times.front()) > AVG_WINDOW) 
    {
        beat_times.pop_front(); 
    }
    
    while (difftime(new_time, pace_times.front()) > AVG_WINDOW)
    {
        pace_times.pop_front();    
    }
 
    
}

// Flash an LED for an alarm and send an MQTT message 
// to the cloud
void monitor_alarm(int alarm) 
{
    int i;
    Timer alarm_t;
    alarm_t.start();
    if (alarm == RATE_ALARM) 
    {
        for (i = 0; i < 3; i++) 
        {
            
            led_fast_alarm = 1;
            while(alarm_t.read_ms() < 200*(i+1));
            led_fast_alarm = 0;
        }
        rate_alarm_count++;
        sprintf(buf, "Fast Alarm :%d", rate_alarm_count);
        pc.printf("Too fast\r\n");
        
    } else if (alarm == PACE_ALARM) 
    {
        pace_alarm_count++;
        sprintf(buf, "Slow Alarm :%d", pace_alarm_count);  
        for (i = 0; i < 3; i++) 
        {
            led_slow_alarm = 1;
            while(alarm_t.read_ms() < 200*(i + 1)) ;
            led_slow_alarm = 0;
        }
        pc.printf("Too slow\r\n");
    }else{
          sprintf(buf, "Normal :%d", 1);    
    }
    message.qos = MQTT::QOS0;
    message.retained = true;
    message.dup = false;
    message.payload = (void*)buf;
    message.payloadlen = strlen(buf);
    int rc = client.publish(topic, message);
    
    client.yield(100);
    if(rc == 0){
        printf("Success PUB%d\n", rc);
    }else{
        printf("Failed PUB%d\n", rc);
        client.connect(data);
    }
} 


// This is a thread for the monitor which simply watches for new beats and
// paces and adds them to the queue(s) when they occur
void monitor_obs() 
{
    
    time_t new_time;
    
    // Monitor just runs forever
    while (1) {
    
        // Wait until you see a sense or pace
        while (!sense_flag && !pace_sent) ;
    
        // Indicate if you saw a sense or a pace, then set the indicator back to
        // 0 so that the current signal is not counted more than once
        if (sense_flag) {
            beat_times.push_back(time(NULL));
            sense_flag = 0;
        }
        if (pace_sent) {
            new_time = time(NULL);
            beat_times.push_back(new_time);
            pace_times.push_back(new_time);
            pace_sent = 0;
        }
    
    }
}

void  monitor_calc() 
{
    time_t current_time;
    time_t wait_start = time(NULL);
    
    int heart_rate;
    int num_paces;
    int normal_count = 0;
    //printf("calc...\n");
    // I want to check the heart rate in bpm for the alarm,
    // so if my window time is smaller than 60 seconds I want to have
    // this window factor to scale it
    int window_factor = 60 / AVG_WINDOW;
    
    // The monitor needs to wait for at least one full AVG_WINDOW
    // before it starts to monitor the average heartrate or else 
    // it is going to give spurious low heartrate alarms
    while (difftime(time(NULL),wait_start) < AVG_WINDOW);
    
    
    message.qos = MQTT::QOS1;
    while(1) {
          //pc.printf("In monitor calc loop\r\n");
         // Get the current time and see if you need to prune any elements from
         // your lists
         current_time = time(NULL);
         prune_lists(current_time);
            
         
         // Find average heart rate and number of paces if it is time to,
         // then set any necessary alarms
            heart_rate = beat_times.size() * window_factor;
            num_paces = pace_times.size();
            pc.printf("H.R = %d\r\n", heart_rate);
            pc.printf("N.P = %d\r\n", num_paces);
            sprintf(buf, "BPM :%d", heart_rate);
            LcdControl.cls();
            LcdControl.printf("BPM: %03d  TC:%d", heart_rate, case_count);
            message.retained = true;
            message.dup = false;
            message.payload = (void*)buf;
            message.payloadlen = strlen(buf);
            int rc = client.publish(topic, message);
            int rate_flag = 0;
            int pace_flag = 0;
            
            
            client.yield(100);
            if(rc == 0){
                printf("Success PUB%d\n", rc);
            }else{
                printf("Failed PUB%d\n", rc);
                client.connect(data);
            }
            //printf("About to alarm\r\n");
            if (heart_rate > URL) {
                monitor_alarm(RATE_ALARM);    
                rate_flag = 1;
            }
            if (num_paces > PACE_THRESH) {
                monitor_alarm(PACE_ALARM);
                pace_flag = 1;    
            }
            if(heart_rate < URL && num_paces < PACE_THRESH){
                  normal_count++;
                  sprintf(buf, "Normal :%d", normal_count);    
            }
            LcdControl.locate(0, 1);
            LcdControl.printf("AF:%d AS:%d NC:%03d", rate_flag, pace_flag, normal_count);
            rate_flag=0; 
            pace_flag=0;
            message.qos = MQTT::QOS0;
            message.retained = true;
            message.dup = false;
            message.payload = (void*)buf;
            message.payloadlen = strlen(buf);
            rc = client.publish(topic, message);
            
            client.yield(100);
            if(rc == 0){
                printf("Success PUB%d\n", rc);
            }else{
                printf("Failed PUB%d\n", rc);
                client.connect(data);
            }
         //printf("Alarm done\r\n");
         wait_start = time(NULL);
         // Wait until you need to calculate averages again
         while (difftime(time(NULL),wait_start) < AVG_INTERVAL); 
    }
}

void flip(){
senseBeatLED = 0;
indicator.detach();    
}
    
// ISR to receive sense signals
void receive_sense_ISR()
{
    sense_received = 1;
}

void case1_sense_ISR()
{
    case_count = 1;
}

void case2_sense_ISR()
{
    case_count = 2;
}

void case3_sense_ISR()
{
    case_count = 3;
}

void pIndicate(){
    sendPaceLED = 0;
    paceIndicator.detach();
}

void pace()
{
    sendPaceLED = 1;
    paceIndicator.attach(&pIndicate, 0.1);   
    pace_signal = 1;
    pace_signal = 0;
}

void pacemaker()
{
    //start_time = timer.read_ms();
    timer.reset();
    timer.start();
    while(true)
    {
        switch(case_count) 
        {
                case 1:
                        LRI = 1100;
                        HRI = 1500;
                        break;
                case 2:
                        LRI = 1100;
                        HRI = 2000;
                        break;
                case 3:
                        LRI = 300;
                        HRI = 500;
                        break;
                default:
                        LRI = 1100;
                        HRI = 1500;
                        break;
            }
        
        while(!sense_received && ((timer.read_ms()) < RI));
        if (sense_received)
        {
            //pc.printf("sense received\n");
            sense_received = 0;
            // Let monitor know there was a heartbeaat
            sense_flag = 1;
            RI = HRI;
            hp = true;
            timer.reset();
            senseBeatLED = 1;
            indicator.attach(&flip, 0.01);
        }
        else
        {
            // Send pace signal to heart
            pace();
            // Indicate oace was sent for monitor
            pace_sent = 1;
            //pc.printf("paced - %d\n", (timer.read_ms() - start_time));
            RI = LRI;
            hp = false;
            //start_time = timer.read_ms();
            timer.reset();
        }
        // Wait for VRP
        receive_sense.disable_irq();
        while((timer.read_ms()) < VRP);
        receive_sense.enable_irq();
        hp_enable = hp;
    }
}
    
int main() 
{
    
    led_slow_alarm = 0;
    led_fast_alarm = 0;
    pc.baud(9600);
    LcdControl.cls();
    LcdControl.printf("PACEMAKER");
    // Enable the ISR to receive snse signals from heart simulator
    wifi.set_credentials(MBED_CONF_APP_WIFI_SSID, MBED_CONF_APP_WIFI_PASSWORD);
    wifi.connect();
    int rc = network.connect(hostname, port);
    pc.printf("Connecting to %s:%d\r\n", hostname, port);
    rc = mqttNetwork.connect(hostname, port);
    data.MQTTVersion = 3;
    data.clientID.cstring = "26013f37-13006018ae2a8ca752c368e3f5001e81";
    data.username.cstring = "mbed";
    data.password.cstring = "homework";
    if ((rc = client.connect(data)) != 0)
        pc.printf("rc from MQTT connect is %d\r\n", rc);
    receive_sense.rise(&receive_sense_ISR);
    case1_sense.rise(&case1_sense_ISR);
    case2_sense.rise(&case2_sense_ISR);
    case3_sense.rise(&case3_sense_ISR);
    
    // Start both the threads - pacemaker and observer
    monitor_observe.start(monitor_obs);
    monitor_calculate.start(monitor_calc);
    pacemaker_thread.start(pacemaker);
}