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
Diff: main.cpp
- Revision:
- 0:977f7cf68014
- Child:
- 2:f6a1f96dc3cd
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Sun Sep 01 23:35:50 2013 +0000 @@ -0,0 +1,259 @@ +// +// 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); + } + +}