Central Heating controller using the real time clock, PHY module for internet, 1-wire interface for temperature sensors, a system log and a configuration file

Dependencies:   net 1-wire lpc1768 crypto clock web fram log

/media/uploads/andrewboyson/heating.sch

/media/uploads/andrewboyson/heating.brd

/media/uploads/andrewboyson/eagle.epf

Revision:
0:3c04f4b47041
Child:
20:904a4f043f2c
diff -r 000000000000 -r 3c04f4b47041 heating/program.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/heating/program.c	Thu Jan 11 17:40:08 2018 +0000
@@ -0,0 +1,195 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include    "rtc.h"
+#include <stdbool.h>
+
+#include  "clock.h"
+#include    "log.h"
+#include   "fram.h"
+
+#define PROGRAMS    3
+#define TRANSITIONS 4
+
+static char    programDay[7];                   static int iDay;
+static int16_t programs[PROGRAMS][TRANSITIONS]; static int iPrograms;
+static char    programNewDayHour;               static int iNewDayHour;
+
+
+int  ProgramGetDay       (int i)             { return (int) programDay[i];    } 
+int  ProgramGetNewDayHour()                  { return (int) programNewDayHour;}
+
+void ProgramSetDay       (int i, int  value) { programDay       [i] = (char)value; FramWrite(iDay        + i, 1, &programDay       [i]); }
+void ProgramSetNewDayHour(       int  value) { programNewDayHour    = (char)value; FramWrite(iNewDayHour,     1, &programNewDayHour   ); }
+
+int ProgramInit()
+{
+    char def1;
+    int address;
+    int programSize = PROGRAMS * TRANSITIONS * sizeof(int16_t);
+              address = FramLoad(7,            programDay,         NULL); if (address < 0) return -1; iDay        = address;
+              address = FramLoad(programSize,  programs,           NULL); if (address < 0) return -1; iPrograms   = address; //3 x 4 x 2
+    def1 = 2; address = FramLoad(1,           &programNewDayHour, &def1); if (address < 0) return -1; iNewDayHour = address;
+    return 0;
+}
+
+/*
+There are three programs available [0|1|2]; any of which can be allocated to a given day [0-6].
+Each program contains four transitions with an index [0|1|2|3].
+A transition is defined to be a short (16 bit) and consists of:
++---------+--------+--------+---------+
+| 15 - 13 |   12   |   11   | 10 - 00 |
++---------+--------+--------+---------+
+|         | in use | switch | minute  |
+|         | yes/no | on/off | in day  |
+|         |   1/0  |  1/0   | 0-1439  |
++---------+--------+--------+---------+
+*/
+static int16_t encodeTransition(bool inuse, bool onoff, int minutes)
+{
+    int16_t    transition  = minutes;
+               transition &= 0x07FF;
+    if (onoff) transition |= 0x0800;
+    if (inuse) transition |= 0x1000;
+    return transition;
+}
+static void decodeTransition(int16_t transition, bool* pinuse, bool* ponoff, int* pminutes)
+{
+    *pinuse   = transition & 0x1000;
+    *ponoff   = transition & 0x0800;
+    *pminutes = transition & 0x07FF;
+}
+
+static int compareTransition (const void * a, const void * b) //-ve a goes before b; 0 same; +ve a goes after b
+{
+    bool  inUseA,   inUseB;
+    bool     onA,      onB;
+    int minutesA, minutesB;
+    decodeTransition(*(int16_t*)a, &inUseA, &onA, &minutesA);
+    decodeTransition(*(int16_t*)b, &inUseB, &onB, &minutesB);
+    
+    if (!inUseA && !inUseB) return  0;
+    if (!inUseA)            return +1;
+    if (!inUseB)            return -1;
+    
+    if (minutesA < programNewDayHour * 60) minutesA += 1440;
+    if (minutesB < programNewDayHour * 60) minutesB += 1440;
+    
+    if (minutesA < minutesB) return -1;
+    if (minutesA > minutesB) return +1;
+    return 0;
+}
+static void sort(int16_t* pProgram)
+{
+    qsort (pProgram, 4, sizeof(int16_t), compareTransition);
+}
+
+//[+|-][00-23][00-59];
+void ProgramToString(int program, int buflen, char* buffer)
+{
+    if (buflen < 25) return;
+    char* p = buffer;
+    for (int i = 0; i < TRANSITIONS; i++)
+    {
+        int16_t transition = programs[program][i];
+        bool  inuse;
+        bool  on;
+        int   minuteUnits;
+        decodeTransition(transition, &inuse, &on, &minuteUnits);
+        if (!inuse) continue;
+        
+        int minuteTens  = minuteUnits / 10; minuteUnits %= 10;
+        int   hourUnits = minuteTens  /  6; minuteTens  %=  6;
+        int   hourTens  =   hourUnits / 10;   hourUnits %= 10;
+        
+        if (p > buffer) *p++ = ' ';
+        *p++ = on ? '+' : '-';
+        *p++ = hourTens    + '0';
+        *p++ = hourUnits   + '0';
+        *p++ = minuteTens  + '0';
+        *p++ = minuteUnits + '0';
+    }
+    *p = 0;
+}
+static void handleParseDelim(int program, int* pIndex, bool* pInUse, bool* pOn, int* pHourTens,  int* pHourUnits, int* pMinuteTens, int* pMinuteUnits)
+{
+    int hour = *pHourTens * 10 + *pHourUnits;
+    if (hour   <  0) *pInUse = false;
+    if (hour   > 23) *pInUse = false;
+    
+    int minute = *pMinuteTens * 10 + *pMinuteUnits;
+    if (minute <  0) *pInUse = false;
+    if (minute > 59) *pInUse = false;
+    
+    int minutes = hour * 60 + minute;
+    
+    int16_t transition = encodeTransition(*pInUse, *pOn, minutes);
+    programs[program][*pIndex] = transition;
+    
+    *pIndex      += 1;
+    *pInUse       = 0;
+    *pOn          = 0;
+    *pHourTens    = 0;
+    *pHourUnits   = 0;
+    *pMinuteTens  = 0;
+    *pMinuteUnits = 0;
+
+}
+void ProgramParse(int program, char* p)
+{
+    int            i = 0;
+    bool       inUse = 0;  bool         on = 0;
+    int    hourUnits = 0;  int    hourTens = 0;
+    int  minuteUnits = 0;  int  minuteTens = 0;
+    while (*p && i < TRANSITIONS) 
+    {
+        if      (*p == '+')              { on = true ; }
+        else if (*p == '-')              { on = false; }
+        else if (*p >= '0' && *p <= '9') { inUse = true; hourTens = hourUnits; hourUnits = minuteTens; minuteTens = minuteUnits; minuteUnits = *p - '0'; }
+        else if (*p == ' ')              { handleParseDelim(program, &i, &inUse, &on, &hourTens, &hourUnits, &minuteTens, &minuteUnits); }
+        p++;
+    }
+    while (i < TRANSITIONS) handleParseDelim(program, &i, &inUse, &on, &hourTens, &hourUnits, &minuteTens, &minuteUnits);
+    sort(&programs[program][0]);
+    FramWrite(iPrograms + program * 8, 8, &programs[program]);
+}
+
+static bool readProgramTimerOutput()
+{   
+
+    if (!ClockIsSet()) return 0;
+
+    struct tm tm;
+    ClockTmLocal(&tm);
+    
+    int dayOfWeek = tm.tm_wday;
+    int minutesNow = tm.tm_hour * 60 + tm.tm_min;
+    if (tm.tm_hour < programNewDayHour) //Before 2am should be matched against yesterday's program.
+    {
+        dayOfWeek--;
+        if (dayOfWeek < 0) dayOfWeek = 6;
+    }
+    
+    int program = programDay[dayOfWeek];
+    
+    bool calling = 0;
+    for (int i = 0; i < TRANSITIONS; i++)
+    {
+        int16_t transition = programs[program][i];
+        bool inuse;
+        bool on;
+        int  minutes;
+        decodeTransition(transition, &inuse, &on, &minutes);
+        if (!inuse) continue;
+        if (minutes <= minutesNow) calling = on;
+    }
+    
+    return calling;
+}
+
+bool ProgramTimerOutput;
+
+int ProgramMain()
+{    
+    ProgramTimerOutput = readProgramTimerOutput();
+    return 0;
+}