Dependencies:   TextLCD mbed-rtos mbed

Fork of 541_Pacermaker by CIS541

main.cpp

Committer:
adamvan101
Date:
2015-12-01
Revision:
0:6c085ebcb2d5
Child:
1:d1c452f164d4

File content as of revision 0:6c085ebcb2d5:

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

#define LRI 0
#define AVI 1
#define VRP 2
#define PVARP 3
#define URI 4
#define PAVB 5
#define VSP 6
#define NR -1               //not running 

DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);
DigitalOut buzzer(p9);
DigitalOut aPace(p7);
DigitalOut vPace(p8);
InterruptIn ASignal(p5);
InterruptIn VSignal(p6);
Serial pc(USBTX, USBRX);

bool expectingASignal, expectingVSignal, paceA, observationChange, digitOneReceived, modeChanged, canPaceV, paceVPending, ringAlarm, ringingAlarm, timerRunning, aSenseOccurred, digitTwoReceived;
int timeOutValue[7];              //timeout array that holds values for LRI, VRP, PVARP, AVI, URI, PAVB, VSP; PVARP >VRP
int heartRate, observationInterval, observationRate, timeOutStatus, waitCount, avgHeartRate, rateCoefficient, heartRateHeart, sec, avgHeartRateHeart;
int paceMakerMode=1;            //1 - Normal, 2 - Exercise, 3 - Sleep, 4 - Manual
int uriTimeOutStatus=URI;
char ch;
char modeString[20];
const int nLRI=1500, nAVI = 60, nPVARP = 150, nURI = 600, nVRP = 100, nVSP = 0, nPAVB = 20;
const int sLRI=2000, sAVI = 60, sPVARP = 150, sURI = 1000, sVRP = 100, sVSP = 0, sPAVB = 20;
const int eLRI=1000, eAVI = 60, ePVARP = 150, eURI = 400, eVRP = 100, eVSP = 0, ePAVB = 20;

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 setTimeOutValues(int tLRI, int tAVI, int tPVARP, int tURI, int tVRP, int tVSP, int tPAVB)
{
    timeOutValue[LRI]=tLRI;
    timeOutValue[AVI]=tAVI;
    timeOutValue[PVARP]=tPVARP;
    timeOutValue[URI]=tURI;
    timeOutValue[VRP]=tVRP;
    timeOutValue[VSP]=tVSP;
    timeOutValue[PAVB]=tPAVB;
}

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

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

void changeMode()
{
    switch(paceMakerMode)
    {
        case 1:             //Normal Mode
        {
            setTimeOutValues(nLRI, nAVI, nPVARP, nURI, nVRP, nVSP, nPAVB);
            strcpy(modeString, "Normal");
            break;
        }
        case 2:             //Exercise Mode
        {
            setTimeOutValues(eLRI, eAVI, ePVARP, eURI, eVRP, eVSP, ePAVB);
            strcpy(modeString, "Exercise");
            break;
        }
        case 3:             //Sleep Mode
        {
            setTimeOutValues(sLRI, sAVI, sPVARP, sURI, sVRP, sVSP, sPAVB);
            strcpy(modeString, "Sleep");
            break;
        }
        case 4:             //Manual Mode; do not chnage the time out values
        {
            strcat(modeString, " + Manual");
            break;
        }
        default:            //Normal mode is any error occurs
        {
            setTimeOutValues(nLRI, nAVI, nPVARP, nURI, nVRP, nVSP, nPAVB);
            strcpy(modeString, "Normal");
        }
    }    
    modeChanged=false;
    resetDisplay();
}

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

void aSense()
{
    //ASignal received from heart  
    if(expectingASignal)
    {
        led4=1;
        wait(0.001);
        pc.printf("ASense Received\r\n");
        led4=0; 
        if(modeChanged)
        {
            (*ModeChangePTR).signal_set(0x03);
        }
        aSenseOccurred=true;
        (*PMSensePTR).signal_set(0x04);
    }    
}

