Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: DHT DS_1337 SDFileSystem USBDevice mbed
Revision 0:2df78a4443cd, committed 2016-04-10
- Comitter:
- Joseph Radford
- Date:
- Sun Apr 10 15:47:33 2016 +1000
- Commit message:
- Initial commit
Changed in this revision
diff -r 000000000000 -r 2df78a4443cd DHT.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DHT.lib Sun Apr 10 15:47:33 2016 +1000 @@ -0,0 +1,1 @@ +http://developer.mbed.org/users/Wimpie/code/DHT/#9b5b3200688f
diff -r 000000000000 -r 2df78a4443cd DS_1337.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DS_1337.lib Sun Apr 10 15:47:33 2016 +1000 @@ -0,0 +1,1 @@ +http://mbed.org/users/loovee/code/DS_1337/#f4f9b627adf9
diff -r 000000000000 -r 2df78a4443cd Handlers/AbstractHandler.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Handlers/AbstractHandler.h Sun Apr 10 15:47:33 2016 +1000
@@ -0,0 +1,34 @@
+#ifndef __ABSTRACT_HANDLER_H__
+#define __ABSTRACT_HANDLER_H__
+
+#include "../timers.h"
+
+/*!
+ * \brief The AbstractHandler class is inherited by all handlers. It forms the basis of any handler, by having
+ * a simple \a run function, called in main.cpp, and a \a setRequest function which is used to set a request
+ * specific to the reimplemented class.
+ */
+class AbstractHandler
+{
+public:
+ AbstractHandler(MyTimers *_timer) : m_timer(_timer) {}
+ ~AbstractHandler() {}
+
+ /*!
+ * \brief run is inherited by each Handler class. It is called from the main while loop in main.cpp.
+ * It runs through the state machine, specific to each Handler class.
+ */
+ virtual void run() = 0; // run the handler
+
+ /*!
+ * \brief setRequest sets a request that the handler will complete when it is able to
+ * \param request unique to the reimplemented class (an enum) that will be completed in the state machine
+ * \param message an optional array of information relevant to the \a request
+ */
+ virtual void setRequest(int request, void *data = 0) = 0;
+
+protected:
+ MyTimers *m_timer; ///< Handler classes use timers to pause in the state machine, and continue after delay has finished
+};
+
+#endif // __ABSTRACT_HANDLER_H__
diff -r 000000000000 -r 2df78a4443cd Handlers/GprsHandler.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Handlers/GprsHandler.cpp Sun Apr 10 15:47:33 2016 +1000
@@ -0,0 +1,260 @@
+#ifdef ENABLE_GPRS_TESTING
+#include "GprsHandler.h"
+#include "mbed.h"
+#include "config.h"
+#include "UsbComms.h"
+#include "circbuff.h"
+#define TX_GSM P1_27
+#define RX_GSM P1_26
+
+// declare led3 to display GPRS handler state
+extern DigitalOut myled3;
+
+/*
+ * PINPWR to low on Q10 drives 3V3 to Q7, which drives Q5 to ground, which powers VBAT_900, with
+ * either VCC_BUCK or VCC_BAT
+ */
+#define PINPWR P1_2
+#define PINONOFF P1_7
+
+#define REQ_SEND_SMS 0b00000001
+
+#define USB_BUFF_SIZE 256
+
+#define SIM900_SERIAL_TIMEOUT 10000
+
+GprsHandler::GprsHandler(MyTimers * _timer, UsbComms *_usb) : AbstractHandler(_timer)
+{
+ m_serial = new Serial(TX_GSM, RX_GSM); // create object for UART comms
+ mode = gprs_Start; // initialise state machine
+
+ m_sim900_pwr = new DigitalOut(PINPWR); // create pin out for
+ m_sim900_on = new DigitalOut(PINONOFF);
+ m_reqReg = 0;
+
+ m_usb = _usb;
+ m_rxBuff = new CircBuff(USB_BUFF_SIZE);
+
+ m_atReq = atreq_Test;
+}
+
+GprsHandler::~GprsHandler()
+{
+ // TODO Auto-generated destructor stub
+ delete m_serial;
+ delete m_rxBuff;
+ delete m_sim900_pwr;
+ delete m_sim900_on;
+}
+
+void GprsHandler::run()
+{
+ switch(mode)
+ {
+ case gprs_Start:
+
+ mode = gprs_PowerOff;
+ break;
+
+
+ // POWER HANDLERS
+
+ case gprs_PowerOff:
+ m_sim900_pwr->write(1); // turn power supply off
+ m_sim900_on->write(1);
+ m_timer->SetTimer(MyTimers::tmr_GprsPower, 500); // wait to settle
+ mode = gprs_PowerOffWait;
+ break;
+
+ case gprs_PowerOffWait:
+ if (!m_timer->GetTimer(MyTimers::tmr_GprsPower))
+ {
+ mode = gprs_PowerSupplyOn; // timer has elapsed
+ }
+ break;
+
+ case gprs_PowerSupplyOn:
+ m_sim900_pwr->write(0); // turn power supply on
+ m_sim900_on->write(0); // from the ref: "drive the PWRKEY to a low level for 1 second then release."
+
+
+ m_timer->SetTimer(MyTimers::tmr_GprsPower, 1000); // wait for one second
+ mode = gprs_PowerSupplyOnWait; // go to wait state
+ break;
+
+ case gprs_PowerSupplyOnWait:
+ if (!m_timer->GetTimer(MyTimers::tmr_GprsPower))
+ {
+ mode = gprs_PowerSwitchOn; // timer has elapsed
+ }
+ break;
+
+ case gprs_PowerSwitchOn:
+ m_sim900_on->write(1); // release power key
+ m_timer->SetTimer(MyTimers::tmr_GprsPower, 500); // wait to settle
+ mode = gprs_PowerSwitchOnWait;
+ break;
+
+ case gprs_PowerSwitchOnWait:
+ if (!m_timer->GetTimer(MyTimers::tmr_GprsPower))
+ {
+ mode = gprs_CheckATReqs; // timer has elapsed
+ }
+ break;
+
+
+ // REQUEST HANDLERS
+
+ case gprs_CheckATReqs:
+ switch (m_atReq) {
+ case atreq_Test:
+ sprintf((char*)txBuf, "AT\r\n");
+ txBufLen = 4;
+ mode = gprs_PostTx;
+ break;
+
+ case atreq_CheckSMS:
+ sprintf((char*)txBuf, "AT+CMGL=\"ALL\"");
+ txBufLen = 13;
+ mode = gprs_PostTx;
+ break;
+
+ default:
+ m_atReq = atreq_Test;
+ }
+ break;
+
+
+ // TX/RX HANDLERS
+
+ case gprs_PostTx:
+ // use putc, other write functions in serial don't really seem to work
+ for (int i = 0; i < txBufLen; i++) {
+ m_serial->putc(txBuf[i]);
+ }
+
+ // make sure buffer is null terminated before printing to USB
+ txBuf[txBufLen+1] = 0;
+ m_usb->setRequest(UsbComms::usbreq_PrintToTerminalTimestamp, txBuf);
+
+ // clear the buffer
+ txBufLen = 0;
+
+ // set timeout
+ m_timer->SetTimer(MyTimers::tmr_GprsRxTx, SIM900_SERIAL_TIMEOUT);
+
+ // wait for a response
+ mode = gprs_WaitRx;
+ break;
+
+ case gprs_WaitRx:
+ if (m_timer->GetTimer(MyTimers::tmr_GprsRxTx))
+ {
+ // we have not timed out yet
+ // we need a generic rx handler here.
+ while (m_serial->readable())
+ {
+ char ch = m_serial->getc();
+
+ // save this to our rx circular buffer
+ m_rxBuff->putc(ch);
+
+ mode = gprs_CheckRx;
+ wait(0.1);
+ }
+ // we have not timed out, and have not got anything back yet
+ // keep waiting in this state
+ }
+ else {
+ m_usb->setRequest(UsbComms::usbreq_PrintToTerminalTimestamp, (char*)"SIM900 TIMEOUT!");
+ mode = gprs_RxTimeout;
+ }
+ break;
+
+ case gprs_CheckRx:
+ if (m_rxBuff->dataAvailable()) {
+
+ // read out
+ unsigned char s[50];
+ uint16_t len = m_rxBuff->read(s, 50);
+
+ // write to USB
+ m_usb->setRequest(UsbComms::usbreq_PrintToTerminalTimestamp, s);
+
+ // process the reply
+ switch(m_atReq) {
+ case atreq_Test:
+ // should have just gotten an ok back
+ bool bOk = false;
+ for (int i = 0; i < (len - 1); i++) {
+ if ((s[i] == 'O') && (s[i+1] == 'K')) {
+ bOk = true;
+ }
+ }
+
+ if (bOk) {
+ myled3 = 1;
+ // so we know that comms are definitely OK.
+ // now check to see what requests need to get fulfilled
+
+ if (m_reqReg&REQ_SEND_SMS) {
+ // we want to check what sms is
+ m_atReq = atreq_SendSMS;
+
+ m_reqReg &= ~REQ_SEND_SMS;
+ }
+ else {
+ // no requests, but see if there are any received SMSs
+ m_atReq = atreq_CheckSMS;
+ }
+ }
+ else {
+ // did not get the reply we were hoping for.
+ }
+ break;
+
+ default:
+ // todo: handle replies for checking/sending SMSs
+ m_atReq = atreq_Test;
+ break;
+ }
+ }
+ else {
+
+ }
+ m_timer->SetTimer(MyTimers::tmr_GprsRxTx, 2000);
+ // now that we're done here, go check what needs to get sent to the SIM900 next
+ mode = gprs_WaitUntilNextRequest;
+ break;
+
+ case gprs_WaitUntilNextRequest:
+ if (!m_timer->GetTimer(MyTimers::tmr_GprsRxTx)) {
+ mode = gprs_CheckATReqs;
+ }
+ break;
+ case gprs_RxTimeout:
+ case gprs_RxError:
+ default:
+ mode = gprs_Start;
+ break;
+
+
+ }
+}
+
+void GprsHandler::setRequest(int request, void *data)
+{
+ m_lastRequest = (request_t)request;
+ switch(request) {
+ case gprsreq_SmsSend:
+ GprsRequest *req = (GprsRequest*)data;
+
+ // make a copy
+ m_lastMessage = *req; // there are strings, do i have to copy these manually?
+
+ // set the request
+ m_reqReg |= REQ_SEND_SMS;
+ break;
+ }
+}
+#endif
diff -r 000000000000 -r 2df78a4443cd Handlers/GprsHandler.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Handlers/GprsHandler.h Sun Apr 10 15:47:33 2016 +1000
@@ -0,0 +1,112 @@
+#ifndef GPRSHANDLER_H_
+#define GPRSHANDLER_H_
+
+#include "config.h"
+#ifdef ENABLE_GPRS_TESTING
+/*
+ * This section of the program is currently under development. The rest of the functions
+ * can run wtihout this component by using the ENABLE_GPRS_TESTING flag.
+ */
+
+#include "USBDevice.h" // need to include this, so that USBSerial has correct typedefs!
+#include "USBSerial.h"
+#include "AbstractHandler.h"
+
+#define GPRS_BUF_LEN 20
+
+#define GPRS_MESSAGE_MAXLEN 160
+#define GPRS_RECIPIENTS_MAXLEN 20
+
+struct GprsRequest
+{
+ char message[GPRS_MESSAGE_MAXLEN];
+ char recipients[GPRS_RECIPIENTS_MAXLEN];
+};
+class UsbComms;
+class CircBuff;
+
+/*!
+ * \brief The GprsHandler class saves recipients and looks after incoming and outgoing messages
+ *
+ * Options: save recipients internally to this class.
+ * Or - request sends a struct that includes recipients list and message string
+ */
+class GprsHandler : public AbstractHandler
+{
+public:
+ GprsHandler(MyTimers * _timer, UsbComms *_usb);
+ virtual ~GprsHandler();
+
+ void run();
+
+ void setRequest(int request, void *data = 0);
+
+ enum request_t{
+ gprsreq_GprsNone, ///< No request (for tracking what the last request was, this is initial value for that)
+ gprsreq_SmsSend, ///< got a string to send to recipient(s)
+ gprsreq_SetRecipients ///< got a string holding the number(s) we want to send
+ };
+
+private:
+ enum mode_t{
+ gprs_Start, ///< Set up the state machine and the hardware
+
+ // Restart sequence
+ gprs_PowerOff, ///< Ensure module is powered down first, so we know it is in its initial state
+ gprs_PowerOffWait, ///< Give module time to power down
+ gprs_PowerSupplyOn, ///< Once module has fully powered down, power back up to begin using it
+ gprs_PowerSupplyOnWait, ///< Give time to power on properly
+ gprs_PowerSwitchOn,
+ gprs_PowerSwitchOnWait,
+
+ gprs_CheckATReqs, ///< Check was AT request is next
+
+ // read AT+CMGR=?
+ // write AT+CMGS=?
+ gprs_PostTx, ///< Send the current buffer to SIM900 and setup timeouts
+ gprs_WaitRx, ///< Wait for a response over serial
+ gprs_CheckRx, ///< Check the response. Go back into state machine depending on response
+
+ gprs_WaitUntilNextRequest,
+
+ gprs_RxTimeout, ///< no response
+ gprs_RxError ///< wrong response
+
+
+ };
+ mode_t mode; ///< the current state in the state machine
+ mode_t returnMode; ///< the state to go back to when the expected reply returns from the SIM900
+
+ ///
+ /// \brief The at_req enum stores what AT command should be sent/was just sent to the SIM900
+ ///
+ enum at_req {
+ atreq_Test, ///< Ping the SIM900
+ atreq_CheckSMS, ///< Check if an SMS is available
+ atreq_SendSMS ///< Send an SMS, according to m_lastRequest
+ };
+ at_req m_atReq;
+
+ request_t m_lastRequest;
+ GprsRequest m_lastMessage;
+
+ Serial * m_serial; //!< Serial port for comms with SIM900
+
+ DigitalOut * m_sim900_pwr; //!< pin used to enable the SIM900 power switch
+ DigitalOut * m_sim900_on; //!< pin used to drive the power key
+
+ uint8_t m_reqReg; ///< request register
+
+ unsigned char txBuf[GPRS_BUF_LEN];
+ uint16_t txBufLen;
+ unsigned char rxBuf[GPRS_BUF_LEN];
+
+ UsbComms *m_usb;
+ CircBuff *m_rxBuff;
+
+};
+
+#endif
+
+#endif /* GPRSHANDLER_H_ */
+
diff -r 000000000000 -r 2df78a4443cd Handlers/GroveDht22.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Handlers/GroveDht22.cpp Sun Apr 10 15:47:33 2016 +1000
@@ -0,0 +1,121 @@
+#include "GroveDht22.h"
+#include "measurementhandler.h"
+
+#define GROVE_NUM_RETRIES 10 // number of retries for reading sensor
+
+DigitalOut grovePwr(P1_3); // if anything else is interfaced to uart/adc/i2c connectors, this will have to change, as they share this enable line
+
+GroveDht22::GroveDht22(MeasurementHandler *_measure, MyTimers * _timer) : AbstractHandler(_timer), m_measure(_measure)
+{
+ // initialise class variables
+ mode = dht_StartTurnOff;
+ _lastCelcius = 0.0f;
+ _lastHumidity = 0.0f;
+ _lastDewpoint = 0.0f;
+ _lastError = ERROR_NONE;
+ _retries = 0;
+ _newInfo = 0;
+
+ m_sensor = new DHT(P1_14,SEN51035P); // Use the SEN51035P sensor
+}
+
+GroveDht22::~GroveDht22()
+{
+ delete m_sensor;
+}
+
+void GroveDht22::run()
+{
+ switch(mode)
+ {
+ case dht_StartTurnOff:
+ powerOn(false);
+ m_timer->SetTimer(MyTimers::tmr_GroveMeasure, 1000); // leave off for 1 second
+ mode = dht_StartTurnOffWait;
+ break;
+
+ case dht_StartTurnOffWait:
+ if (!m_timer->GetTimer(MyTimers::tmr_GroveMeasure)) // wait until timer has elapsed
+ mode = dht_StartTurnOn;
+ // else come back here
+ break;
+
+ case dht_StartTurnOn:
+ powerOn(true);
+ m_timer->SetTimer(MyTimers::tmr_GroveMeasure, 1000); // wait one second for sensor to settle
+ mode = dht_StartTurnOnWait;
+ break;
+
+ case dht_StartTurnOnWait:
+ if (!m_timer->GetTimer(MyTimers::tmr_GroveMeasure)) // wait until timer has elapsed
+ mode = dht_TakeMeasurement;
+ // else come back here
+ break;
+
+ case dht_TakeMeasurement:
+ _lastError = (eError)m_sensor->readData(); // take the measurement (todo: see if nonblocking is available)
+ if (_lastError == ERROR_NONE)
+ {
+ _retries = 0; // reset retries as measurement was successful
+ _lastCelcius = m_sensor->ReadTemperature(CELCIUS);
+ _lastHumidity = m_sensor->ReadHumidity();
+ _lastDewpoint = m_sensor->CalcdewPoint(_lastCelcius, _lastHumidity);
+ m_timer->SetTimer(MyTimers::tmr_GroveMeasure, 3000); // wait three seconds
+
+ // add the date time
+ time_t _time = time(NULL); // get the seconds since dawn of time
+ Dht22Result data = {_time, _lastCelcius, _lastHumidity, _lastDewpoint};
+ m_measure->setRequest(MeasurementHandler::measreq_DhtResult, (void*)&data);
+ mode = dht_WaitMeasurement;
+ }
+ else
+ {
+ _retries++; // there was an error. See if we have reached critical retries
+ if (_retries >= GROVE_NUM_RETRIES)
+ {
+ _retries = 0;
+ mode = dht_StartTurnOff; // restart the sensor
+ }
+ else
+ {
+ // haven't reach critical retries yet, so try again, after waiting
+ m_timer->SetTimer(MyTimers::tmr_GroveMeasure, 3000); // wait three seconds
+ mode = dht_WaitMeasurement;
+ }
+ int sendData = (int)_lastError; // just to make sure nothing funny happens with the enum
+ m_measure->setRequest(MeasurementHandler::measreq_DhtError, (int*)&sendData);
+ }
+ _newInfo = 1;
+ break;
+
+ case dht_WaitMeasurement:
+ if (!m_timer->GetTimer(MyTimers::tmr_GroveMeasure)) // if timer elapsed
+ mode = dht_TakeMeasurement;
+ // else come back here
+ break;
+
+ }
+}
+
+void GroveDht22::setRequest(int request, void *data)
+{
+ // no requests (yet)
+}
+
+// check if there is new information and reset the flag once the check occurs
+unsigned char GroveDht22::newInfo()
+{
+ unsigned char retval = _newInfo;
+ _newInfo = 0;
+ return retval;
+}
+
+// turn the enable pin for the peripheral plugins on the Arch GPRS v2
+// it is active low and acts on Q1
+void GroveDht22::powerOn(unsigned char ON)
+{
+ if (ON)
+ grovePwr = 0; // active low, will turn power on
+ else
+ grovePwr = 1; // will turn power off
+}
diff -r 000000000000 -r 2df78a4443cd Handlers/GroveDht22.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Handlers/GroveDht22.h Sun Apr 10 15:47:33 2016 +1000
@@ -0,0 +1,81 @@
+#ifndef __GROVE_DHT_22_H__
+#define __GROVE_DHT_22_H__
+
+#include "DHT.h"
+#include "mbed.h"
+#include "AbstractHandler.h"
+
+class MeasurementHandler;
+
+/*!
+ * \brief The Dht22Result struct is the information read from a Dht22 Grove sensor
+ */
+struct Dht22Result {
+ time_t resultTime; ///< timestamp of when the result was returned from the Dht22
+ float lastCelcius; ///< Temperature result (degC)
+ float lastHumidity; ///< Humidity result
+ float lastDewpoint; ///< Dewpoint result
+};
+
+/*!
+ * \brief The GroveDht22 class handles the interface to the DHT22 humidity and temperature sensor.
+ *
+ * The state machine checks for errors and retries and will power cycle the sensor if there are
+ * GROVE_NUM_RETRIES number of retries.
+
+ * The state machine also ensures that at least two seconds is left between readings.
+
+ * At any time the parent class can access the last good readings, or the last error.
+
+ * The newInfo flag exists so that the parent can decide to only notify (print to terminal or otherwise) when there
+ * is new information available. Calling the newInfo getter will clear the newInfo flag.
+ */
+class GroveDht22 : public AbstractHandler
+{
+public:
+ GroveDht22(MeasurementHandler *_measure, MyTimers * _timer);
+ ~GroveDht22();
+
+ void run();
+
+ void setRequest(int request, void *data = 0);
+
+ // getters
+ float lastCelcius() { return _lastCelcius; }
+ float lastHumidity() { return _lastHumidity; }
+ float lastDewPoint() { return _lastDewpoint; }
+ eError lastError() { return _lastError; }
+ unsigned char newInfo();
+
+private:
+ // state machine
+ typedef enum {
+ dht_StartTurnOff, ///< Begin by ensuring the sensor is switched off
+ dht_StartTurnOffWait, ///< Allow it to power down completely
+ dht_StartTurnOn, ///< Turn the sensor on
+ dht_StartTurnOnWait, ///< Allow sensor to settle after powering on
+ dht_TakeMeasurement, ///< Take a measurement, check if valid, update measurment vars, set newInfo
+ dht_WaitMeasurement ///< Wait for 2 seconds between measurements
+ } mode_t;
+
+ mode_t mode; ///< The current state in the state machine
+
+ float _lastCelcius; ///< Last temperature reading from the Dht22 sensor
+ float _lastHumidity; ///< Last humidity reading from the Dht22 sensor
+ float _lastDewpoint; ///< Last dewpoint calculation from last temp, humidity vales
+ unsigned char _newInfo; ///< This flag indicates there is new information (an error, or a measurement)
+ int _retries; ///< Number of bad readings from the Dht22 sensor
+ eError _lastError; ///< The last error, or lack thereof
+
+ /*!
+ * \brief powerOn powers the Dht22 on or off, by toggling the enable pin
+ * \param ON true to power on, false to power off
+ */
+ void powerOn(unsigned char ON);
+
+ MeasurementHandler *m_measure; ///< Reference to send measurement results and errors to for handling
+
+ DHT *m_sensor; ///< Interface to hardware DHT sensor
+};
+
+#endif // __GROVE_DHT_22_H__
diff -r 000000000000 -r 2df78a4443cd Handlers/SdHandler.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Handlers/SdHandler.cpp Sun Apr 10 15:47:33 2016 +1000
@@ -0,0 +1,224 @@
+#include "SdHandler.h"
+
+#include "GroveDht22.h" // for interpreting the result struct
+#include "circbuff.h"
+
+#define SD_BUFFER_LEN 256u // length of circular buffers
+
+// define pins for communicating with SD card
+#define PIN_MOSI P1_22
+#define PIN_MISO P1_21
+#define PIN_SCK P1_20
+#define PIN_CS P1_23
+
+#define DATA_FILE_NAME "/sd/data.csv"
+#define SYSLOG_FILE_NAME "/sd/log.txt"
+
+// declare led that will be used to express state of SD card
+extern DigitalOut myled2;
+
+SdHandler::SdHandler(MyTimers * _timer) : AbstractHandler(_timer)
+{
+ // init file system and files
+ m_sdfs = new SDFileSystem(PIN_MOSI, PIN_MISO, PIN_SCK, PIN_CS, "sd");
+ m_data = NULL;
+ m_syslog = NULL;
+
+ // initialise circular buffers
+ m_dataLogBuff = new CircBuff(SD_BUFFER_LEN);
+ m_sysLogBuff = new CircBuff(SD_BUFFER_LEN);
+
+ mode = sd_Start;
+ m_lastRequest = sdreq_SdNone;
+}
+
+SdHandler::~SdHandler()
+{
+ delete m_dataLogBuff;
+ delete m_sysLogBuff;
+}
+
+void SdHandler::run()
+{
+ uint16_t tempInt = 0, tempInt2 = 0;
+
+ unsigned char tempBuff[SD_BUFFER_LEN];
+
+ switch(mode)
+ {
+ case sd_Start: /* Set up the state machine */
+ // check if card is inserted??
+ //m_sdfs->unmount();
+ // close both files if necessary
+ if (m_data != NULL)
+ fclose(m_data);
+ if (m_syslog != NULL)
+ fclose(m_syslog);
+
+ m_data = NULL;
+ m_syslog = NULL;
+
+ //mkdir("/sd", 0777);
+ //m_sdfs->mount();
+ m_data = fopen(DATA_FILE_NAME, "a");
+ m_syslog = fopen(SYSLOG_FILE_NAME, "a");
+
+ if ((m_data != NULL) && (m_syslog != NULL))
+ {
+ // both opened successfully
+ fprintf(m_syslog, "Unit booted OK\n");
+ fclose(m_syslog);
+
+ // write the header in on startup
+ fprintf(m_data, "Timestamp, Temperature (degC), Humidity (pc), Dewpoint\n");
+ fclose(m_data);
+ mode = sd_CheckSysLogBuffer;
+ }
+ break;
+
+ case sd_CheckSysLogBuffer: /* See if any data should be written to the log file */
+ if (m_sysLogBuff->dataAvailable())
+ {
+ tempInt = m_sysLogBuff->read(tempBuff, SD_BUFFER_LEN);
+ tempInt2 = fprintf(m_syslog, (const char*)tempBuff);
+ if (tempInt == tempInt2)
+ {
+ // success
+ mode = sd_CheckDataLogBuffer;
+ }
+ else
+ {
+ // something went wrong
+ m_timer->SetTimer(MyTimers::tmr_SdWaitError, 2000);
+ mode = sd_WaitError;
+ }
+ }
+ else {
+ mode = sd_CheckDataLogBuffer;
+ }
+ break;
+
+ case sd_CheckDataLogBuffer: /* See if any data should be written to the data file */
+ if (m_dataLogBuff->dataAvailable())
+ {
+ m_data = fopen(DATA_FILE_NAME, "a");
+
+ if (m_data != NULL)
+ {
+ // opened successfully
+ tempInt = m_dataLogBuff->read(tempBuff, SD_BUFFER_LEN);
+ tempInt2 = fprintf(m_data, (const char*)tempBuff);
+ fclose(m_data);
+ if (tempInt == tempInt2)
+ {
+ // success
+ myled2 = 0;
+ mode = sd_CheckSysLogBuffer;
+ }
+ else
+ {
+ // something went wrong
+ m_timer->SetTimer(MyTimers::tmr_SdWaitError, 2000);
+ mode = sd_WaitError;
+ }
+ }
+ else
+ {
+ // something went wrong
+ m_timer->SetTimer(MyTimers::tmr_SdWaitError, 2000);
+ mode = sd_WaitError;
+ }
+ }
+ else {
+ mode = sd_CheckSysLogBuffer;
+ }
+ break;
+
+ case sd_WaitError: /* Many fails, much wow, wait for a while */
+ if (!m_timer->GetTimer(MyTimers::tmr_SdWaitError))
+ {
+ // timer has elapsed. go back to start.
+ mode = sd_Start;
+ }
+ break;
+ }
+}
+
+void SdHandler::setRequest(int request, void *data)
+{
+ request_t req = (request_t)request;
+ m_lastRequest = req;
+ switch(req) {
+ case sdreq_SdNone:
+
+ break;
+ case sdreq_LogData:
+
+ myled2 = 1;
+ // have received the data struct. cast it
+ Dht22Result *result = (Dht22Result*)data;
+
+ // write things to sd card buffer
+ char s[50]; // buffer
+ int temp; // length of buffer
+ csvStart(result->resultTime);
+ temp = sprintf(s, "%4.2f", result->lastCelcius);
+ csvData(s, temp);
+ temp = sprintf(s, "%4.2f", result->lastHumidity);
+ csvData(s, temp);
+ temp = sprintf(s, "%4.2f", result->lastDewpoint);
+ csvData(s, temp);
+ csvEnd();
+ break;
+ case sdreq_LogSystem:
+ char *str = (char*)data;
+ logEvent(str);
+ break;
+ }
+}
+
+void SdHandler::csvStart(time_t _time)
+{
+ unsigned char sTemp[17];
+
+
+ // extract time_t to time info struct
+
+ struct tm * timeinfo = localtime(&_time);
+
+ // print the formatted timestamp at the start of terminalBuffer, with comma
+ sprintf((char*)&sTemp[0], "%04d%02d%02d %02d%02d%02d,", (timeinfo->tm_year + 1900),
+ (timeinfo->tm_mon + 1),
+ timeinfo->tm_mday,
+ timeinfo->tm_hour,
+ timeinfo->tm_min,
+ timeinfo->tm_sec);
+
+ sTemp[16] = 0;
+
+ m_dataLogBuff->add(sTemp);
+}
+
+void SdHandler::csvData(const char * s, int len)
+{
+ unsigned char sTemp[50];
+ int idx = 0;
+ // add a column to the buffer
+ sprintf((char*)&sTemp[idx], s);
+ idx += len;
+ sTemp[idx++] = ',';
+ sTemp[idx] = 0;
+ m_dataLogBuff->add(sTemp);
+}
+
+void SdHandler::csvEnd()
+{
+ unsigned char sTemp[2];
+ sTemp[0] = '\n';
+ sTemp[1] = 0;
+ m_dataLogBuff->add(sTemp);
+}
+
+void SdHandler::logEvent(const char * s)
+{
+}
diff -r 000000000000 -r 2df78a4443cd Handlers/SdHandler.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Handlers/SdHandler.h Sun Apr 10 15:47:33 2016 +1000
@@ -0,0 +1,59 @@
+#ifndef __SD_HANDLER_H__
+#define __SD_HANDLER_H__
+
+#include "SDFileSystem.h"
+#include "AbstractHandler.h"
+
+class CircBuff;
+
+/*!
+ * \brief The SdHandler class writes messages to file and handles SD card status
+ *
+ * A data CSV file is written with timestamps and the result from the GroveDht22.
+ * A system log, not yet fully implemented, tracks system events for debugging purposes.
+ */
+class SdHandler : public AbstractHandler
+{
+public:
+ SdHandler(MyTimers * _timer);
+ ~SdHandler();
+
+ void run();
+
+ void setRequest(int request, void *data = 0);
+
+ bool sdOk();
+
+ enum request_t {
+ sdreq_SdNone, ///< to init
+ sdreq_LogData, ///< Send struct containing a result and timestamp. This turns it into a line in a csv file
+ sdreq_LogSystem ///< write raw string to system logging file (errors, events, etc)
+ };
+
+private:
+ SDFileSystem * m_sdfs;
+ FILE * m_data;
+ FILE * m_syslog;
+
+ enum mode_t{
+ sd_Start, ///< Set up the state machine
+ sd_CheckSysLogBuffer, ///< See if any data should be written to the log file
+ sd_CheckDataLogBuffer, ///< See if any data should be written to the data file
+
+ sd_WaitError ///< Error. wait for a while
+ };
+ mode_t mode;
+
+ request_t m_lastRequest;
+
+ // helpers
+ void csvStart(time_t time);
+ void csvData(const char * s, int len);
+ void csvEnd();
+ void logEvent(const char * s);
+
+ CircBuff *m_dataLogBuff; ///< Data waiting to be written to the data CSV file
+ CircBuff *m_sysLogBuff; ///< Data waiting to be written to the system log file (not yet implemented)
+};
+
+#endif // __SD_HANDLER_H__
diff -r 000000000000 -r 2df78a4443cd Handlers/UsbComms.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Handlers/UsbComms.cpp Sun Apr 10 15:47:33 2016 +1000
@@ -0,0 +1,125 @@
+#include "UsbComms.h"
+#include "mbed.h"
+
+#include "USBDevice.h"
+#include "USBSerial.h"
+
+#include "circbuff.h"
+
+#define USB_CIRC_BUFF 256
+
+extern DigitalOut myled1; // this led is used to notify state of USB comms
+
+UsbComms::UsbComms(MyTimers *_timer) : AbstractHandler(_timer)
+{
+ mode = usb_Start;
+
+ m_circBuff = new CircBuff(USB_CIRC_BUFF);
+
+ // Declare serial port for communication with PC over USB
+ _serial = new USBSerial;
+}
+
+UsbComms::~UsbComms()
+{
+ delete _serial;
+ delete m_circBuff;
+}
+
+void UsbComms::run()
+{
+ unsigned char temp;
+ switch(mode) {
+ case usb_Start:
+ mode = usb_CheckInput;
+ break;
+ case usb_CheckInput:
+ if (_serial->readable()) {
+ _serial->getc();
+ // todo: do something with it! this is where config events are started
+ // uncomment to print a message confirming input
+ // _serial->writeBlock((unsigned char*)"getc\r\n", 6);
+ //mode = usb_WaitForInput;
+ mode = usb_CheckOutput;
+ } else {
+ mode = usb_CheckOutput;
+ }
+ break;
+ case usb_CheckOutput:
+ if (m_circBuff->dataAvailable() && _serial->writeable()) {
+ // ensure only 64 bytes or less are written at a time
+ unsigned char s[TX_USB_MSG_MAX];
+ int len = m_circBuff->read(s, TX_USB_MSG_MAX);
+ _serial->writeBlock((unsigned char*)s, len);
+ myled1 = 1;
+
+ } else {
+ myled1 = 0;
+ }
+ mode = usb_CheckInput;
+ break;
+ }
+}
+
+void UsbComms::setRequest(int request, void *data)
+{
+ request_t req = (request_t)request;
+
+ switch (req) {
+ case usbreq_PrintToTerminal:
+ printToTerminal((char*)data);
+ break;
+ case usbreq_PrintToTerminalTimestamp:
+ printToTerminalEx((char*)data);
+ break;
+ }
+}
+
+void UsbComms::printToTerminal(char *s)
+{
+ // simply add this string to the circular buffer
+ m_circBuff->add((unsigned char*)s);
+}
+
+// print the message, but prepend it with a standard timestamp
+// YYYYMMDD HHMMSS:
+// 01234567890123456
+void UsbComms::printToTerminalEx(char *s)
+{
+ unsigned char tempBuff[TX_USB_BUFF_SIZE];
+ // this won't work! needs to be a circular buffer...
+ uint16_t sSize = 0, i = 0, j = 0;
+
+ // get the length of the passed array (it should be null terminated, but include max buffer size for caution)
+ for (sSize = 0; (sSize < TX_USB_BUFF_SIZE) && (s[sSize] != 0); sSize++);
+
+
+ time_t _time = time(NULL); // get the seconds since dawn of time
+
+ // extract time_t to time info struct
+ struct tm * timeinfo = localtime(&_time);
+
+ // print the formatted timestamp at the start of terminalBuffer
+ sprintf((char*)&tempBuff[0], "%04d%02d%02d %02d%02d%02d:", (timeinfo->tm_year + 1900),
+ (timeinfo->tm_mon + 1),
+ timeinfo->tm_mday,
+ timeinfo->tm_hour,
+ timeinfo->tm_min,
+ timeinfo->tm_sec);
+
+
+ // copy the string into the remainder of the terminal buffer
+ for (i = 16; i < (16 + sSize); i++) {
+ tempBuff[i] = s[j++];
+ }
+
+ // add a carriage return and new line to the output buffer
+ tempBuff[i++] = '\r';
+ tempBuff[i++] = '\n';
+ tempBuff[i++] = 0;
+
+ // add it to the circular buffer
+ m_circBuff->add(tempBuff);
+}
+
+
diff -r 000000000000 -r 2df78a4443cd Handlers/UsbComms.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Handlers/UsbComms.h Sun Apr 10 15:47:33 2016 +1000
@@ -0,0 +1,51 @@
+#ifndef __USB_COMMS_H__
+#define __USB_COMMS_H__
+#include "AbstractHandler.h"
+
+#define TX_USB_MSG_MAX 64u // only send 64 bytes at a time
+#define TX_USB_BUFF_SIZE 256u // the tx buffer can hold up to 256 bytes
+
+class USBSerial;
+class CircBuff;
+
+/*!
+ * \brief The UsbComms class handles input and output for the serial port connected to a PC
+ * The main run() function cycles through checking for input and copying to a buffer to be handled,
+ * and checking the output buffer to see if there is anything to be sent out.
+ *
+ * Data can be queued for output by copying it to the circular buffer
+ */
+class UsbComms : public AbstractHandler
+{
+public:
+ UsbComms(MyTimers *_timer);
+ ~UsbComms();
+
+ void run();
+
+ void setRequest(int request, void *data = 0);
+
+ enum request_t{
+ usbreq_PrintToTerminal, ///< Print to terminal normally
+ usbreq_PrintToTerminalTimestamp ///< Print to terminal, including the timestamp
+ };
+
+private:
+ USBSerial *_serial; ///< Interface to the serial port
+ CircBuff *m_circBuff; ///< Data waiting to be printed to the serial port
+
+ // state machine
+ enum mode_t{
+ usb_Start, ///< Set up the state machine
+ usb_CheckInput, ///< See if any data is waiting to be read in - currently does not process anything
+ usb_CheckOutput, ///< See if any data should be sent over serial
+ };
+ mode_t mode;
+
+ // helpers
+ void printToTerminal(char *s); // raw
+ void printToTerminalEx(char *s); // add timestamp
+};
+
+
+#endif
diff -r 000000000000 -r 2df78a4443cd Handlers/measurementhandler.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Handlers/measurementhandler.cpp Sun Apr 10 15:47:33 2016 +1000
@@ -0,0 +1,234 @@
+#include "measurementhandler.h"
+#include "mbed.h"
+#include "SdHandler.h"
+#include "UsbComms.h"
+
+// declare led4 so we can flash it to reflect state of this handler
+extern DigitalOut myled4;
+
+// flags for the request register
+#define REQ_RESULT 0b00000001
+#define REQ_ERROR 0b00000010
+#ifdef ENABLE_GPRS_TESTING
+#define REQ_SMS 0b00000100
+#endif
+
+#ifdef ENABLE_GPRS_TESTING
+MeasurementHandler::MeasurementHandler(SdHandler *_sd, UsbComms *_usb, GprsHandler *_gprs, MyTimers *_timer)
+ : AbstractHandler(_timer), m_sd(_sd), m_usb(_usb), m_gprs(_gprs)
+#else
+MeasurementHandler::MeasurementHandler(SdHandler *_sd, UsbComms *_usb, MyTimers *_timer)
+ : AbstractHandler(_timer), m_sd(_sd), m_usb(_usb)
+#endif
+{
+ m_lastError = ERROR_NONE;
+ mode = meas_Start;
+ m_lastRequest = measreq_MeasReqNone;
+ m_flashOn = false;
+ m_requestRegister = 0;
+
+#ifdef ENABLE_GPRS_TESTING
+ for (int i = 0; i < GPRS_RECIPIENTS_MAXLEN; i++) {
+ m_lastSender[i] = 0;
+ }
+#endif
+}
+
+void MeasurementHandler::run()
+{
+ switch(mode) {
+ case meas_Start:
+ // start here, and come back here if an error has been flushed out and waited
+ mode = meas_CheckRequest;
+ break;
+
+ case meas_CheckRequest:
+ if (m_requestRegister) {
+ // check what has been requested, starting from most highest priority
+
+#ifdef ENABLE_GPRS_TESTING
+ if (m_requestRegister&REQ_SMS) {
+ // an SMS has been requested
+ mode = meas_PostStateSMS;
+ }
+ else if (m_requestRegister&REQ_RESULT) {
+#else
+ if (m_requestRegister&REQ_RESULT) {
+#endif
+ // a result has been sent, we need to post it
+ mode = meas_PostResult;
+ }
+ else if (m_requestRegister&REQ_ERROR) {
+ // an error has been sent, we need to post it
+ mode = meas_PostError;
+ }
+ else {
+ // something went wrong, a flag was set that isn't defined
+ m_requestRegister = 0;
+ mode = meas_FlashTimer;
+ }
+ }
+ else {
+ // no requests, check if running led needs to be flashed
+ mode = meas_FlashTimer;
+ }
+ break;
+
+#ifdef ENABLE_GPRS_TESTING
+ case meas_PostStateSMS:
+ if (m_requestRegister&REQ_SMS) {
+ char s[64];
+ // usb print
+ sprintf(s, "Temperature is %4.2f degC\nHumidity is %4.2f pc\nDew point is %4.2f", m_lastResult.lastCelcius, m_lastResult.lastHumidity, m_lastResult.lastDewpoint);
+
+ GprsRequest req;
+ strcpy(req.message, s);
+ strcpy(req.recipients, m_lastSender);
+ m_gprs->setRequest(GprsHandler::gprsreq_SmsSend, &req);
+
+ // clear the request reqister's sms flag
+ m_requestRegister &= ~REQ_SMS;
+ }
+ mode = meas_CheckRequest;
+ break;
+#endif
+
+ case meas_PostResult:
+ if (m_requestRegister&REQ_RESULT) {
+ // we have a result, post it
+
+ // TODO: check when the last result came in. if it has not been very long (< 5s? < 1s?) avoid posting, so we don't hammer it
+
+ char s[50];
+ // usb print
+ sprintf(s, "Temperature is %4.2f degC", m_lastResult.lastCelcius);
+ m_usb->setRequest(UsbComms::usbreq_PrintToTerminalTimestamp, s);
+ sprintf(s, "Humidity is %4.2f pc", m_lastResult.lastHumidity);
+ m_usb->setRequest(UsbComms::usbreq_PrintToTerminalTimestamp, s);
+ sprintf(s, "Dew point is %4.2f ", m_lastResult.lastDewpoint);
+ m_usb->setRequest(UsbComms::usbreq_PrintToTerminalTimestamp, s);
+
+ // post to SD card
+ m_sd->setRequest(SdHandler::sdreq_LogData, &m_lastResult);
+
+ // clear the request
+ m_requestRegister &= ~REQ_RESULT;
+ }
+
+ // go back to check if there are more requests
+ mode = meas_CheckRequest;
+ break;
+
+
+ case meas_PostError:
+ if (m_requestRegister&REQ_ERROR) {
+ // there is an error, check the value of it and post the corresponding string to USB
+ // TODO: post to SD syslog
+ switch (m_lastError)
+ {
+ case BUS_BUSY:
+ m_usb->setRequest(UsbComms::usbreq_PrintToTerminalTimestamp, (char*)"BUSY!");
+ break;
+ case ERROR_NOT_PRESENT:
+ m_usb->setRequest(UsbComms::usbreq_PrintToTerminalTimestamp, (char*)"NOT PRESENT");
+ break;
+ case ERROR_ACK_TOO_LONG:
+ m_usb->setRequest(UsbComms::usbreq_PrintToTerminalTimestamp, (char*)"TOO LONG");
+ break;
+ case ERROR_SYNC_TIMEOUT:
+ m_usb->setRequest(UsbComms::usbreq_PrintToTerminalTimestamp, (char*)"SYNC TIMEOUTr\n");
+ break;
+ case ERROR_DATA_TIMEOUT:
+ m_usb->setRequest(UsbComms::usbreq_PrintToTerminalTimestamp, (char*)"DATA TIMEOUT");
+ break;
+ case ERROR_CHECKSUM:
+ m_usb->setRequest(UsbComms::usbreq_PrintToTerminalTimestamp, (char*)"CHECKSUM");
+ break;
+ case ERROR_NO_PATIENCE:
+ m_usb->setRequest(UsbComms::usbreq_PrintToTerminalTimestamp, (char*)"NO PATIENCE!");
+ break;
+ default:
+ m_usb->setRequest(UsbComms::usbreq_PrintToTerminalTimestamp, (char*)"UNKNOWN");
+ break;
+ }
+
+ // we have posted it, clear the flag
+ m_requestRegister &= ~REQ_ERROR;
+ }
+ // check if there are any more requests
+ mode = meas_CheckRequest;
+ break;
+
+ case meas_FlashTimer:
+ // flash timer to know that we are still alive.
+ if (!m_timer->GetTimer(MyTimers::tmr_MeasFlash)) { // wait until timer has elapsed
+ if (m_flashOn) {
+ // turn off
+ myled4 = 0;
+ m_timer->SetTimer(MyTimers::tmr_MeasFlash, 2000); // stay off for 2 seconds
+ m_flashOn = false;
+ }
+ else {
+ // turn on
+ myled4 = 1;
+ m_timer->SetTimer(MyTimers::tmr_MeasFlash, 1000); // stay on for 1 second
+ m_flashOn = true;
+ }
+
+ }
+ mode = meas_CheckRequest;
+ break;
+
+ case meas_WaitError:
+ // TODO: timer
+ mode = meas_Start;
+ break;
+ }
+}
+
+void MeasurementHandler::setRequest(int request, void *data)
+{
+ m_lastRequest = (request_t)request;
+ switch(request) {
+ case measreq_DhtResult:
+ // this should contain time as well
+ Dht22Result *result = (Dht22Result*)data;
+
+ // copy the structure into our own structure
+ m_lastResult = *result;
+
+ // set the request
+ m_requestRegister |= REQ_RESULT;
+
+ break;
+
+ case measreq_DhtError:
+ int *iResult = (int*)data;
+ m_lastError = *iResult;
+ m_requestRegister |= REQ_ERROR;
+
+ break;
+
+#ifdef ENABLE_GPRS_TESTING
+ case measreq_Status:
+ // need to send SMS of last result
+ // the sender's number is the sent data
+ char *sender = (char*)data;
+
+ int i = 0;
+ // copy the sender's number
+ for (i = 0; (i < GPRS_RECIPIENTS_MAXLEN) && (sender[i] != 0); i++) {
+ m_lastSender[i] = sender[i];
+ }
+
+ // set the rest of the destination array to null
+ for (i; i < GPRS_RECIPIENTS_MAXLEN; i++) {
+ m_lastSender[i] = 0;
+ }
+
+ // set the request
+ m_requestRegister |= REQ_SMS;
+ break;
+#endif
+ }
+}
diff -r 000000000000 -r 2df78a4443cd Handlers/measurementhandler.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Handlers/measurementhandler.h Sun Apr 10 15:47:33 2016 +1000
@@ -0,0 +1,94 @@
+#ifndef MEASUREMENTHANDLER_H
+#define MEASUREMENTHANDLER_H
+
+#include "AbstractHandler.h"
+#include "GroveDht22.h"
+#include "config.h"
+#ifdef ENABLE_GPRS_TESTING
+#include "GprsHandler.h"
+#endif
+
+class SdHandler;
+class UsbComms;
+
+
+/*!
+ * \brief The MeasurementHandler class forms the link between data generation and data output, and stores settings.
+ *
+ * Receives requests from \a GroveDht22 when a new measurement has been taken or error has occurred. This handler then
+ * sends that information on to \a UsbComms for printing that information to terminal and \a SdHandler for printing
+ * that information to the CSV data file.
+ *
+ * This handler also determines if the necessary conditions have been met to send an SMS. This is based on last measurement,
+ * the set alert threshold, and time since last alert was sent. An SMS is sent using \a GprsHandler.
+ *
+ * Other requests from inputs asking for current measurement states (such as the latest measurement) may come from \a UsbComms
+ * or \a GprsHandler. The string inspection and matching is handled here, and responses sent to the data outputs.
+ *
+ *
+ * Flashes LED4 constantly to inform that normal operation is occurring.
+ */
+class MeasurementHandler : public AbstractHandler
+{
+public:
+#ifdef ENABLE_GPRS_TESTING
+ MeasurementHandler(SdHandler *_sd, UsbComms *_usb, GprsHandler *_gprs, MyTimers *_timer);
+#else
+ MeasurementHandler(SdHandler *_sd, UsbComms *_usb, MyTimers *_timer);
+#endif
+
+ void run();
+
+ void setRequest(int request, void *data = 0);
+
+ Dht22Result lastResult() const { return m_lastResult; }
+
+ enum request_t{
+ measreq_MeasReqNone, ///< No request (for tracking what the last request was, this is initial value for that)
+ measreq_DhtResult, ///< Dht22 returned with a result
+ measreq_DhtError, ///< Dht22 returned with an error
+#ifdef ENABLE_GPRS_TESTING
+ measreq_Status, ///< We got an SMS asking for the status (time, last error, last result)
+#endif
+ };
+
+private:
+ SdHandler *m_sd; ///< Reference to write to SD card
+ UsbComms *m_usb; ///< Reference to write to USB serial port
+
+#ifdef ENABLE_GPRS_TESTING
+ GprsHandler *m_gprs; ///< Reference to write to GPRS (SMS)
+#endif
+
+ Dht22Result m_lastResult; ///< Copy of the last result that came from Dht22
+ int m_lastError; ///< Copy of the last error that came from Dht22
+
+#ifdef ENABLE_GPRS_TESTING
+ char m_lastSender[GPRS_RECIPIENTS_MAXLEN]; ///< The last sender of an SMS
+#endif
+
+ bool m_flashOn; ///< LED is currently on when true
+
+ enum mode_t{
+ meas_Start, ///< Set up the state machine
+ meas_CheckRequest, ///< Check request register
+
+#ifdef ENABLE_GPRS_TESTING
+ meas_PostStateSMS, ///< Send an SMS of the last result and state
+#endif
+ meas_PostResult, ///< Write the last Grove result to SD and USB
+ meas_PostError, ///< Write the last Grove error to USB (and in future, SD syslog)
+
+ meas_FlashTimer, ///< Flash an LED on and off so user knows device is still running
+
+ meas_WaitError ///< Lots of fails, wait for a while
+ };
+ mode_t mode;
+
+ request_t m_lastRequest; ///< tracks if result or error was the last request
+
+ uint8_t m_requestRegister; ///< contains the current pending requests as bitwise flags
+
+};
+
+#endif // MEASUREMENTHANDLER_H
diff -r 000000000000 -r 2df78a4443cd SDFileSystem.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SDFileSystem.lib Sun Apr 10 15:47:33 2016 +1000 @@ -0,0 +1,1 @@ +http://developer.mbed.org/teams/mbed/code/SDFileSystem/#7b35d1709458
diff -r 000000000000 -r 2df78a4443cd USBDevice.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBDevice.lib Sun Apr 10 15:47:33 2016 +1000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/USBDevice/#d17693b10ae6
diff -r 000000000000 -r 2df78a4443cd circbuff.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/circbuff.cpp Sun Apr 10 15:47:33 2016 +1000
@@ -0,0 +1,106 @@
+#include "circbuff.h"
+
+CircBuff::CircBuff(uint16_t buffSize)
+{
+ // set up the buffer with parsed size
+ m_buffSize = buffSize;
+ m_buf = new unsigned char [m_buffSize];
+ for (int i = 0; i < m_buffSize; i++) {
+ m_buf[i] = 0;
+ }
+
+ // init indexes
+ m_start = 0;
+ m_end = 0;
+}
+
+CircBuff::~CircBuff()
+{
+ delete m_buf;
+}
+
+void CircBuff::putc(unsigned char c)
+{
+ // get the remaining space left in the buffer by checking end and start idx
+ uint16_t remSize = remainingSize();
+
+ // check we have enough room for the new array passed in
+ if (remSize == 0) {
+ return;
+ }
+
+ // else copy the byte in
+ m_buf[m_end++] = c;
+ if (m_end == m_buffSize) {
+ m_end = 0; // wrap around
+ }
+
+}
+
+void CircBuff::add(unsigned char *s)
+{
+ // check if can write? How to check if we have connected.
+ uint16_t sSize = 0, i = 0, j = 0;
+
+ // get the length of the passed array (it should be null terminated, but include max buffer size for caution)
+ for (sSize = 0; (sSize < m_buffSize) && (s[sSize] != 0); sSize++);
+
+ // get the remaining space left in the buffer by checking end and start idx
+ uint16_t remSize = remainingSize();
+
+ // check we have enough room for the new array passed in
+ if (sSize > remSize) {
+ return;
+ }
+
+ // copy the array in
+ for (i = 0; i < sSize; i++) {
+ m_buf[m_end++] = s[i];
+ if (m_end == m_buffSize) {
+ m_end = 0; // wrap around
+ }
+ }
+}
+
+uint16_t CircBuff::remainingSize()
+{
+ // get the remaining space left in the buffer by checking end and start idx
+ uint16_t retval = 0;
+ if (m_start == m_end) {
+ retval = m_buffSize;
+ }
+ else if (m_start < m_end) {
+ // the distance between the start and end point
+ // subtract that from the total length of the buffer
+ retval = m_buffSize - (m_end - m_start);
+ }
+ else {
+ // the amount of space left is whatever is between the end point and the start point
+ retval = m_start - m_end;
+ }
+ return retval;
+}
+
+uint16_t CircBuff::read(unsigned char *s, uint16_t len)
+{
+ if (m_start == m_end) {
+ return 0; // there is nothing stored in the circular buffer
+ }
+
+ // start copying the desired amount over
+ for (int i = 0; i < len; i++) {
+ s[i] = m_buf[m_start++];
+
+ if (m_start == m_buffSize) {
+ m_start = 0; // wrap start pointer
+ }
+
+ if (m_start == m_end) {
+ s[++i] = 0;
+ return (i); // we have reached the end of the buffer
+ }
+ }
+ return len;
+}
+
+
diff -r 000000000000 -r 2df78a4443cd circbuff.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/circbuff.h Sun Apr 10 15:47:33 2016 +1000
@@ -0,0 +1,46 @@
+#ifndef __CIRC_BUFF_H__
+#define __CIRC_BUFF_H__
+
+#include "mbed.h"
+
+/*!
+ * \brief The CircBuff class writes in and reads out byte arrays into a circular buffer
+ */
+class CircBuff {
+public:
+ CircBuff(uint16_t buffSize = 256);
+ ~CircBuff();
+
+ /*!
+ * \brief putc adds a single byte, \a c, into the array
+ * \param c is the byte copied into the circular buffer.
+ */
+ void putc(unsigned char c);
+
+ /*!
+ * \brief add adds \a s into the buffer, up until the NULL byte
+ * \param s is the byte array copied into the buffer
+ */
+ void add(unsigned char *s);
+
+ /*!
+ * \brief read puts the current data from the buffer into \a s
+ * \param s is the reference buffer to copy current data into. Caller's responsibility to make it the correct size
+ * \param len is the number of bytes to copy into \a s
+ * \return the number of bytes copied into \a s. Will be less than \a len if there was less data in the buffer.
+ */
+ uint16_t read(unsigned char *s, uint16_t len);
+ bool dataAvailable() { return (m_start != m_end); }
+
+
+private:
+ uint16_t m_start; ///< The start index of the circular buffer, where the current data starts
+ uint16_t m_end; ///< The end index, where the current data goes to
+ unsigned char *m_buf; ///< the byte array
+ uint16_t m_buffSize; ///< size of \a m_buf
+
+ // helper
+ uint16_t remainingSize();
+};
+
+#endif // __CIRC_BUFF_H__
diff -r 000000000000 -r 2df78a4443cd config.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/config.h Sun Apr 10 15:47:33 2016 +1000 @@ -0,0 +1,11 @@ +#ifndef CONFIG_H_ +#define CONFIG_H_ + +/* + * This file contains global definitions to configure the program + */ + +// uncomment this to continue development and testing with GPRS +// #define ENABLE_GPRS_TESTING + +#endif /* CONFIG_H_ */
diff -r 000000000000 -r 2df78a4443cd main.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp Sun Apr 10 15:47:33 2016 +1000
@@ -0,0 +1,205 @@
+/*!
+ * Project: Humidity SMS Alert
+ * Author: Joseph Radford
+ * Date start: January 2016
+ * Date mod:
+ * Target: Arch GPRS V2
+ * Peripherals: SD Card
+ * SIM Card
+ * Grove Humidity and Temperature Sensor Pro (DHT22 on a breakout board)
+ *
+ *
+ * Takes intermittent readings from the humidity temperature sensor. These are written to a timestamped CSV file
+ * on the SD card and printed over serial if there is a connection to a terminal window (Screen on Linux, Putty on Windows, etc)
+ *
+ * When conditions have been met, an SMS alert is sent notifying the recipient of the last sensor readings.
+ *
+ * States can be requested, and configurations changed, by sending requests over USB serial or SMS.
+ *
+ * Inputs:
+ * \a GroveDht22
+ *
+ * Outputs:
+ * \a SdHandler
+ *
+ *
+ * Inputs and outputs:
+ * \a GprsHandler
+ * \a UsbComms
+ *
+ * Linker:
+ * \a MeasurementHandler
+ *
+ * 10/04/2016 v0.0.1 - Writes timestamped humidity data to an SD card
+ *
+ * Issues:
+ * Stops communicating over USB after ~10 mins.
+ * Will not work if USB not present.
+ * Will not work if SD card is not present
+ * GPRS yet to be implemented
+ * RTC is set to 01/01/2000 00:00:00 at startup. No way of setting it yet.
+ */
+
+#include "config.h"
+
+#include "mbed.h"
+#include "math.h"
+
+// Clocks and timers
+#include "DS1337.h"
+#include "rtc.h"
+#include "timers.h"
+
+// Handlers
+#include "Handlers/GroveDht22.h"
+#include "Handlers/UsbComms.h"
+#include "Handlers/SdHandler.h"
+#include "Handlers/measurementhandler.h"
+
+#ifdef ENABLE_GPRS_TESTING
+#include "Handlers/GprsHandler.h"
+#endif
+
+/* Declare hardware classes */
+
+DigitalOut myled1(LED2); ///< startup, and USB handler when writing occurring (right most)
+DigitalOut myled2(LED3); ///< SD handler - on when buffer pending, off when written. If error, will be on as buffer won't clear
+DigitalOut myled3(LED4); ///< GPRS handler information
+DigitalOut myled4(LED1); ///< measurement handler flashes, periodically to inform running (left most)
+
+//DigitalOut myenable(P0_6);
+
+DS1337 * RTC_DS1337; ///< RTC interface class
+
+I2C i2c(P0_5, P0_4); ///< I2C comms - this is required by the RTC - do NOT change the name of the instance
+
+
+/* Declare helpers */
+MyTimers *mytimer; ///< declare timers class - required for other classes to use timers (do not change name)
+
+
+/* Declare handlers */
+GroveDht22 *grove; ///< grove humidity sensor handler class
+UsbComms *usbcomms; ///< reading and writing to usb
+SdHandler *sdhandler; ///< Writing data to a file on SD
+MeasurementHandler *measure; ///< Handle measurements, and route data to the user and user to configuration
+
+#ifdef ENABLE_GPRS_TESTING
+GprsHandler * gprs; ///< Reading and writing to the SIM900
+#endif
+
+#ifdef ENABLE_GPRS_TESTING
+#define NUM_HANDLERS 5
+#else
+#define NUM_HANDLERS 4
+#endif
+
+#define PROGRAM_TITLE "Arch GPRS V2 Alert and Request"
+#define PROGRAM_INFO "v0.0.1, released 09/04/2016"
+
+/*!
+ * \brief main pulses LED1, creates all classes, pulses LED1, then runs through all handlers forever
+ * \return
+ */
+int main()
+{
+ /* start up sequence, so we know we reached main */
+ myled1 = 1;
+ wait(0.2);
+ myled1 = 0;
+ wait(0.2);
+ myled1 = 1;
+ wait(0.2);
+ myled1 = 0;
+ wait(1);
+ myled1 = 1;
+ wait(0.2);
+ myled1 = 0;
+ wait(0.2);
+ myled1 = 1;
+ wait(0.2);
+ myled1 = 0;
+ wait(1);
+
+ /* Declare all classes */
+
+ // create MyTimers object, which can be used for waiting in handlers
+ mytimer = new MyTimers();
+
+ // RTC interface class
+ RTC_DS1337 = new DS1337();
+ attach_rtc(&my_rtc_read, &my_rtc_write, &my_rtc_init, &my_rtc_enabled);
+
+ // set the time to the start of the year 2000, by default
+ // this will be removed when time can be set, so that time is not reset each time the program starts.
+ tm timeinfo;
+ timeinfo.tm_hour = 0; timeinfo.tm_min = 0; timeinfo.tm_sec = 0;
+ timeinfo.tm_year = (2001 - 1900); timeinfo.tm_mon = 0; timeinfo.tm_mday = 1;
+ set_time(mktime(&timeinfo));
+
+ // declare usbcomms
+ usbcomms = new UsbComms(mytimer);
+
+ // declare sd handler
+ sdhandler = new SdHandler(mytimer);
+
+#ifdef ENABLE_GPRS_TESTING
+ gprs = new GprsHandler(mytimer, usbcomms);
+ measure = new MeasurementHandler(sdhandler, usbcomms, gprs, mytimer);
+#else
+ measure = new MeasurementHandler(sdhandler, usbcomms, mytimer);
+#endif
+
+ // declare grove
+ grove = new GroveDht22(measure, mytimer);
+
+ // put the handlers in an array for easy reference
+#ifdef ENABLE_GPRS_TESTING
+ AbstractHandler* handlers[] = {grove, usbcomms, sdhandler, measure, gprs};
+#else
+ AbstractHandler* handlers[] = {grove, usbcomms, measure, sdhandler};
+#endif
+
+ // send startup message to terminal
+ usbcomms->setRequest(UsbComms::usbreq_PrintToTerminalTimestamp, (char*)PROGRAM_TITLE);
+ usbcomms->setRequest(UsbComms::usbreq_PrintToTerminalTimestamp, (char*)PROGRAM_INFO);
+ usbcomms->setRequest(UsbComms::usbreq_PrintToTerminalTimestamp, (char*)"\r\n******************\r\n");
+
+ // flush output
+ fflush(stdout);
+
+
+ /* Pulse LED1 again to signify start up was successful */
+ myled1 = 1;
+ wait(0.2);
+ myled1 = 0;
+ wait(0.2);
+ myled1 = 1;
+ wait(0.2);
+ myled1 = 0;
+ wait(1);
+ myled1 = 1;
+ wait(0.2);
+ myled1 = 0;
+ wait(0.2);
+ myled1 = 1;
+ wait(0.2);
+ myled1 = 0;
+ wait(1);
+
+
+ while(1)
+ {
+ // perform run functions for all handlers, one after the other
+ for (int i = 0; i < NUM_HANDLERS; i++) {
+ handlers[i]->run();
+ }
+ } // while
+
+ for (int i = 0; i < NUM_HANDLERS; i++) {
+ delete handlers[i];
+ }
+} // main
+
+
+
diff -r 000000000000 -r 2df78a4443cd mbed.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Sun Apr 10 15:47:33 2016 +1000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/4f6c30876dfa \ No newline at end of file
diff -r 000000000000 -r 2df78a4443cd readme.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/readme.md Sun Apr 10 15:47:33 2016 +1000 @@ -0,0 +1,59 @@ +This project is written for the Arch GPRS V2. + +It aims to provide a convenient method of alerting a user of humidity. However, the grove DHT22 +sensor could easily be replaced with another Grove sensor with small changes to the code. + +Directories: + * DHT + - for accessing the grove + * DS_1337 + - interface to the real time clock (which is a separate chip, i.e. not part of the micro) + * mbed + - all mbed libraries + * SDFileSystem + - for accessing the SD card. You need to be careful to import the right one (link to my blog) + * USBDevice + - interface to serial comms over USB (talk to it from a PC) + * Handlers + - this is where almost all of my code lives + +Handlers +The handlers have the same structure (although they do not inherit from a common base class, but they should). They have a run function, which is a state machine called from the main while loop in main.cpp. This will run continuous routines such as polling and checking if a request has been raised. + +A request might be raised through a common request interface that passes an enum. However this might have to be more specific. Either way, the request is then handled in the state machine. + +GroveDht22 + * Takes a measurement from the DHT22 hardware at a set interval + * On success, sends to measurement handler + +SdHandler + * Initialises and polls the SD card, checks for errors, etc + * Receives requests for writing a system message to the log, or writing a measurement to CSV + +UsbComms + * Checks to see if there is a connection to a PC + * Receives requests to send messages to PC + * Diverts incoming messages from PC to appropriate handlers + +MeasurementHandler + * GroveDht22 sends a measurement to this and it decides what to do with it + * Stores values for schedules, thresholds, last measurements + * Decides if a new measurement should be sent over SMS, SD + * Receives a request for last measurement, state, etc, from either UsbComms or SmsHandler + +GprsHandler (WIP) + * Checks to see if there are any incoming messages, directs them appropriately + * Gets requests from other handlers to send an SMS + + + + +To do: + * Complete basic GprsHandler + * Set a threshold for humidity (hardcoded to start with) and send messages at this threshold + * Avoid sending more than x messages per y time (so don't get bombarded with messages) + * Send messages to a list of numbers, not just one + * Send messages on a schedule, e.g. send current humidity and temp once a day, so user knows it's OK + * Make the above three points configurable over USB (threshold, time off, list of numbers, schedule) + * Respond to certain messages, over SMS, to configure and make status known. + * Make a base class for handlers to inherit from, so that interface stays consistent
diff -r 000000000000 -r 2df78a4443cd rtc.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rtc.cpp Sun Apr 10 15:47:33 2016 +1000
@@ -0,0 +1,60 @@
+#include "rtc.h"
+#include "DS1337.h"
+
+// declare reference to interface to the hardware real time clock
+extern DS1337* RTC_DS1337;
+
+// RTC enabled flag
+static int _rtcEnabled;
+
+time_t my_rtc_read()
+{
+ time_t retval = 0; // time since start of epoch
+ tm _time_tm;
+
+ RTC_DS1337->readTime();
+
+ // extract values from RTC to tm struct
+ _time_tm.tm_year = ((int)RTC_DS1337->getYears()) - 1900; // struct tm stores (year - 1900)
+ _time_tm.tm_mon = (int)RTC_DS1337->getMonths() - 1; // struct tm stores months 0 - 11, DS1337 stores 1-12
+ _time_tm.tm_mday = (int)RTC_DS1337->getDays();
+ _time_tm.tm_hour = (int)RTC_DS1337->getHours();
+ _time_tm.tm_min = (int)RTC_DS1337->getMinutes();
+ _time_tm.tm_sec = (int)RTC_DS1337->getSeconds();
+
+ // convert to time_t
+ retval = mktime(&_time_tm);
+ if (retval == (time_t) -1)
+ return (time_t)1; // error
+ else
+ return retval;
+}
+
+
+//https://developer.mbed.org/teams/Seeed/code/Seeed_Arch_GPRS_V2_RTC_HelloWorld/file/6db7dfbab0f1/main.cpp
+void my_rtc_write(time_t _time)
+{
+ // extract time_t to time info struct
+ tm * timeinfo = localtime(&_time);
+
+ RTC_DS1337->setSeconds (timeinfo->tm_sec);
+ RTC_DS1337->setMinutes (timeinfo->tm_min);
+ RTC_DS1337->setHours (timeinfo->tm_hour);
+ RTC_DS1337->setDays (timeinfo->tm_mday); // day of month
+ RTC_DS1337->setDayOfWeek (timeinfo->tm_wday);
+ RTC_DS1337->setMonths (timeinfo->tm_mon + 1); // struct tm stores months 0 - 11, DS1337 stores 1-12
+ RTC_DS1337->setYears (timeinfo->tm_year + 1900); // struct tm subtracts 1900 from year
+
+ RTC_DS1337->setTime();
+}
+
+void my_rtc_init()
+{
+ RTC_DS1337->start();
+ _rtcEnabled = 1;
+}
+
+int my_rtc_enabled()
+{
+ return _rtcEnabled;
+}
diff -r 000000000000 -r 2df78a4443cd rtc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rtc.h Sun Apr 10 15:47:33 2016 +1000 @@ -0,0 +1,50 @@ +#ifndef __RTC_H__ +#define __RTC_H__ + +#include "mbed.h" + +//! The functions needed to configure time in the micro, used in \sa attach_rtc, using the on board DS_1337 +/*! + As there is no on-chip RTC, connecting the time functionality to the DS_1337 enables more convenient use of time + + The function which is called to configure is as such: + void attach_rtc(time_t (*read_rtc)(void), void (*write_rtc)(time_t), void (*init_rtc)(void), int (*isenabled_rtc)(void)) + + read_rtc is assigned \sa my_rtc_read + + write_rtc is assigned \sa my_rtc_write + + init_rtc is assigned \sa my_rtc_init + + isenabled_rtc is assigned \sa my_rtc_enabled + */ + + +/*! + * \brief my_rtc_read Interfaces to the on board RTC DS1337 and converts read values to time_t + * \return the value read from the on board RTC converted to system struct time_t + */ +time_t my_rtc_read(); + + +/*! + * \brief my_rtc_write Interfaces to the on board RTC DS1337 and converts and writes the time given as time_t + * \param _time is the time in system time_t format which will be written to DS1337 + */ +void my_rtc_write(time_t _time); + + +/*! + * \brief my_rtc_init Initialises the RTC DS1337 + */ +void my_rtc_init(); + + +/*! + * \brief my_rtc_enabled Checks if RTC DS1337 is enabled + * \return 1 if enabled, 0 if not enabled (i.e. \sa my_rtc_init never called) + */ +int my_rtc_enabled(); + + +#endif // __RTC_H__
diff -r 000000000000 -r 2df78a4443cd timers.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/timers.cpp Sun Apr 10 15:47:33 2016 +1000
@@ -0,0 +1,74 @@
+#include "timers.h"
+
+MyTimers::MyTimers()
+{
+ // initialise timers
+ groveMeasureTimer = 0;
+ gprsPowerTimer = 0;
+ gprsRxTxTimer = 0;
+ sdWaitErrorTimer = 0;
+ measFlashTimer = 0;
+
+ m_tick = new Ticker();
+ // configure the ticker object to run every 1ms, and to call \sa run when it does so.
+ m_tick->attach(this, &MyTimers::run, 0.001);
+}
+
+MyTimers::~MyTimers()
+{
+ delete m_tick;
+}
+
+void MyTimers::run()
+{
+ // decrement each timer in the class
+ if (groveMeasureTimer) groveMeasureTimer--;
+ if (gprsPowerTimer ) gprsPowerTimer--;
+ if (gprsRxTxTimer ) gprsRxTxTimer--;
+ if (sdWaitErrorTimer ) sdWaitErrorTimer--;
+ if (measFlashTimer ) measFlashTimer--;
+}
+
+
+void MyTimers::SetTimer(eTimerType timertype, unsigned long time_ms)
+{
+ // see which timer we have to set, and set it
+ switch(timertype)
+ {
+ case tmr_GroveMeasure:
+ groveMeasureTimer = time_ms;
+ break;
+ case tmr_GprsPower:
+ gprsPowerTimer = time_ms;
+ break;
+ case tmr_GprsRxTx:
+ gprsRxTxTimer = time_ms;
+ break;
+ case tmr_SdWaitError:
+ sdWaitErrorTimer = time_ms;
+ break;
+ case tmr_MeasFlash:
+ measFlashTimer = time_ms;
+ break;
+ }
+}
+
+unsigned long MyTimers::GetTimer(eTimerType timertype)
+{
+ // see which timer we have to get, and return it.
+ switch(timertype)
+ {
+ case tmr_GroveMeasure:
+ return groveMeasureTimer;
+ case tmr_GprsPower:
+ return gprsPowerTimer;
+ case tmr_GprsRxTx:
+ return gprsRxTxTimer;
+ case tmr_SdWaitError:
+ return sdWaitErrorTimer;
+ case tmr_MeasFlash:
+ return measFlashTimer;
+ }
+ return 0;
+}
+
diff -r 000000000000 -r 2df78a4443cd timers.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/timers.h Sun Apr 10 15:47:33 2016 +1000
@@ -0,0 +1,57 @@
+#ifndef __TIMERS_H__
+#define __TIMERS_H__
+
+#include "mbed.h"
+
+/*!
+ * \brief The MyTimers class creates a Ticker and decrements a collection of unsigned longs that act as timers across the program
+ *
+ * \sa eTimerType is used to link external callers with a collection of unsigned longs which are decremented
+ * each ms by \sa run().
+ * This acts as a collection of timers.
+ * This collection can be set by \sa SetTimer and retrieved by \sa GetTimer.
+ */
+class MyTimers
+{
+public:
+ MyTimers();
+ ~MyTimers();
+
+ ///< eTimerType identifies each of the timers in program, and is used to set and get a timer
+ typedef enum
+ {
+ tmr_GroveMeasure, ///< Used in GroveDht22 handler
+ tmr_GprsPower, ///< Used to power the SIM900 on and off
+ tmr_GprsRxTx, ///< Timeout waiting for a response from the SIM900 over the serial line
+ tmr_SdWaitError, ///< Sd card has hit an error, wait before retrying
+ tmr_MeasFlash ///< Flash once every 2 seconds for heartbeat
+ } eTimerType;
+
+ //! run is called each time Ticker fires, which is every 1ms, and decrements all timers if necessary
+ void run();
+
+ /*!
+ * \brief SetTimer sets the value of the timer
+ * \param timertype identifies the timer whose value we want to set
+ * \param time_ms is the value the timer will be set to, to start counting down from, in ms
+ */
+ void SetTimer(eTimerType timertype, unsigned long time_ms);
+
+ /*!
+ * \brief GetTimer gets the value of a timer
+ * \param timertype identifies the timer whose value we want to get
+ * \return the value of the timer
+ */
+ unsigned long GetTimer(eTimerType timertype);
+
+private:
+ unsigned long groveMeasureTimer; ///< current value of timer for \sa tmr_GroveMeasure
+ unsigned long gprsPowerTimer; ///< current value of timer for \sa tmr_GprsPower
+ unsigned long gprsRxTxTimer; ///< current value of timer for \sa tmr_GprsRxTx
+ unsigned long sdWaitErrorTimer; ///< current value of timer for \sa tmr_SdWaitError
+ unsigned long measFlashTimer; ///< current value of timer for \sa tmr_MeasFlash
+
+ Ticker *m_tick; ///< Used to call \a run a function periodically
+};
+
+#endif