Dependencies:   TextLCD mbed-rtos mbed

Fork of 541-pacemaker by Terry Fang

Files at this revision

API Documentation at this revision

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);