void vSense()
{
    //VSignal received from heart
    //reset timeout
    //increment heart rate
    heartRateHeart++;
    if(expectingVSignal)
    {
        led3=1;
        pc.printf("VSense Received\r\n");
        wait(0.001);
        led3=0;
        if(modeChanged)
        {
            (*ModeChangePTR).signal_set(0x03);
        }
        canPaceV=false;
        aSenseOccurred=false;
        (*PMSensePTR).signal_set(0x04);
    }
    
}

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  
    //led2=1; 
    if(timeOutStatus==AVI)
    {
        //generate VPace
        if(canPaceV)
        {
            paceA=false;
            (*PacePTR).signal_set(0x01);
        }
        else
        {
            canPaceV=true;
        }
    }
    else if(timeOutStatus==PAVB)
    {
        expectVMutex.lock();
        expectingVSignal=true;
        expectVMutex.unlock();
        timeOutStatusMutex.lock();
        timeOutStatus=AVI;
        timeOutStatusMutex.unlock();
        timerRunning=true;
        TimeOutTimer->start(timeOutValue[AVI]-timeOutValue[PAVB]);
    }
    else if(timeOutStatus==VRP)
    {
        //now we can sense a Ventrival event, but not an atrial event as PVARP is not over 
        //restart timer for PVARP
        expectVMutex.lock();        
        expectingVSignal=true;         
        expectVMutex.unlock();
        timeOutStatusMutex.lock();
        timeOutStatus=PVARP;
        timeOutStatusMutex.unlock();
        timerRunning=true;
        TimeOutTimer->start(timeOutValue[PVARP]-timeOutValue[VRP]);
    }
    else if(timeOutStatus==PVARP)
    {
        //now we can sense Atrial events as well
        expectAMutex.lock();
        expectingASignal=true;
        expectAMutex.unlock();
        timeOutStatusMutex.lock();
        timeOutStatus=LRI;
        timeOutStatusMutex.unlock();
        timerRunning=true;
        TimeOutTimer->start(timeOutValue[LRI]-timeOutValue[PVARP]-timeOutValue[AVI]);
    }
    else if(timeOutStatus==LRI)
    {
        //generate APace
        paceA=true;
        (*PacePTR).signal_set(0x01);
    }
}

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(0x01);
    }
    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(0x04);
        if(timerRunning)
        {
            TimeOutTimer->stop();
            timerRunning=false;
        }
        if(aSenseOccurred)
        {
            expectAMutex.lock();
            expectingASignal=false;
            expectAMutex.unlock();
            expectVMutex.lock();
            expectingVSignal=true;
            expectVMutex.unlock();
            timerRunning=true;
            timeOutStatusMutex.lock();
            timeOutStatus=AVI;
            timeOutStatusMutex.unlock();
            TimeOutTimer->start(timeOutValue[AVI]);//500);            
        }
        else
        {
            heartRateMutex.lock();
            heartRate++;
            heartRateMutex.unlock();
            expectVMutex.lock();         
            expectingVSignal=false;         
            expectVMutex.unlock();
            expectAMutex.lock();
            expectingASignal=false;
            expectAMutex.unlock();
            canPaceV=false;
            URITimeOutTimer->start(timeOutValue[URI]);
            timerRunning=true;
            timeOutStatusMutex.lock();
            timeOutStatus=VRP;
            timeOutStatusMutex.unlock();
            TimeOutTimer->start(timeOutValue[VRP]);
        }
    }
}
        

void pace(const void *args)
{
    while(1)
    {
        Thread::signal_wait(0x01);
        if(paceA)
        {
            pc.printf("APace Sent\r\n");
            led2=1;
            aPace=1;
            Thread::wait(1);
            aPace=0;
            led2=0;
            if(modeChanged)
            {
                changeMode();
            }
            // start AVI Timer
            expectAMutex.lock();
            expectingASignal=false;
            expectAMutex.unlock();
            expectVMutex.lock();         
            expectingVSignal=false;         
            expectVMutex.unlock();
            timeOutStatusMutex.lock();
            timeOutStatus=PAVB;
            timeOutStatusMutex.unlock();
            timerRunning=true;
            TimeOutTimer->start(timeOutValue[PAVB]);
            //generate the APace pulse
        }
        else
        {
            pc.printf("VPace Sent\r\n");
            led1=1;
            vPace=1;
            Thread::wait(1);
            vPace=0;
            led1=0;
            if(modeChanged)
            {
                changeMode();
            }
            // start VRP and URI timers
            expectVMutex.lock();         
            expectingVSignal=false;         
            expectVMutex.unlock();
            expectAMutex.lock();
            expectingASignal=false;
            expectAMutex.unlock();
            heartRateMutex.lock();
            heartRate++;
            heartRateMutex.unlock();
            canPaceV=false;
            URITimeOutTimer->start(timeOutValue[URI]);
            timeOutStatusMutex.lock();
            timeOutStatus=VRP;
            timeOutStatusMutex.unlock();
            timerRunning=true;
            TimeOutTimer->start(timeOutValue[VRP]);
            //generate the VPace pulse
        }
    }
}

