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
heating/program.c@0:3c04f4b47041, 2018-01-11 (annotated)
- Committer:
- andrewboyson
- Date:
- Thu Jan 11 17:40:08 2018 +0000
- Revision:
- 0:3c04f4b47041
- Child:
- 20:904a4f043f2c
Removed dependence on Mbed OS
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
andrewboyson | 0:3c04f4b47041 | 1 | #include <stdint.h> |
andrewboyson | 0:3c04f4b47041 | 2 | #include <stdlib.h> |
andrewboyson | 0:3c04f4b47041 | 3 | #include "rtc.h" |
andrewboyson | 0:3c04f4b47041 | 4 | #include <stdbool.h> |
andrewboyson | 0:3c04f4b47041 | 5 | |
andrewboyson | 0:3c04f4b47041 | 6 | #include "clock.h" |
andrewboyson | 0:3c04f4b47041 | 7 | #include "log.h" |
andrewboyson | 0:3c04f4b47041 | 8 | #include "fram.h" |
andrewboyson | 0:3c04f4b47041 | 9 | |
andrewboyson | 0:3c04f4b47041 | 10 | #define PROGRAMS 3 |
andrewboyson | 0:3c04f4b47041 | 11 | #define TRANSITIONS 4 |
andrewboyson | 0:3c04f4b47041 | 12 | |
andrewboyson | 0:3c04f4b47041 | 13 | static char programDay[7]; static int iDay; |
andrewboyson | 0:3c04f4b47041 | 14 | static int16_t programs[PROGRAMS][TRANSITIONS]; static int iPrograms; |
andrewboyson | 0:3c04f4b47041 | 15 | static char programNewDayHour; static int iNewDayHour; |
andrewboyson | 0:3c04f4b47041 | 16 | |
andrewboyson | 0:3c04f4b47041 | 17 | |
andrewboyson | 0:3c04f4b47041 | 18 | int ProgramGetDay (int i) { return (int) programDay[i]; } |
andrewboyson | 0:3c04f4b47041 | 19 | int ProgramGetNewDayHour() { return (int) programNewDayHour;} |
andrewboyson | 0:3c04f4b47041 | 20 | |
andrewboyson | 0:3c04f4b47041 | 21 | void ProgramSetDay (int i, int value) { programDay [i] = (char)value; FramWrite(iDay + i, 1, &programDay [i]); } |
andrewboyson | 0:3c04f4b47041 | 22 | void ProgramSetNewDayHour( int value) { programNewDayHour = (char)value; FramWrite(iNewDayHour, 1, &programNewDayHour ); } |
andrewboyson | 0:3c04f4b47041 | 23 | |
andrewboyson | 0:3c04f4b47041 | 24 | int ProgramInit() |
andrewboyson | 0:3c04f4b47041 | 25 | { |
andrewboyson | 0:3c04f4b47041 | 26 | char def1; |
andrewboyson | 0:3c04f4b47041 | 27 | int address; |
andrewboyson | 0:3c04f4b47041 | 28 | int programSize = PROGRAMS * TRANSITIONS * sizeof(int16_t); |
andrewboyson | 0:3c04f4b47041 | 29 | address = FramLoad(7, programDay, NULL); if (address < 0) return -1; iDay = address; |
andrewboyson | 0:3c04f4b47041 | 30 | address = FramLoad(programSize, programs, NULL); if (address < 0) return -1; iPrograms = address; //3 x 4 x 2 |
andrewboyson | 0:3c04f4b47041 | 31 | def1 = 2; address = FramLoad(1, &programNewDayHour, &def1); if (address < 0) return -1; iNewDayHour = address; |
andrewboyson | 0:3c04f4b47041 | 32 | return 0; |
andrewboyson | 0:3c04f4b47041 | 33 | } |
andrewboyson | 0:3c04f4b47041 | 34 | |
andrewboyson | 0:3c04f4b47041 | 35 | /* |
andrewboyson | 0:3c04f4b47041 | 36 | There are three programs available [0|1|2]; any of which can be allocated to a given day [0-6]. |
andrewboyson | 0:3c04f4b47041 | 37 | Each program contains four transitions with an index [0|1|2|3]. |
andrewboyson | 0:3c04f4b47041 | 38 | A transition is defined to be a short (16 bit) and consists of: |
andrewboyson | 0:3c04f4b47041 | 39 | +---------+--------+--------+---------+ |
andrewboyson | 0:3c04f4b47041 | 40 | | 15 - 13 | 12 | 11 | 10 - 00 | |
andrewboyson | 0:3c04f4b47041 | 41 | +---------+--------+--------+---------+ |
andrewboyson | 0:3c04f4b47041 | 42 | | | in use | switch | minute | |
andrewboyson | 0:3c04f4b47041 | 43 | | | yes/no | on/off | in day | |
andrewboyson | 0:3c04f4b47041 | 44 | | | 1/0 | 1/0 | 0-1439 | |
andrewboyson | 0:3c04f4b47041 | 45 | +---------+--------+--------+---------+ |
andrewboyson | 0:3c04f4b47041 | 46 | */ |
andrewboyson | 0:3c04f4b47041 | 47 | static int16_t encodeTransition(bool inuse, bool onoff, int minutes) |
andrewboyson | 0:3c04f4b47041 | 48 | { |
andrewboyson | 0:3c04f4b47041 | 49 | int16_t transition = minutes; |
andrewboyson | 0:3c04f4b47041 | 50 | transition &= 0x07FF; |
andrewboyson | 0:3c04f4b47041 | 51 | if (onoff) transition |= 0x0800; |
andrewboyson | 0:3c04f4b47041 | 52 | if (inuse) transition |= 0x1000; |
andrewboyson | 0:3c04f4b47041 | 53 | return transition; |
andrewboyson | 0:3c04f4b47041 | 54 | } |
andrewboyson | 0:3c04f4b47041 | 55 | static void decodeTransition(int16_t transition, bool* pinuse, bool* ponoff, int* pminutes) |
andrewboyson | 0:3c04f4b47041 | 56 | { |
andrewboyson | 0:3c04f4b47041 | 57 | *pinuse = transition & 0x1000; |
andrewboyson | 0:3c04f4b47041 | 58 | *ponoff = transition & 0x0800; |
andrewboyson | 0:3c04f4b47041 | 59 | *pminutes = transition & 0x07FF; |
andrewboyson | 0:3c04f4b47041 | 60 | } |
andrewboyson | 0:3c04f4b47041 | 61 | |
andrewboyson | 0:3c04f4b47041 | 62 | static int compareTransition (const void * a, const void * b) //-ve a goes before b; 0 same; +ve a goes after b |
andrewboyson | 0:3c04f4b47041 | 63 | { |
andrewboyson | 0:3c04f4b47041 | 64 | bool inUseA, inUseB; |
andrewboyson | 0:3c04f4b47041 | 65 | bool onA, onB; |
andrewboyson | 0:3c04f4b47041 | 66 | int minutesA, minutesB; |
andrewboyson | 0:3c04f4b47041 | 67 | decodeTransition(*(int16_t*)a, &inUseA, &onA, &minutesA); |
andrewboyson | 0:3c04f4b47041 | 68 | decodeTransition(*(int16_t*)b, &inUseB, &onB, &minutesB); |
andrewboyson | 0:3c04f4b47041 | 69 | |
andrewboyson | 0:3c04f4b47041 | 70 | if (!inUseA && !inUseB) return 0; |
andrewboyson | 0:3c04f4b47041 | 71 | if (!inUseA) return +1; |
andrewboyson | 0:3c04f4b47041 | 72 | if (!inUseB) return -1; |
andrewboyson | 0:3c04f4b47041 | 73 | |
andrewboyson | 0:3c04f4b47041 | 74 | if (minutesA < programNewDayHour * 60) minutesA += 1440; |
andrewboyson | 0:3c04f4b47041 | 75 | if (minutesB < programNewDayHour * 60) minutesB += 1440; |
andrewboyson | 0:3c04f4b47041 | 76 | |
andrewboyson | 0:3c04f4b47041 | 77 | if (minutesA < minutesB) return -1; |
andrewboyson | 0:3c04f4b47041 | 78 | if (minutesA > minutesB) return +1; |
andrewboyson | 0:3c04f4b47041 | 79 | return 0; |
andrewboyson | 0:3c04f4b47041 | 80 | } |
andrewboyson | 0:3c04f4b47041 | 81 | static void sort(int16_t* pProgram) |
andrewboyson | 0:3c04f4b47041 | 82 | { |
andrewboyson | 0:3c04f4b47041 | 83 | qsort (pProgram, 4, sizeof(int16_t), compareTransition); |
andrewboyson | 0:3c04f4b47041 | 84 | } |
andrewboyson | 0:3c04f4b47041 | 85 | |
andrewboyson | 0:3c04f4b47041 | 86 | //[+|-][00-23][00-59]; |
andrewboyson | 0:3c04f4b47041 | 87 | void ProgramToString(int program, int buflen, char* buffer) |
andrewboyson | 0:3c04f4b47041 | 88 | { |
andrewboyson | 0:3c04f4b47041 | 89 | if (buflen < 25) return; |
andrewboyson | 0:3c04f4b47041 | 90 | char* p = buffer; |
andrewboyson | 0:3c04f4b47041 | 91 | for (int i = 0; i < TRANSITIONS; i++) |
andrewboyson | 0:3c04f4b47041 | 92 | { |
andrewboyson | 0:3c04f4b47041 | 93 | int16_t transition = programs[program][i]; |
andrewboyson | 0:3c04f4b47041 | 94 | bool inuse; |
andrewboyson | 0:3c04f4b47041 | 95 | bool on; |
andrewboyson | 0:3c04f4b47041 | 96 | int minuteUnits; |
andrewboyson | 0:3c04f4b47041 | 97 | decodeTransition(transition, &inuse, &on, &minuteUnits); |
andrewboyson | 0:3c04f4b47041 | 98 | if (!inuse) continue; |
andrewboyson | 0:3c04f4b47041 | 99 | |
andrewboyson | 0:3c04f4b47041 | 100 | int minuteTens = minuteUnits / 10; minuteUnits %= 10; |
andrewboyson | 0:3c04f4b47041 | 101 | int hourUnits = minuteTens / 6; minuteTens %= 6; |
andrewboyson | 0:3c04f4b47041 | 102 | int hourTens = hourUnits / 10; hourUnits %= 10; |
andrewboyson | 0:3c04f4b47041 | 103 | |
andrewboyson | 0:3c04f4b47041 | 104 | if (p > buffer) *p++ = ' '; |
andrewboyson | 0:3c04f4b47041 | 105 | *p++ = on ? '+' : '-'; |
andrewboyson | 0:3c04f4b47041 | 106 | *p++ = hourTens + '0'; |
andrewboyson | 0:3c04f4b47041 | 107 | *p++ = hourUnits + '0'; |
andrewboyson | 0:3c04f4b47041 | 108 | *p++ = minuteTens + '0'; |
andrewboyson | 0:3c04f4b47041 | 109 | *p++ = minuteUnits + '0'; |
andrewboyson | 0:3c04f4b47041 | 110 | } |
andrewboyson | 0:3c04f4b47041 | 111 | *p = 0; |
andrewboyson | 0:3c04f4b47041 | 112 | } |
andrewboyson | 0:3c04f4b47041 | 113 | static void handleParseDelim(int program, int* pIndex, bool* pInUse, bool* pOn, int* pHourTens, int* pHourUnits, int* pMinuteTens, int* pMinuteUnits) |
andrewboyson | 0:3c04f4b47041 | 114 | { |
andrewboyson | 0:3c04f4b47041 | 115 | int hour = *pHourTens * 10 + *pHourUnits; |
andrewboyson | 0:3c04f4b47041 | 116 | if (hour < 0) *pInUse = false; |
andrewboyson | 0:3c04f4b47041 | 117 | if (hour > 23) *pInUse = false; |
andrewboyson | 0:3c04f4b47041 | 118 | |
andrewboyson | 0:3c04f4b47041 | 119 | int minute = *pMinuteTens * 10 + *pMinuteUnits; |
andrewboyson | 0:3c04f4b47041 | 120 | if (minute < 0) *pInUse = false; |
andrewboyson | 0:3c04f4b47041 | 121 | if (minute > 59) *pInUse = false; |
andrewboyson | 0:3c04f4b47041 | 122 | |
andrewboyson | 0:3c04f4b47041 | 123 | int minutes = hour * 60 + minute; |
andrewboyson | 0:3c04f4b47041 | 124 | |
andrewboyson | 0:3c04f4b47041 | 125 | int16_t transition = encodeTransition(*pInUse, *pOn, minutes); |
andrewboyson | 0:3c04f4b47041 | 126 | programs[program][*pIndex] = transition; |
andrewboyson | 0:3c04f4b47041 | 127 | |
andrewboyson | 0:3c04f4b47041 | 128 | *pIndex += 1; |
andrewboyson | 0:3c04f4b47041 | 129 | *pInUse = 0; |
andrewboyson | 0:3c04f4b47041 | 130 | *pOn = 0; |
andrewboyson | 0:3c04f4b47041 | 131 | *pHourTens = 0; |
andrewboyson | 0:3c04f4b47041 | 132 | *pHourUnits = 0; |
andrewboyson | 0:3c04f4b47041 | 133 | *pMinuteTens = 0; |
andrewboyson | 0:3c04f4b47041 | 134 | *pMinuteUnits = 0; |
andrewboyson | 0:3c04f4b47041 | 135 | |
andrewboyson | 0:3c04f4b47041 | 136 | } |
andrewboyson | 0:3c04f4b47041 | 137 | void ProgramParse(int program, char* p) |
andrewboyson | 0:3c04f4b47041 | 138 | { |
andrewboyson | 0:3c04f4b47041 | 139 | int i = 0; |
andrewboyson | 0:3c04f4b47041 | 140 | bool inUse = 0; bool on = 0; |
andrewboyson | 0:3c04f4b47041 | 141 | int hourUnits = 0; int hourTens = 0; |
andrewboyson | 0:3c04f4b47041 | 142 | int minuteUnits = 0; int minuteTens = 0; |
andrewboyson | 0:3c04f4b47041 | 143 | while (*p && i < TRANSITIONS) |
andrewboyson | 0:3c04f4b47041 | 144 | { |
andrewboyson | 0:3c04f4b47041 | 145 | if (*p == '+') { on = true ; } |
andrewboyson | 0:3c04f4b47041 | 146 | else if (*p == '-') { on = false; } |
andrewboyson | 0:3c04f4b47041 | 147 | else if (*p >= '0' && *p <= '9') { inUse = true; hourTens = hourUnits; hourUnits = minuteTens; minuteTens = minuteUnits; minuteUnits = *p - '0'; } |
andrewboyson | 0:3c04f4b47041 | 148 | else if (*p == ' ') { handleParseDelim(program, &i, &inUse, &on, &hourTens, &hourUnits, &minuteTens, &minuteUnits); } |
andrewboyson | 0:3c04f4b47041 | 149 | p++; |
andrewboyson | 0:3c04f4b47041 | 150 | } |
andrewboyson | 0:3c04f4b47041 | 151 | while (i < TRANSITIONS) handleParseDelim(program, &i, &inUse, &on, &hourTens, &hourUnits, &minuteTens, &minuteUnits); |
andrewboyson | 0:3c04f4b47041 | 152 | sort(&programs[program][0]); |
andrewboyson | 0:3c04f4b47041 | 153 | FramWrite(iPrograms + program * 8, 8, &programs[program]); |
andrewboyson | 0:3c04f4b47041 | 154 | } |
andrewboyson | 0:3c04f4b47041 | 155 | |
andrewboyson | 0:3c04f4b47041 | 156 | static bool readProgramTimerOutput() |
andrewboyson | 0:3c04f4b47041 | 157 | { |
andrewboyson | 0:3c04f4b47041 | 158 | |
andrewboyson | 0:3c04f4b47041 | 159 | if (!ClockIsSet()) return 0; |
andrewboyson | 0:3c04f4b47041 | 160 | |
andrewboyson | 0:3c04f4b47041 | 161 | struct tm tm; |
andrewboyson | 0:3c04f4b47041 | 162 | ClockTmLocal(&tm); |
andrewboyson | 0:3c04f4b47041 | 163 | |
andrewboyson | 0:3c04f4b47041 | 164 | int dayOfWeek = tm.tm_wday; |
andrewboyson | 0:3c04f4b47041 | 165 | int minutesNow = tm.tm_hour * 60 + tm.tm_min; |
andrewboyson | 0:3c04f4b47041 | 166 | if (tm.tm_hour < programNewDayHour) //Before 2am should be matched against yesterday's program. |
andrewboyson | 0:3c04f4b47041 | 167 | { |
andrewboyson | 0:3c04f4b47041 | 168 | dayOfWeek--; |
andrewboyson | 0:3c04f4b47041 | 169 | if (dayOfWeek < 0) dayOfWeek = 6; |
andrewboyson | 0:3c04f4b47041 | 170 | } |
andrewboyson | 0:3c04f4b47041 | 171 | |
andrewboyson | 0:3c04f4b47041 | 172 | int program = programDay[dayOfWeek]; |
andrewboyson | 0:3c04f4b47041 | 173 | |
andrewboyson | 0:3c04f4b47041 | 174 | bool calling = 0; |
andrewboyson | 0:3c04f4b47041 | 175 | for (int i = 0; i < TRANSITIONS; i++) |
andrewboyson | 0:3c04f4b47041 | 176 | { |
andrewboyson | 0:3c04f4b47041 | 177 | int16_t transition = programs[program][i]; |
andrewboyson | 0:3c04f4b47041 | 178 | bool inuse; |
andrewboyson | 0:3c04f4b47041 | 179 | bool on; |
andrewboyson | 0:3c04f4b47041 | 180 | int minutes; |
andrewboyson | 0:3c04f4b47041 | 181 | decodeTransition(transition, &inuse, &on, &minutes); |
andrewboyson | 0:3c04f4b47041 | 182 | if (!inuse) continue; |
andrewboyson | 0:3c04f4b47041 | 183 | if (minutes <= minutesNow) calling = on; |
andrewboyson | 0:3c04f4b47041 | 184 | } |
andrewboyson | 0:3c04f4b47041 | 185 | |
andrewboyson | 0:3c04f4b47041 | 186 | return calling; |
andrewboyson | 0:3c04f4b47041 | 187 | } |
andrewboyson | 0:3c04f4b47041 | 188 | |
andrewboyson | 0:3c04f4b47041 | 189 | bool ProgramTimerOutput; |
andrewboyson | 0:3c04f4b47041 | 190 | |
andrewboyson | 0:3c04f4b47041 | 191 | int ProgramMain() |
andrewboyson | 0:3c04f4b47041 | 192 | { |
andrewboyson | 0:3c04f4b47041 | 193 | ProgramTimerOutput = readProgramTimerOutput(); |
andrewboyson | 0:3c04f4b47041 | 194 | return 0; |
andrewboyson | 0:3c04f4b47041 | 195 | } |