Monitor for central heating system (e.g. 2zones+hw) Supports up to 15 temp probes (DS18B20/DS18S20) 3 valve monitors Gas pulse meter recording Use stand-alone or with nodeEnergyServer See http://robdobson.com/2015/09/central-heating-monitor
Dependencies: EthernetInterfacePlusHostname NTPClient Onewire RdWebServer SDFileSystem-RTOS mbed-rtos mbed-src
Revision 12:a52996515063, committed 2015-02-22
- Comitter:
- Bobty
- Date:
- Sun Feb 22 22:08:37 2015 +0000
- Parent:
- 11:30182b9aa833
- Child:
- 13:9ec0e11cf3c1
- Commit message:
- Watchdog implemented and working; Improved logging of events and data
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Logger.cpp Sun Feb 22 22:08:37 2015 +0000
@@ -0,0 +1,57 @@
+// Log to SD
+// Rob Dobson, 2015
+
+#include "Logger.h"
+
+Logger::Logger(const char* eventLogFileName, const char* dataLogFileBase)
+{
+ _eventLogFileName = eventLogFileName;
+ _dataLogFileBase = dataLogFileBase;
+}
+
+void Logger::LogEvent(const char* format, ...)
+{
+ char timeBuf[40];
+ time_t seconds = time(NULL);
+ strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d\t%H:%M:%S\t", localtime(&seconds));
+
+ FILE* fp = fopen(_eventLogFileName, "a");
+ if (fp == NULL)
+ {
+ printf ("Event Log ... Filename %s not found\r\n", _eventLogFileName);
+ }
+ else
+ {
+ fprintf(fp, timeBuf);
+ va_list argptr;
+ va_start(argptr, format);
+ vfprintf(fp, format, argptr);
+ va_end(argptr);
+ fprintf(fp, "\r\n");
+ fclose(fp);
+ }
+}
+
+// Utility function to log data
+void Logger::LogData(const char* format, ...)
+{
+ char fileNameBuf[60];
+ strcpy(fileNameBuf, _dataLogFileBase);
+ time_t seconds = time(NULL);
+ strftime(fileNameBuf+strlen(fileNameBuf), sizeof(fileNameBuf)-strlen(fileNameBuf), "Data_%Y%m%d.txt", localtime(&seconds));
+
+ FILE* fp = fopen(fileNameBuf, "a");
+ if (fp == NULL)
+ {
+ printf ("Data Log ... Filename %s not found\r\n", _eventLogFileName);
+ }
+ else
+ {
+ va_list argptr;
+ va_start(argptr, format);
+ vfprintf(fp, format, argptr);
+ va_end(argptr);
+ fprintf(fp, "\r\n");
+ fclose(fp);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Logger.h Sun Feb 22 22:08:37 2015 +0000
@@ -0,0 +1,22 @@
+// Log to SD
+// Rob Dobson, 2015
+
+#ifndef __LOGGER__H
+#define __LOGGER__H
+#include "mbed.h"
+#include <stdarg.h>
+
+class Logger
+{
+ public:
+ Logger(const char* eventLogFileName, const char* dataLogFileBase);
+ void LogEvent(const char* format, ...);
+ void LogData(const char* format, ...);
+
+ private:
+ const char* _eventLogFileName;
+ const char* _dataLogFileBase;
+};
+
+
+#endif
\ No newline at end of file
--- a/RdWebServer.lib Sun Feb 22 20:28:21 2015 +0000 +++ b/RdWebServer.lib Sun Feb 22 22:08:37 2015 +0000 @@ -1,1 +1,1 @@ -http://mbed.org/users/Bobty/code/RdWebServer/#35668248199b +http://mbed.org/users/Bobty/code/RdWebServer/#b4b9d4d5e5be
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Watchdog.h Sun Feb 22 22:08:37 2015 +0000
@@ -0,0 +1,35 @@
+#ifndef __WATCHDOG__H
+#define __WATCHDOG__H
+#include "mbed.h"
+
+// Simon's Watchdog code from
+// http://mbed.org/forum/mbed/topic/508/
+class Watchdog
+{
+ public:
+ // Load timeout value in watchdog timer and enable
+ void SetTimeoutSecs(float s)
+ {
+ LPC_WDT->WDCLKSEL = 0x1; // Set CLK src to PCLK
+ uint32_t clk = SystemCoreClock / 16; // WD has a fixed /4 prescaler, PCLK default is /4
+ LPC_WDT->WDTC = s * (float)clk;
+ LPC_WDT->WDMOD = 0x3; // Enabled and Reset
+ Feed();
+ }
+ // "kick" or "feed" the dog - reset the watchdog timer
+ // by writing this required bit pattern
+ void Feed()
+ {
+ LPC_WDT->WDFEED = 0xAA;
+ LPC_WDT->WDFEED = 0x55;
+ }
+
+ bool WatchdogCausedRestart()
+ {
+ if ((LPC_WDT->WDMOD >> 2) & 1)
+ return true;
+ return false;
+ }
+};
+
+#endif
--- a/main.cpp Sun Feb 22 20:28:21 2015 +0000
+++ b/main.cpp Sun Feb 22 22:08:37 2015 +0000
@@ -5,7 +5,8 @@
#include "GasUseCounter.h"
#include "Thermometers.h"
#include "VoltAlerter.h"
-#include <stdarg.h>
+#include "Watchdog.h"
+#include "Logger.h"
// Web and UDB ports
const int WEBPORT = 80; // Port for web server
@@ -33,10 +34,16 @@
// File system for SD card
SDFileSystem sd(p5, p6, p7, p8, "sd");
+// Log file names
+const char* gasPulseFileName = "/sd/curPulse.txt";
+const char* eventLogFileName = "/sd/log.txt";
+const char* dataLogFileBase = "/sd/";
+
+// Logger
+Logger logger(eventLogFileName, dataLogFileBase);
+
// Gas use counter
DigitalIn gasPulsePin(p21);
-const char* gasPulseFileName = "/sd/curPulse.txt";
-const char* logFilename = "/sd/log.txt";
GasUseCounter gasUseCounter(gasPulseFileName, gasPulsePin, pc);
// Thermometers - DS18B20 OneWire Thermometer connections
@@ -49,6 +56,9 @@
VoltAlerter voltAlerter2(p24);
VoltAlerter voltAlerter3(p25);
+// Watchdog
+Watchdog watchdog;
+
// Broadcast message format
// Data format of the broadcast message - senml - https://tools.ietf.org/html/draft-jennings-senml-08
// {
@@ -77,28 +87,11 @@
60;
char broadcastMsgBuffer[broadcastMsgLen];
-// Utility function to log data
-void LogData(const char* format, ...)
-{
- FILE* fp = fopen(logFilename, "a");
- if (fp == NULL)
- {
- pc.printf ("Log ... Filename %s not found\r\n", logFilename);
- }
- else
- {
- va_list argptr;
- va_start(argptr, format);
- vfprintf(fp, format, argptr);
- va_end(argptr);
- fclose(fp);
- }
-}
-
// Send broadcast message with current data
void SendInfoBroadcast()
{
led3 = true;
+
// Init the sending socket
sendUDPSocket.init();
sendUDPSocket.set_broadcasting();
@@ -112,7 +105,7 @@
// printf("Temp: %.1f, Addr: %s, Time: %d\r\n", tempValues[tempIdx].tempInCentigrade, tempValues[tempIdx].address, tempValues[tempIdx].timeStamp);
// }
- // Send the broadcast
+ // Format the broadcast message
time_t timeNow = time(NULL);
strcpy(broadcastMsgBuffer, broadcastMsgPrefix);
sprintf(broadcastMsgBuffer+strlen(broadcastMsgBuffer), broadcastMsgGasFormat, gasUseCounter.GetCount(), gasUseCounter.GetPulseRateMs());
@@ -145,11 +138,8 @@
pc.printf("Broadcast Didn't send all of %s\r\n", broadcastMsgBuffer);
}
- // Log
- char timeBuf[32];
- time_t seconds = time(NULL);
- strftime(timeBuf, 32, "%Y-%m-%d %H:%M:%S", localtime(&seconds));
- LogData("%s\t%d\t%d ms\n", timeBuf, gasUseCounter.GetCount(), gasUseCounter.GetPulseRateMs());
+ // Log the data
+ logger.LogData(broadcastMsgBuffer);
led3 = false;
}
@@ -180,6 +170,7 @@
RdWebServer webServer;
webServer.addCommand("", RdWebServerCmdDef::CMD_SDORUSBFILE, NULL, "index.htm", false);
webServer.addCommand("gear-gr.png", RdWebServerCmdDef::CMD_SDORUSBFILE, NULL, NULL, true);
+ webServer.addCommand("listfiles", RdWebServerCmdDef::CMD_SDORUSBFILE, NULL, "/", false);
webServer.addCommand("getgascount", RdWebServerCmdDef::CMD_CALLBACK, &getGasUseCallback);
webServer.addCommand("setgascount", RdWebServerCmdDef::CMD_CALLBACK, &setGasUseCallback);
webServer.init(WEBPORT, &led4, baseWebFolder);
@@ -220,6 +211,11 @@
}
}
+// #define TEST_WATCHDOG 1
+#ifdef TEST_WATCHDOG
+int watchdogTestLoopCount = 0;
+#endif
+
// Main
int main()
{
@@ -244,6 +240,15 @@
// Web Server
Thread httpServer(&http_thread, NULL, osPriorityNormal, (DEFAULT_STACK_SIZE * 3));
+ // Record the reason for restarting in the log file
+ if (watchdog.WatchdogCausedRestart())
+ logger.LogEvent("Watchdog Restart");
+ else
+ logger.LogEvent("Normal Restart");
+
+ // Setup the watchdog for 10s reset
+ watchdog.SetTimeoutSecs(10);
+
// Time of last broadcast
time_t timeOfLastBroadcast = time(NULL);
const int TIME_BETWEEN_BROADCASTS_IN_SECS = 60;
@@ -251,6 +256,7 @@
{
osDelay(LOOP_DELAY_IN_MS);
led1 = !led1;
+ watchdog.Feed();
// Service gas count
if (gasUseCounter.Service())
@@ -276,6 +282,15 @@
// Set LED2 to the state of the first volt alerter
led2 = voltAlerter1.GetState();
+
+#ifdef TEST_WATCHDOG
+ // After about 20 seconds of operation we'll hang to test the watchdog
+ if (watchdogTestLoopCount++ > 80)
+ {
+ // This should cause watchdog to kick in and reset
+ osDelay(20000);
+ }
+#endif
}
}