CIS441 Controller

Dependencies:   TextLCD mbed-rtos mbed

Fork of PacemakerController by Chad Nachiappan

Committer:
chadnach1
Date:
Wed Dec 02 21:34:46 2015 +0000
Revision:
47:bac7fc1a44fe
Parent:
46:2d9cf50b4bc3
Child:
48:f459ab609d59
Final PacemakerController Code

Who changed what in which revision?

UserRevisionLine numberNew contents of line
chadnach1 0:d92e0b71c6b5 1 #include "mbed.h"
lucastai 2:5e9c4d83d038 2 #include "LPC17xx.h"
lucastai 2:5e9c4d83d038 3 #include "TextLCD.h"
lucastai 2:5e9c4d83d038 4 #include "rtos.h"
lucastai 2:5e9c4d83d038 5 #include "Thread.h"
lucastai 2:5e9c4d83d038 6 using namespace rtos;
chadnach1 0:d92e0b71c6b5 7
chadnach1 0:d92e0b71c6b5 8 // This is for the pacemaker
lucastai 2:5e9c4d83d038 9 volatile unsigned short timer_count;
lucastai 2:5e9c4d83d038 10 Serial pc(USBTX, USBRX);
lucastai 2:5e9c4d83d038 11 TextLCD lcd(p15, p16, p17, p18, p19, p20, TextLCD::LCD20x4); // rs, e, d4-d7
lucastai 2:5e9c4d83d038 12
chadnach1 46:2d9cf50b4bc3 13 Ticker rate_monitor;
chadnach1 46:2d9cf50b4bc3 14 // counters
chadnach1 46:2d9cf50b4bc3 15 volatile int beats = 0;
chadnach1 46:2d9cf50b4bc3 16 volatile double bpm = 0;
mhowar 5:9eee15818b0e 17 int keyboard_needs_numeric = 0; // boolean - is in middle of interval input?
chadnach1 0:d92e0b71c6b5 18
chadnach1 0:d92e0b71c6b5 19 int h_clock;
amiche 3:44d132582373 20 int pm_clock;
chadnach1 27:2c5aefcf3000 21 Timer avi_clk;
mhowar 44:dfa38e4b3146 22 Timer sense_clk;
mhowar 44:dfa38e4b3146 23 Timer pulse_clk;
chadnach1 0:d92e0b71c6b5 24
chadnach1 43:f28bc869321e 25 int LRI = 1000;
chadnach1 43:f28bc869321e 26 int AVI = 300;
amiche 38:ceabf8f1dfa0 27 int PVARP = 150;
amiche 38:ceabf8f1dfa0 28 int VRP = 100;
lucastai 2:5e9c4d83d038 29
lucastai 2:5e9c4d83d038 30 // constants
lucastai 2:5e9c4d83d038 31 int MAX_PM_RT = 180;
lucastai 2:5e9c4d83d038 32 int MIN_PM_RT = 40;
lucastai 2:5e9c4d83d038 33 enum mode {NORMAL, SLEEP, EXERCISE, MANUAL};
lucastai 2:5e9c4d83d038 34
lucastai 2:5e9c4d83d038 35 // state variables
lucastai 2:5e9c4d83d038 36 int upper_bound = 100;
lucastai 2:5e9c4d83d038 37 int lower_bound = 40;
lucastai 2:5e9c4d83d038 38 int obs_int = 10;
lucastai 2:5e9c4d83d038 39 mode curr_mode = NORMAL;
lucastai 2:5e9c4d83d038 40
amiche 19:f3615321b5c4 41 // alarms
lucastai 14:a16b636c2bbc 42 DigitalOut led_apace(LED1);
lucastai 14:a16b636c2bbc 43 DigitalOut led_vpace(LED2);
chadnach1 33:b68c1648206e 44 DigitalOut led_asense(LED3);
chadnach1 33:b68c1648206e 45 DigitalOut led_vsense(LED4);
lucastai 2:5e9c4d83d038 46
chadnach1 27:2c5aefcf3000 47 DigitalIn agetSignal(p24);
chadnach1 27:2c5aefcf3000 48 DigitalIn vgetSignal(p23);
chadnach1 27:2c5aefcf3000 49 DigitalOut apaceSignal(p22);
chadnach1 27:2c5aefcf3000 50 DigitalOut vpaceSignal(p21);
chadnach1 27:2c5aefcf3000 51
chadnach1 27:2c5aefcf3000 52 bool v_sense;
chadnach1 27:2c5aefcf3000 53 bool a_sense;
chadnach1 27:2c5aefcf3000 54
chadnach1 27:2c5aefcf3000 55 void asense()
chadnach1 27:2c5aefcf3000 56 {
chadnach1 27:2c5aefcf3000 57 a_sense = 1;
chadnach1 33:b68c1648206e 58 led_asense = 1;
chadnach1 27:2c5aefcf3000 59 Thread::wait(10);
chadnach1 33:b68c1648206e 60 led_asense = 0;
chadnach1 27:2c5aefcf3000 61 a_sense = 0;
chadnach1 27:2c5aefcf3000 62 }
lucastai 18:d4cd9d12345e 63
chadnach1 27:2c5aefcf3000 64 void vsense()
chadnach1 27:2c5aefcf3000 65 {
chadnach1 27:2c5aefcf3000 66 v_sense = 1;
chadnach1 33:b68c1648206e 67 led_vsense = 1;
chadnach1 27:2c5aefcf3000 68 Thread::wait(10);
chadnach1 33:b68c1648206e 69 led_vsense = 0;
chadnach1 27:2c5aefcf3000 70 v_sense = 0;
chadnach1 27:2c5aefcf3000 71 }
chadnach1 27:2c5aefcf3000 72
chadnach1 27:2c5aefcf3000 73 void apace()
chadnach1 27:2c5aefcf3000 74 {
chadnach1 27:2c5aefcf3000 75 apaceSignal = 1;
chadnach1 27:2c5aefcf3000 76 led_apace = 1;
chadnach1 27:2c5aefcf3000 77 Thread::wait(10);
chadnach1 33:b68c1648206e 78 led_apace = 0;
chadnach1 27:2c5aefcf3000 79 apaceSignal = 0;
chadnach1 27:2c5aefcf3000 80
chadnach1 27:2c5aefcf3000 81 }
chadnach1 27:2c5aefcf3000 82
chadnach1 27:2c5aefcf3000 83 void vpace()
chadnach1 27:2c5aefcf3000 84 {
chadnach1 27:2c5aefcf3000 85 vpaceSignal = 1;
chadnach1 27:2c5aefcf3000 86 led_vpace = 1;
chadnach1 27:2c5aefcf3000 87 Thread::wait(10);
chadnach1 33:b68c1648206e 88 led_vpace = 0;
chadnach1 27:2c5aefcf3000 89 vpaceSignal = 0;
chadnach1 43:f28bc869321e 90
chadnach1 27:2c5aefcf3000 91 }
amiche 24:81cd9ef5c4f6 92
chadnach1 27:2c5aefcf3000 93 void PM_ALARM(void const *args)
amiche 19:f3615321b5c4 94 {
chadnach1 29:5cec671cb80d 95 while (1) {
chadnach1 29:5cec671cb80d 96 // min hr alarm
chadnach1 47:bac7fc1a44fe 97 if( bpm < lower_bound) {
chadnach1 29:5cec671cb80d 98 lcd.locate(0,1);
chadnach1 46:2d9cf50b4bc3 99 lcd.printf("!<");
chadnach1 47:bac7fc1a44fe 100 pc.printf("BPM low: %.1f ", bpm);
chadnach1 29:5cec671cb80d 101 }
chadnach1 31:7f0e865e3d4b 102
chadnach1 29:5cec671cb80d 103 // max hr alarm
chadnach1 47:bac7fc1a44fe 104 else if(beats > upper_bound) {
chadnach1 46:2d9cf50b4bc3 105 lcd.locate(0,1);
chadnach1 46:2d9cf50b4bc3 106 lcd.printf("!>");
chadnach1 47:bac7fc1a44fe 107 pc.printf("BPM high: %.1f ", bpm);
chadnach1 46:2d9cf50b4bc3 108 } else {
chadnach1 29:5cec671cb80d 109 lcd.locate(0,1);
chadnach1 46:2d9cf50b4bc3 110 lcd.printf(" ");
chadnach1 46:2d9cf50b4bc3 111
chadnach1 29:5cec671cb80d 112 }
chadnach1 46:2d9cf50b4bc3 113
chadnach1 46:2d9cf50b4bc3 114 lcd.locate(0,0);
chadnach1 46:2d9cf50b4bc3 115 lcd.printf("BPM: %.1f ", bpm);
amiche 19:f3615321b5c4 116 }
chadnach1 0:d92e0b71c6b5 117 }
chadnach1 0:d92e0b71c6b5 118
lucastai 2:5e9c4d83d038 119 // hw interrupt callback, deal with the keyboard input from PC
lucastai 2:5e9c4d83d038 120
chadnach1 27:2c5aefcf3000 121 void pm_sense(void const *args)
amiche 19:f3615321b5c4 122 {
amiche 19:f3615321b5c4 123
mhowar 44:dfa38e4b3146 124 while(1) {
amiche 19:f3615321b5c4 125
mhowar 44:dfa38e4b3146 126 if (sense_clk.read_ms() >= VRP && vgetSignal == 1) {
chadnach1 34:b4b50ca26e8c 127
amiche 24:81cd9ef5c4f6 128 // Valid_V state
mhowar 44:dfa38e4b3146 129 sense_clk.reset();
amiche 24:81cd9ef5c4f6 130 vsense();
amiche 24:81cd9ef5c4f6 131
mhowar 44:dfa38e4b3146 132 } else if (sense_clk.read_ms() < VRP && vgetSignal == 1) {
chadnach1 20:dc272bfaa276 133 // Invalid_V state
chadnach1 4:f04eb7f96f4b 134 }
amiche 19:f3615321b5c4 135
mhowar 44:dfa38e4b3146 136 if (sense_clk.read_ms() < PVARP && agetSignal == 1) {
chadnach1 20:dc272bfaa276 137 // Invalid_A state
chadnach1 34:b4b50ca26e8c 138
mhowar 44:dfa38e4b3146 139 } else if (sense_clk.read_ms() >= PVARP && agetSignal == 1) {
chadnach1 20:dc272bfaa276 140 // Valid_A state
amiche 24:81cd9ef5c4f6 141 asense();
chadnach1 4:f04eb7f96f4b 142 }
chadnach1 4:f04eb7f96f4b 143 }
amiche 3:44d132582373 144 }
amiche 3:44d132582373 145
chadnach1 27:2c5aefcf3000 146 void pm_response(void const *args)
amiche 19:f3615321b5c4 147 {
chadnach1 4:f04eb7f96f4b 148 while(1) {
chadnach1 34:b4b50ca26e8c 149
mhowar 44:dfa38e4b3146 150 bool goInitialState = 1;
mhowar 44:dfa38e4b3146 151 if (pulse_clk.read_ms() >= LRI - AVI) {
chadnach1 33:b68c1648206e 152
mhowar 44:dfa38e4b3146 153 goInitialState = 0;
chadnach1 34:b4b50ca26e8c 154
amiche 19:f3615321b5c4 155 avi_clk.reset();
amiche 19:f3615321b5c4 156
mhowar 44:dfa38e4b3146 157 // PM_A! sets the LED high
amiche 19:f3615321b5c4 158 apace();
chadnach1 34:b4b50ca26e8c 159
amiche 19:f3615321b5c4 160 // At Atrial Event State
chadnach1 33:b68c1648206e 161 while (avi_clk.read_ms() < AVI) {
chadnach1 34:b4b50ca26e8c 162
chadnach1 27:2c5aefcf3000 163 if (v_sense == 1) {
chadnach1 46:2d9cf50b4bc3 164 beats++;
mhowar 44:dfa38e4b3146 165 //sensed valid ventricular event
mhowar 44:dfa38e4b3146 166 goInitialState = 1;
mhowar 44:dfa38e4b3146 167 pulse_clk.reset();
amiche 24:81cd9ef5c4f6 168 break;
amiche 24:81cd9ef5c4f6 169 }
amiche 24:81cd9ef5c4f6 170 }
mhowar 44:dfa38e4b3146 171 if (!goInitialState) {
amiche 24:81cd9ef5c4f6 172 // Ventricular Event
mhowar 44:dfa38e4b3146 173 pulse_clk.reset();
mhowar 44:dfa38e4b3146 174 sense_clk.reset();
mhowar 44:dfa38e4b3146 175
amiche 24:81cd9ef5c4f6 176 // PM_V! sets the LED high
chadnach1 46:2d9cf50b4bc3 177 beats++;
amiche 24:81cd9ef5c4f6 178 vpace();
amiche 24:81cd9ef5c4f6 179 }
mhowar 44:dfa38e4b3146 180 } else if (pulse_clk.read_ms() < LRI - AVI) {
chadnach1 34:b4b50ca26e8c 181
amiche 24:81cd9ef5c4f6 182 // if Asense, move on to atrial event
chadnach1 27:2c5aefcf3000 183 if (a_sense == 1) {
mhowar 44:dfa38e4b3146 184 goInitialState = 0;
chadnach1 34:b4b50ca26e8c 185
amiche 24:81cd9ef5c4f6 186 avi_clk.reset();
amiche 19:f3615321b5c4 187
amiche 24:81cd9ef5c4f6 188 // At Atrial Event State
amiche 24:81cd9ef5c4f6 189 while (avi_clk.read() < AVI) {
chadnach1 27:2c5aefcf3000 190 if (v_sense == 1) {
chadnach1 46:2d9cf50b4bc3 191 beats++;
mhowar 44:dfa38e4b3146 192 pulse_clk.reset();
mhowar 44:dfa38e4b3146 193 goInitialState = 1;
amiche 24:81cd9ef5c4f6 194 break;
amiche 24:81cd9ef5c4f6 195 }
amiche 24:81cd9ef5c4f6 196 }
mhowar 44:dfa38e4b3146 197 if (!goInitialState) {
mhowar 44:dfa38e4b3146 198 // Ventricular Event
chadnach1 46:2d9cf50b4bc3 199 beats++;
mhowar 44:dfa38e4b3146 200 sense_clk.reset();
mhowar 44:dfa38e4b3146 201 pulse_clk.reset();
mhowar 44:dfa38e4b3146 202
mhowar 44:dfa38e4b3146 203 vpace();
mhowar 44:dfa38e4b3146 204 }
amiche 24:81cd9ef5c4f6 205 }
amiche 19:f3615321b5c4 206 }
amiche 19:f3615321b5c4 207 }
amiche 3:44d132582373 208 }
lucastai 2:5e9c4d83d038 209
chadnach1 46:2d9cf50b4bc3 210 /* Every observation interval, calculate beats per minute and display
chadnach1 46:2d9cf50b4bc3 211 *
chadnach1 46:2d9cf50b4bc3 212 */
chadnach1 46:2d9cf50b4bc3 213 void update_display() {
chadnach1 46:2d9cf50b4bc3 214 bpm = beats / (double) obs_int * 60;
chadnach1 46:2d9cf50b4bc3 215 //reset count
chadnach1 46:2d9cf50b4bc3 216 beats = 0;
chadnach1 46:2d9cf50b4bc3 217 }
chadnach1 46:2d9cf50b4bc3 218
amiche 19:f3615321b5c4 219 int main()
amiche 19:f3615321b5c4 220 {
chadnach1 16:ae9df4194011 221 // https://developer.mbed.org/users/chadnach1/code/PacemakerController/
lucastai 2:5e9c4d83d038 222 // connect the serial device (PC keybd) to the interrupt
amiche 19:f3615321b5c4 223
chadnach1 16:ae9df4194011 224 // Start LED's Off
chadnach1 17:c89cddf30925 225 led_apace = 0;
chadnach1 17:c89cddf30925 226 led_vpace = 0;
amiche 19:f3615321b5c4 227
chadnach1 16:ae9df4194011 228 // Start the avi_clock
chadnach1 16:ae9df4194011 229 avi_clk.start();
chadnach1 33:b68c1648206e 230 avi_clk.reset();
amiche 19:f3615321b5c4 231
chadnach1 30:97db5a684eaa 232 Thread t1(pm_sense, (void *)"");
chadnach1 30:97db5a684eaa 233 Thread t2(pm_response, (void *)"");
chadnach1 31:7f0e865e3d4b 234 Thread t3(PM_ALARM, (void *)"");
mhowar 44:dfa38e4b3146 235 sense_clk.start();
mhowar 44:dfa38e4b3146 236 pulse_clk.start();
chadnach1 46:2d9cf50b4bc3 237
chadnach1 46:2d9cf50b4bc3 238 //update_display
chadnach1 46:2d9cf50b4bc3 239 rate_monitor.attach(&update_display, obs_int);
chadnach1 46:2d9cf50b4bc3 240
chadnach1 31:7f0e865e3d4b 241 while(1) {
mhowar 35:b5e8650a7669 242 if (pc.readable()) {
mhowar 35:b5e8650a7669 243
mhowar 35:b5e8650a7669 244 char a = pc.getc();
mhowar 35:b5e8650a7669 245
mhowar 35:b5e8650a7669 246 // Handle different keyboard inputs
mhowar 35:b5e8650a7669 247 if (keyboard_needs_numeric) {
mhowar 35:b5e8650a7669 248 if (a >= '0' && a <= '9') {
mhowar 35:b5e8650a7669 249 // update observation interval
mhowar 35:b5e8650a7669 250 obs_int = (a - '0' + 1) * 5;
mhowar 35:b5e8650a7669 251 keyboard_needs_numeric = 0;
chadnach1 46:2d9cf50b4bc3 252 rate_monitor.attach(&update_display, obs_int);
chadnach1 46:2d9cf50b4bc3 253 pc.printf("Set observation interval to %d seconds\n", obs_int);
mhowar 35:b5e8650a7669 254 } else {
mhowar 35:b5e8650a7669 255 pc.printf("Expected numeric key\n");
mhowar 35:b5e8650a7669 256 }
chadnach1 46:2d9cf50b4bc3 257 } else if(a == 'N') {
mhowar 35:b5e8650a7669 258 // if the char is N, update bounds to normal mode
mhowar 35:b5e8650a7669 259 curr_mode = NORMAL;
mhowar 35:b5e8650a7669 260 upper_bound = 100;
chadnach1 45:ec9e76ccec6c 261 LRI = 600;
mhowar 35:b5e8650a7669 262 lower_bound = 40;
mhowar 35:b5e8650a7669 263 pc.printf("MODE IS N\n");
mhowar 35:b5e8650a7669 264 // if the char is S, set bounds to sleep
mhowar 35:b5e8650a7669 265 } else if (a == 'S') {
mhowar 35:b5e8650a7669 266 curr_mode = SLEEP;
mhowar 35:b5e8650a7669 267 upper_bound = 60;
chadnach1 45:ec9e76ccec6c 268 LRI = 1000;
mhowar 35:b5e8650a7669 269 lower_bound = 30;
mhowar 35:b5e8650a7669 270 pc.printf("MODE IS S\n");
mhowar 35:b5e8650a7669 271 // if the char is E, set bounds to exercise
mhowar 35:b5e8650a7669 272 } else if (a == 'E') {
mhowar 35:b5e8650a7669 273 curr_mode = EXERCISE;
mhowar 35:b5e8650a7669 274 upper_bound = 175;
chadnach1 45:ec9e76ccec6c 275 LRI = 343;
mhowar 35:b5e8650a7669 276 lower_bound = 100;
mhowar 35:b5e8650a7669 277 pc.printf("MODE IS E\n");
mhowar 35:b5e8650a7669 278 // if the char is M, set to manual
mhowar 35:b5e8650a7669 279 } else if (a == 'M') {
mhowar 35:b5e8650a7669 280 curr_mode = MANUAL;
mhowar 35:b5e8650a7669 281 upper_bound = 175;
chadnach1 43:f28bc869321e 282 LRI = 1750;
mhowar 35:b5e8650a7669 283 lower_bound = 30;
mhowar 35:b5e8650a7669 284 pc.printf("MODE IS MANUAL\n");
mhowar 35:b5e8650a7669 285 // check for A if mode is manual
mhowar 35:b5e8650a7669 286 } else if (a == 'A') {
mhowar 35:b5e8650a7669 287 if(curr_mode == MANUAL) {
chadnach1 43:f28bc869321e 288 pc.printf("MODE IS MANUAL SENT APACE\n");
chadnach1 39:51c4ec84f6fd 289 apace();
mhowar 35:b5e8650a7669 290 }
mhowar 35:b5e8650a7669 291 // check for V is mode is manual
mhowar 35:b5e8650a7669 292 } else if (a == 'V') {
mhowar 35:b5e8650a7669 293 if(curr_mode == MANUAL) {
chadnach1 43:f28bc869321e 294 pc.printf("MODE IS MANUAL SENT VPACE\n");
chadnach1 39:51c4ec84f6fd 295 vpace();
mhowar 35:b5e8650a7669 296 }
mhowar 35:b5e8650a7669 297 } else if (a == 'O') {
mhowar 35:b5e8650a7669 298 keyboard_needs_numeric = 1;
mhowar 35:b5e8650a7669 299 } else {
mhowar 35:b5e8650a7669 300 // do nothing for invalid char
mhowar 35:b5e8650a7669 301 }
chadnach1 31:7f0e865e3d4b 302 }
chadnach1 31:7f0e865e3d4b 303 }
chadnach1 47:bac7fc1a44fe 304 }