Dependencies: TextLCD mbed-rtos mbed
Fork of 541-pacemaker by
Revision 5:b506b5bdeee7, committed 2016-12-12
- Comitter:
- ems316
- Date:
- Mon Dec 12 21:50:48 2016 +0000
- Parent:
- 4:a9c37c60425c
- Commit message:
- final
Changed in this revision
main.cpp | Show annotated file Show diff for this revision Revisions of this file |
--- a/main.cpp Sun Dec 11 21:11:54 2016 +0000 +++ b/main.cpp Mon Dec 12 21:50:48 2016 +0000 @@ -1,8 +1,61 @@ +/* @Author: Grayson Honan, Phil Perilstein, Terry Fang, Eric Stahl + @Course: CIS 541 + @Due Date: 12 Dec 2016 + @Assignment: Pacemaker Project - Pacemaker Component + + @Description: This code is representative of the functionality + of a DDD pacemaker. The code was generated from an UPAAL model + that describes the basic timing functionality of a pacemaker and + the operation of system peripherals (lcd screen, alarm, keyboard). + + Main timing threads: + + PaceSense - handles triggering pace output events via timeouts + + PaceSignal - filters and accepts heart signal input events by + synchronizing with interupt ins. + + Main Peripheral Threads: + + displayThread - displays current bpm and then resets the bpm + and determines if abnormal bpm + + alarmThread - synchronizes with displayThread if abnormal bpm + and displays warning message to lcd screen + + ledThread - synchronizes with PaceSense or PaceSignal on a Vsense, + Asense, Vpace, Apace + + Rx_interrupt - interrupt that accepts keyboard input and filters + for valid keyboard input. Synchrnoizes with the thread that the + keyboard input is destined for via a Queue. + + Pace Mode Threads: + + Main - initializes to a Normal mode Pacemaker with an observation + interval of 10 seconds. Synchronizes with the Rx_interrupt when + valid keyboard input is determined. The main thread acts as the + Choose_PaceMode automata. + + manualmode - disables pace events from the pacemaker & allows for + user input to manually pace an atrial or ventrical event. + + Reference: https://developer.mbed.org/handbook/CMSIS-RTOS + + Run Instructions: Whenever I ran the program, I found I needed to first + run screen to open up the fd pointing to the usb. I would then kill the + screen process and run the ./start_game script after uncommenting the + port selection in the script. + +*/ + #include "mbed.h" #include "rtos.h" #include "TextLCD.h" #include <stdio.h> +// Input/Output declarations + InterruptIn vsignal(p7); InterruptIn asignal(p8); DigitalOut Vpace(p5); @@ -13,8 +66,7 @@ DigitalOut apace_led(LED3); DigitalOut vpace_led(LED4); -Thread *pacemodeThread; - +// thread definitions osThreadId signalTid; osThreadId senseTid; osThreadId displayTid; @@ -22,65 +74,77 @@ osThreadId alarmTid; osThreadId ledTid; +//peripheral API declarations TextLCD lcd(p15, p16, p17, p18, p19, p20, TextLCD::LCD16x2); RawSerial pc(USBTX, USBRX); +//timing declarations Timer vClock; -Timer aClock; //PaceSignal model +Timer aClock; Timer arpClock; +//normal mode timing constants double LRI = 1000; double URI = 700; -double VRP = 200; // V noise interval -double ARP = 50; // A noise interval -double AVI = 150; // A-V max interval -double PVARP = 300; // V-A max interval +double VRP = 200; +double ARP = 50; +double AVI = 150; +double PVARP = 300; double ratio; -int wait_period = 10; // 3a requirement +int wait_period = 10; double observation_interval = 10000; // In miliseconds int upperBound; //for mode changes int lowerBound; //for mode changes double heart_beats = 0; // Heart-Beats (sensed or paced) since the last observation interval -char mode = 'n'; -char key = 'n'; -char newObsInt[8]; -int manual_mode = 0; Mutex hr_mutex; //hr_mutex.lock()/unlock() +//message passing queues Queue<char,256> mode_q; Queue<char,256> signal_q; Queue<char,256> obsint_q; +//keyboard interrupt variables volatile char c; volatile int mm = 0; volatile int om = 0; + +//flag to disable automatic pacing int mm_flag = 0; +//init the ventrical timing values void initialize_intervals() { LRI = 1000; URI = 700; } +//interrupt for keyboard input. Filters valid input. void Rx_interrupt() { while(pc.readable()) { c = pc.getc(); + + //synchronize mode switch thread for manual mode if(c == 'm' && om != 1) { mode_q.put((char*)c); mm = 1; + //synchronize mode switch thread for normal, excercise or sleep mode } else if(c == 'n' || c == 'e' || c == 's' && om != 1) { mode_q.put((char*)c); mm = 0; + //if manual mode, synchronize with manual mode thread for a or v signal } else if((c == 'a' || c == 'v') && mm) { signal_q.put((char*)c); + //start accepting input to update the observation interval. Disable mode switching. } else if(c == 'o' && om != 1) { mode_q.put((char*)c); om = 1; + //end receiving input to update observation interval. Enable mode switching. } else if (c == '\r' && om) { obsint_q.put((char*)c); om = 0; + //updating observation interval, filter valid input. } else if ((int)c > 47 && (int)c < 58 && om) { obsint_q.put((char*)c); } @@ -92,22 +156,23 @@ { while (1) { + //wait for synchronization for Apace, Vpace, Asense, Vsense osEvent ext_signal = osSignalWait(0, osWaitForever); int evt = ext_signal.value.signals; - if (evt == 0xA) { + if (evt == 0xA) { //asense asense_led = 1; Thread::wait(wait_period); asense_led = 0; - } else if (evt == 0xB) { + } else if (evt == 0xB) { //vsense vsense_led = 1; Thread::wait(wait_period); vsense_led = 0; - } else if (evt == 0xC) { + } else if (evt == 0xC) { //apace apace_led = 1; Thread::wait(wait_period); apace_led = 0; - } else if (evt == 0xD) { + } else if (evt == 0xD) { //vpace vpace_led = 1; Thread::wait(wait_period); vpace_led = 0; @@ -115,36 +180,37 @@ } } +//Synchronized with displayThread if alarmThread should alarm void alarmThread(void const *args) { while (1) { osEvent ext_signal = osSignalWait(0, osWaitForever); int evt = ext_signal.value.signals; - if (evt == 0xb) { + if (evt == 0xb) { //upper bound violated lcd.printf("%s", "\nALARM HIGH"); - } else if (evt == 0xc) { + } else if (evt == 0xc) { //lower bound violated lcd.printf("%s", "\nALARM LOW"); } } } - +//Thread for displaying bpm & alerts void displayThread(void const *args) { while (1) { Thread::wait(observation_interval); lcd.cls(); - hr_mutex.lock(); - double hr = (heart_beats*60) / (observation_interval / 1000); - heart_beats = 0; + hr_mutex.lock(); //acquire lock because changing bpm + double hr = (heart_beats*60) / (observation_interval / 1000); //calculate bpm + heart_beats = 0; //reset bpm hr_mutex.unlock(); - lcd.printf("%s%d%s","HR: ", (int)hr, " bpm"); + lcd.printf("%s%d%s","HR: ", (int)hr, " bpm"); //display bpm - if (hr > upperBound) { + if (hr > upperBound) { //synchronize if upperBound violated osSignalSet(alarmTid, 0xb); - } else if (hr < lowerBound) { + } else if (hr < lowerBound) { //synchronize if lowerBound violated osSignalSet(alarmTid, 0xc); } } @@ -152,23 +218,26 @@ -// Incoming signal from the heart +// Incoming atrial signal from the heart void asignal_irq() { - osSignalSet(signalTid, 0x1); + osSignalSet(signalTid, 0x1); //synchronize with pacesignal thread } -// Incoming signal from the heart +// Incoming ventrical signal from the heart void vsignal_irq() { - osSignalSet(signalTid, 0x2); + osSignalSet(signalTid, 0x2); //synchronize with pacesignal thread } - +//Main timing thread for filtering Asignal and Vsignal from heart and +//generating Asense and Vsense to synchronize with the PaceSense thread. void PaceSignal(void const *args) { - int pFlag1 = 0; - int pFlag2 = 0; + + int pFlag1 = 0; //flag that allows us to move to the second UPPAAL state in PaceSignal + int pFlag2 = 0; //flag that allows us to move to the first UPPAAL state in PaceSignal + vClock.start(); aClock.start(); arpClock.start(); @@ -185,16 +254,16 @@ pFlag1 = 1; } else if(evt == 0x2 && vClock.read_ms() >= VRP) { //vSense hr_mutex.lock(); - osSignalSet(senseTid, 0x2); - heart_beats++; + osSignalSet(senseTid, 0x2); //syncrhonize with PaceSense thread + heart_beats++; //increment bpm vClock.reset(); aClock.reset(); arpClock.reset(); hr_mutex.unlock(); - pFlag1 = 1; + pFlag1 = 1; //progress to state 2 } else if (evt == 0x3) { //aPace - pFlag1 = 1; + pFlag1 = 1; //progress to state 2 } } pFlag1 = 0; @@ -205,19 +274,19 @@ if (evt == 0x1 && arpClock.read_ms() >= ARP) { //aSense osSignalSet(senseTid, 0x1); - arpClock.reset(); + arpClock.reset(); //determine valid consecutive a event } else if(evt == 0x2) { //vSense hr_mutex.lock(); osSignalSet(senseTid, 0x2); - heart_beats++; + heart_beats++; //increment bpm vClock.reset(); aClock.reset(); arpClock.reset(); hr_mutex.unlock(); - pFlag2 = 1; + pFlag2 = 1; //progress to state 1 } else if (evt == 0x4) { //vPace - pFlag2 = 1; + pFlag2 = 1; //progress to state 1 } } pFlag2 = 0; @@ -226,27 +295,26 @@ void PaceSense(void const *args) { - int interval; - int pFlag1 = 0; - int pFlag2 = 0; - int time_sub = 0; + int pFlag1 = 0; //flag that allows us to move to the second UPPAAL state in PaceSense + int pFlag2 = 0; //flag that allows us to move to the first UPPAAL state in PaceSense + int time_sub = 0; //used to determine timeout for when to pace (this is our invariant) int evt = 0; while(1) { while (!pFlag1) { - time_sub = LRI-AVI - vClock.read_ms(); + time_sub = LRI-AVI - vClock.read_ms(); //aPace at LRI-AVI default if (time_sub > 0 && !mm_flag) { - osEvent ext_signal = osSignalWait(0, time_sub); + osEvent ext_signal = osSignalWait(0, time_sub); //allow pacing evt = ext_signal.value.signals; } else if(mm_flag) { - osEvent ext_signal = osSignalWait(0, osWaitForever); + osEvent ext_signal = osSignalWait(0, osWaitForever); //disable pacing evt = ext_signal.value.signals; } else { - evt = 0x0; + evt = 0x0; //time_sub is less than 0 } - if (evt == 0x0) { //aPace 0x0 + if (evt == 0x0) { //aPace aClock.reset(); arpClock.reset(); Apace = 1; @@ -254,38 +322,33 @@ Apace = 0; osSignalSet(signalTid, 0x3); osSignalSet(ledTid, 0xC); - - interval = AVI; pFlag1 = 1; } else if (evt == 0x1) { //aSense - if(!mm_flag) { - interval = (vClock.read_ms() + AVI >= URI) ? AVI : URI; - time_sub = interval; - } osSignalSet(ledTid, 0xA); pFlag1 = 1; } else if(evt == 0x2) { //vSense osSignalSet(ledTid, 0xB); - } else if(evt == 0x3) { //apace + } else if(evt == 0x3) { //manual apace pFlag1 = 1; } } pFlag1 = 0; while(!pFlag2) { - time_sub = (interval == AVI) ? AVI - aClock.read_ms() : URI - vClock.read_ms(); + //vpace occurs at either URI or vclock + AVI + time_sub = (vClock.read_ms() + AVI >= URI) ? AVI - aClock.read_ms() : URI - vClock.read_ms(); - if (time_sub > 0 && !mm_flag) { + if (time_sub > 0 && !mm_flag) { //allow pacing osEvent ext_signal = osSignalWait(0, time_sub); evt = ext_signal.value.signals; - } else if(mm_flag) { + } else if(mm_flag) { //disable pacing osEvent ext_signal = osSignalWait(0, osWaitForever); evt = ext_signal.value.signals; } else { - evt = 0x0; + evt = 0x0; //time_sub is negative } - if (evt == 0x0) { //vPace 0x0 + if (evt == 0x0) { //vPace hr_mutex.lock(); heart_beats++; @@ -306,20 +369,37 @@ } else if(evt == 0x2) { //vSense osSignalSet(ledTid, 0xB); pFlag2 = 1; - } else if (evt == 0x4) { //vpace + } else if (evt == 0x4) { //manual vpace pFlag2 = 1; } } pFlag2 = 0; } } - +//update timing constraints for mode and reset bpm void normalmode(void const *args) { initialize_intervals(); - mode = 'n'; upperBound = 100; //beats per msecond lowerBound = 40; //beats per msecond + //hr_mutex.lock(); + //reset bpm + heart_beats = 0; + hr_mutex.unlock(); + + vClock.reset(); + aClock.reset(); +} +//update timing constraints for mode and reset bpm +void exercisemode(void const *args) +{ + initialize_intervals(); + upperBound = 175; //beats per msecond + lowerBound = 100; //beats per msecond + ratio = (175.00/100.00 + 100.00/40.00) / 2.00; + LRI /= ratio; + URI /= ratio; + //reset bpm hr_mutex.lock(); heart_beats = 0; hr_mutex.unlock(); @@ -327,42 +407,24 @@ vClock.reset(); aClock.reset(); } - -void exercisemode(void const *args) +//update timing constraints for mode and reset bpm +void sleepmode(void const *args) { initialize_intervals(); - mode = 'e'; - upperBound = 175; //beats per msecond - lowerBound = 100; //beats per msecond - ratio = (175.00/100.00 + 100.00/40.00) / 2.00; + upperBound = 60; //beats per msecond + lowerBound = 30; //beats per msecond v-v 0.5s + ratio = (60.00/100.00 + 30.00/40.00) / 2.00; LRI /= ratio; URI /= ratio; - //reset obs interval hr_mutex.lock(); + //reset bpm heart_beats = 0; hr_mutex.unlock(); vClock.reset(); aClock.reset(); } - -void sleepmode(void const *args) -{ - initialize_intervals(); - mode = 's'; - upperBound = 60; //beats per msecond - lowerBound = 30; //beats per msecond v-v 0.5s - ratio = (60.00/100.00 + 30.00/40.00) / 2.00; - LRI /= ratio; - URI /= ratio; - hr_mutex.lock(); - heart_beats = 0; - hr_mutex.unlock(); - - vClock.reset(); - aClock.reset(); -} - +//handle manual pacing events void m_vpace() { vClock.reset(); @@ -379,7 +441,7 @@ osSignalSet(ledTid, 0xD); } - +//handle manual pacing events void m_apace() { aClock.reset(); @@ -391,12 +453,11 @@ osSignalSet(signalTid, 0x3); osSignalSet(ledTid, 0xC); } - +//update timing constraints for mode and handle manual pace events void manualmode(void const *args) { upperBound = 175; //beats per msecond lowerBound = 30; //beats per msecond - mode = 'm'; LRI = 2125; // max V-V (LRI) based on exercise mode URI = 675; // min V-V (URI) based on sleep mode @@ -411,25 +472,27 @@ } } } - +//manage user input for updating the observation interval void obsinterval() { char newObsInt[8]; int isChangingObsInt = 1; int i = 0; + char key = 'n'; while(isChangingObsInt) { osEvent evt = obsint_q.get(); if(evt.status == osEventMessage) { key = (char)evt.value.p; - if(key != '\r' && i < 7 ) { + if(key != '\r' && i < 7 ) { //bound number of integers for overflow newObsInt[i] = key; i++; - } else if((key == '\r') && (i > 0)) { + } else if((key == '\r') && (i > 0)) { //conver input to observatio interval heart_beats = 0; int obsint; newObsInt[i] = '\0'; sscanf(newObsInt, "%d", &obsint); + //check bounds if(obsint < 300) { observation_interval = 300.0; } else if (obsint > 10000) { @@ -444,35 +507,42 @@ } } + +//create thread definitions osThreadDef(PaceSignal, osPriorityNormal, DEFAULT_STACK_SIZE); osThreadDef(PaceSense, osPriorityNormal, DEFAULT_STACK_SIZE); -osThreadDef(alarmThread, osPriorityBelowNormal, DEFAULT_STACK_SIZE); //priority BelowNormal +osThreadDef(alarmThread, osPriorityBelowNormal, DEFAULT_STACK_SIZE); osThreadDef(ledThread, osPriorityBelowNormal, DEFAULT_STACK_SIZE); -osThreadDef(displayThread, osPriorityLow, DEFAULT_STACK_SIZE); //priority Low +osThreadDef(displayThread, osPriorityLow, DEFAULT_STACK_SIZE); osThreadDef(manualmode, osPriorityNormal, DEFAULT_STACK_SIZE); int main() { + //create thread ids alarmTid = osThreadCreate(osThread(alarmThread), NULL); senseTid = osThreadCreate(osThread(PaceSense), NULL); signalTid = osThreadCreate(osThread(PaceSignal), NULL); displayTid = osThreadCreate(osThread(displayThread), NULL); ledTid = osThreadCreate(osThread(ledThread), NULL); + //start pacemaker in normal mode normalmode(NULL); - vsignal.rise(&vsignal_irq); //rising edge of timer + //set interrupt ins on signaling inputs + vsignal.rise(&vsignal_irq); asignal.rise(&asignal_irq); + //clear lcd lcd.cls(); + //set interrupt in for serial input pc.attach(&Rx_interrupt, RawSerial::RxIrq); - while(true) { + while(true) { //handle mode switching synchronization osEvent evt = mode_q.get(); if(evt.status == osEventMessage) { switch((char)evt.value.p) { - case('n'): + case('n'): //normal mode mm_flag = 0; osSignalSet(senseTid, 0x5); osThreadTerminate (pacemodeTid); @@ -480,7 +550,7 @@ normalmode(NULL); displayTid = osThreadCreate(osThread(displayThread), NULL); break; - case('s'): + case('s'): //sleep mode mm_flag = 0; osSignalSet(senseTid, 0x5); osThreadTerminate (pacemodeTid); @@ -488,7 +558,7 @@ sleepmode(NULL); displayTid = osThreadCreate(osThread(displayThread), NULL); break; - case('e'): + case('e'): //excercise mode mm_flag = 0; osSignalSet(senseTid, 0x5); osThreadTerminate (pacemodeTid); @@ -496,13 +566,13 @@ exercisemode(NULL); displayTid = osThreadCreate(osThread(displayThread), NULL); break; - case('m'): + case('m'): //manual mode mm_flag = 1; + osSignalSet(senseTid, 0x5); osThreadTerminate (pacemodeTid); pacemodeTid = osThreadCreate(osThread(manualmode), NULL); - manual_mode = 1; break; - case('o'): + case('o'): //observation interval obsinterval(); osThreadTerminate (displayTid); displayTid = osThreadCreate(osThread(displayThread), NULL);