yay!

Dependencies:   TextLCD mbed-rtos mbed

Fork of 541_Pacermaker by CIS541

main.cpp

Committer:
adamvan101
Date:
2015-12-02
Revision:
1:d1c452f164d4
Parent:
0:6c085ebcb2d5
Child:
2:3d47bb081502

File content as of revision 1:d1c452f164d4:

#include "mbed.h"
#include "rtos.h"
//#include "TextLCD.h"

#define NORMAL 1
#define EXERCISE 2
#define SLEEP 3
#define MANUAL 4

#define LRI_const 1
#define URI_const 2
#define AVI_const 3
#define VRP_const 4
#define PVAB_const 5
#define PVARP_const 6  

DigitalOut vpaceLED(LED1);
DigitalOut apaceLED(LED2);
DigitalOut vsenseLED(LED3);
DigitalOut asenseLED(LED4);
DigitalOut buzzer(p9);
DigitalOut aPace(p7);
DigitalOut vPace(p8);
InterruptIn ASignal(p5);
InterruptIn VSignal(p6);
Serial pc(USBTX, USBRX);

int32_t signal1 = 0x01;
int32_t signal2 = 0x02;
int32_t signal3 = 0x03;
int32_t signal4 = 0x04;

bool waitASignal, waitVSignal, paceA, observationChange, digitOneReceived, modeChanged, canPaceV, paceVPending, ringAlarm, ringingAlarm, timerRunning, aSenseOccurred, digitTwoReceived;
int heartRate, observationInterval, observationRate, waitCount, avgHeartRate, rateCoefficient, heartRateHeart, sec, avgHeartRateHeart;
int paceMakerMode=1;            //1 - Normal, 2 - Exercise, 3 - Sleep, 4 - Manual
int uriTimeOutStatus=4;
char ch;

int timeConstraint;

const int normalModeLRI= 1500;
const int normalModeAVI = 65;
const int normalModePVARP = 150;
const int normalModeURI = 600;
const int normalModeVRP = 100;
const int normalModePVAB = 10;

const int sleepModeLRI= 2000;
const int sleepModeAVI = 65;
const int sleepModePVARP = 150;
const int sleepModeURI = 1000;
const int sleepModeVRP = 100;
const int sleepModePVAB = 10;

const int exerciseModeLRI=1000;
const int exerciseModeAVI = 65;
const int exerciseModePVARP = 150;
const int exerciseModeURI = 400;
const int exerciseModeVRP = 100;
const int exerciseModePVAB = 10;

int LRI;
int VRP;
int PVARP;
int AVI;
int URI;
int PVAB;

Mutex displayMutex;
Mutex observationChangeMutex;
Mutex expectAMutex;
Mutex expectVMutex;
Mutex timeOutStatusMutex;
Mutex heartRateMutex;

Thread *SerialThreadPTR;
Thread *PacePTR;
Thread *ModeChangePTR;
Thread *PMSensePTR;

RtosTimer *TimeOutTimer;
RtosTimer *URITimeOutTimer;
RtosTimer *KeyTimeOutTimer;
RtosTimer *SecondsTimer;

void println(const char *c) {
    pc.printf(c);
    pc.printf("\r\n");
}

void switchToNormal() {
    LRI = normalModeLRI;
    AVI = normalModeAVI;
    PVARP = normalModePVARP;
    URI = normalModeURI;
    VRP = normalModeVRP;
    PVAB = normalModePVAB;
}

void switchToExercise() {
    LRI = exerciseModeLRI;
    AVI = exerciseModeAVI;
    PVARP = exerciseModePVARP;
    URI = exerciseModeURI;
    VRP = exerciseModeVRP;
    PVAB = exerciseModePVAB;
}

void switchToSleep() {
    LRI = sleepModeLRI;
    AVI = sleepModeAVI;
    PVARP = sleepModePVARP;
    URI = sleepModeURI;
    VRP = sleepModeVRP;
    PVAB = sleepModePVAB;
}

void resetDisplay()
{
    displayMutex.lock();
    println("Pace Maker Display");
    pc.printf("Heart Rate :  %04d bpm\r\n", avgHeartRate);
    pc.printf("Observation Interval :  %02d seconds\r\n", observationInterval/1000);
    pc.printf("Heart Beat Rate :  %04d  bpm\r\n", (heartRateHeart*(60/sec)));    
    displayMutex.unlock();
    ringingAlarm=false;
}

void updateDisplay()
{
    displayMutex.lock();
    pc.printf("%04d\r\n", avgHeartRate);
    pc.printf("%02d\r\n", observationInterval/1000);
    pc.printf("%04d\r\n", (heartRateHeart*(60/sec))); 
    displayMutex.unlock();
}   

