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

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?

UserRevisionLine numberNew 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 }