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:
Sun Sep 01 23:35:50 2013 +0000
Revision:
0:977f7cf68014
Child:
2:f6a1f96dc3cd
This is my first draft of the UCSC Extension USB Programming final project.

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 0:977f7cf68014 58 DigitalOut tempLoLED(LED3);
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 0:977f7cf68014 82 lcd.printf("x = %.2f y = %.2f z = %.2f\n", delta.x, delta.y, delta.z);
groletter 0:977f7cf68014 83 return true;
groletter 0:977f7cf68014 84
groletter 0:977f7cf68014 85 }
groletter 0:977f7cf68014 86 else {
groletter 0:977f7cf68014 87 return false;
groletter 0:977f7cf68014 88 }
groletter 0:977f7cf68014 89 }
groletter 0:977f7cf68014 90
groletter 0:977f7cf68014 91 void store_alert(alert_type alert) {
groletter 0:977f7cf68014 92 switch (alert) {
groletter 0:977f7cf68014 93 case MOTION:
groletter 0:977f7cf68014 94 alertState.pendMotion = true;
groletter 0:977f7cf68014 95 break;
groletter 0:977f7cf68014 96 case TEMP_LOW:
groletter 0:977f7cf68014 97 alertState.pendTempLo = true;
groletter 0:977f7cf68014 98 break;
groletter 0:977f7cf68014 99 case TEMP_HI:
groletter 0:977f7cf68014 100 alertState.pendTempHi = true;
groletter 0:977f7cf68014 101 break;
groletter 0:977f7cf68014 102 }
groletter 0:977f7cf68014 103 }
groletter 0:977f7cf68014 104
groletter 0:977f7cf68014 105 #define MS_IN_SEC 1000.0
groletter 0:977f7cf68014 106
groletter 0:977f7cf68014 107 int main() {
groletter 0:977f7cf68014 108
groletter 0:977f7cf68014 109 alertState.pendMotion = false;
groletter 0:977f7cf68014 110 alertState.pendTempHi = false;
groletter 0:977f7cf68014 111 alertState.pendTempLo = false;
groletter 0:977f7cf68014 112
groletter 0:977f7cf68014 113 Motion myMotion;
groletter 0:977f7cf68014 114 Temperature myTemp;
groletter 0:977f7cf68014 115 double theTemp;
groletter 0:977f7cf68014 116 double lastTimeMS, curTimeMS;
groletter 0:977f7cf68014 117 double lastTempAlertSecs, lastMotionAlertSecs;
groletter 0:977f7cf68014 118 double MotionAlertWaitSecs, TempAlertWaitSecs;
groletter 0:977f7cf68014 119
groletter 0:977f7cf68014 120 // Don't send too many alerts too quickly
groletter 0:977f7cf68014 121 // These are just debug settings. A real system would
groletter 0:977f7cf68014 122 // have much longer temperature settings
groletter 0:977f7cf68014 123
groletter 0:977f7cf68014 124 MotionAlertWaitSecs = 5.0; // Don't allow multiple alerts within 5.0 seconds
groletter 0:977f7cf68014 125 TempAlertWaitSecs = 60.0; // Wait at least a minute between temp alerts
groletter 0:977f7cf68014 126
groletter 0:977f7cf68014 127 char host_cmd;
groletter 0:977f7cf68014 128 msg_type msg;
groletter 0:977f7cf68014 129
groletter 0:977f7cf68014 130 motion_vec current_motion;
groletter 0:977f7cf68014 131 motion_vec last_motion;
groletter 0:977f7cf68014 132
groletter 0:977f7cf68014 133 last_motion.x = MMA.x();
groletter 0:977f7cf68014 134 last_motion.y = MMA.y();
groletter 0:977f7cf68014 135 last_motion.z = MMA.z();
groletter 0:977f7cf68014 136
groletter 0:977f7cf68014 137 sysMonTime.start();
groletter 0:977f7cf68014 138 lastTimeMS = sysMonTime.read_ms()/MS_IN_SEC;
groletter 0:977f7cf68014 139 lastTempAlertSecs = sysMonTime.read();
groletter 0:977f7cf68014 140 lastMotionAlertSecs = lastTempAlertSecs;
groletter 0:977f7cf68014 141
groletter 0:977f7cf68014 142 // This method of setting the temperature is just for demo
groletter 0:977f7cf68014 143 // purposes. I use the current temp to initialize the ranges.
groletter 0:977f7cf68014 144
groletter 0:977f7cf68014 145 theTemp = get_temp();
groletter 0:977f7cf68014 146 myTemp.set_min(theTemp - 1.0);
groletter 0:977f7cf68014 147 myTemp.set_max(theTemp + 1.0);
groletter 0:977f7cf68014 148
groletter 0:977f7cf68014 149 state = monDISCONNECTED;
groletter 0:977f7cf68014 150
groletter 0:977f7cf68014 151 while(1) {
groletter 0:977f7cf68014 152 if (state == monDISCONNECTED) {
groletter 0:977f7cf68014 153 if (check_connection()) {
groletter 0:977f7cf68014 154 connectionLED = 1;
groletter 0:977f7cf68014 155 state = monCONNECTED;
groletter 0:977f7cf68014 156 if (alertState.pendMotion) {
groletter 0:977f7cf68014 157 alertState.pendMotion = false;
groletter 0:977f7cf68014 158 send_alert(MOTION);
groletter 0:977f7cf68014 159 }
groletter 0:977f7cf68014 160 else if (alertState.pendTempHi) {
groletter 0:977f7cf68014 161 alertState.pendTempHi = false;
groletter 0:977f7cf68014 162 send_alert(MOTION);
groletter 0:977f7cf68014 163 }
groletter 0:977f7cf68014 164 else if (alertState.pendTempLo) {
groletter 0:977f7cf68014 165 alertState.pendTempLo = false;
groletter 0:977f7cf68014 166 send_alert(MOTION);
groletter 0:977f7cf68014 167 }
groletter 0:977f7cf68014 168 }
groletter 0:977f7cf68014 169 else {
groletter 0:977f7cf68014 170 connectionLED = 0;
groletter 0:977f7cf68014 171 }
groletter 0:977f7cf68014 172 }
groletter 0:977f7cf68014 173 // We are connected so listen for commands from
groletter 0:977f7cf68014 174 // host.
groletter 0:977f7cf68014 175 else {
groletter 0:977f7cf68014 176 if (serial.available()) {
groletter 0:977f7cf68014 177 host_cmd = rec_command();
groletter 0:977f7cf68014 178 msg = parse_msg(host_cmd);
groletter 0:977f7cf68014 179 host_command_resp(msg, myTemp, myMotion);
groletter 0:977f7cf68014 180 // FIXME - debug
groletter 0:977f7cf68014 181 lcd.cls();
groletter 0:977f7cf68014 182 lcd.locate(0,3);
groletter 0:977f7cf68014 183 lcd.printf("Received command %c\n", host_cmd);
groletter 0:977f7cf68014 184 }
groletter 0:977f7cf68014 185 }
groletter 0:977f7cf68014 186
groletter 0:977f7cf68014 187 // Detect if motion has occurred and handle it
groletter 0:977f7cf68014 188 current_motion.x = MMA.x();
groletter 0:977f7cf68014 189 current_motion.y = MMA.y();
groletter 0:977f7cf68014 190 current_motion.z = MMA.z();
groletter 0:977f7cf68014 191 if(detect_motion(current_motion, last_motion, myMotion)) {
groletter 0:977f7cf68014 192 // Only alert if last alert was outside window of alert time
groletter 0:977f7cf68014 193 if (sysMonTime.read() > (lastMotionAlertSecs + MotionAlertWaitSecs)) {
groletter 0:977f7cf68014 194 // moved
groletter 0:977f7cf68014 195 motionLED = 1;
groletter 0:977f7cf68014 196 // Adds the time of motion to the database of motion
groletter 0:977f7cf68014 197 myMotion.add_sample(sysMonTime.read());
groletter 0:977f7cf68014 198 // Send it over serial port
groletter 0:977f7cf68014 199 if (state == monCONNECTED) {
groletter 0:977f7cf68014 200 send_alert(MOTION);
groletter 0:977f7cf68014 201 // clear LED since host is connected
groletter 0:977f7cf68014 202 motionLED = 0;
groletter 0:977f7cf68014 203 }
groletter 0:977f7cf68014 204 else {
groletter 0:977f7cf68014 205 store_alert(MOTION);
groletter 0:977f7cf68014 206 }
groletter 0:977f7cf68014 207 lastMotionAlertSecs = sysMonTime.read();
groletter 0:977f7cf68014 208 }
groletter 0:977f7cf68014 209 }
groletter 0:977f7cf68014 210
groletter 0:977f7cf68014 211 // Now check temperature and generate an alert
groletter 0:977f7cf68014 212 theTemp = get_temp();
groletter 0:977f7cf68014 213 if (theTemp > myTemp.get_max()) {
groletter 0:977f7cf68014 214 if (sysMonTime.read() > (lastTempAlertSecs + TempAlertWaitSecs)) {
groletter 0:977f7cf68014 215 tempHiLED = 1;
groletter 0:977f7cf68014 216 if (state == monCONNECTED) {
groletter 0:977f7cf68014 217 send_alert(TEMP_HI);
groletter 0:977f7cf68014 218 // clear if connected
groletter 0:977f7cf68014 219 tempHiLED = 0;
groletter 0:977f7cf68014 220 }
groletter 0:977f7cf68014 221 else {
groletter 0:977f7cf68014 222 store_alert(TEMP_HI);
groletter 0:977f7cf68014 223 }
groletter 0:977f7cf68014 224 lastTempAlertSecs = sysMonTime.read();
groletter 0:977f7cf68014 225 }
groletter 0:977f7cf68014 226 }
groletter 0:977f7cf68014 227 else if (theTemp < myTemp.get_min()) {
groletter 0:977f7cf68014 228 if (sysMonTime.read() > (lastTempAlertSecs + TempAlertWaitSecs)) {
groletter 0:977f7cf68014 229 tempLoLED = 1;
groletter 0:977f7cf68014 230 if (state == monCONNECTED) {
groletter 0:977f7cf68014 231 send_alert(TEMP_LOW);
groletter 0:977f7cf68014 232 // clear if connected
groletter 0:977f7cf68014 233 tempLoLED = 0;
groletter 0:977f7cf68014 234 }
groletter 0:977f7cf68014 235 else {
groletter 0:977f7cf68014 236 store_alert(TEMP_LOW);
groletter 0:977f7cf68014 237 }
groletter 0:977f7cf68014 238 lastTempAlertSecs = sysMonTime.read();
groletter 0:977f7cf68014 239 }
groletter 0:977f7cf68014 240 }
groletter 0:977f7cf68014 241
groletter 0:977f7cf68014 242 // See if it is time to store the temperature samples
groletter 0:977f7cf68014 243 if (sysMonTime.read_ms()/MS_IN_SEC > (lastTimeMS + myTemp.get_period())) {
groletter 0:977f7cf68014 244 lcd.printf("time to send temperature\n");
groletter 0:977f7cf68014 245 lastTimeMS = sysMonTime.read_ms()/MS_IN_SEC;
groletter 0:977f7cf68014 246 myTemp.add_sample(get_temp());
groletter 0:977f7cf68014 247 }
groletter 0:977f7cf68014 248
groletter 0:977f7cf68014 249 //lcd.cls();
groletter 0:977f7cf68014 250 //lcd.locate(0,3);
groletter 0:977f7cf68014 251 //lcd.printf("temp = %.2f\n", theTemp);
groletter 0:977f7cf68014 252
groletter 0:977f7cf68014 253 last_motion.x = current_motion.x;
groletter 0:977f7cf68014 254 last_motion.y = current_motion.y;
groletter 0:977f7cf68014 255 last_motion.z = current_motion.z;
groletter 0:977f7cf68014 256 wait(0.3);
groletter 0:977f7cf68014 257 }
groletter 0:977f7cf68014 258
groletter 0:977f7cf68014 259 }