void changeMode()
{
    switch(paceMakerMode)
    {
        default:
        case NORMAL:
        {
            switchToNormal();
            break;
        }
        case EXERCISE:
        {
            switchToExercise();
            break;
        }
        case SLEEP:
        {
            switchToSleep();
            break;
        }
        case MANUAL:
        {
            break;
        }
    }    
    modeChanged=false;
    resetDisplay();
}

void modeChange(const void *args)
{
    while(1)
    {
        Thread::signal_wait(signal3);
        if(modeChanged)
        {
            changeMode();
        }
    }
}
            

void aSense()
{
    if(waitASignal)
    {
        asenseLED=1;
        wait(0.001);
        println("ASense Received");
        asenseLED=0; 
        if(modeChanged)
        {
            (*ModeChangePTR).signal_set(signal3);
        }
        aSenseOccurred=true;
        (*PMSensePTR).signal_set(signal4);
    }    
}

void vSense()
{
    heartRateHeart++;
    if(waitVSignal)
    {
        vsenseLED=1;
        println("VSense Received");
        wait(0.001);
        vsenseLED=0;
        if(modeChanged)
        {
            (*ModeChangePTR).signal_set(signal3);
        }
        canPaceV=false;
        aSenseOccurred=false;
        (*PMSensePTR).signal_set(signal4);
    }
}

void seconds(const void *args)
{
    sec++;
    if(sec>=60)
    {
        avgHeartRateHeart=heartRateHeart;
        heartRateHeart=0;
        sec=0;
    }
}

void timeOut(const void *args)
{
    // check which time out has occurred
    // generate appropriate pace signal
    // reset timer to new value  
    //apaceLED=1; 
    if(timeConstraint==AVI_const)
    {
        //generate VPace
        if(canPaceV)
        {
            paceA=false;
            (*PacePTR).signal_set(signal1);
        }
        else
        {
            canPaceV=true;
        }
    }
    else if(timeConstraint==PVAB_const)
    {
        expectVMutex.lock();
        waitVSignal=true;
        expectVMutex.unlock();
        timeOutStatusMutex.lock();
        timeConstraint=AVI_const;
        timeOutStatusMutex.unlock();
        timerRunning=true;
        TimeOutTimer->start(AVI-PVAB);
    }
    else if(timeConstraint==VRP_const)
    {
        //now we can sense a Ventrival event, but not an atrial event as PVARP is not over 
        //restart timer for PVARP
        expectVMutex.lock();        
        waitVSignal=true;         
        expectVMutex.unlock();
        timeOutStatusMutex.lock();
        timeConstraint=PVARP_const;
        timeOutStatusMutex.unlock();
        timerRunning=true;
        TimeOutTimer->start(PVARP-VRP);
    }
    else if(timeConstraint==PVARP_const)
    {
        //now we can sense Atrial events as well
        expectAMutex.lock();
        waitASignal=true;
        expectAMutex.unlock();
        timeOutStatusMutex.lock();
        timeConstraint=LRI_const;
        timeOutStatusMutex.unlock();
        timerRunning=true;
        TimeOutTimer->start(LRI-PVARP-AVI);
    }
    else if(timeConstraint==LRI_const)
    {
        //generate APace
        paceA=true;
        (*PacePTR).signal_set(signal1);
    }
}

void uriTimeOut(const void *args)
{
    // uri is over 
    //check is a vpace has to be generated; If yes then generate the pace; else enable a flag that lets the thread generate the pace
    if(paceVPending || canPaceV)
    {
        //pace V as a pace occurred during URI
        paceA=false;
        paceVPending=false;
        (*PacePTR).signal_set(signal1);
    }
    else
    {
        canPaceV=true;              //allow the PM to pace V as URI is now over
    }
    
}   

void keyTimeOut(const void *args)
{
    if(digitOneReceived)
    {
        observationChange=false;
    }
    else
    {
        observationChange=false;
    }
    resetDisplay();
}

