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

Files at this revision

API Documentation at this revision

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

Logger.cpp Show annotated file Show diff for this revision Revisions of this file
Logger.h Show annotated file Show diff for this revision Revisions of this file
RdWebServer.lib Show annotated file Show diff for this revision Revisions of this file
Watchdog.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
--- /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
     }
 }