
final
Dependencies: TextLCD mbed-rtos mbed
Fork of 541-pacemaker by
main.cpp@5:b506b5bdeee7, 2016-12-12 (annotated)
- Committer:
- ems316
- Date:
- Mon Dec 12 21:50:48 2016 +0000
- Revision:
- 5:b506b5bdeee7
- Parent:
- 4:a9c37c60425c
final
Who changed what in which revision?
User | Revision | Line number | New 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 | } |