void pmSense(const void *args)
{
    while(1)
    {
        Thread::signal_wait(signal4);
        if(timerRunning)
        {
            TimeOutTimer->stop();
            timerRunning=false;
        }
        if(aSenseOccurred)
        {
            expectAMutex.lock();
            waitASignal=false;
            expectAMutex.unlock();
            expectVMutex.lock();
            waitVSignal=true;
            expectVMutex.unlock();
            timerRunning=true;
            timeOutStatusMutex.lock();
            timeConstraint=AVI_const;
            timeOutStatusMutex.unlock();
            TimeOutTimer->start(AVI);//500);            
        }
        else
        {
            heartRateMutex.lock();
            heartRate++;
            heartRateMutex.unlock();
            expectVMutex.lock();         
            waitVSignal=false;         
            expectVMutex.unlock();
            expectAMutex.lock();
            waitASignal=false;
            expectAMutex.unlock();
            canPaceV=false;
            URITimeOutTimer->start(URI);
            timerRunning=true;
            timeOutStatusMutex.lock();
            timeConstraint=VRP_const;
            timeOutStatusMutex.unlock();
            TimeOutTimer->start(VRP);
        }
    }
}
        

void pace(const void *args)
{
    while(1)
    {
        Thread::signal_wait(signal1);
        if(paceA)
        {
            println("APace Sent");
            apaceLED=1;
            aPace=1;
            Thread::wait(1);
            aPace=0;
            apaceLED=0;
            if(modeChanged)
            {
                changeMode();
            }
            // start AVI Timer
            expectAMutex.lock();
            waitASignal=false;
            expectAMutex.unlock();
            expectVMutex.lock();         
            waitVSignal=false;         
            expectVMutex.unlock();
            timeOutStatusMutex.lock();
            timeConstraint=PVAB_const;
            timeOutStatusMutex.unlock();
            timerRunning=true;
            TimeOutTimer->start(PVAB);
            //generate the APace pulse
        }
        else
        {
            println("VPace Sent");
            vpaceLED=1;
            vPace=1;
            Thread::wait(1);
            vPace=0;
            vpaceLED=0;
            if(modeChanged)
            {
                changeMode();
            }
            // start VRP and URI timers
            expectVMutex.lock();         
            waitVSignal=false;         
            expectVMutex.unlock();
            expectAMutex.lock();
            waitASignal=false;
            expectAMutex.unlock();
            heartRateMutex.lock();
            heartRate++;
            heartRateMutex.unlock();
            canPaceV=false;
            URITimeOutTimer->start(URI);
            timeOutStatusMutex.lock();
            timeConstraint=VRP_const;
            timeOutStatusMutex.unlock();
            timerRunning=true;
            TimeOutTimer->start(VRP);
            //generate the VPace pulse
        }
    }
}

void serialThread(const void *args)
{
    while(1)
    {
        Thread::signal_wait(signal2);
        if((((ch=='a')||(ch=='A')) && paceMakerMode==MANUAL) && !observationChange)
        {
            //fire A Pace
            paceA=true;
            (*PacePTR).signal_set(signal1);
        }
        else if((((ch=='v')||(ch=='V')) && paceMakerMode==MANUAL) && !observationChange)
        {
            //fire V Pace
            if(canPaceV)
            {
                paceA=false;
                paceVPending=false;
                (*PacePTR).signal_set(signal1);
            }
            else
            {
                paceVPending=true;
            }
        }
        else if(((((ch=='n')||(ch=='N'))&& paceMakerMode!=NORMAL) && !observationChange) && !modeChanged)
        {
            paceMakerMode=NORMAL;
            modeChanged=true;
        }
        else if(((((ch=='e')||(ch=='E')) && paceMakerMode!=EXERCISE) && !observationChange) && !modeChanged)
        {
            paceMakerMode=EXERCISE;
            modeChanged=true;
        }
        else if(((((ch=='s')||(ch=='S')) && paceMakerMode!=SLEEP) && !observationChange) && !modeChanged)
        {
            paceMakerMode=SLEEP;
            modeChanged=true;
        }
        else if(((((ch=='b')||(ch=='B')) ) && !observationChange) )
        {
            ringAlarm=!ringAlarm;
        }
        else if(((((ch=='m')||(ch=='M')) && paceMakerMode!=MANUAL) && !observationChange) && !modeChanged)
        {
            paceMakerMode=MANUAL;
            modeChanged=true;
        }
        else if(((((ch=='o')||(ch=='O')) && !observationChange) && !modeChanged))
        {
            observationChange=true;
            digitOneReceived=false;
            digitTwoReceived=false;
            //spawn a timer for  3 seconds
            displayMutex.lock();
            displayMutex.unlock();
            KeyTimeOutTimer=new RtosTimer(keyTimeOut, osTimerOnce, (void *)0);
            KeyTimeOutTimer->start(3000);
        }
        else if((observationChange) && ((ch>=48) && (ch<=57)))
        {
            if(!digitOneReceived)
            {
                KeyTimeOutTimer->start(3000);
                observationChangeMutex.lock();
                observationRate=ch-'0';
                observationChangeMutex.unlock();
                digitOneReceived=true;
                displayMutex.lock();
                pc.printf("%02d\r\n", observationRate);
                displayMutex.unlock();
            }
            else
            {
                KeyTimeOutTimer->stop();
                digitTwoReceived=true;
                observationChangeMutex.lock();
                observationRate=(observationRate*10)+(ch-'0');
                observationChangeMutex.unlock();
                observationChange=false;
                displayMutex.lock();
                pc.printf("%02d\r\n", observationRate);
                displayMutex.unlock();
            }
        }                
    }
}

