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 08:55:16 2013 +0000
Revision:
2:f6a1f96dc3cd
Parent:
0:977f7cf68014
Child:
3:21245644a2e3
A couple bug fixes.  Should be final for the final class.

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 0:977f7cf68014 163 }
groletter 0:977f7cf68014 164 else if (alertState.pendTempHi) {
groletter 0:977f7cf68014 165 alertState.pendTempHi = false;
groletter 2:f6a1f96dc3cd 166 send_alert(TEMP_HI);
groletter 0:977f7cf68014 167 }
groletter 0:977f7cf68014 168 else if (alertState.pendTempLo) {
groletter 0:977f7cf68014 169 alertState.pendTempLo = false;
groletter 2:f6a1f96dc3cd 170 send_alert(TEMP_LOW);
groletter 0:977f7cf68014 171 }
groletter 0:977f7cf68014 172 }
groletter 0:977f7cf68014 173 else {
groletter 2:f6a1f96dc3cd 174 lcd.cls();
groletter 2:f6a1f96dc3cd 175 lcd.locate(0,3);
groletter 2:f6a1f96dc3cd 176 lcd.printf("Not Connected to Host\n");
groletter 0:977f7cf68014 177 connectionLED = 0;
groletter 0:977f7cf68014 178 }
groletter 0:977f7cf68014 179 }
groletter 0:977f7cf68014 180 // We are connected so listen for commands from
groletter 0:977f7cf68014 181 // host.
groletter 0:977f7cf68014 182 else {
groletter 0:977f7cf68014 183 if (serial.available()) {
groletter 0:977f7cf68014 184 host_cmd = rec_command();
groletter 0:977f7cf68014 185 msg = parse_msg(host_cmd);
groletter 0:977f7cf68014 186 host_command_resp(msg, myTemp, myMotion);
groletter 0:977f7cf68014 187 // FIXME - debug
groletter 0:977f7cf68014 188 lcd.cls();
groletter 0:977f7cf68014 189 lcd.locate(0,3);
groletter 0:977f7cf68014 190 lcd.printf("Received command %c\n", host_cmd);
groletter 0:977f7cf68014 191 }
groletter 0:977f7cf68014 192 }
groletter 0:977f7cf68014 193
groletter 0:977f7cf68014 194 // Detect if motion has occurred and handle it
groletter 0:977f7cf68014 195 current_motion.x = MMA.x();
groletter 0:977f7cf68014 196 current_motion.y = MMA.y();
groletter 0:977f7cf68014 197 current_motion.z = MMA.z();
groletter 0:977f7cf68014 198 if(detect_motion(current_motion, last_motion, myMotion)) {
groletter 0:977f7cf68014 199 // Only alert if last alert was outside window of alert time
groletter 0:977f7cf68014 200 if (sysMonTime.read() > (lastMotionAlertSecs + MotionAlertWaitSecs)) {
groletter 0:977f7cf68014 201 // moved
groletter 0:977f7cf68014 202 motionLED = 1;
groletter 0:977f7cf68014 203 // Adds the time of motion to the database of motion
groletter 0:977f7cf68014 204 myMotion.add_sample(sysMonTime.read());
groletter 0:977f7cf68014 205 // Send it over serial port
groletter 0:977f7cf68014 206 if (state == monCONNECTED) {
groletter 0:977f7cf68014 207 send_alert(MOTION);
groletter 0:977f7cf68014 208 // clear LED since host is connected
groletter 0:977f7cf68014 209 motionLED = 0;
groletter 0:977f7cf68014 210 }
groletter 0:977f7cf68014 211 else {
groletter 0:977f7cf68014 212 store_alert(MOTION);
groletter 0:977f7cf68014 213 }
groletter 0:977f7cf68014 214 lastMotionAlertSecs = sysMonTime.read();
groletter 0:977f7cf68014 215 }
groletter 0:977f7cf68014 216 }
groletter 0:977f7cf68014 217
groletter 0:977f7cf68014 218 // Now check temperature and generate an alert
groletter 0:977f7cf68014 219 theTemp = get_temp();
groletter 0:977f7cf68014 220 if (theTemp > myTemp.get_max()) {
groletter 0:977f7cf68014 221 if (sysMonTime.read() > (lastTempAlertSecs + TempAlertWaitSecs)) {
groletter 2:f6a1f96dc3cd 222 lcd.cls();
groletter 2:f6a1f96dc3cd 223 lcd.locate(0,3);
groletter 2:f6a1f96dc3cd 224 lcd.printf("TEMP ALERT %.2f over %.2f - sending alert!\n", theTemp, myTemp.get_max());
groletter 0:977f7cf68014 225 tempHiLED = 1;
groletter 0:977f7cf68014 226 if (state == monCONNECTED) {
groletter 0:977f7cf68014 227 send_alert(TEMP_HI);
groletter 0:977f7cf68014 228 // clear if connected
groletter 0:977f7cf68014 229 tempHiLED = 0;
groletter 0:977f7cf68014 230 }
groletter 0:977f7cf68014 231 else {
groletter 0:977f7cf68014 232 store_alert(TEMP_HI);
groletter 0:977f7cf68014 233 }
groletter 0:977f7cf68014 234 lastTempAlertSecs = sysMonTime.read();
groletter 0:977f7cf68014 235 }
groletter 0:977f7cf68014 236 }
groletter 0:977f7cf68014 237 else if (theTemp < myTemp.get_min()) {
groletter 0:977f7cf68014 238 if (sysMonTime.read() > (lastTempAlertSecs + TempAlertWaitSecs)) {
groletter 2:f6a1f96dc3cd 239 lcd.cls();
groletter 2:f6a1f96dc3cd 240 lcd.locate(0,3);
groletter 2:f6a1f96dc3cd 241 lcd.printf("TEMP ALERT %.2f under %.2f - sending alert!\n", theTemp, myTemp.get_min());
groletter 0:977f7cf68014 242 tempLoLED = 1;
groletter 0:977f7cf68014 243 if (state == monCONNECTED) {
groletter 0:977f7cf68014 244 send_alert(TEMP_LOW);
groletter 0:977f7cf68014 245 // clear if connected
groletter 0:977f7cf68014 246 tempLoLED = 0;
groletter 0:977f7cf68014 247 }
groletter 0:977f7cf68014 248 else {
groletter 0:977f7cf68014 249 store_alert(TEMP_LOW);
groletter 0:977f7cf68014 250 }
groletter 0:977f7cf68014 251 lastTempAlertSecs = sysMonTime.read();
groletter 0:977f7cf68014 252 }
groletter 0:977f7cf68014 253 }
groletter 0:977f7cf68014 254
groletter 0:977f7cf68014 255 // See if it is time to store the temperature samples
groletter 0:977f7cf68014 256 if (sysMonTime.read_ms()/MS_IN_SEC > (lastTimeMS + myTemp.get_period())) {
groletter 2:f6a1f96dc3cd 257 // DEBUG lcd.printf("time to send temperature\n");
groletter 0:977f7cf68014 258 lastTimeMS = sysMonTime.read_ms()/MS_IN_SEC;
groletter 0:977f7cf68014 259 myTemp.add_sample(get_temp());
groletter 0:977f7cf68014 260 }
groletter 0:977f7cf68014 261
groletter 0:977f7cf68014 262 //lcd.cls();
groletter 0:977f7cf68014 263 //lcd.locate(0,3);
groletter 0:977f7cf68014 264 //lcd.printf("temp = %.2f\n", theTemp);
groletter 0:977f7cf68014 265
groletter 0:977f7cf68014 266 last_motion.x = current_motion.x;
groletter 0:977f7cf68014 267 last_motion.y = current_motion.y;
groletter 0:977f7cf68014 268 last_motion.z = current_motion.z;
groletter 0:977f7cf68014 269 wait(0.3);
groletter 0:977f7cf68014 270 }
groletter 0:977f7cf68014 271
groletter 0:977f7cf68014 272 }