void serialThread(const void *args)
{
    while(1)
    {
        Thread::signal_wait(0x02);
        if((((ch=='a')||(ch=='A')) && paceMakerMode==4) && !observationChange)
        {
            //fire A Pace
            paceA=true;
            (*PacePTR).signal_set(0x01);
        }
        else if((((ch=='v')||(ch=='V')) && paceMakerMode==4) && !observationChange)
        {
            //fire V Pace
            if(canPaceV)
            {
                paceA=false;
                paceVPending=false;
                (*PacePTR).signal_set(0x01);
            }
            else
            {
                paceVPending=true;
            }
        }
        else if(((((ch=='n')||(ch=='N'))&& paceMakerMode!=1) && !observationChange) && !modeChanged)
        {
            paceMakerMode=1;                //change Mode to Normal
            modeChanged=true;
        }
        else if(((((ch=='e')||(ch=='E')) && paceMakerMode!=2) && !observationChange) && !modeChanged)
        {
            paceMakerMode=2;                //chnage mode to Exercise
            modeChanged=true;
        }
        else if(((((ch=='s')||(ch=='S')) && paceMakerMode!=3) && !observationChange) && !modeChanged)
        {
            paceMakerMode=3;            //change mode to Sleep
            modeChanged=true;
        }
        else if(((((ch=='b')||(ch=='B')) ) && !observationChange) )
        {
            ringAlarm=!ringAlarm;
        }
        else if(((((ch=='m')||(ch=='M')) && paceMakerMode!=4) && !observationChange) && !modeChanged)
        {
            paceMakerMode=4;            //change mode to Sleep
            modeChanged=true;
        }
        else if(((((ch=='o')||(ch=='O')) && !observationChange) && !modeChanged))
        {
            observationChange=true;
            digitOneReceived=false;
            digitTwoReceived=false;
            //spawn a timer for  3 seconds
            displayMutex.lock();
            ////////pc.locate(30, 18);
            pc.printf("Observation Interval change : -- seconds");
            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.locate(60, 18);
                pc.printf("%02d", observationRate);
                displayMutex.unlock();
            }
            else
            {
                KeyTimeOutTimer->stop();
                digitTwoReceived=true;
                observationChangeMutex.lock();
                observationRate=(observationRate*10)+(ch-'0');
                observationChangeMutex.unlock();
                observationChange=false;
                displayMutex.lock();
                ////pc.locate(60, 18);
                pc.printf("%02d", observationRate);
                displayMutex.unlock();
            }
        }                
    }
}

void alarm(const void *args)
{
    while(1)
    {
        Thread::wait(1000);
        while(((heartRateHeart*(60/sec))>(60000/timeOutValue[URI])) && ringAlarm)
        {
            buzzer=1;
            Thread::wait(5);
            buzzer=0;
            Thread::wait(5);
            if(!ringingAlarm)
            {
                displayMutex.lock();
                ////pc.locate(30, 16);
                pc.printf("Alarm : HeartRate too high");
                displayMutex.unlock();
                ringingAlarm=true;
            }
        }
        while(((heartRateHeart*(60/sec))<(60000/timeOutValue[LRI])) && ringAlarm)
        {
            buzzer=1;
            Thread::wait(10);
            buzzer=0;
            Thread::wait(10);
            if(!ringingAlarm)
            {
                displayMutex.lock();
                ////pc.locate(30, 16);
                pc.printf("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);
            } 
            else
            {
//                updateDisplay();
                resetDisplay();
            }
            waitCount=0;   
        }        
    }
}

int main() 
{
    pc.printf("Pace Maker Display\r\n");
    pc.printf("Heart Rate :  --- bpm\r\n");
    pc.printf("Observation Interval :  -- seconds\r\n");
    pc.printf("Mode :  Normal\r\n");
    pc.printf("Heart Beat Rate :  ----  bpm\r\n");   
    
    //initialize variables
    expectAMutex.lock();
    expectingASignal=true;
    expectAMutex.unlock();
    expectVMutex.lock();         
    expectingVSignal=true;         
    expectVMutex.unlock();
    setTimeOutValues(nLRI, nAVI, nPVARP, nURI, nVRP, nVSP, nPAVB);
    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;                              //assume at begining that URI has lapsed and start with an atrial event
    paceVPending=false;                                //assume that a VPace request has not happened already
    strcpy(modeString, "Normal");
    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();
    timeOutStatus=VRP;
    timeOutStatusMutex.unlock();
    //test lines to start pacing without heart; heart starts immediately after an Atrial event
    //timeOutStatus=AVI;
    TimeOutTimer->start(timeOutValue[VRP]);
    while(1) {
        if(pc.readable())
        {
            ch=pc.getc();
            (*SerialThreadPTR).signal_set(0x02);     //initiate the serial thread to change the state of the timer
        }
    }
}