void alarm(const void *args)
{
    while(1)
    {
        Thread::wait(1000);
        while(((heartRateHeart*(60/sec))>(60000/URI)) && ringAlarm)
        {
            buzzer=1;
            Thread::wait(5);
            buzzer=0;
            Thread::wait(5);
            if(!ringingAlarm)
            {
                displayMutex.lock();
                println("Alarm : HeartRate too high");
                displayMutex.unlock();
                ringingAlarm=true;
            }
        }
        while(((heartRateHeart*(60/sec))<(60000/LRI)) && ringAlarm)
        {
            buzzer=1;
            Thread::wait(10);
            buzzer=0;
            Thread::wait(10);
            if(!ringingAlarm)
            {
                displayMutex.lock();
                println("Alarm : HeartRate too Low");
                displayMutex.unlock();
                ringingAlarm=true;
            }
        }
        if(ringingAlarm)
        {
            ringingAlarm=false;
            resetDisplay();
        }
    }
}

void display(const void *args)
{
    while(1)
    {
        Thread::wait(observationInterval);
        waitCount++;
        if(!observationChange)
        {
            avgHeartRate=heartRate*rateCoefficient/waitCount;
            heartRateMutex.lock();
            heartRate=0;
            heartRateMutex.unlock();
            if(observationRate!=(observationInterval/1000))
            {
                resetDisplay();
                observationInterval=observationRate*1000;           
                rateCoefficient=(60000/observationInterval);
            }
            waitCount=0;   
        }        
    }
}

int main() 
{    
    //initialize variables
    expectAMutex.lock();
    waitASignal=true;
    expectAMutex.unlock();
    expectVMutex.lock();         
    waitVSignal=true;         
    expectVMutex.unlock();
    switchToNormal();
    heartRate=0;
    avgHeartRate=0;
    paceMakerMode=1;
    observationInterval=5000;
    observationRate=5;
    waitCount=0;
    rateCoefficient=12;
    paceA=false;
    observationChange=false;
    digitOneReceived=false;
    digitTwoReceived=false;
    modeChanged=false;
    canPaceV=true;
    paceVPending=false;
    buzzer=0;
    ringAlarm=true;
    heartRateHeart=0;
    sec=0;
    avgHeartRateHeart=0;
    ringingAlarm=false;
    timerRunning=false;
    aSenseOccurred=true;
    
    ASignal.fall(&aSense);
    VSignal.fall(&vSense);
    TimeOutTimer=new RtosTimer(timeOut, osTimerOnce, (void*)0);
    URITimeOutTimer=new RtosTimer(uriTimeOut, osTimerOnce, (void *)0);
    SecondsTimer=new RtosTimer(seconds, osTimerPeriodic, (void *)0);                //timer that over runs every 1 second and is used to reset the heart rate count coming from the heart
    SecondsTimer->start(1000);                                                      //start the timer to run for every 1 second
    
    Thread Pace(pace);
    PacePTR=&Pace;
    Pace.set_priority(osPriorityHigh);
    Thread PMSense(pmSense);
    PMSensePTR=&PMSense;
    PMSense.set_priority(osPriorityAboveNormal);
    Thread Alarm(alarm);
    Alarm.set_priority(osPriorityAboveNormal);
    Thread ModeChange(modeChange);
    ModeChangePTR=&ModeChange;
    ModeChange.set_priority(osPriorityAboveNormal);
    Thread Display(display);
    Thread SerialThread(serialThread);
    SerialThreadPTR=&SerialThread;
    SerialThread.set_priority(osPriorityRealtime);
    Display.set_priority(osPriorityAboveNormal);
    
    timeOutStatusMutex.lock();
    timeConstraint=VRP_const;
    timeOutStatusMutex.unlock();
    TimeOutTimer->start(VRP);
    while(1) {
        if(pc.readable())
        {
            ch=pc.getc();
            (*SerialThreadPTR).signal_set(signal2);     //initiate the serial thread to change the state of the timer
        }
    }
}