Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: TextLCD mbed-rtos mbed
Fork of 541-pacemaker by
main.cpp
00001 /* @Author: Grayson Honan, Phil Perilstein, Terry Fang, Eric Stahl 00002 @Course: CIS 541 00003 @Due Date: 12 Dec 2016 00004 @Assignment: Pacemaker Project - Pacemaker Component 00005 00006 @Description: This code is representative of the functionality 00007 of a DDD pacemaker. The code was generated from an UPAAL model 00008 that describes the basic timing functionality of a pacemaker and 00009 the operation of system peripherals (lcd screen, alarm, keyboard). 00010 00011 Main timing threads: 00012 00013 PaceSense - handles triggering pace output events via timeouts 00014 00015 PaceSignal - filters and accepts heart signal input events by 00016 synchronizing with interupt ins. 00017 00018 Main Peripheral Threads: 00019 00020 displayThread - displays current bpm and then resets the bpm 00021 and determines if abnormal bpm 00022 00023 alarmThread - synchronizes with displayThread if abnormal bpm 00024 and displays warning message to lcd screen 00025 00026 ledThread - synchronizes with PaceSense or PaceSignal on a Vsense, 00027 Asense, Vpace, Apace 00028 00029 Rx_interrupt - interrupt that accepts keyboard input and filters 00030 for valid keyboard input. Synchrnoizes with the thread that the 00031 keyboard input is destined for via a Queue. 00032 00033 Pace Mode Threads: 00034 00035 Main - initializes to a Normal mode Pacemaker with an observation 00036 interval of 10 seconds. Synchronizes with the Rx_interrupt when 00037 valid keyboard input is determined. The main thread acts as the 00038 Choose_PaceMode automata. 00039 00040 manualmode - disables pace events from the pacemaker & allows for 00041 user input to manually pace an atrial or ventrical event. 00042 00043 Reference: https://developer.mbed.org/handbook/CMSIS-RTOS 00044 00045 Run Instructions: Whenever I ran the program, I found I needed to first 00046 run screen to open up the fd pointing to the usb. I would then kill the 00047 screen process and run the ./start_game script after uncommenting the 00048 port selection in the script. 00049 00050 */ 00051 00052 #include "mbed.h" 00053 #include "rtos.h" 00054 #include "TextLCD.h" 00055 #include <stdio.h> 00056 00057 // Input/Output declarations 00058 00059 InterruptIn vsignal(p7); 00060 InterruptIn asignal(p8); 00061 DigitalOut Vpace(p5); 00062 DigitalOut Apace(p6); 00063 00064 DigitalOut asense_led(LED1); 00065 DigitalOut vsense_led(LED2); 00066 DigitalOut apace_led(LED3); 00067 DigitalOut vpace_led(LED4); 00068 00069 // thread definitions 00070 osThreadId signalTid; 00071 osThreadId senseTid; 00072 osThreadId displayTid; 00073 osThreadId pacemodeTid; 00074 osThreadId alarmTid; 00075 osThreadId ledTid; 00076 00077 //peripheral API declarations 00078 TextLCD lcd(p15, p16, p17, p18, p19, p20, TextLCD::LCD16x2); 00079 RawSerial pc(USBTX, USBRX); 00080 00081 //timing declarations 00082 Timer vClock; 00083 Timer aClock; 00084 Timer arpClock; 00085 00086 //normal mode timing constants 00087 double LRI = 1000; 00088 double URI = 700; 00089 double VRP = 200; 00090 double ARP = 50; 00091 double AVI = 150; 00092 double PVARP = 300; 00093 double ratio; 00094 int wait_period = 10; 00095 00096 double observation_interval = 10000; // In miliseconds 00097 int upperBound; //for mode changes 00098 int lowerBound; //for mode changes 00099 double heart_beats = 0; // Heart-Beats (sensed or paced) since the last observation interval 00100 Mutex hr_mutex; //hr_mutex.lock()/unlock() 00101 00102 //message passing queues 00103 Queue<char,256> mode_q; 00104 Queue<char,256> signal_q; 00105 Queue<char,256> obsint_q; 00106 00107 //keyboard interrupt variables 00108 volatile char c; 00109 volatile int mm = 0; 00110 volatile int om = 0; 00111 00112 //flag to disable automatic pacing 00113 int mm_flag = 0; 00114 00115 //init the ventrical timing values 00116 void initialize_intervals() 00117 { 00118 LRI = 1000; 00119 URI = 700; 00120 } 00121 00122 //interrupt for keyboard input. Filters valid input. 00123 void Rx_interrupt() 00124 { 00125 while(pc.readable()) { 00126 c = pc.getc(); 00127 00128 //synchronize mode switch thread for manual mode 00129 if(c == 'm' && om != 1) { 00130 mode_q.put((char*)c); 00131 mm = 1; 00132 //synchronize mode switch thread for normal, excercise or sleep mode 00133 } else if(c == 'n' || c == 'e' || c == 's' && om != 1) { 00134 mode_q.put((char*)c); 00135 mm = 0; 00136 //if manual mode, synchronize with manual mode thread for a or v signal 00137 } else if((c == 'a' || c == 'v') && mm) { 00138 signal_q.put((char*)c); 00139 //start accepting input to update the observation interval. Disable mode switching. 00140 } else if(c == 'o' && om != 1) { 00141 mode_q.put((char*)c); 00142 om = 1; 00143 //end receiving input to update observation interval. Enable mode switching. 00144 } else if (c == '\r' && om) { 00145 obsint_q.put((char*)c); 00146 om = 0; 00147 //updating observation interval, filter valid input. 00148 } else if ((int)c > 47 && (int)c < 58 && om) { 00149 obsint_q.put((char*)c); 00150 } 00151 } 00152 } 00153 00154 // Function to toggle the LEDs 1,2,3,4 00155 void ledThread(void const *args) 00156 00157 { 00158 while (1) { 00159 //wait for synchronization for Apace, Vpace, Asense, Vsense 00160 osEvent ext_signal = osSignalWait(0, osWaitForever); 00161 int evt = ext_signal.value.signals; 00162 00163 if (evt == 0xA) { //asense 00164 asense_led = 1; 00165 Thread::wait(wait_period); 00166 asense_led = 0; 00167 } else if (evt == 0xB) { //vsense 00168 vsense_led = 1; 00169 Thread::wait(wait_period); 00170 vsense_led = 0; 00171 } else if (evt == 0xC) { //apace 00172 apace_led = 1; 00173 Thread::wait(wait_period); 00174 apace_led = 0; 00175 } else if (evt == 0xD) { //vpace 00176 vpace_led = 1; 00177 Thread::wait(wait_period); 00178 vpace_led = 0; 00179 } 00180 } 00181 } 00182 00183 //Synchronized with displayThread if alarmThread should alarm 00184 void alarmThread(void const *args) 00185 { 00186 while (1) { 00187 osEvent ext_signal = osSignalWait(0, osWaitForever); 00188 int evt = ext_signal.value.signals; 00189 00190 if (evt == 0xb) { //upper bound violated 00191 lcd.printf("%s", "\nALARM HIGH"); 00192 } else if (evt == 0xc) { //lower bound violated 00193 lcd.printf("%s", "\nALARM LOW"); 00194 } 00195 } 00196 } 00197 //Thread for displaying bpm & alerts 00198 void displayThread(void const *args) 00199 { 00200 while (1) { 00201 Thread::wait(observation_interval); 00202 lcd.cls(); 00203 00204 hr_mutex.lock(); //acquire lock because changing bpm 00205 double hr = (heart_beats*60) / (observation_interval / 1000); //calculate bpm 00206 heart_beats = 0; //reset bpm 00207 hr_mutex.unlock(); 00208 00209 lcd.printf("%s%d%s","HR: ", (int)hr, " bpm"); //display bpm 00210 00211 if (hr > upperBound) { //synchronize if upperBound violated 00212 osSignalSet(alarmTid, 0xb); 00213 } else if (hr < lowerBound) { //synchronize if lowerBound violated 00214 osSignalSet(alarmTid, 0xc); 00215 } 00216 } 00217 } 00218 00219 00220 00221 // Incoming atrial signal from the heart 00222 void asignal_irq() 00223 { 00224 osSignalSet(signalTid, 0x1); //synchronize with pacesignal thread 00225 } 00226 00227 // Incoming ventrical signal from the heart 00228 void vsignal_irq() 00229 { 00230 osSignalSet(signalTid, 0x2); //synchronize with pacesignal thread 00231 } 00232 00233 //Main timing thread for filtering Asignal and Vsignal from heart and 00234 //generating Asense and Vsense to synchronize with the PaceSense thread. 00235 void PaceSignal(void const *args) 00236 { 00237 00238 int pFlag1 = 0; //flag that allows us to move to the second UPPAAL state in PaceSignal 00239 int pFlag2 = 0; //flag that allows us to move to the first UPPAAL state in PaceSignal 00240 00241 vClock.start(); 00242 aClock.start(); 00243 arpClock.start(); 00244 00245 while(1) { 00246 while (!pFlag1) { 00247 osEvent ext_signal = osSignalWait(0, osWaitForever); 00248 int evt = ext_signal.value.signals; 00249 00250 if (evt == 0x1 && vClock.read_ms() >= PVARP) { //aSense 00251 osSignalSet(senseTid, 0x1); 00252 aClock.reset(); 00253 arpClock.reset(); 00254 pFlag1 = 1; 00255 } else if(evt == 0x2 && vClock.read_ms() >= VRP) { //vSense 00256 hr_mutex.lock(); 00257 osSignalSet(senseTid, 0x2); //syncrhonize with PaceSense thread 00258 heart_beats++; //increment bpm 00259 vClock.reset(); 00260 aClock.reset(); 00261 arpClock.reset(); 00262 hr_mutex.unlock(); 00263 pFlag1 = 1; //progress to state 2 00264 00265 } else if (evt == 0x3) { //aPace 00266 pFlag1 = 1; //progress to state 2 00267 } 00268 } 00269 pFlag1 = 0; 00270 while(!pFlag2) { 00271 00272 osEvent ext_signal = osSignalWait(0, osWaitForever); 00273 int evt = ext_signal.value.signals; 00274 00275 if (evt == 0x1 && arpClock.read_ms() >= ARP) { //aSense 00276 osSignalSet(senseTid, 0x1); 00277 arpClock.reset(); //determine valid consecutive a event 00278 00279 } else if(evt == 0x2) { //vSense 00280 hr_mutex.lock(); 00281 osSignalSet(senseTid, 0x2); 00282 heart_beats++; //increment bpm 00283 vClock.reset(); 00284 aClock.reset(); 00285 arpClock.reset(); 00286 hr_mutex.unlock(); 00287 pFlag2 = 1; //progress to state 1 00288 } else if (evt == 0x4) { //vPace 00289 pFlag2 = 1; //progress to state 1 00290 } 00291 } 00292 pFlag2 = 0; 00293 } 00294 } 00295 00296 void PaceSense(void const *args) 00297 { 00298 int pFlag1 = 0; //flag that allows us to move to the second UPPAAL state in PaceSense 00299 int pFlag2 = 0; //flag that allows us to move to the first UPPAAL state in PaceSense 00300 int time_sub = 0; //used to determine timeout for when to pace (this is our invariant) 00301 int evt = 0; 00302 while(1) { 00303 while (!pFlag1) { 00304 00305 time_sub = LRI-AVI - vClock.read_ms(); //aPace at LRI-AVI default 00306 00307 if (time_sub > 0 && !mm_flag) { 00308 osEvent ext_signal = osSignalWait(0, time_sub); //allow pacing 00309 evt = ext_signal.value.signals; 00310 } else if(mm_flag) { 00311 osEvent ext_signal = osSignalWait(0, osWaitForever); //disable pacing 00312 evt = ext_signal.value.signals; 00313 } else { 00314 evt = 0x0; //time_sub is less than 0 00315 } 00316 00317 if (evt == 0x0) { //aPace 00318 aClock.reset(); 00319 arpClock.reset(); 00320 Apace = 1; 00321 Thread::wait(1); 00322 Apace = 0; 00323 osSignalSet(signalTid, 0x3); 00324 osSignalSet(ledTid, 0xC); 00325 pFlag1 = 1; 00326 } else if (evt == 0x1) { //aSense 00327 osSignalSet(ledTid, 0xA); 00328 pFlag1 = 1; 00329 } else if(evt == 0x2) { //vSense 00330 osSignalSet(ledTid, 0xB); 00331 } else if(evt == 0x3) { //manual apace 00332 pFlag1 = 1; 00333 } 00334 } 00335 pFlag1 = 0; 00336 00337 while(!pFlag2) { 00338 //vpace occurs at either URI or vclock + AVI 00339 time_sub = (vClock.read_ms() + AVI >= URI) ? AVI - aClock.read_ms() : URI - vClock.read_ms(); 00340 00341 if (time_sub > 0 && !mm_flag) { //allow pacing 00342 osEvent ext_signal = osSignalWait(0, time_sub); 00343 evt = ext_signal.value.signals; 00344 } else if(mm_flag) { //disable pacing 00345 osEvent ext_signal = osSignalWait(0, osWaitForever); 00346 evt = ext_signal.value.signals; 00347 } else { 00348 evt = 0x0; //time_sub is negative 00349 } 00350 00351 if (evt == 0x0) { //vPace 00352 00353 hr_mutex.lock(); 00354 heart_beats++; 00355 vClock.reset(); 00356 aClock.reset(); 00357 arpClock.reset(); 00358 Vpace = 1; 00359 Thread::wait(1); 00360 Vpace = 0; 00361 osSignalSet(signalTid, 0x4); 00362 hr_mutex.unlock(); 00363 00364 osSignalSet(ledTid, 0xD); 00365 pFlag2 = 1; 00366 00367 } else if (evt == 0x1) { //aSense 00368 osSignalSet(ledTid, 0xA); 00369 } else if(evt == 0x2) { //vSense 00370 osSignalSet(ledTid, 0xB); 00371 pFlag2 = 1; 00372 } else if (evt == 0x4) { //manual vpace 00373 pFlag2 = 1; 00374 } 00375 } 00376 pFlag2 = 0; 00377 } 00378 } 00379 //update timing constraints for mode and reset bpm 00380 void normalmode(void const *args) 00381 { 00382 initialize_intervals(); 00383 upperBound = 100; //beats per msecond 00384 lowerBound = 40; //beats per msecond 00385 //hr_mutex.lock(); 00386 //reset bpm 00387 heart_beats = 0; 00388 hr_mutex.unlock(); 00389 00390 vClock.reset(); 00391 aClock.reset(); 00392 } 00393 //update timing constraints for mode and reset bpm 00394 void exercisemode(void const *args) 00395 { 00396 initialize_intervals(); 00397 upperBound = 175; //beats per msecond 00398 lowerBound = 100; //beats per msecond 00399 ratio = (175.00/100.00 + 100.00/40.00) / 2.00; 00400 LRI /= ratio; 00401 URI /= ratio; 00402 //reset bpm 00403 hr_mutex.lock(); 00404 heart_beats = 0; 00405 hr_mutex.unlock(); 00406 00407 vClock.reset(); 00408 aClock.reset(); 00409 } 00410 //update timing constraints for mode and reset bpm 00411 void sleepmode(void const *args) 00412 { 00413 initialize_intervals(); 00414 upperBound = 60; //beats per msecond 00415 lowerBound = 30; //beats per msecond v-v 0.5s 00416 ratio = (60.00/100.00 + 30.00/40.00) / 2.00; 00417 LRI /= ratio; 00418 URI /= ratio; 00419 hr_mutex.lock(); 00420 //reset bpm 00421 heart_beats = 0; 00422 hr_mutex.unlock(); 00423 00424 vClock.reset(); 00425 aClock.reset(); 00426 } 00427 //handle manual pacing events 00428 void m_vpace() 00429 { 00430 vClock.reset(); 00431 aClock.reset(); 00432 arpClock.reset(); 00433 Vpace = 1; 00434 Thread::wait(1); 00435 Vpace = 0; 00436 osSignalSet(signalTid, 0x4); 00437 osSignalSet(senseTid, 0x4); 00438 hr_mutex.lock(); 00439 heart_beats++; 00440 hr_mutex.unlock(); 00441 00442 osSignalSet(ledTid, 0xD); 00443 } 00444 //handle manual pacing events 00445 void m_apace() 00446 { 00447 aClock.reset(); 00448 arpClock.reset(); 00449 Apace = 1; 00450 Thread::wait(1); 00451 Apace = 0; 00452 osSignalSet(senseTid, 0x3); 00453 osSignalSet(signalTid, 0x3); 00454 osSignalSet(ledTid, 0xC); 00455 } 00456 //update timing constraints for mode and handle manual pace events 00457 void manualmode(void const *args) 00458 { 00459 upperBound = 175; //beats per msecond 00460 lowerBound = 30; //beats per msecond 00461 LRI = 2125; // max V-V (LRI) based on exercise mode 00462 URI = 675; // min V-V (URI) based on sleep mode 00463 00464 while(1) { 00465 osEvent evt = signal_q.get(); 00466 if(evt.status == osEventMessage) { 00467 if((char)evt.value.p == 'v') { 00468 m_vpace(); 00469 } else if((char)evt.value.p == 'a') { 00470 m_apace(); 00471 } 00472 } 00473 } 00474 } 00475 //manage user input for updating the observation interval 00476 void obsinterval() 00477 { 00478 char newObsInt[8]; 00479 int isChangingObsInt = 1; 00480 int i = 0; 00481 char key = 'n'; 00482 while(isChangingObsInt) { 00483 osEvent evt = obsint_q.get(); 00484 if(evt.status == osEventMessage) { 00485 key = (char)evt.value.p; 00486 if(key != '\r' && i < 7 ) { //bound number of integers for overflow 00487 newObsInt[i] = key; 00488 i++; 00489 } else if((key == '\r') && (i > 0)) { //conver input to observatio interval 00490 heart_beats = 0; 00491 int obsint; 00492 newObsInt[i] = '\0'; 00493 sscanf(newObsInt, "%d", &obsint); 00494 00495 //check bounds 00496 if(obsint < 300) { 00497 observation_interval = 300.0; 00498 } else if (obsint > 10000) { 00499 observation_interval = 10000.0; 00500 } else { 00501 observation_interval = (double)obsint; 00502 } 00503 isChangingObsInt = 0; 00504 00505 } 00506 } 00507 } 00508 } 00509 00510 00511 //create thread definitions 00512 osThreadDef(PaceSignal, osPriorityNormal, DEFAULT_STACK_SIZE); 00513 osThreadDef(PaceSense, osPriorityNormal, DEFAULT_STACK_SIZE); 00514 osThreadDef(alarmThread, osPriorityBelowNormal, DEFAULT_STACK_SIZE); 00515 osThreadDef(ledThread, osPriorityBelowNormal, DEFAULT_STACK_SIZE); 00516 00517 osThreadDef(displayThread, osPriorityLow, DEFAULT_STACK_SIZE); 00518 osThreadDef(manualmode, osPriorityNormal, DEFAULT_STACK_SIZE); 00519 00520 int main() 00521 { 00522 //create thread ids 00523 alarmTid = osThreadCreate(osThread(alarmThread), NULL); 00524 senseTid = osThreadCreate(osThread(PaceSense), NULL); 00525 signalTid = osThreadCreate(osThread(PaceSignal), NULL); 00526 displayTid = osThreadCreate(osThread(displayThread), NULL); 00527 ledTid = osThreadCreate(osThread(ledThread), NULL); 00528 00529 //start pacemaker in normal mode 00530 normalmode(NULL); 00531 00532 //set interrupt ins on signaling inputs 00533 vsignal.rise(&vsignal_irq); 00534 asignal.rise(&asignal_irq); 00535 00536 //clear lcd 00537 lcd.cls(); 00538 00539 //set interrupt in for serial input 00540 pc.attach(&Rx_interrupt, RawSerial::RxIrq); 00541 while(true) { //handle mode switching synchronization 00542 osEvent evt = mode_q.get(); 00543 if(evt.status == osEventMessage) { 00544 switch((char)evt.value.p) { 00545 case('n'): //normal mode 00546 mm_flag = 0; 00547 osSignalSet(senseTid, 0x5); 00548 osThreadTerminate (pacemodeTid); 00549 osThreadTerminate (displayTid); 00550 normalmode(NULL); 00551 displayTid = osThreadCreate(osThread(displayThread), NULL); 00552 break; 00553 case('s'): //sleep mode 00554 mm_flag = 0; 00555 osSignalSet(senseTid, 0x5); 00556 osThreadTerminate (pacemodeTid); 00557 osThreadTerminate (displayTid); 00558 sleepmode(NULL); 00559 displayTid = osThreadCreate(osThread(displayThread), NULL); 00560 break; 00561 case('e'): //excercise mode 00562 mm_flag = 0; 00563 osSignalSet(senseTid, 0x5); 00564 osThreadTerminate (pacemodeTid); 00565 osThreadTerminate (displayTid); 00566 exercisemode(NULL); 00567 displayTid = osThreadCreate(osThread(displayThread), NULL); 00568 break; 00569 case('m'): //manual mode 00570 mm_flag = 1; 00571 osSignalSet(senseTid, 0x5); 00572 osThreadTerminate (pacemodeTid); 00573 pacemodeTid = osThreadCreate(osThread(manualmode), NULL); 00574 break; 00575 case('o'): //observation interval 00576 obsinterval(); 00577 osThreadTerminate (displayTid); 00578 displayTid = osThreadCreate(osThread(displayThread), NULL); 00579 break; 00580 } 00581 } 00582 } 00583 }
Generated on Wed Mar 15 2023 01:36:28 by
1.7.2
