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

Committer:
groletter
Date:
2013-09-01
Revision:
0:977f7cf68014
Child:
2:f6a1f96dc3cd

File content as of revision 0:977f7cf68014:

//
// Jerry Roletter - 9/1/13
// UCSC Extension - USB Programming Class (Summer 2013)
//
// This code is for a simple home monitoring system that
// detects temperature out of a programmed range, and any
// motion of the mbed application board.  If motion or out
// of range temperature is detected it sends alerts to the
// host if one is connected via a USB Serial device.  Otherwise
// it stores them until a host is connected.
//
// It keeps track of historic temperature and movement data.
// The host can request those buffers for analysis.
//
// I build a protocol on top of the serial port.  This allows
// the host and device to communicate.  As of 9/1/13 there still
// seem to be some issues around the communication protocol
// due to lost acks or improper error handling.  Running out
// of time to fully debug.
//

#include "mbed.h"
#include "MMA7660.h"
#include "C12832_lcd.h"
#include "LM75B.h"
#include "USBSerial.h"
#include <ctype.h>

// My specific classes for this assignment

#include "USBHomeMon.h"
#include "Motion.h"
#include "Temperature.h"
#include "Communication.h"

// TODO:
//  - Add a command to allow host to disconnect
//  - Add a command to allow the host to ignore Alert messages
//  - Longer term allow host to change alert window period (collapse alerts)
//  - Clean up FIXME, printf(), etc.
//  - Add time to temperature information
//

// LCD for debug
C12832_LCD lcd;
// Temperature Sensor
LM75B tmp(p28,p27);
// Accelerometer
MMA7660 MMA(p28, p27);
// USB Device 
USBSerial serial;

Timer sysMonTime;

DigitalOut connectionLED(LED1);
DigitalOut motionLED(LED2);
DigitalOut tempHiLED(LED3);
DigitalOut tempLoLED(LED3);

// Global State       
int state;
alert_state alertState; 

double get_temp() {
   // Convert temperature to farenheit
   return tmp.read() * 9.0 / 5.0 + 32.0;
}

bool detect_motion(motion_vec current_motion, motion_vec last_motion, Motion &myMotion) { 
    motion_vec thresh = myMotion.get_motion_thresh();
    motion_vec delta;
    delta.x = current_motion.x - last_motion.x;
    delta.y = current_motion.y - last_motion.y;
    delta.z = current_motion.z - last_motion.z;
    
    if (last_motion.x > (current_motion.x+thresh.x) || last_motion.x < (current_motion.x-thresh.x) || 
      last_motion.y > (current_motion.y+thresh.y) || last_motion.y < (current_motion.y-thresh.y) || 
      last_motion.z > (current_motion.z+thresh.z) || last_motion.z < (current_motion.z-thresh.z)) {
        // FIXME - for debug 
        lcd.cls();
        lcd.locate(0,3);
        lcd.printf("x = %.2f y = %.2f z = %.2f\n", delta.x, delta.y, delta.z);  
        return true;  
        
    }
    else {
        return false;
    }
}

void store_alert(alert_type alert) {
    switch (alert) {
        case MOTION:
            alertState.pendMotion = true;
            break;
        case TEMP_LOW:
            alertState.pendTempLo = true;
            break;
        case TEMP_HI:
            alertState.pendTempHi = true;
            break;
    }
}

#define MS_IN_SEC 1000.0

