This is my final project for UCSC Extension - USB Programming. It is a home monitoring program for motion and temperature and requires host-side code.
Dependencies: C12832_lcd HomeMon LM75B MMA7660 USBDevice mbed
main.cpp@4:04f83503d219, 2013-09-03 (annotated)
- Committer:
- groletter
- Date:
- Tue Sep 03 20:24:26 2013 +0000
- Revision:
- 4:04f83503d219
- Parent:
- 3:21245644a2e3
Created documentation for my classes.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
groletter | 0:977f7cf68014 | 1 | // |
groletter | 0:977f7cf68014 | 2 | // Jerry Roletter - 9/1/13 |
groletter | 0:977f7cf68014 | 3 | // UCSC Extension - USB Programming Class (Summer 2013) |
groletter | 0:977f7cf68014 | 4 | // |
groletter | 0:977f7cf68014 | 5 | // This code is for a simple home monitoring system that |
groletter | 0:977f7cf68014 | 6 | // detects temperature out of a programmed range, and any |
groletter | 0:977f7cf68014 | 7 | // motion of the mbed application board. If motion or out |
groletter | 0:977f7cf68014 | 8 | // of range temperature is detected it sends alerts to the |
groletter | 0:977f7cf68014 | 9 | // host if one is connected via a USB Serial device. Otherwise |
groletter | 0:977f7cf68014 | 10 | // it stores them until a host is connected. |
groletter | 0:977f7cf68014 | 11 | // |
groletter | 0:977f7cf68014 | 12 | // It keeps track of historic temperature and movement data. |
groletter | 0:977f7cf68014 | 13 | // The host can request those buffers for analysis. |
groletter | 0:977f7cf68014 | 14 | // |
groletter | 0:977f7cf68014 | 15 | // I build a protocol on top of the serial port. This allows |
groletter | 0:977f7cf68014 | 16 | // the host and device to communicate. As of 9/1/13 there still |
groletter | 0:977f7cf68014 | 17 | // seem to be some issues around the communication protocol |
groletter | 0:977f7cf68014 | 18 | // due to lost acks or improper error handling. Running out |
groletter | 0:977f7cf68014 | 19 | // of time to fully debug. |
groletter | 0:977f7cf68014 | 20 | // |
groletter | 0:977f7cf68014 | 21 | |
groletter | 0:977f7cf68014 | 22 | #include "mbed.h" |
groletter | 0:977f7cf68014 | 23 | #include "MMA7660.h" |
groletter | 0:977f7cf68014 | 24 | #include "C12832_lcd.h" |
groletter | 0:977f7cf68014 | 25 | #include "LM75B.h" |
groletter | 0:977f7cf68014 | 26 | #include "USBSerial.h" |
groletter | 0:977f7cf68014 | 27 | #include <ctype.h> |
groletter | 0:977f7cf68014 | 28 | |
groletter | 0:977f7cf68014 | 29 | // My specific classes for this assignment |
groletter | 0:977f7cf68014 | 30 | |
groletter | 0:977f7cf68014 | 31 | #include "USBHomeMon.h" |
groletter | 0:977f7cf68014 | 32 | #include "Motion.h" |
groletter | 0:977f7cf68014 | 33 | #include "Temperature.h" |
groletter | 0:977f7cf68014 | 34 | #include "Communication.h" |
groletter | 0:977f7cf68014 | 35 | |
groletter | 0:977f7cf68014 | 36 | // TODO: |
groletter | 0:977f7cf68014 | 37 | // - Add a command to allow host to disconnect |
groletter | 0:977f7cf68014 | 38 | // - Add a command to allow the host to ignore Alert messages |
groletter | 0:977f7cf68014 | 39 | // - Longer term allow host to change alert window period (collapse alerts) |
groletter | 0:977f7cf68014 | 40 | // - Clean up FIXME, printf(), etc. |
groletter | 0:977f7cf68014 | 41 | // - Add time to temperature information |
groletter | 0:977f7cf68014 | 42 | // |
groletter | 0:977f7cf68014 | 43 | |
groletter | 0:977f7cf68014 | 44 | // LCD for debug |
groletter | 0:977f7cf68014 | 45 | C12832_LCD lcd; |
groletter | 0:977f7cf68014 | 46 | // Temperature Sensor |
groletter | 0:977f7cf68014 | 47 | LM75B tmp(p28,p27); |
groletter | 0:977f7cf68014 | 48 | // Accelerometer |
groletter | 0:977f7cf68014 | 49 | MMA7660 MMA(p28, p27); |
groletter | 0:977f7cf68014 | 50 | // USB Device |
groletter | 0:977f7cf68014 | 51 | USBSerial serial; |
groletter | 0:977f7cf68014 | 52 | |
groletter | 0:977f7cf68014 | 53 | Timer sysMonTime; |
groletter | 0:977f7cf68014 | 54 | |
groletter | 0:977f7cf68014 | 55 | DigitalOut connectionLED(LED1); |
groletter | 0:977f7cf68014 | 56 | DigitalOut motionLED(LED2); |
groletter | 0:977f7cf68014 | 57 | DigitalOut tempHiLED(LED3); |
groletter | 2:f6a1f96dc3cd | 58 | DigitalOut tempLoLED(LED4); |
groletter | 0:977f7cf68014 | 59 | |
groletter | 0:977f7cf68014 | 60 | // Global State |
groletter | 0:977f7cf68014 | 61 | int state; |
groletter | 0:977f7cf68014 | 62 | alert_state alertState; |
groletter | 0:977f7cf68014 | 63 | |
groletter | 0:977f7cf68014 | 64 | double get_temp() { |
groletter | 0:977f7cf68014 | 65 | // Convert temperature to farenheit |
groletter | 0:977f7cf68014 | 66 | return tmp.read() * 9.0 / 5.0 + 32.0; |
groletter | 0:977f7cf68014 | 67 | } |
groletter | 0:977f7cf68014 | 68 | |
groletter | 0:977f7cf68014 | 69 | bool detect_motion(motion_vec current_motion, motion_vec last_motion, Motion &myMotion) { |
groletter | 0:977f7cf68014 | 70 | motion_vec thresh = myMotion.get_motion_thresh(); |
groletter | 0:977f7cf68014 | 71 | motion_vec delta; |
groletter | 0:977f7cf68014 | 72 | delta.x = current_motion.x - last_motion.x; |
groletter | 0:977f7cf68014 | 73 | delta.y = current_motion.y - last_motion.y; |
groletter | 0:977f7cf68014 | 74 | delta.z = current_motion.z - last_motion.z; |
groletter | 0:977f7cf68014 | 75 | |
groletter | 0:977f7cf68014 | 76 | if (last_motion.x > (current_motion.x+thresh.x) || last_motion.x < (current_motion.x-thresh.x) || |
groletter | 0:977f7cf68014 | 77 | last_motion.y > (current_motion.y+thresh.y) || last_motion.y < (current_motion.y-thresh.y) || |
groletter | 0:977f7cf68014 | 78 | last_motion.z > (current_motion.z+thresh.z) || last_motion.z < (current_motion.z-thresh.z)) { |
groletter | 0:977f7cf68014 | 79 | // FIXME - for debug |
groletter | 0:977f7cf68014 | 80 | lcd.cls(); |
groletter | 0:977f7cf68014 | 81 | lcd.locate(0,3); |
groletter | 2:f6a1f96dc3cd | 82 | lcd.printf("Motion detected - sending alert!\n"); |
groletter | 0:977f7cf68014 | 83 | lcd.printf("x = %.2f y = %.2f z = %.2f\n", delta.x, delta.y, delta.z); |
groletter | 0:977f7cf68014 | 84 | return true; |
groletter | 0:977f7cf68014 | 85 | |
groletter | 0:977f7cf68014 | 86 | } |
groletter | 0:977f7cf68014 | 87 | else { |
groletter | 0:977f7cf68014 | 88 | return false; |
groletter | 0:977f7cf68014 | 89 | } |
groletter | 0:977f7cf68014 | 90 | } |
groletter | 0:977f7cf68014 | 91 | |
groletter | 0:977f7cf68014 | 92 | void store_alert(alert_type alert) { |
groletter | 0:977f7cf68014 | 93 | switch (alert) { |
groletter | 0:977f7cf68014 | 94 | case MOTION: |
groletter | 0:977f7cf68014 | 95 | alertState.pendMotion = true; |
groletter | 0:977f7cf68014 | 96 | break; |
groletter | 0:977f7cf68014 | 97 | case TEMP_LOW: |
groletter | 0:977f7cf68014 | 98 | alertState.pendTempLo = true; |
groletter | 0:977f7cf68014 | 99 | break; |
groletter | 0:977f7cf68014 | 100 | case TEMP_HI: |
groletter | 0:977f7cf68014 | 101 | alertState.pendTempHi = true; |
groletter | 0:977f7cf68014 | 102 | break; |
groletter | 0:977f7cf68014 | 103 | } |
groletter | 0:977f7cf68014 | 104 | } |
groletter | 0:977f7cf68014 | 105 | |
groletter | 0:977f7cf68014 | 106 | #define MS_IN_SEC 1000.0 |
groletter | 0:977f7cf68014 | 107 | |
groletter | 0:977f7cf68014 | 108 | int main() { |
groletter | 0:977f7cf68014 | 109 | |
groletter | 0:977f7cf68014 | 110 | alertState.pendMotion = false; |
groletter | 0:977f7cf68014 | 111 | alertState.pendTempHi = false; |
groletter | 0:977f7cf68014 | 112 | alertState.pendTempLo = false; |
groletter | 0:977f7cf68014 | 113 | |
groletter | 0:977f7cf68014 | 114 | Motion myMotion; |
groletter | 0:977f7cf68014 | 115 | Temperature myTemp; |
groletter | 0:977f7cf68014 | 116 | double theTemp; |
groletter | 0:977f7cf68014 | 117 | double lastTimeMS, curTimeMS; |
groletter | 0:977f7cf68014 | 118 | double lastTempAlertSecs, lastMotionAlertSecs; |
groletter | 0:977f7cf68014 | 119 | double MotionAlertWaitSecs, TempAlertWaitSecs; |
groletter | 0:977f7cf68014 | 120 | |
groletter | 0:977f7cf68014 | 121 | // Don't send too many alerts too quickly |
groletter | 0:977f7cf68014 | 122 | // These are just debug settings. A real system would |
groletter | 0:977f7cf68014 | 123 | // have much longer temperature settings |
groletter | 0:977f7cf68014 | 124 | |
groletter | 0:977f7cf68014 | 125 | MotionAlertWaitSecs = 5.0; // Don't allow multiple alerts within 5.0 seconds |
groletter | 0:977f7cf68014 | 126 | TempAlertWaitSecs = 60.0; // Wait at least a minute between temp alerts |
groletter | 0:977f7cf68014 | 127 | |
groletter | 0:977f7cf68014 | 128 | char host_cmd; |
groletter | 0:977f7cf68014 | 129 | msg_type msg; |
groletter | 0:977f7cf68014 | 130 | |
groletter | 0:977f7cf68014 | 131 | motion_vec current_motion; |
groletter | 0:977f7cf68014 | 132 | motion_vec last_motion; |
groletter | 0:977f7cf68014 | 133 | |
groletter | 0:977f7cf68014 | 134 | last_motion.x = MMA.x(); |
groletter | 0:977f7cf68014 | 135 | last_motion.y = MMA.y(); |
groletter | 0:977f7cf68014 | 136 | last_motion.z = MMA.z(); |
groletter | 0:977f7cf68014 | 137 | |
groletter | 0:977f7cf68014 | 138 | sysMonTime.start(); |
groletter | 0:977f7cf68014 | 139 | lastTimeMS = sysMonTime.read_ms()/MS_IN_SEC; |
groletter | 0:977f7cf68014 | 140 | lastTempAlertSecs = sysMonTime.read(); |
groletter | 0:977f7cf68014 | 141 | lastMotionAlertSecs = lastTempAlertSecs; |
groletter | 0:977f7cf68014 | 142 | |
groletter | 0:977f7cf68014 | 143 | // This method of setting the temperature is just for demo |
groletter | 0:977f7cf68014 | 144 | // purposes. I use the current temp to initialize the ranges. |
groletter | 0:977f7cf68014 | 145 | |
groletter | 0:977f7cf68014 | 146 | theTemp = get_temp(); |
groletter | 0:977f7cf68014 | 147 | myTemp.set_min(theTemp - 1.0); |
groletter | 0:977f7cf68014 | 148 | myTemp.set_max(theTemp + 1.0); |
groletter | 0:977f7cf68014 | 149 | |
groletter | 0:977f7cf68014 | 150 | state = monDISCONNECTED; |
groletter | 0:977f7cf68014 | 151 | |
groletter | 0:977f7cf68014 | 152 | while(1) { |
groletter | 0:977f7cf68014 | 153 | if (state == monDISCONNECTED) { |
groletter | 0:977f7cf68014 | 154 | if (check_connection()) { |
groletter | 0:977f7cf68014 | 155 | connectionLED = 1; |
groletter | 2:f6a1f96dc3cd | 156 | lcd.cls(); |
groletter | 2:f6a1f96dc3cd | 157 | lcd.locate(0,3); |
groletter | 2:f6a1f96dc3cd | 158 | lcd.printf("Connected to Host\n"); |
groletter | 0:977f7cf68014 | 159 | state = monCONNECTED; |
groletter | 0:977f7cf68014 | 160 | if (alertState.pendMotion) { |
groletter | 0:977f7cf68014 | 161 | alertState.pendMotion = false; |
groletter | 0:977f7cf68014 | 162 | send_alert(MOTION); |
groletter | 3:21245644a2e3 | 163 | motionLED = 0; |
groletter | 0:977f7cf68014 | 164 | } |
groletter | 3:21245644a2e3 | 165 | if (alertState.pendTempHi) { |
groletter | 0:977f7cf68014 | 166 | alertState.pendTempHi = false; |
groletter | 2:f6a1f96dc3cd | 167 | send_alert(TEMP_HI); |
groletter | 3:21245644a2e3 | 168 | tempHiLED = 0; |
groletter | 0:977f7cf68014 | 169 | } |
groletter | 3:21245644a2e3 | 170 | if (alertState.pendTempLo) { |
groletter | 0:977f7cf68014 | 171 | alertState.pendTempLo = false; |
groletter | 2:f6a1f96dc3cd | 172 | send_alert(TEMP_LOW); |
groletter | 3:21245644a2e3 | 173 | tempLoLED = 0; |
groletter | 0:977f7cf68014 | 174 | } |
groletter | 0:977f7cf68014 | 175 | } |
groletter | 0:977f7cf68014 | 176 | else { |
groletter | 2:f6a1f96dc3cd | 177 | lcd.cls(); |
groletter | 2:f6a1f96dc3cd | 178 | lcd.locate(0,3); |
groletter | 2:f6a1f96dc3cd | 179 | lcd.printf("Not Connected to Host\n"); |
groletter | 3:21245644a2e3 | 180 | theTemp= get_temp(); |
groletter | 3:21245644a2e3 | 181 | lcd.printf("L=%.2f H=%.2f Temp=%.2f\n", myTemp.get_min(), myTemp.get_max(), theTemp); |
groletter | 0:977f7cf68014 | 182 | connectionLED = 0; |
groletter | 0:977f7cf68014 | 183 | } |
groletter | 0:977f7cf68014 | 184 | } |
groletter | 0:977f7cf68014 | 185 | // We are connected so listen for commands from |
groletter | 0:977f7cf68014 | 186 | // host. |
groletter | 0:977f7cf68014 | 187 | else { |
groletter | 0:977f7cf68014 | 188 | if (serial.available()) { |
groletter | 0:977f7cf68014 | 189 | host_cmd = rec_command(); |
groletter | 0:977f7cf68014 | 190 | msg = parse_msg(host_cmd); |
groletter | 0:977f7cf68014 | 191 | host_command_resp(msg, myTemp, myMotion); |
groletter | 0:977f7cf68014 | 192 | // FIXME - debug |
groletter | 0:977f7cf68014 | 193 | lcd.cls(); |
groletter | 0:977f7cf68014 | 194 | lcd.locate(0,3); |
groletter | 0:977f7cf68014 | 195 | lcd.printf("Received command %c\n", host_cmd); |
groletter | 0:977f7cf68014 | 196 | } |
groletter | 0:977f7cf68014 | 197 | } |
groletter | 0:977f7cf68014 | 198 | |
groletter | 0:977f7cf68014 | 199 | // Detect if motion has occurred and handle it |
groletter | 0:977f7cf68014 | 200 | current_motion.x = MMA.x(); |
groletter | 0:977f7cf68014 | 201 | current_motion.y = MMA.y(); |
groletter | 0:977f7cf68014 | 202 | current_motion.z = MMA.z(); |
groletter | 0:977f7cf68014 | 203 | if(detect_motion(current_motion, last_motion, myMotion)) { |
groletter | 0:977f7cf68014 | 204 | // Only alert if last alert was outside window of alert time |
groletter | 0:977f7cf68014 | 205 | if (sysMonTime.read() > (lastMotionAlertSecs + MotionAlertWaitSecs)) { |
groletter | 0:977f7cf68014 | 206 | // moved |
groletter | 0:977f7cf68014 | 207 | motionLED = 1; |
groletter | 0:977f7cf68014 | 208 | // Adds the time of motion to the database of motion |
groletter | 0:977f7cf68014 | 209 | myMotion.add_sample(sysMonTime.read()); |
groletter | 0:977f7cf68014 | 210 | // Send it over serial port |
groletter | 0:977f7cf68014 | 211 | if (state == monCONNECTED) { |
groletter | 0:977f7cf68014 | 212 | send_alert(MOTION); |
groletter | 0:977f7cf68014 | 213 | // clear LED since host is connected |
groletter | 0:977f7cf68014 | 214 | motionLED = 0; |
groletter | 0:977f7cf68014 | 215 | } |
groletter | 0:977f7cf68014 | 216 | else { |
groletter | 0:977f7cf68014 | 217 | store_alert(MOTION); |
groletter | 0:977f7cf68014 | 218 | } |
groletter | 0:977f7cf68014 | 219 | lastMotionAlertSecs = sysMonTime.read(); |
groletter | 0:977f7cf68014 | 220 | } |
groletter | 0:977f7cf68014 | 221 | } |
groletter | 0:977f7cf68014 | 222 | |
groletter | 0:977f7cf68014 | 223 | // Now check temperature and generate an alert |
groletter | 0:977f7cf68014 | 224 | theTemp = get_temp(); |
groletter | 0:977f7cf68014 | 225 | if (theTemp > myTemp.get_max()) { |
groletter | 0:977f7cf68014 | 226 | if (sysMonTime.read() > (lastTempAlertSecs + TempAlertWaitSecs)) { |
groletter | 2:f6a1f96dc3cd | 227 | lcd.cls(); |
groletter | 2:f6a1f96dc3cd | 228 | lcd.locate(0,3); |
groletter | 2:f6a1f96dc3cd | 229 | lcd.printf("TEMP ALERT %.2f over %.2f - sending alert!\n", theTemp, myTemp.get_max()); |
groletter | 0:977f7cf68014 | 230 | tempHiLED = 1; |
groletter | 0:977f7cf68014 | 231 | if (state == monCONNECTED) { |
groletter | 0:977f7cf68014 | 232 | send_alert(TEMP_HI); |
groletter | 0:977f7cf68014 | 233 | // clear if connected |
groletter | 0:977f7cf68014 | 234 | tempHiLED = 0; |
groletter | 0:977f7cf68014 | 235 | } |
groletter | 0:977f7cf68014 | 236 | else { |
groletter | 0:977f7cf68014 | 237 | store_alert(TEMP_HI); |
groletter | 0:977f7cf68014 | 238 | } |
groletter | 0:977f7cf68014 | 239 | lastTempAlertSecs = sysMonTime.read(); |
groletter | 0:977f7cf68014 | 240 | } |
groletter | 0:977f7cf68014 | 241 | } |
groletter | 0:977f7cf68014 | 242 | else if (theTemp < myTemp.get_min()) { |
groletter | 0:977f7cf68014 | 243 | if (sysMonTime.read() > (lastTempAlertSecs + TempAlertWaitSecs)) { |
groletter | 2:f6a1f96dc3cd | 244 | lcd.cls(); |
groletter | 2:f6a1f96dc3cd | 245 | lcd.locate(0,3); |
groletter | 2:f6a1f96dc3cd | 246 | lcd.printf("TEMP ALERT %.2f under %.2f - sending alert!\n", theTemp, myTemp.get_min()); |
groletter | 0:977f7cf68014 | 247 | tempLoLED = 1; |
groletter | 0:977f7cf68014 | 248 | if (state == monCONNECTED) { |
groletter | 0:977f7cf68014 | 249 | send_alert(TEMP_LOW); |
groletter | 0:977f7cf68014 | 250 | // clear if connected |
groletter | 0:977f7cf68014 | 251 | tempLoLED = 0; |
groletter | 0:977f7cf68014 | 252 | } |
groletter | 0:977f7cf68014 | 253 | else { |
groletter | 0:977f7cf68014 | 254 | store_alert(TEMP_LOW); |
groletter | 0:977f7cf68014 | 255 | } |
groletter | 0:977f7cf68014 | 256 | lastTempAlertSecs = sysMonTime.read(); |
groletter | 0:977f7cf68014 | 257 | } |
groletter | 0:977f7cf68014 | 258 | } |
groletter | 0:977f7cf68014 | 259 | |
groletter | 0:977f7cf68014 | 260 | // See if it is time to store the temperature samples |
groletter | 0:977f7cf68014 | 261 | if (sysMonTime.read_ms()/MS_IN_SEC > (lastTimeMS + myTemp.get_period())) { |
groletter | 2:f6a1f96dc3cd | 262 | // DEBUG lcd.printf("time to send temperature\n"); |
groletter | 0:977f7cf68014 | 263 | lastTimeMS = sysMonTime.read_ms()/MS_IN_SEC; |
groletter | 0:977f7cf68014 | 264 | myTemp.add_sample(get_temp()); |
groletter | 0:977f7cf68014 | 265 | } |
groletter | 0:977f7cf68014 | 266 | |
groletter | 0:977f7cf68014 | 267 | //lcd.cls(); |
groletter | 0:977f7cf68014 | 268 | //lcd.locate(0,3); |
groletter | 0:977f7cf68014 | 269 | //lcd.printf("temp = %.2f\n", theTemp); |
groletter | 0:977f7cf68014 | 270 | |
groletter | 0:977f7cf68014 | 271 | last_motion.x = current_motion.x; |
groletter | 0:977f7cf68014 | 272 | last_motion.y = current_motion.y; |
groletter | 0:977f7cf68014 | 273 | last_motion.z = current_motion.z; |
groletter | 0:977f7cf68014 | 274 | wait(0.3); |
groletter | 0:977f7cf68014 | 275 | } |
groletter | 0:977f7cf68014 | 276 | |
groletter | 0:977f7cf68014 | 277 | } |