final

Dependencies:   TextLCD mbed-rtos mbed

Fork of 541-pacemaker by Terry Fang

Committer:
ems316
Date:
Mon Dec 12 21:50:48 2016 +0000
Revision:
5:b506b5bdeee7
Parent:
4:a9c37c60425c
final

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ems316 5:b506b5bdeee7 1 /* @Author: Grayson Honan, Phil Perilstein, Terry Fang, Eric Stahl
ems316 5:b506b5bdeee7 2 @Course: CIS 541
ems316 5:b506b5bdeee7 3 @Due Date: 12 Dec 2016
ems316 5:b506b5bdeee7 4 @Assignment: Pacemaker Project - Pacemaker Component
ems316 5:b506b5bdeee7 5
ems316 5:b506b5bdeee7 6 @Description: This code is representative of the functionality
ems316 5:b506b5bdeee7 7 of a DDD pacemaker. The code was generated from an UPAAL model
ems316 5:b506b5bdeee7 8 that describes the basic timing functionality of a pacemaker and
ems316 5:b506b5bdeee7 9 the operation of system peripherals (lcd screen, alarm, keyboard).
ems316 5:b506b5bdeee7 10
ems316 5:b506b5bdeee7 11 Main timing threads:
ems316 5:b506b5bdeee7 12
ems316 5:b506b5bdeee7 13 PaceSense - handles triggering pace output events via timeouts
ems316 5:b506b5bdeee7 14
ems316 5:b506b5bdeee7 15 PaceSignal - filters and accepts heart signal input events by
ems316 5:b506b5bdeee7 16 synchronizing with interupt ins.
ems316 5:b506b5bdeee7 17
ems316 5:b506b5bdeee7 18 Main Peripheral Threads:
ems316 5:b506b5bdeee7 19
ems316 5:b506b5bdeee7 20 displayThread - displays current bpm and then resets the bpm
ems316 5:b506b5bdeee7 21 and determines if abnormal bpm
ems316 5:b506b5bdeee7 22
ems316 5:b506b5bdeee7 23 alarmThread - synchronizes with displayThread if abnormal bpm
ems316 5:b506b5bdeee7 24 and displays warning message to lcd screen
ems316 5:b506b5bdeee7 25
ems316 5:b506b5bdeee7 26 ledThread - synchronizes with PaceSense or PaceSignal on a Vsense,
ems316 5:b506b5bdeee7 27 Asense, Vpace, Apace
ems316 5:b506b5bdeee7 28
ems316 5:b506b5bdeee7 29 Rx_interrupt - interrupt that accepts keyboard input and filters
ems316 5:b506b5bdeee7 30 for valid keyboard input. Synchrnoizes with the thread that the
ems316 5:b506b5bdeee7 31 keyboard input is destined for via a Queue.
ems316 5:b506b5bdeee7 32
ems316 5:b506b5bdeee7 33 Pace Mode Threads:
ems316 5:b506b5bdeee7 34
ems316 5:b506b5bdeee7 35 Main - initializes to a Normal mode Pacemaker with an observation
ems316 5:b506b5bdeee7 36 interval of 10 seconds. Synchronizes with the Rx_interrupt when
ems316 5:b506b5bdeee7 37 valid keyboard input is determined. The main thread acts as the
ems316 5:b506b5bdeee7 38 Choose_PaceMode automata.
ems316 5:b506b5bdeee7 39
ems316 5:b506b5bdeee7 40 manualmode - disables pace events from the pacemaker & allows for
ems316 5:b506b5bdeee7 41 user input to manually pace an atrial or ventrical event.
ems316 5:b506b5bdeee7 42
ems316 5:b506b5bdeee7 43 Reference: https://developer.mbed.org/handbook/CMSIS-RTOS
ems316 5:b506b5bdeee7 44
ems316 5:b506b5bdeee7 45 Run Instructions: Whenever I ran the program, I found I needed to first
ems316 5:b506b5bdeee7 46 run screen to open up the fd pointing to the usb. I would then kill the
ems316 5:b506b5bdeee7 47 screen process and run the ./start_game script after uncommenting the
ems316 5:b506b5bdeee7 48 port selection in the script.
ems316 5:b506b5bdeee7 49
ems316 5:b506b5bdeee7 50 */
ems316 5:b506b5bdeee7 51
terryfan 0:dac187b013e0 52 #include "mbed.h"
terryfan 0:dac187b013e0 53 #include "rtos.h"
terryfan 0:dac187b013e0 54 #include "TextLCD.h"
terryfan 0:dac187b013e0 55 #include <stdio.h>
terryfan 3:77efff091ef1 56
ems316 5:b506b5bdeee7 57 // Input/Output declarations
ems316 5:b506b5bdeee7 58
terryfan 0:dac187b013e0 59 InterruptIn vsignal(p7);
terryfan 0:dac187b013e0 60 InterruptIn asignal(p8);
terryfan 0:dac187b013e0 61 DigitalOut Vpace(p5);
terryfan 0:dac187b013e0 62 DigitalOut Apace(p6);
terryfan 3:77efff091ef1 63
terryfan 0:dac187b013e0 64 DigitalOut asense_led(LED1);
terryfan 0:dac187b013e0 65 DigitalOut vsense_led(LED2);
terryfan 0:dac187b013e0 66 DigitalOut apace_led(LED3);
terryfan 0:dac187b013e0 67 DigitalOut vpace_led(LED4);
terryfan 3:77efff091ef1 68
ems316 5:b506b5bdeee7 69 // thread definitions
terryfan 0:dac187b013e0 70 osThreadId signalTid;
terryfan 0:dac187b013e0 71 osThreadId senseTid;
terryfan 0:dac187b013e0 72 osThreadId displayTid;
terryfan 0:dac187b013e0 73 osThreadId pacemodeTid;
terryfan 1:e6f6471e2c00 74 osThreadId alarmTid;
terryfan 4:a9c37c60425c 75 osThreadId ledTid;
terryfan 0:dac187b013e0 76
ems316 5:b506b5bdeee7 77 //peripheral API declarations
terryfan 0:dac187b013e0 78 TextLCD lcd(p15, p16, p17, p18, p19, p20, TextLCD::LCD16x2);
terryfan 0:dac187b013e0 79 RawSerial pc(USBTX, USBRX);
terryfan 3:77efff091ef1 80
ems316 5:b506b5bdeee7 81 //timing declarations
terryfan 0:dac187b013e0 82 Timer vClock;
ems316 5:b506b5bdeee7 83 Timer aClock;
terryfan 3:77efff091ef1 84 Timer arpClock;
terryfan 3:77efff091ef1 85
ems316 5:b506b5bdeee7 86 //normal mode timing constants
terryfan 0:dac187b013e0 87 double LRI = 1000;
terryfan 0:dac187b013e0 88 double URI = 700;
ems316 5:b506b5bdeee7 89 double VRP = 200;
ems316 5:b506b5bdeee7 90 double ARP = 50;
ems316 5:b506b5bdeee7 91 double AVI = 150;
ems316 5:b506b5bdeee7 92 double PVARP = 300;
terryfan 0:dac187b013e0 93 double ratio;
ems316 5:b506b5bdeee7 94 int wait_period = 10;
terryfan 3:77efff091ef1 95
terryfan 4:a9c37c60425c 96 double observation_interval = 10000; // In miliseconds
terryfan 0:dac187b013e0 97 int upperBound; //for mode changes
terryfan 0:dac187b013e0 98 int lowerBound; //for mode changes
terryfan 4:a9c37c60425c 99 double heart_beats = 0; // Heart-Beats (sensed or paced) since the last observation interval
terryfan 1:e6f6471e2c00 100 Mutex hr_mutex; //hr_mutex.lock()/unlock()
terryfan 3:77efff091ef1 101
ems316 5:b506b5bdeee7 102 //message passing queues
terryfan 0:dac187b013e0 103 Queue<char,256> mode_q;
terryfan 0:dac187b013e0 104 Queue<char,256> signal_q;
terryfan 1:e6f6471e2c00 105 Queue<char,256> obsint_q;
terryfan 3:77efff091ef1 106
ems316 5:b506b5bdeee7 107 //keyboard interrupt variables
terryfan 0:dac187b013e0 108 volatile char c;
terryfan 0:dac187b013e0 109 volatile int mm = 0;
terryfan 3:77efff091ef1 110 volatile int om = 0;
ems316 5:b506b5bdeee7 111
ems316 5:b506b5bdeee7 112 //flag to disable automatic pacing
terryfan 0:dac187b013e0 113 int mm_flag = 0;
terryfan 3:77efff091ef1 114
ems316 5:b506b5bdeee7 115 //init the ventrical timing values
terryfan 0:dac187b013e0 116 void initialize_intervals()
terryfan 0:dac187b013e0 117 {
terryfan 0:dac187b013e0 118 LRI = 1000;
terryfan 0:dac187b013e0 119 URI = 700;
terryfan 0:dac187b013e0 120 }
terryfan 3:77efff091ef1 121
ems316 5:b506b5bdeee7 122 //interrupt for keyboard input. Filters valid input.
terryfan 0:dac187b013e0 123 void Rx_interrupt()
terryfan 0:dac187b013e0 124 {
terryfan 0:dac187b013e0 125 while(pc.readable()) {
terryfan 0:dac187b013e0 126 c = pc.getc();
ems316 5:b506b5bdeee7 127
ems316 5:b506b5bdeee7 128 //synchronize mode switch thread for manual mode
terryfan 1:e6f6471e2c00 129 if(c == 'm' && om != 1) {
terryfan 0:dac187b013e0 130 mode_q.put((char*)c);
terryfan 0:dac187b013e0 131 mm = 1;
ems316 5:b506b5bdeee7 132 //synchronize mode switch thread for normal, excercise or sleep mode
terryfan 1:e6f6471e2c00 133 } else if(c == 'n' || c == 'e' || c == 's' && om != 1) {
terryfan 0:dac187b013e0 134 mode_q.put((char*)c);
terryfan 0:dac187b013e0 135 mm = 0;
ems316 5:b506b5bdeee7 136 //if manual mode, synchronize with manual mode thread for a or v signal
terryfan 0:dac187b013e0 137 } else if((c == 'a' || c == 'v') && mm) {
terryfan 0:dac187b013e0 138 signal_q.put((char*)c);
ems316 5:b506b5bdeee7 139 //start accepting input to update the observation interval. Disable mode switching.
terryfan 1:e6f6471e2c00 140 } else if(c == 'o' && om != 1) {
terryfan 1:e6f6471e2c00 141 mode_q.put((char*)c);
terryfan 1:e6f6471e2c00 142 om = 1;
ems316 5:b506b5bdeee7 143 //end receiving input to update observation interval. Enable mode switching.
terryfan 1:e6f6471e2c00 144 } else if (c == '\r' && om) {
terryfan 1:e6f6471e2c00 145 obsint_q.put((char*)c);
terryfan 1:e6f6471e2c00 146 om = 0;
ems316 5:b506b5bdeee7 147 //updating observation interval, filter valid input.
terryfan 1:e6f6471e2c00 148 } else if ((int)c > 47 && (int)c < 58 && om) {
terryfan 1:e6f6471e2c00 149 obsint_q.put((char*)c);
terryfan 0:dac187b013e0 150 }
terryfan 0:dac187b013e0 151 }
terryfan 0:dac187b013e0 152 }
terryfan 0:dac187b013e0 153
terryfan 3:77efff091ef1 154 // Function to toggle the LEDs 1,2,3,4
terryfan 4:a9c37c60425c 155 void ledThread(void const *args)
terryfan 4:a9c37c60425c 156
terryfan 3:77efff091ef1 157 {
terryfan 4:a9c37c60425c 158 while (1) {
ems316 5:b506b5bdeee7 159 //wait for synchronization for Apace, Vpace, Asense, Vsense
terryfan 4:a9c37c60425c 160 osEvent ext_signal = osSignalWait(0, osWaitForever);
terryfan 4:a9c37c60425c 161 int evt = ext_signal.value.signals;
terryfan 4:a9c37c60425c 162
ems316 5:b506b5bdeee7 163 if (evt == 0xA) { //asense
terryfan 3:77efff091ef1 164 asense_led = 1;
terryfan 3:77efff091ef1 165 Thread::wait(wait_period);
terryfan 3:77efff091ef1 166 asense_led = 0;
ems316 5:b506b5bdeee7 167 } else if (evt == 0xB) { //vsense
terryfan 3:77efff091ef1 168 vsense_led = 1;
terryfan 3:77efff091ef1 169 Thread::wait(wait_period);
terryfan 3:77efff091ef1 170 vsense_led = 0;
ems316 5:b506b5bdeee7 171 } else if (evt == 0xC) { //apace
terryfan 3:77efff091ef1 172 apace_led = 1;
terryfan 3:77efff091ef1 173 Thread::wait(wait_period);
terryfan 3:77efff091ef1 174 apace_led = 0;
ems316 5:b506b5bdeee7 175 } else if (evt == 0xD) { //vpace
terryfan 3:77efff091ef1 176 vpace_led = 1;
terryfan 3:77efff091ef1 177 Thread::wait(wait_period);
terryfan 3:77efff091ef1 178 vpace_led = 0;
terryfan 4:a9c37c60425c 179 }
terryfan 3:77efff091ef1 180 }
terryfan 3:77efff091ef1 181 }
terryfan 3:77efff091ef1 182
ems316 5:b506b5bdeee7 183 //Synchronized with displayThread if alarmThread should alarm
terryfan 3:77efff091ef1 184 void alarmThread(void const *args)
terryfan 0:dac187b013e0 185 {
terryfan 2:682a3ac9d7a3 186 while (1) {
terryfan 2:682a3ac9d7a3 187 osEvent ext_signal = osSignalWait(0, osWaitForever);
terryfan 2:682a3ac9d7a3 188 int evt = ext_signal.value.signals;
terryfan 3:77efff091ef1 189
ems316 5:b506b5bdeee7 190 if (evt == 0xb) { //upper bound violated
terryfan 3:77efff091ef1 191 lcd.printf("%s", "\nALARM HIGH");
ems316 5:b506b5bdeee7 192 } else if (evt == 0xc) { //lower bound violated
terryfan 1:e6f6471e2c00 193 lcd.printf("%s", "\nALARM LOW");
terryfan 1:e6f6471e2c00 194 }
terryfan 1:e6f6471e2c00 195 }
terryfan 1:e6f6471e2c00 196 }
ems316 5:b506b5bdeee7 197 //Thread for displaying bpm & alerts
terryfan 0:dac187b013e0 198 void displayThread(void const *args)
terryfan 0:dac187b013e0 199 {
terryfan 0:dac187b013e0 200 while (1) {
terryfan 0:dac187b013e0 201 Thread::wait(observation_interval);
terryfan 0:dac187b013e0 202 lcd.cls();
terryfan 3:77efff091ef1 203
ems316 5:b506b5bdeee7 204 hr_mutex.lock(); //acquire lock because changing bpm
ems316 5:b506b5bdeee7 205 double hr = (heart_beats*60) / (observation_interval / 1000); //calculate bpm
ems316 5:b506b5bdeee7 206 heart_beats = 0; //reset bpm
terryfan 1:e6f6471e2c00 207 hr_mutex.unlock();
terryfan 3:77efff091ef1 208
ems316 5:b506b5bdeee7 209 lcd.printf("%s%d%s","HR: ", (int)hr, " bpm"); //display bpm
terryfan 3:77efff091ef1 210
ems316 5:b506b5bdeee7 211 if (hr > upperBound) { //synchronize if upperBound violated
terryfan 1:e6f6471e2c00 212 osSignalSet(alarmTid, 0xb);
ems316 5:b506b5bdeee7 213 } else if (hr < lowerBound) { //synchronize if lowerBound violated
terryfan 1:e6f6471e2c00 214 osSignalSet(alarmTid, 0xc);
terryfan 1:e6f6471e2c00 215 }
terryfan 0:dac187b013e0 216 }
terryfan 0:dac187b013e0 217 }
terryfan 3:77efff091ef1 218
terryfan 3:77efff091ef1 219
terryfan 3:77efff091ef1 220
ems316 5:b506b5bdeee7 221 // Incoming atrial signal from the heart
terryfan 0:dac187b013e0 222 void asignal_irq()
terryfan 0:dac187b013e0 223 {
ems316 5:b506b5bdeee7 224 osSignalSet(signalTid, 0x1); //synchronize with pacesignal thread
terryfan 0:dac187b013e0 225 }
terryfan 3:77efff091ef1 226
ems316 5:b506b5bdeee7 227 // Incoming ventrical signal from the heart
terryfan 0:dac187b013e0 228 void vsignal_irq()
terryfan 0:dac187b013e0 229 {
ems316 5:b506b5bdeee7 230 osSignalSet(signalTid, 0x2); //synchronize with pacesignal thread
terryfan 0:dac187b013e0 231 }
terryfan 3:77efff091ef1 232
ems316 5:b506b5bdeee7 233 //Main timing thread for filtering Asignal and Vsignal from heart and
ems316 5:b506b5bdeee7 234 //generating Asense and Vsense to synchronize with the PaceSense thread.
terryfan 0:dac187b013e0 235 void PaceSignal(void const *args)
terryfan 0:dac187b013e0 236 {
ems316 5:b506b5bdeee7 237
ems316 5:b506b5bdeee7 238 int pFlag1 = 0; //flag that allows us to move to the second UPPAAL state in PaceSignal
ems316 5:b506b5bdeee7 239 int pFlag2 = 0; //flag that allows us to move to the first UPPAAL state in PaceSignal
ems316 5:b506b5bdeee7 240
terryfan 0:dac187b013e0 241 vClock.start();
terryfan 0:dac187b013e0 242 aClock.start();
terryfan 3:77efff091ef1 243 arpClock.start();
terryfan 4:a9c37c60425c 244
terryfan 0:dac187b013e0 245 while(1) {
terryfan 0:dac187b013e0 246 while (!pFlag1) {
terryfan 0:dac187b013e0 247 osEvent ext_signal = osSignalWait(0, osWaitForever);
terryfan 0:dac187b013e0 248 int evt = ext_signal.value.signals;
terryfan 3:77efff091ef1 249
terryfan 3:77efff091ef1 250 if (evt == 0x1 && vClock.read_ms() >= PVARP) { //aSense
terryfan 0:dac187b013e0 251 osSignalSet(senseTid, 0x1);
terryfan 0:dac187b013e0 252 aClock.reset();
terryfan 3:77efff091ef1 253 arpClock.reset();
terryfan 0:dac187b013e0 254 pFlag1 = 1;
terryfan 4:a9c37c60425c 255 } else if(evt == 0x2 && vClock.read_ms() >= VRP) { //vSense
terryfan 4:a9c37c60425c 256 hr_mutex.lock();
ems316 5:b506b5bdeee7 257 osSignalSet(senseTid, 0x2); //syncrhonize with PaceSense thread
ems316 5:b506b5bdeee7 258 heart_beats++; //increment bpm
terryfan 0:dac187b013e0 259 vClock.reset();
terryfan 4:a9c37c60425c 260 aClock.reset();
terryfan 4:a9c37c60425c 261 arpClock.reset();
terryfan 4:a9c37c60425c 262 hr_mutex.unlock();
ems316 5:b506b5bdeee7 263 pFlag1 = 1; //progress to state 2
terryfan 4:a9c37c60425c 264
terryfan 0:dac187b013e0 265 } else if (evt == 0x3) { //aPace
ems316 5:b506b5bdeee7 266 pFlag1 = 1; //progress to state 2
terryfan 0:dac187b013e0 267 }
terryfan 0:dac187b013e0 268 }
terryfan 0:dac187b013e0 269 pFlag1 = 0;
terryfan 0:dac187b013e0 270 while(!pFlag2) {
terryfan 3:77efff091ef1 271
terryfan 0:dac187b013e0 272 osEvent ext_signal = osSignalWait(0, osWaitForever);
terryfan 0:dac187b013e0 273 int evt = ext_signal.value.signals;
terryfan 3:77efff091ef1 274
terryfan 4:a9c37c60425c 275 if (evt == 0x1 && arpClock.read_ms() >= ARP) { //aSense
terryfan 0:dac187b013e0 276 osSignalSet(senseTid, 0x1);
ems316 5:b506b5bdeee7 277 arpClock.reset(); //determine valid consecutive a event
terryfan 4:a9c37c60425c 278
terryfan 3:77efff091ef1 279 } else if(evt == 0x2) { //vSense
terryfan 2:682a3ac9d7a3 280 hr_mutex.lock();
terryfan 3:77efff091ef1 281 osSignalSet(senseTid, 0x2);
ems316 5:b506b5bdeee7 282 heart_beats++; //increment bpm
terryfan 3:77efff091ef1 283 vClock.reset();
terryfan 4:a9c37c60425c 284 aClock.reset();
terryfan 4:a9c37c60425c 285 arpClock.reset();
terryfan 2:682a3ac9d7a3 286 hr_mutex.unlock();
ems316 5:b506b5bdeee7 287 pFlag2 = 1; //progress to state 1
terryfan 0:dac187b013e0 288 } else if (evt == 0x4) { //vPace
ems316 5:b506b5bdeee7 289 pFlag2 = 1; //progress to state 1
terryfan 0:dac187b013e0 290 }
terryfan 0:dac187b013e0 291 }
terryfan 0:dac187b013e0 292 pFlag2 = 0;
terryfan 0:dac187b013e0 293 }
terryfan 0:dac187b013e0 294 }
terryfan 3:77efff091ef1 295
terryfan 0:dac187b013e0 296 void PaceSense(void const *args)
terryfan 0:dac187b013e0 297 {
ems316 5:b506b5bdeee7 298 int pFlag1 = 0; //flag that allows us to move to the second UPPAAL state in PaceSense
ems316 5:b506b5bdeee7 299 int pFlag2 = 0; //flag that allows us to move to the first UPPAAL state in PaceSense
ems316 5:b506b5bdeee7 300 int time_sub = 0; //used to determine timeout for when to pace (this is our invariant)
terryfan 4:a9c37c60425c 301 int evt = 0;
terryfan 0:dac187b013e0 302 while(1) {
terryfan 0:dac187b013e0 303 while (!pFlag1) {
terryfan 4:a9c37c60425c 304
ems316 5:b506b5bdeee7 305 time_sub = LRI-AVI - vClock.read_ms(); //aPace at LRI-AVI default
terryfan 3:77efff091ef1 306
terryfan 4:a9c37c60425c 307 if (time_sub > 0 && !mm_flag) {
ems316 5:b506b5bdeee7 308 osEvent ext_signal = osSignalWait(0, time_sub); //allow pacing
terryfan 4:a9c37c60425c 309 evt = ext_signal.value.signals;
terryfan 4:a9c37c60425c 310 } else if(mm_flag) {
ems316 5:b506b5bdeee7 311 osEvent ext_signal = osSignalWait(0, osWaitForever); //disable pacing
terryfan 4:a9c37c60425c 312 evt = ext_signal.value.signals;
terryfan 4:a9c37c60425c 313 } else {
ems316 5:b506b5bdeee7 314 evt = 0x0; //time_sub is less than 0
terryfan 4:a9c37c60425c 315 }
terryfan 4:a9c37c60425c 316
ems316 5:b506b5bdeee7 317 if (evt == 0x0) { //aPace
terryfan 4:a9c37c60425c 318 aClock.reset();
terryfan 4:a9c37c60425c 319 arpClock.reset();
terryfan 3:77efff091ef1 320 Apace = 1;
terryfan 3:77efff091ef1 321 Thread::wait(1);
terryfan 3:77efff091ef1 322 Apace = 0;
terryfan 3:77efff091ef1 323 osSignalSet(signalTid, 0x3);
terryfan 4:a9c37c60425c 324 osSignalSet(ledTid, 0xC);
terryfan 0:dac187b013e0 325 pFlag1 = 1;
terryfan 4:a9c37c60425c 326 } else if (evt == 0x1) { //aSense
terryfan 4:a9c37c60425c 327 osSignalSet(ledTid, 0xA);
terryfan 3:77efff091ef1 328 pFlag1 = 1;
terryfan 3:77efff091ef1 329 } else if(evt == 0x2) { //vSense
terryfan 4:a9c37c60425c 330 osSignalSet(ledTid, 0xB);
ems316 5:b506b5bdeee7 331 } else if(evt == 0x3) { //manual apace
terryfan 4:a9c37c60425c 332 pFlag1 = 1;
terryfan 3:77efff091ef1 333 }
terryfan 0:dac187b013e0 334 }
terryfan 0:dac187b013e0 335 pFlag1 = 0;
terryfan 4:a9c37c60425c 336
terryfan 0:dac187b013e0 337 while(!pFlag2) {
ems316 5:b506b5bdeee7 338 //vpace occurs at either URI or vclock + AVI
ems316 5:b506b5bdeee7 339 time_sub = (vClock.read_ms() + AVI >= URI) ? AVI - aClock.read_ms() : URI - vClock.read_ms();
terryfan 4:a9c37c60425c 340
ems316 5:b506b5bdeee7 341 if (time_sub > 0 && !mm_flag) { //allow pacing
terryfan 4:a9c37c60425c 342 osEvent ext_signal = osSignalWait(0, time_sub);
terryfan 4:a9c37c60425c 343 evt = ext_signal.value.signals;
ems316 5:b506b5bdeee7 344 } else if(mm_flag) { //disable pacing
terryfan 4:a9c37c60425c 345 osEvent ext_signal = osSignalWait(0, osWaitForever);
terryfan 4:a9c37c60425c 346 evt = ext_signal.value.signals;
terryfan 4:a9c37c60425c 347 } else {
ems316 5:b506b5bdeee7 348 evt = 0x0; //time_sub is negative
terryfan 4:a9c37c60425c 349 }
terryfan 4:a9c37c60425c 350
ems316 5:b506b5bdeee7 351 if (evt == 0x0) { //vPace
terryfan 4:a9c37c60425c 352
terryfan 3:77efff091ef1 353 hr_mutex.lock();
terryfan 4:a9c37c60425c 354 heart_beats++;
terryfan 4:a9c37c60425c 355 vClock.reset();
terryfan 4:a9c37c60425c 356 aClock.reset();
terryfan 4:a9c37c60425c 357 arpClock.reset();
terryfan 3:77efff091ef1 358 Vpace = 1;
terryfan 3:77efff091ef1 359 Thread::wait(1);
terryfan 3:77efff091ef1 360 Vpace = 0;
terryfan 3:77efff091ef1 361 osSignalSet(signalTid, 0x4);
terryfan 3:77efff091ef1 362 hr_mutex.unlock();
terryfan 3:77efff091ef1 363
terryfan 4:a9c37c60425c 364 osSignalSet(ledTid, 0xD);
terryfan 0:dac187b013e0 365 pFlag2 = 1;
terryfan 4:a9c37c60425c 366
terryfan 3:77efff091ef1 367 } else if (evt == 0x1) { //aSense
terryfan 4:a9c37c60425c 368 osSignalSet(ledTid, 0xA);
terryfan 3:77efff091ef1 369 } else if(evt == 0x2) { //vSense
terryfan 4:a9c37c60425c 370 osSignalSet(ledTid, 0xB);
terryfan 4:a9c37c60425c 371 pFlag2 = 1;
ems316 5:b506b5bdeee7 372 } else if (evt == 0x4) { //manual vpace
terryfan 0:dac187b013e0 373 pFlag2 = 1;
terryfan 0:dac187b013e0 374 }
terryfan 0:dac187b013e0 375 }
terryfan 0:dac187b013e0 376 pFlag2 = 0;
terryfan 0:dac187b013e0 377 }
terryfan 0:dac187b013e0 378 }
ems316 5:b506b5bdeee7 379 //update timing constraints for mode and reset bpm
terryfan 0:dac187b013e0 380 void normalmode(void const *args)
terryfan 0:dac187b013e0 381 {
terryfan 0:dac187b013e0 382 initialize_intervals();
terryfan 0:dac187b013e0 383 upperBound = 100; //beats per msecond
terryfan 0:dac187b013e0 384 lowerBound = 40; //beats per msecond
ems316 5:b506b5bdeee7 385 //hr_mutex.lock();
ems316 5:b506b5bdeee7 386 //reset bpm
ems316 5:b506b5bdeee7 387 heart_beats = 0;
ems316 5:b506b5bdeee7 388 hr_mutex.unlock();
ems316 5:b506b5bdeee7 389
ems316 5:b506b5bdeee7 390 vClock.reset();
ems316 5:b506b5bdeee7 391 aClock.reset();
ems316 5:b506b5bdeee7 392 }
ems316 5:b506b5bdeee7 393 //update timing constraints for mode and reset bpm
ems316 5:b506b5bdeee7 394 void exercisemode(void const *args)
ems316 5:b506b5bdeee7 395 {
ems316 5:b506b5bdeee7 396 initialize_intervals();
ems316 5:b506b5bdeee7 397 upperBound = 175; //beats per msecond
ems316 5:b506b5bdeee7 398 lowerBound = 100; //beats per msecond
ems316 5:b506b5bdeee7 399 ratio = (175.00/100.00 + 100.00/40.00) / 2.00;
ems316 5:b506b5bdeee7 400 LRI /= ratio;
ems316 5:b506b5bdeee7 401 URI /= ratio;
ems316 5:b506b5bdeee7 402 //reset bpm
terryfan 1:e6f6471e2c00 403 hr_mutex.lock();
terryfan 1:e6f6471e2c00 404 heart_beats = 0;
terryfan 1:e6f6471e2c00 405 hr_mutex.unlock();
terryfan 3:77efff091ef1 406
terryfan 3:77efff091ef1 407 vClock.reset();
terryfan 3:77efff091ef1 408 aClock.reset();
terryfan 0:dac187b013e0 409 }
ems316 5:b506b5bdeee7 410 //update timing constraints for mode and reset bpm
ems316 5:b506b5bdeee7 411 void sleepmode(void const *args)
terryfan 0:dac187b013e0 412 {
terryfan 0:dac187b013e0 413 initialize_intervals();
ems316 5:b506b5bdeee7 414 upperBound = 60; //beats per msecond
ems316 5:b506b5bdeee7 415 lowerBound = 30; //beats per msecond v-v 0.5s
ems316 5:b506b5bdeee7 416 ratio = (60.00/100.00 + 30.00/40.00) / 2.00;
terryfan 0:dac187b013e0 417 LRI /= ratio;
terryfan 0:dac187b013e0 418 URI /= ratio;
terryfan 1:e6f6471e2c00 419 hr_mutex.lock();
ems316 5:b506b5bdeee7 420 //reset bpm
terryfan 1:e6f6471e2c00 421 heart_beats = 0;
terryfan 1:e6f6471e2c00 422 hr_mutex.unlock();
terryfan 3:77efff091ef1 423
terryfan 3:77efff091ef1 424 vClock.reset();
terryfan 3:77efff091ef1 425 aClock.reset();
terryfan 0:dac187b013e0 426 }
ems316 5:b506b5bdeee7 427 //handle manual pacing events
terryfan 1:e6f6471e2c00 428 void m_vpace()
terryfan 1:e6f6471e2c00 429 {
terryfan 0:dac187b013e0 430 vClock.reset();
terryfan 4:a9c37c60425c 431 aClock.reset();
terryfan 4:a9c37c60425c 432 arpClock.reset();
terryfan 0:dac187b013e0 433 Vpace = 1;
terryfan 3:77efff091ef1 434 Thread::wait(1);
terryfan 0:dac187b013e0 435 Vpace = 0;
terryfan 0:dac187b013e0 436 osSignalSet(signalTid, 0x4);
terryfan 4:a9c37c60425c 437 osSignalSet(senseTid, 0x4);
terryfan 1:e6f6471e2c00 438 hr_mutex.lock();
terryfan 0:dac187b013e0 439 heart_beats++;
terryfan 1:e6f6471e2c00 440 hr_mutex.unlock();
terryfan 4:a9c37c60425c 441
terryfan 4:a9c37c60425c 442 osSignalSet(ledTid, 0xD);
terryfan 0:dac187b013e0 443 }
ems316 5:b506b5bdeee7 444 //handle manual pacing events
terryfan 1:e6f6471e2c00 445 void m_apace()
terryfan 1:e6f6471e2c00 446 {
terryfan 0:dac187b013e0 447 aClock.reset();
terryfan 4:a9c37c60425c 448 arpClock.reset();
terryfan 0:dac187b013e0 449 Apace = 1;
terryfan 3:77efff091ef1 450 Thread::wait(1);
terryfan 0:dac187b013e0 451 Apace = 0;
terryfan 4:a9c37c60425c 452 osSignalSet(senseTid, 0x3);
terryfan 0:dac187b013e0 453 osSignalSet(signalTid, 0x3);
terryfan 4:a9c37c60425c 454 osSignalSet(ledTid, 0xC);
terryfan 0:dac187b013e0 455 }
ems316 5:b506b5bdeee7 456 //update timing constraints for mode and handle manual pace events
terryfan 0:dac187b013e0 457 void manualmode(void const *args)
terryfan 0:dac187b013e0 458 {
terryfan 0:dac187b013e0 459 upperBound = 175; //beats per msecond
terryfan 0:dac187b013e0 460 lowerBound = 30; //beats per msecond
terryfan 1:e6f6471e2c00 461 LRI = 2125; // max V-V (LRI) based on exercise mode
terryfan 1:e6f6471e2c00 462 URI = 675; // min V-V (URI) based on sleep mode
terryfan 3:77efff091ef1 463
terryfan 0:dac187b013e0 464 while(1) {
terryfan 0:dac187b013e0 465 osEvent evt = signal_q.get();
terryfan 0:dac187b013e0 466 if(evt.status == osEventMessage) {
terryfan 0:dac187b013e0 467 if((char)evt.value.p == 'v') {
terryfan 0:dac187b013e0 468 m_vpace();
terryfan 0:dac187b013e0 469 } else if((char)evt.value.p == 'a') {
terryfan 0:dac187b013e0 470 m_apace();
terryfan 0:dac187b013e0 471 }
terryfan 0:dac187b013e0 472 }
terryfan 0:dac187b013e0 473 }
terryfan 0:dac187b013e0 474 }
ems316 5:b506b5bdeee7 475 //manage user input for updating the observation interval
terryfan 1:e6f6471e2c00 476 void obsinterval()
terryfan 1:e6f6471e2c00 477 {
terryfan 1:e6f6471e2c00 478 char newObsInt[8];
terryfan 1:e6f6471e2c00 479 int isChangingObsInt = 1;
terryfan 1:e6f6471e2c00 480 int i = 0;
ems316 5:b506b5bdeee7 481 char key = 'n';
terryfan 1:e6f6471e2c00 482 while(isChangingObsInt) {
terryfan 1:e6f6471e2c00 483 osEvent evt = obsint_q.get();
terryfan 1:e6f6471e2c00 484 if(evt.status == osEventMessage) {
terryfan 1:e6f6471e2c00 485 key = (char)evt.value.p;
ems316 5:b506b5bdeee7 486 if(key != '\r' && i < 7 ) { //bound number of integers for overflow
terryfan 1:e6f6471e2c00 487 newObsInt[i] = key;
terryfan 1:e6f6471e2c00 488 i++;
ems316 5:b506b5bdeee7 489 } else if((key == '\r') && (i > 0)) { //conver input to observatio interval
terryfan 1:e6f6471e2c00 490 heart_beats = 0;
terryfan 1:e6f6471e2c00 491 int obsint;
terryfan 1:e6f6471e2c00 492 newObsInt[i] = '\0';
terryfan 1:e6f6471e2c00 493 sscanf(newObsInt, "%d", &obsint);
terryfan 4:a9c37c60425c 494
ems316 5:b506b5bdeee7 495 //check bounds
terryfan 4:a9c37c60425c 496 if(obsint < 300) {
terryfan 4:a9c37c60425c 497 observation_interval = 300.0;
terryfan 4:a9c37c60425c 498 } else if (obsint > 10000) {
terryfan 4:a9c37c60425c 499 observation_interval = 10000.0;
terryfan 4:a9c37c60425c 500 } else {
terryfan 4:a9c37c60425c 501 observation_interval = (double)obsint;
terryfan 4:a9c37c60425c 502 }
terryfan 1:e6f6471e2c00 503 isChangingObsInt = 0;
terryfan 4:a9c37c60425c 504
terryfan 1:e6f6471e2c00 505 }
terryfan 1:e6f6471e2c00 506 }
terryfan 1:e6f6471e2c00 507 }
terryfan 1:e6f6471e2c00 508 }
terryfan 3:77efff091ef1 509
ems316 5:b506b5bdeee7 510
ems316 5:b506b5bdeee7 511 //create thread definitions
terryfan 0:dac187b013e0 512 osThreadDef(PaceSignal, osPriorityNormal, DEFAULT_STACK_SIZE);
terryfan 0:dac187b013e0 513 osThreadDef(PaceSense, osPriorityNormal, DEFAULT_STACK_SIZE);
ems316 5:b506b5bdeee7 514 osThreadDef(alarmThread, osPriorityBelowNormal, DEFAULT_STACK_SIZE);
terryfan 4:a9c37c60425c 515 osThreadDef(ledThread, osPriorityBelowNormal, DEFAULT_STACK_SIZE);
terryfan 3:77efff091ef1 516
ems316 5:b506b5bdeee7 517 osThreadDef(displayThread, osPriorityLow, DEFAULT_STACK_SIZE);
terryfan 0:dac187b013e0 518 osThreadDef(manualmode, osPriorityNormal, DEFAULT_STACK_SIZE);
terryfan 3:77efff091ef1 519
terryfan 0:dac187b013e0 520 int main()
terryfan 0:dac187b013e0 521 {
ems316 5:b506b5bdeee7 522 //create thread ids
terryfan 1:e6f6471e2c00 523 alarmTid = osThreadCreate(osThread(alarmThread), NULL);
terryfan 0:dac187b013e0 524 senseTid = osThreadCreate(osThread(PaceSense), NULL);
terryfan 0:dac187b013e0 525 signalTid = osThreadCreate(osThread(PaceSignal), NULL);
terryfan 0:dac187b013e0 526 displayTid = osThreadCreate(osThread(displayThread), NULL);
terryfan 4:a9c37c60425c 527 ledTid = osThreadCreate(osThread(ledThread), NULL);
terryfan 4:a9c37c60425c 528
ems316 5:b506b5bdeee7 529 //start pacemaker in normal mode
terryfan 3:77efff091ef1 530 normalmode(NULL);
terryfan 4:a9c37c60425c 531
ems316 5:b506b5bdeee7 532 //set interrupt ins on signaling inputs
ems316 5:b506b5bdeee7 533 vsignal.rise(&vsignal_irq);
terryfan 0:dac187b013e0 534 asignal.rise(&asignal_irq);
terryfan 3:77efff091ef1 535
ems316 5:b506b5bdeee7 536 //clear lcd
terryfan 0:dac187b013e0 537 lcd.cls();
terryfan 3:77efff091ef1 538
ems316 5:b506b5bdeee7 539 //set interrupt in for serial input
terryfan 0:dac187b013e0 540 pc.attach(&Rx_interrupt, RawSerial::RxIrq);
ems316 5:b506b5bdeee7 541 while(true) { //handle mode switching synchronization
terryfan 0:dac187b013e0 542 osEvent evt = mode_q.get();
terryfan 0:dac187b013e0 543 if(evt.status == osEventMessage) {
terryfan 0:dac187b013e0 544 switch((char)evt.value.p) {
ems316 5:b506b5bdeee7 545 case('n'): //normal mode
terryfan 0:dac187b013e0 546 mm_flag = 0;
terryfan 4:a9c37c60425c 547 osSignalSet(senseTid, 0x5);
terryfan 0:dac187b013e0 548 osThreadTerminate (pacemodeTid);
terryfan 1:e6f6471e2c00 549 osThreadTerminate (displayTid);
terryfan 3:77efff091ef1 550 normalmode(NULL);
terryfan 1:e6f6471e2c00 551 displayTid = osThreadCreate(osThread(displayThread), NULL);
terryfan 0:dac187b013e0 552 break;
ems316 5:b506b5bdeee7 553 case('s'): //sleep mode
terryfan 0:dac187b013e0 554 mm_flag = 0;
terryfan 4:a9c37c60425c 555 osSignalSet(senseTid, 0x5);
terryfan 0:dac187b013e0 556 osThreadTerminate (pacemodeTid);
terryfan 1:e6f6471e2c00 557 osThreadTerminate (displayTid);
terryfan 3:77efff091ef1 558 sleepmode(NULL);
terryfan 1:e6f6471e2c00 559 displayTid = osThreadCreate(osThread(displayThread), NULL);
terryfan 0:dac187b013e0 560 break;
ems316 5:b506b5bdeee7 561 case('e'): //excercise mode
terryfan 0:dac187b013e0 562 mm_flag = 0;
terryfan 4:a9c37c60425c 563 osSignalSet(senseTid, 0x5);
terryfan 0:dac187b013e0 564 osThreadTerminate (pacemodeTid);
terryfan 1:e6f6471e2c00 565 osThreadTerminate (displayTid);
terryfan 3:77efff091ef1 566 exercisemode(NULL);
terryfan 1:e6f6471e2c00 567 displayTid = osThreadCreate(osThread(displayThread), NULL);
terryfan 0:dac187b013e0 568 break;
ems316 5:b506b5bdeee7 569 case('m'): //manual mode
terryfan 0:dac187b013e0 570 mm_flag = 1;
ems316 5:b506b5bdeee7 571 osSignalSet(senseTid, 0x5);
terryfan 0:dac187b013e0 572 osThreadTerminate (pacemodeTid);
terryfan 0:dac187b013e0 573 pacemodeTid = osThreadCreate(osThread(manualmode), NULL);
terryfan 0:dac187b013e0 574 break;
ems316 5:b506b5bdeee7 575 case('o'): //observation interval
terryfan 3:77efff091ef1 576 obsinterval();
terryfan 1:e6f6471e2c00 577 osThreadTerminate (displayTid);
terryfan 1:e6f6471e2c00 578 displayTid = osThreadCreate(osThread(displayThread), NULL);
terryfan 0:dac187b013e0 579 break;
terryfan 0:dac187b013e0 580 }
terryfan 0:dac187b013e0 581 }
terryfan 0:dac187b013e0 582 }
terryfan 4:a9c37c60425c 583 }