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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 //
00002 // Jerry Roletter - 9/1/13
00003 // UCSC Extension - USB Programming Class (Summer 2013)
00004 //
00005 // This code is for a simple home monitoring system that
00006 // detects temperature out of a programmed range, and any
00007 // motion of the mbed application board.  If motion or out
00008 // of range temperature is detected it sends alerts to the
00009 // host if one is connected via a USB Serial device.  Otherwise
00010 // it stores them until a host is connected.
00011 //
00012 // It keeps track of historic temperature and movement data.
00013 // The host can request those buffers for analysis.
00014 //
00015 // I build a protocol on top of the serial port.  This allows
00016 // the host and device to communicate.  As of 9/1/13 there still
00017 // seem to be some issues around the communication protocol
00018 // due to lost acks or improper error handling.  Running out
00019 // of time to fully debug.
00020 //
00021 
00022 #include "mbed.h"
00023 #include "MMA7660.h"
00024 #include "C12832_lcd.h"
00025 #include "LM75B.h"
00026 #include "USBSerial.h"
00027 #include <ctype.h>
00028 
00029 // My specific classes for this assignment
00030 
00031 #include "USBHomeMon.h"
00032 #include "Motion.h"
00033 #include "Temperature.h"
00034 #include "Communication.h"
00035 
00036 // TODO:
00037 //  - Add a command to allow host to disconnect
00038 //  - Add a command to allow the host to ignore Alert messages
00039 //  - Longer term allow host to change alert window period (collapse alerts)
00040 //  - Clean up FIXME, printf(), etc.
00041 //  - Add time to temperature information
00042 //
00043 
00044 // LCD for debug
00045 C12832_LCD lcd;
00046 // Temperature Sensor
00047 LM75B tmp(p28,p27);
00048 // Accelerometer
00049 MMA7660 MMA(p28, p27);
00050 // USB Device 
00051 USBSerial serial;
00052 
00053 Timer sysMonTime;
00054 
00055 DigitalOut connectionLED(LED1);
00056 DigitalOut motionLED(LED2);
00057 DigitalOut tempHiLED(LED3);
00058 DigitalOut tempLoLED(LED4);
00059 
00060 // Global State       
00061 int state;
00062 alert_state alertState; 
00063 
00064 double get_temp() {
00065    // Convert temperature to farenheit
00066    return tmp.read() * 9.0 / 5.0 + 32.0;
00067 }
00068 
00069 bool detect_motion(motion_vec current_motion, motion_vec last_motion, Motion &myMotion) { 
00070     motion_vec thresh = myMotion.get_motion_thresh();
00071     motion_vec delta;
00072     delta.x = current_motion.x - last_motion.x;
00073     delta.y = current_motion.y - last_motion.y;
00074     delta.z = current_motion.z - last_motion.z;
00075     
00076     if (last_motion.x > (current_motion.x+thresh.x) || last_motion.x < (current_motion.x-thresh.x) || 
00077       last_motion.y > (current_motion.y+thresh.y) || last_motion.y < (current_motion.y-thresh.y) || 
00078       last_motion.z > (current_motion.z+thresh.z) || last_motion.z < (current_motion.z-thresh.z)) {
00079         // FIXME - for debug 
00080         lcd.cls();
00081         lcd.locate(0,3);
00082         lcd.printf("Motion detected - sending alert!\n");
00083         lcd.printf("x = %.2f y = %.2f z = %.2f\n", delta.x, delta.y, delta.z);  
00084         return true;  
00085         
00086     }
00087     else {
00088         return false;
00089     }
00090 }
00091 
00092 void store_alert(alert_type alert) {
00093     switch (alert) {
00094         case MOTION:
00095             alertState.pendMotion = true;
00096             break;
00097         case TEMP_LOW:
00098             alertState.pendTempLo = true;
00099             break;
00100         case TEMP_HI:
00101             alertState.pendTempHi = true;
00102             break;
00103     }
00104 }
00105 
00106 #define MS_IN_SEC 1000.0
00107 
00108 int main() {  
00109     
00110     alertState.pendMotion = false;
00111     alertState.pendTempHi = false;
00112     alertState.pendTempLo = false;
00113     
00114     Motion myMotion;
00115     Temperature myTemp;
00116     double theTemp;
00117     double lastTimeMS, curTimeMS;
00118     double lastTempAlertSecs, lastMotionAlertSecs;
00119     double MotionAlertWaitSecs, TempAlertWaitSecs;
00120     
00121     // Don't send too many alerts too quickly
00122     // These are just debug settings.  A real system would
00123     // have much longer temperature settings
00124     
00125     MotionAlertWaitSecs = 5.0;  // Don't allow multiple alerts within 5.0 seconds
00126     TempAlertWaitSecs = 60.0;   // Wait at least a minute between temp alerts
00127     
00128     char host_cmd;
00129     msg_type msg;
00130     
00131     motion_vec current_motion;
00132     motion_vec last_motion;
00133 
00134     last_motion.x = MMA.x();
00135     last_motion.y = MMA.y();
00136     last_motion.z = MMA.z();    
00137     
00138     sysMonTime.start();
00139     lastTimeMS = sysMonTime.read_ms()/MS_IN_SEC;
00140     lastTempAlertSecs = sysMonTime.read();
00141     lastMotionAlertSecs = lastTempAlertSecs;
00142     
00143     // This method of setting the temperature is just for demo
00144     // purposes.  I use the current temp to initialize the ranges.
00145     
00146     theTemp = get_temp();
00147     myTemp.set_min(theTemp - 1.0);
00148     myTemp.set_max(theTemp + 1.0);
00149     
00150     state = monDISCONNECTED;
00151     
00152     while(1) {
00153         if (state == monDISCONNECTED) {
00154             if (check_connection()) {
00155                 connectionLED = 1;
00156                 lcd.cls();
00157                 lcd.locate(0,3);
00158                 lcd.printf("Connected to Host\n");
00159                 state = monCONNECTED;
00160                 if (alertState.pendMotion) {
00161                     alertState.pendMotion = false;
00162                     send_alert(MOTION);
00163                     motionLED = 0;
00164                 }
00165                 if (alertState.pendTempHi) {
00166                     alertState.pendTempHi = false;
00167                     send_alert(TEMP_HI);
00168                     tempHiLED = 0;
00169                 }
00170                 if (alertState.pendTempLo) {
00171                     alertState.pendTempLo = false;
00172                     send_alert(TEMP_LOW);
00173                     tempLoLED = 0;
00174                 }
00175             }
00176             else {
00177                 lcd.cls();
00178                 lcd.locate(0,3);
00179                 lcd.printf("Not Connected to Host\n");
00180                 theTemp= get_temp();
00181                 lcd.printf("L=%.2f H=%.2f Temp=%.2f\n", myTemp.get_min(), myTemp.get_max(), theTemp);
00182                 connectionLED = 0;
00183             }
00184         }
00185         // We are connected so listen for commands from
00186         // host.
00187         else {
00188             if (serial.available()) {
00189                 host_cmd = rec_command();
00190                 msg = parse_msg(host_cmd);
00191                 host_command_resp(msg, myTemp, myMotion);
00192                 // FIXME - debug
00193                 lcd.cls();
00194                 lcd.locate(0,3);
00195                 lcd.printf("Received command %c\n", host_cmd); 
00196             }
00197         }
00198         
00199         // Detect if motion has occurred and handle it
00200         current_motion.x = MMA.x();
00201         current_motion.y = MMA.y();
00202         current_motion.z = MMA.z();
00203         if(detect_motion(current_motion, last_motion, myMotion)) { 
00204           // Only alert if last alert was outside window of alert time
00205           if (sysMonTime.read() > (lastMotionAlertSecs + MotionAlertWaitSecs)) {
00206             // moved
00207             motionLED = 1;
00208             // Adds the time of motion to the database of motion
00209             myMotion.add_sample(sysMonTime.read());
00210             // Send it over serial port
00211             if (state == monCONNECTED) {
00212                 send_alert(MOTION);
00213                 // clear LED since host is connected
00214                 motionLED = 0;
00215             }
00216             else {
00217                 store_alert(MOTION);
00218             }
00219             lastMotionAlertSecs = sysMonTime.read();
00220           }
00221         }
00222                 
00223         // Now check temperature and generate an alert 
00224         theTemp = get_temp();
00225         if (theTemp > myTemp.get_max()) {
00226           if (sysMonTime.read() > (lastTempAlertSecs + TempAlertWaitSecs)) {
00227             lcd.cls();
00228             lcd.locate(0,3);
00229             lcd.printf("TEMP ALERT %.2f over %.2f - sending alert!\n", theTemp, myTemp.get_max()); 
00230             tempHiLED = 1;
00231             if (state == monCONNECTED) {
00232                 send_alert(TEMP_HI);
00233                 // clear if connected
00234                 tempHiLED = 0;
00235             }
00236             else {
00237                 store_alert(TEMP_HI);
00238             }
00239             lastTempAlertSecs = sysMonTime.read();
00240           }
00241         }
00242         else if (theTemp < myTemp.get_min()) {
00243           if (sysMonTime.read() > (lastTempAlertSecs + TempAlertWaitSecs)) {
00244             lcd.cls();
00245             lcd.locate(0,3);
00246             lcd.printf("TEMP ALERT %.2f under %.2f - sending alert!\n", theTemp, myTemp.get_min()); 
00247             tempLoLED = 1;
00248             if (state == monCONNECTED) {
00249                 send_alert(TEMP_LOW);
00250                 // clear if connected
00251                 tempLoLED = 0;
00252             }
00253             else {
00254                 store_alert(TEMP_LOW);
00255             }
00256             lastTempAlertSecs = sysMonTime.read();
00257           }
00258         }   
00259         
00260         // See if it is time to store the temperature samples
00261         if (sysMonTime.read_ms()/MS_IN_SEC > (lastTimeMS + myTemp.get_period())) {
00262             // DEBUG lcd.printf("time to send temperature\n");
00263             lastTimeMS = sysMonTime.read_ms()/MS_IN_SEC;
00264             myTemp.add_sample(get_temp());
00265         }
00266          
00267         //lcd.cls();
00268         //lcd.locate(0,3);
00269         //lcd.printf("temp = %.2f\n", theTemp);
00270         
00271         last_motion.x = current_motion.x;
00272         last_motion.y = current_motion.y;
00273         last_motion.z = current_motion.z;
00274         wait(0.3);
00275     }
00276 
00277 }