Project 1 Self-powered Health & Security Monitoring System USB device
Dependencies: C12832_lcd LM75B MMA7660 USBDevice mbed
Diff: main.cpp
- Revision:
- 0:88dc49222b35
- Child:
- 1:930838234048
diff -r 000000000000 -r 88dc49222b35 main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Fri Mar 28 01:21:17 2014 +0000 @@ -0,0 +1,874 @@ +// Project: Self-powered USB Health and Security Monitoring Device (HSMD) + +/* 241: Added temp alarm + 251: Added motion alarm, sensitivity level + Validated alarm status handling + 252: Added lock, passcode control, mode (T-Testing; O-Operational) + 261: Added non-blocking serial entry + +TO-DO: + + implement USB connection detection + try record sound + try gps + add menu to LCD + +*/ + +#include "mbed.h" +#include "C12832_lcd.h" +#include "LM75B.h" +#include "MMA7660.h" +#include "USBKeyboard.h" + +// Configure device as USBKeyboard +USBKeyboard dev; + +#define UP 0x1 +#define DOWN 0x2 +#define LEFT 0x4 +#define RIGHT 0x8 +#define ON true +#define OFF false + +// System configuration parameters +#define YEAR 2014 +#define MONTH 3 +#define DATE 26 +#define HOUR 17 +#define MIN 35 +#define DEF_LOWER_TEMP 72 // Lower bound of monitoring temperature +#define DEF_UPPER_TEMP 89 // Upper bound of monitoring temperature +#define LOW_SEN 0.7 // Low sensitivity +#define MID_SEN 0.5 // Medium sensitivity +#define HIGH_SEN 0.3 // High sensitivity +#define BUZZ_POWER 0.5 // Buzz power level +#define BUZZ_SPERIOD 0.2 // Security alarm buzz period +#define BUZZ_TPERIOD 1 // Temperature alarm buzz period + +// System I/O +C12832_LCD lcd; +PwmOut alarm(p21); +BusIn joy(p15,p12,p13,p16); +InterruptIn IRQJoyUp(p15); +InterruptIn IRQJoyDown(p12); +InterruptIn IRQJoyLeft(p13); +InterruptIn IRQJoyRight(p16); +//DigitalIn fire(p14); +InterruptIn IRQFire(p14); + +Serial pc(USBTX, USBRX); // tx, rx +LM75B Ctmp(p28,p27); +AnalogIn pot1(p19); +AnalogIn pot2(p20); +MMA7660 MMA(p28, p27); +DigitalOut connectionLed(LED1); +DigitalOut lockLed(LED2); +//PwmOut Xaxis_p(LED2); +//BusOut leds(LED3,LED4); +//DigitalOut ledTAlarm(LED3); +//DigitalOut ledSAlarm(LED4); +PwmOut ledSAlarm(LED4); +PwmOut ledTAlarm(LED3); + +// Gobal parameters +float setUpperTemp; // Upper bound of temperature monitoring range +float setLowerTemp; // Lower bound of temperature monitoring range +bool sAlarmOn; // State of alarm +int statusAlarm; // Status indicating whether health or/and security alarm is triggered +bool sHealthFeatureActive; // State indicating temperature monitoring is activated +bool sSecurityFeatureActive; // State indicating motion monitoring is activated +bool sLockActive; // State indicating lock is active +char sState; // security setting state +char gState; // Global state +int buzzPattern; +float buzzPeriod; +Ticker timer1; +Ticker timer3; +Ticker timer4; +Timer timer2; +Ticker ticAlarm; +bool first; +int count; +bool activated; // for debounce fire +time_t yet; +time_t now; +int alarmType; // 0 - Health; 1 - Security +char senLevel; // Sensitivity level of motion alarm +int mode; // Operation mode: + // 0 = Test mode (for testing features) + // 1 = Lock mode (lock and unlock device) +int passcode; // 4-digit passcode for lock and unlock +bool sPCOK; // state indicating a valid passcode is existing + +bool updateCurTempDisplay; +bool updateJoyDisplay; +bool tempOverride; +float lowerTempBase; // For simulated lower bound temperature +float upperTempBase; // For simulated upper bound temperature +float temp; + +bool entryReady; // For tracking if user input is comlete +unsigned char entryState; // State tracking input entry +char inBuf[128]; // Input buffer +char pos; // Gobal buffer index + + +float timeElapsed; +int tol; // Tolerance for hysteresis effect +time_t seconds; + +float potBase1; +float potBase2; + +#ifdef C +#define deg 'C' +#else +#define deg 'F' +#endif + +typedef struct { + bool active; + float factor; + unsigned char sym[3]; +} SENTYPE; + +const SENTYPE senParm[4] = { + { false, LOW_SEN, " " }, + { true, LOW_SEN, "S1" }, // Low sensitivity + { true, MID_SEN, "S2" }, // Mid sensitivity + { true, HIGH_SEN, "S3" }, // High sensitivity +}; + +const char modeSym[2] = { 'T', 'O' }; + +/* +enum FUNCTION_KEY { + KEY_SCROLL_LOCK = 141, // Scroll lock + KEY_CAPS_LOCK, // caps lock + KEY_NUM_LOCK, // num lock +}; +*/ + +// Function prototype +void ISRFirePressed(); +void ISRJoyUp(); +void ISRJoyDown(); +void ISRJoyLeft(); +void ISRJoyRight(); +void debounce(); +void buzzOn(int pattern, float period); +void buzzOff(); +void buzzTest(); +void peepEntry(); +void calibratePot(); +bool EnterTemp(); +bool SetPasscode(); +bool UnlockPasscode(); +void USBConnCheck(); +void SetTime(int year, int month, int date, int hour, int min, int sec); +void TempMonitor(); +void ReadTemp(); +void MotionMonitor(); +void DisplayLCD(); +void AlarmCheck(); +void FSM(void); + + +// ISR for fire button +void ISRFirePressed() +{ + now = time(NULL); + if (!activated && now > yet) { + + tempOverride = !tempOverride; + //EnterTemp(); + if (tempOverride) + gState = 3; + yet = now + 1; + activated = true; + } + +} + + +/* + now = time(NULL); + if (!activated && now > yet) { + sAlarmOn = !sAlarmOn; + yet = now + 1; + activated = true; + //first = true; + count++; + //printf("sAlarmOn: %d\n\r", sAlarmOn); + } +*/ + + +// ISR for joystick up direction +void ISRJoyUp() +{ + now = time(NULL); + if (!activated && now > yet) { + //if (mode == 1 && sPCOK == false) + // EnterPasscode(); + senLevel = (senLevel + 1) % 4; + sSecurityFeatureActive = senParm[senLevel].active; + updateJoyDisplay = true; + yet = now + 1; + activated = true; + } +} + +// ISR for joystick down direction +void ISRJoyDown() +{ + now = time(NULL); + if (!activated && now > yet) { + mode = (mode + 1) % 2; + updateJoyDisplay = true; + yet = now + 1; + activated = true; + } +} + +// ISR for joystick left direction +void ISRJoyLeft() +{ + now = time(NULL); + if (!activated && now > yet) { + sHealthFeatureActive = !sHealthFeatureActive; + updateJoyDisplay = true; + yet = now + 1; + activated = true; + } +} + +// ISR for joystick right direction +void ISRJoyRight() +{ + now = time(NULL); + if (!activated && now > yet) { + if (mode == 1) + { + if (!sLockActive) + gState = 1; + else + gState = 2; + } + yet = now + 1; + activated = true; + } +} + +// Debouncer function +void debounce() +{ + if (activated) + activated = false; +} + +// Turn on buzz in different patterns +void buzzOn(int pattern, float period) +{ + switch (pattern) { + case 0: // Temperature + alarm = BUZZ_POWER; + wait(0.2); + alarm = 0; + wait(period); + /* + for(float p=0; p<1.0; p += 0.1) { + alarm = p; + wait(period); + } + */ + break; + case 1: // Security + alarm = BUZZ_POWER; + wait(0.2); + alarm = 0; + wait(period); + break; + + } + /* + led = led + 0.01; + wait(0.2); + if(led == 1.0) { + led = 0; + } + */ + +} + +// Turn on led in different patterns +void ledOn(int type, float period) +{ + switch (type) { + case 0: + ledTAlarm = 1; + wait(0.1); + ledTAlarm = 0; + wait(0.05); + break; + case 1: + for(int p=0; p<10; p += 1) { + ledSAlarm = 1; + wait(0.02); + ledSAlarm = 0; + wait(0.02); + } + /* + ledSAlarm = 1; + wait(0.1); + ledSAlarm = 0; + wait(0.02); + */ + break; + + } + /* + for(float p=0; p<1.0; p += 0.1) { + leds = statusAlarm; + wait(period); + } + */ + + /* + led = led + 0.01; + wait(0.2); + if(led == 1.0) { + led = 0; + } + */ + +} + +// Turn off alarm +void buzzOff() +{ + alarm = 0; +} + +void buzzTest() +{ + sAlarmOn = OFF; + + timer1.attach(&debounce, 1); + //IRQFire.rise(&ISRFirePressed); + //IRQFire.fall(&ISRFireRelease); + //IRQJoyUp.rise(&ISRJoyUp); + //IRQJoyDown.rise(&ISRJoyDown); + + alarm.period(0.020); // servo requires a 20ms period + + printf("Test starts...\n\r"); + + while (1) + { + if (sAlarmOn) { + buzzOn(buzzPattern, buzzPeriod); + printf("%s: pattern: %d period: %.1f count: %d\n\r", sAlarmOn? "ON": "OFF", buzzPattern, buzzPeriod, count); + } else { + buzzOff(); + buzzPattern = (buzzPattern + 1) % 2; + count = 0; + } + wait(0.02); + } +} + + +// Set date and time +// Input: Year, month, date, hour, minute, second +void SetTime(int year, int month, int date, int hour, int min, int sec) +{ + struct tm Clock; + Clock.tm_year = year - 1900; + Clock.tm_mon = month - 1; + Clock.tm_mday = date; + Clock.tm_hour = hour; + Clock.tm_min = min; + Clock.tm_sec = sec; + time_t epoch = mktime(&Clock); + if (epoch == (time_t) -1) { + error("Error: Invalid clock setting! Please try again.\n"); + } + set_time(epoch); +} + +// Calibrate analog pot to allow tuning each pot for controlling upper and lower bound control temperature +void calibratePot() +{ + potBase1 = pot1.read(); + potBase2 = pot2.read(); + //tempBase = temp; + lowerTempBase = setLowerTemp; + upperTempBase = setUpperTemp; + + + updateJoyDisplay = true; + + wait(0.5); + +} + +// Non-blockingly innput a simulated temperature +// Input: None +bool EnterTemp() +{ + int i; + bool done = false; + + switch (entryState) + { + case 0: + break; + case 1: + pc.printf("\n\rEnter a simulated temperature: "); + entryReady = false; + entryState = 2; + break; + case 2: + peepEntry(); + if (!entryReady) + break; + else + entryState = 3; + case 3: + sscanf(inBuf, "%d", &i); + if (i < 0 || i >= 100) { + printf("\n\rEnter a temperature between 0F and 100F: "); + entryReady = false; + entryState = 2; + break; + } else { + temp = i; + printf("Current temperature is now %dF.\n\r", i); + updateCurTempDisplay = true; + entryState = 1; + done = true; + calibratePot(); + break; + } + + + } + return done; + +} + +// Peep if serial data is received and read if so +void peepEntry() +{ + int i; + char c; + i = pc.readable(); + + if (i > 0) { + //pc.printf("%d: ", i); + while (i > 0) { + c = pc.getc(); + + if (c == '\r') { + pc.printf("\n\r"); + inBuf[pos] = '\0'; + //pc.printf("Return: %s\n\r", inBuf); + pos = 0; + entryReady = true; + + } else { + //pc.printf("%c\n\r", c); + pc.putc(c); + inBuf[pos] = c; + pos++; + } + i--; + } + + } +} + +// Non-blockingly set a passcode +// Input: None +bool SetPasscode() +{ + int i; + bool done = false; + + switch (entryState) + { + case 0: + break; + case 1: + if (statusAlarm & 0x80000000) + { + if (!sPCOK) + entryState = 2; + else + entryState = 5; + } + else + { + pc.printf("No USB connection detected. Check USB device being connected.\n\r"); + } + break; + + case 2: + pc.printf("\n\rEnter a 4-digit passcode: "); + entryReady = false; + entryState = 3; + break; + case 3: + peepEntry(); + if (!entryReady) + break; + else + entryState = 4; + case 4: + sscanf(inBuf, "%d", &i); + if (i < 0000 || i > 9999) { + pc.printf("\n\rEnter a passcode between 0000 and 9999: "); + entryReady = false; + entryState = 3; + break; + } else { + passcode = i; + pc.printf("\n\rPasscode is set (%d).\n\r", passcode); + sPCOK = true; + entryState = 5; + } + case 5: + sLockActive = true; + lockLed = 1; + updateJoyDisplay = true; + pc.printf("USB is now locked. Enter passcode to unlock.\n\r"); + entryState = 1; + done = true; + break; + } + return done; +} + +// Non-blockingly enter data to unlock passcode +bool UnlockPasscode() +{ + int i = 0; + bool done = false; + + switch (entryState) + { + case 0: + break; + case 1: + pc.printf("\n\rTo unlock, enter a 4-digit passcode: "); + entryReady = false; + entryState = 2; + break; + case 2: + peepEntry(); + if (!entryReady) + break; + else + entryState = 3; + case 3: + sscanf(inBuf, "%d", &i); + if (i < 0000 || i > 9999) { + pc.printf("\n\rEnter a passcode between 0000 and 9999: "); + entryReady = false; + entryState = 3; + } else { + if (passcode == i) { + pc.printf("\n\r====> Unlock successful. :-) \n\r"); + sLockActive = false; + statusAlarm &= 0xFFFFFFFD; + lockLed = 0; + updateJoyDisplay = true; + } else { + pc.printf("\n\r====> Incorrect passcode!\n\r"); + } + done = true; + entryState = 1; + + } + break; + + } + return done; +} + +// Check if USB is connected +// To read lock status: bit0=NUM_LOCK bit1=CAP_LOCK bit2=SCROLL_LOCK +void USBConnCheck() +{ + char status = 0; + char result; + + //if (!(statusAlarm & 0x80000000)) + //{ + // dev.keyCode(KEY_NUM_LOCK); + + if (dev.keyCode(KEY_CAPS_LOCK)) + printf("\rSend KEY_CAPS_LOCK OK\n\r"); + + status = dev.lockStatus(); + //printf("1: lockStatus = 0x%x statusAlarm = 0x%x\n\r", status, statusAlarm); + if (!(statusAlarm & 0x80000000) && (status & 0x2)) + { + statusAlarm |= 0x80000000; + result = true; + } + else if ((statusAlarm & 0x80000000) && !(status & 0x2)) + { + statusAlarm &= 0x7FFFFFFF; + result = false; + } + //printf("2: lockStatus = 0x%x statusAlarm = 0x%x\n\r", status, statusAlarm); + //return result; + +} + +// Turn on and off the alarm comparing the current temperature with and the set temperature +// Input: None +void TempMonitor() +{ + // Record current state of relay switch + int tempAlarm = statusAlarm & 0x1; + if (((temp < (setLowerTemp - tol)) || (temp > (setUpperTemp + tol))) && sHealthFeatureActive) + { + statusAlarm |= 0x1; + alarmType = 0; + } + else if (((temp >= setLowerTemp) && (temp <= setUpperTemp)) || !sHealthFeatureActive) + { + statusAlarm &= 0xFFFFFFFE; + } + // When alarm is turned on or off + if (tempAlarm != (statusAlarm & 0x1)) + { + seconds = time(NULL); + char buffer[32]; + strftime(buffer, 32, "%T", localtime(&seconds)); + + if (statusAlarm & 0x1) + { + if (timer2.read()) + { + timer2.stop(); + pc.printf("Temperature Alarm off for %.2f sec.\n\r", timer2.read()); + } + timer2.reset(); + pc.printf("Temperature Alarm on.... %s\n\r", buffer); + timer2.start(); + } + else + { + timer2.stop(); + timeElapsed = timer2.read(); + pc.printf("Temperature Alarm off... %s (Duration: %.2f sec)\n\r", buffer, timeElapsed); + timer2.reset(); + timer2.start(); + } + updateJoyDisplay = true; + } +} + + + +// Read temperature sensor +// Input: None +void ReadTemp() +{ + //temp = Ctmp.read(); + temp = Ctmp.read()*1.8+32; + updateCurTempDisplay = true; +} + +// Monitor accelerometer to detect motion and turn on and off the alarm after comparing the motion data with +// preconfigurated motion factor. +void MotionMonitor() +{ + //Xaxis_p = MMA.x() || -MMA.x(); + + float xpos, ypos, zpos; + float senNum = senParm[senLevel].factor; + xpos = MMA.x(); + ypos = MMA.y(); + zpos = MMA.z(); + if ((xpos > senNum || xpos < -(senNum) || ypos > senNum || ypos < -(senNum)) && sSecurityFeatureActive) + { + statusAlarm |= 0x2; + pc.printf("Security Alarm ON 0x%x(senNum: %f Xpos: %6.3f Ypos: %6.3f Zpos: %6.3f)\n\r", statusAlarm, senNum, xpos, ypos, zpos); + //updateJoyDisplay = true; + } + else + { + if ((statusAlarm & 0x2) && (mode == 0 || !sLockActive)) + { + statusAlarm &= 0xFFFFFFFD; + pc.printf("Security Alarm OFF 0x%x(Xpos: %6.3f Ypos: %6.3f Zpos: %6.3f)\n\r", statusAlarm, xpos, ypos, zpos); + } + //else + // pc.printf("Security Alarm %s (Xpos: %6.3f Ypos: %6.3f Zpos: %6.3f)\n\r", (statusAlarm & 0x2)? "sON": "sOFF", xpos, ypos, zpos); + //updateJoyDisplay = true; + } +} + +// Display date, time, heater state, relay state, current and set temperature at LCD +// Input: None +void DisplayLCD() +{ + seconds = time(NULL); + + char buffer[32]; + strftime(buffer, 32, "%F %T", localtime(&seconds)); + + lcd.locate(0,3); + lcd.printf("%s\n",buffer); + if (updateCurTempDisplay || updateJoyDisplay) + { + lcd.printf("Now: %.1f%c L:%3.0f%c U: %3.1f%c\n", temp, deg, setLowerTemp, deg, setUpperTemp, deg); + updateCurTempDisplay = false; + } + + + if (updateJoyDisplay) + { + lcd.printf("Mode: %c %1s%2s Status: %s%s\n", modeSym[mode], sHealthFeatureActive? "H": " ", senParm[senLevel].sym, sLockActive? "L":" ", sAlarmOn? "A": " "); + updateJoyDisplay = false; + } + +} + +// Check if alarm is to be triggered by either temp or security events +// Do buzz for temperature and security alarm events accordingly +void AlarmCheck() +{ + bool prevState = sAlarmOn; + if (statusAlarm & 0x1 || statusAlarm & 0x2) + sAlarmOn = ON; + else + sAlarmOn = OFF; + + if (statusAlarm & 0x80000000) + connectionLed = 1; + else + connectionLed = 0; + + if (prevState != sAlarmOn) + updateJoyDisplay = true; + + //leds = statusAlarm; + if ((statusAlarm & 0x2) && (statusAlarm & 0x1)) + { + buzzOn(1, BUZZ_SPERIOD); + ledOn(1, BUZZ_SPERIOD); + ledOn(0, BUZZ_TPERIOD); + } + // Security alarm + else if (statusAlarm & 0x2) + { + buzzOn(1, BUZZ_SPERIOD); + ledOn(1, BUZZ_SPERIOD); + } + // Temperature alarm + else if (statusAlarm & 0x1) + { + buzzOn(0, BUZZ_TPERIOD); + ledOn(0, BUZZ_TPERIOD); + } +} + + +// Initialize settings +void Init(void) +{ + SetTime(YEAR, MONTH, DATE, HOUR, MIN, 0); + + IRQFire.rise(&ISRFirePressed); + IRQJoyUp.rise(&ISRJoyUp); + IRQJoyDown.rise(&ISRJoyDown); + IRQJoyLeft.rise(&ISRJoyLeft); + IRQJoyRight.rise(&ISRJoyRight); + timer1.attach(&DisplayLCD, 1); + timer3.attach(&debounce, 1); + //timer4.attach(&USBConnCheck, 2); + timer4.attach(&AlarmCheck, 1); + //timer2.attach(&ReadTemp, 5); + sHealthFeatureActive = OFF; + sSecurityFeatureActive = OFF; + sAlarmOn = OFF; + statusAlarm = 0; + sState = 0; + setLowerTemp = DEF_LOWER_TEMP; + setUpperTemp = DEF_UPPER_TEMP; + tempOverride = false; + senLevel = 0; + buzzPattern = 0; + buzzPeriod = 0.2; + mode = 0; + timeElapsed = 0; + entryState = 1; + lcd.cls(); + lcd.locate(0,3); + updateJoyDisplay = true; + + calibratePot(); + pc.printf("\n\rHealth & Security Monitoring starts...\n\r"); + +} + +// Main loop in executing major temperature, motion monitoring tasks and alarm check task +void FSM(void) +{ + while(1) + { + //USBConnCheck(); + + // Override temperature read for testing. Use pot to control temperature + if (!tempOverride) + ReadTemp(); + + setLowerTemp = lowerTempBase + (pot1.read()-potBase1) * 12; + setUpperTemp = upperTempBase + (pot2.read()-potBase2) * 12; + updateCurTempDisplay = true; + + switch (gState) + { + case 0: + break; + case 1: + if (SetPasscode()) + gState = 0; + break; + case 2: + if (UnlockPasscode()) + gState = 0; + break; + case 3: + if (EnterTemp()) + gState = 0; + break; + } + + MotionMonitor(); + TempMonitor(); + //AlarmCheck(); + + /* Live check + lockLed = 1; + wait (0.1); + lockLed = 0; + wait(0.1); + */ + } + +} + +int main() +{ + //buzzTest(); + Init(); + FSM(); +}