int main() {  
    
    alertState.pendMotion = false;
    alertState.pendTempHi = false;
    alertState.pendTempLo = false;
    
    Motion myMotion;
    Temperature myTemp;
    double theTemp;
    double lastTimeMS, curTimeMS;
    double lastTempAlertSecs, lastMotionAlertSecs;
    double MotionAlertWaitSecs, TempAlertWaitSecs;
    
    // Don't send too many alerts too quickly
    // These are just debug settings.  A real system would
    // have much longer temperature settings
    
    MotionAlertWaitSecs = 5.0;  // Don't allow multiple alerts within 5.0 seconds
    TempAlertWaitSecs = 60.0;   // Wait at least a minute between temp alerts
    
    char host_cmd;
    msg_type msg;
    
    motion_vec current_motion;
    motion_vec last_motion;

    last_motion.x = MMA.x();
    last_motion.y = MMA.y();
    last_motion.z = MMA.z();    
    
    sysMonTime.start();
    lastTimeMS = sysMonTime.read_ms()/MS_IN_SEC;
    lastTempAlertSecs = sysMonTime.read();
    lastMotionAlertSecs = lastTempAlertSecs;
    
    // This method of setting the temperature is just for demo
    // purposes.  I use the current temp to initialize the ranges.
    
    theTemp = get_temp();
    myTemp.set_min(theTemp - 1.0);
    myTemp.set_max(theTemp + 1.0);
    
    state = monDISCONNECTED;
    
    while(1) {
        if (state == monDISCONNECTED) {
            if (check_connection()) {
                connectionLED = 1;
                state = monCONNECTED;
                if (alertState.pendMotion) {
                    alertState.pendMotion = false;
                    send_alert(MOTION);
                }
                else if (alertState.pendTempHi) {
                    alertState.pendTempHi = false;
                    send_alert(MOTION);
                }
                else if (alertState.pendTempLo) {
                    alertState.pendTempLo = false;
                    send_alert(MOTION);
                }
            }
            else {
                connectionLED = 0;
            }
        }
        // We are connected so listen for commands from
        // host.
        else {
            if (serial.available()) {
                host_cmd = rec_command();
                msg = parse_msg(host_cmd);
                host_command_resp(msg, myTemp, myMotion);
                // FIXME - debug
                lcd.cls();
                lcd.locate(0,3);
                lcd.printf("Received command %c\n", host_cmd); 
            }
        }
        
        // Detect if motion has occurred and handle it
        current_motion.x = MMA.x();
        current_motion.y = MMA.y();
        current_motion.z = MMA.z();
        if(detect_motion(current_motion, last_motion, myMotion)) { 
          // Only alert if last alert was outside window of alert time
          if (sysMonTime.read() > (lastMotionAlertSecs + MotionAlertWaitSecs)) {
            // moved
            motionLED = 1;
            // Adds the time of motion to the database of motion
            myMotion.add_sample(sysMonTime.read());
            // Send it over serial port
            if (state == monCONNECTED) {
                send_alert(MOTION);
                // clear LED since host is connected
                motionLED = 0;
            }
            else {
                store_alert(MOTION);
            }
            lastMotionAlertSecs = sysMonTime.read();
          }
        }
                
        // Now check temperature and generate an alert 
        theTemp = get_temp();
        if (theTemp > myTemp.get_max()) {
          if (sysMonTime.read() > (lastTempAlertSecs + TempAlertWaitSecs)) {
            tempHiLED = 1;
            if (state == monCONNECTED) {
                send_alert(TEMP_HI);
                // clear if connected
                tempHiLED = 0;
            }
            else {
                store_alert(TEMP_HI);
            }
            lastTempAlertSecs = sysMonTime.read();
          }
        }
        else if (theTemp < myTemp.get_min()) {
          if (sysMonTime.read() > (lastTempAlertSecs + TempAlertWaitSecs)) {
            tempLoLED = 1;
            if (state == monCONNECTED) {
                send_alert(TEMP_LOW);
                // clear if connected
                tempLoLED = 0;
            }
            else {
                store_alert(TEMP_LOW);
            }
            lastTempAlertSecs = sysMonTime.read();
          }
        }   
        
        // See if it is time to store the temperature samples
        if (sysMonTime.read_ms()/MS_IN_SEC > (lastTimeMS + myTemp.get_period())) {
            lcd.printf("time to send temperature\n");
            lastTimeMS = sysMonTime.read_ms()/MS_IN_SEC;
            myTemp.add_sample(get_temp());
        }
         
        //lcd.cls();
        //lcd.locate(0,3);
        //lcd.printf("temp = %.2f\n", theTemp);
        
        last_motion.x = current_motion.x;
        last_motion.y = current_motion.y;
        last_motion.z = current_motion.z;
        wait(0.3);
    }

}