|
@@ -39,29 +39,32 @@ LiquidCrystal g_lcd(PIN_LCD_RS, PIN_LCD_ENABLE, PIN_LCD_D0, PIN_LCD_D1, PIN_LCD_
|
39
|
39
|
UiStateEnum g_modeSequence[3] = {WaterSetting, HeaterSetting, Lighting};
|
40
|
40
|
#define MODE_SEQUENCE_COUNT (sizeof(g_modeSequence) / sizeof(*g_modeSequence))
|
41
|
41
|
|
42
|
|
-BoilerState g_boilerState = {
|
43
|
|
- .water = {
|
44
|
|
- .current = 44,
|
45
|
|
- .setting = 44,
|
46
|
|
- .isActive = false
|
47
|
|
- },
|
48
|
|
- .heater = {
|
49
|
|
- .current = 44,
|
50
|
|
- .setting = 44,
|
51
|
|
- .isActive = false
|
|
42
|
+GlobalState g_globalState = {
|
|
43
|
+ .appState = {
|
|
44
|
+ .water = {
|
|
45
|
+ .current = 44,
|
|
46
|
+ .setting = 44,
|
|
47
|
+ .isActive = false
|
|
48
|
+ },
|
|
49
|
+ .heater = {
|
|
50
|
+ .current = 44,
|
|
51
|
+ .setting = 44,
|
|
52
|
+ .isActive = false
|
|
53
|
+ }
|
52
|
54
|
},
|
53
|
55
|
.uiState = {
|
54
|
56
|
.state = Lighting,
|
55
|
57
|
.lastOpMs = 0,
|
56
|
|
- .modeSequenceIndex = MODE_SEQUENCE_COUNT - 1
|
|
58
|
+ .modeSequenceIndex = MODE_SEQUENCE_COUNT - 1,
|
|
59
|
+ .isUpdateNeeded = true
|
57
|
60
|
}
|
58
|
61
|
};
|
59
|
62
|
|
60
|
|
-void printStateLine(char prefix, const BoilerLineState& boilerLineState, bool isModifying, bool isActive, LiquidCrystal lcd)
|
|
63
|
+void printStateLine(char prefix, const BoilerItemState& boilerItemState, bool isModifying, bool isActive, LiquidCrystal lcd)
|
61
|
64
|
{
|
62
|
65
|
char curTmp[5], setTmp[5], tmp[17];
|
63
|
|
- dtostrf(boilerLineState.current / 2.0f, 2, 1, curTmp);
|
64
|
|
- dtostrf(boilerLineState.setting / 2.0f, 2, 1, setTmp);
|
|
66
|
+ dtostrf(boilerItemState.current / 2.0f, 2, 1, curTmp);
|
|
67
|
+ dtostrf(boilerItemState.setting / 2.0f, 2, 1, setTmp);
|
65
|
68
|
int count = snprintf(tmp, sizeof(tmp), "%c: %s [%s]%c%c", prefix, curTmp, setTmp, isModifying ? '<' : ' ', isActive ? LCD_CHAR_SENSOR : ' ');
|
66
|
69
|
for (; count < 17; ++count)
|
67
|
70
|
{
|
|
@@ -71,12 +74,47 @@ void printStateLine(char prefix, const BoilerLineState& boilerLineState, bool is
|
71
|
74
|
lcd.print(tmp);
|
72
|
75
|
}
|
73
|
76
|
|
74
|
|
-void printState(const BoilerState& boilerState, LiquidCrystal lcd)
|
|
77
|
+void printState(const GlobalState& globalState, LiquidCrystal lcd)
|
75
|
78
|
{
|
|
79
|
+ Serial.println("Updating display");
|
|
80
|
+
|
76
|
81
|
lcd.setCursor(0, 0);
|
77
|
|
- printStateLine('S', boilerState.water, boilerState.uiState.state == WaterSetting, boilerState.water.isActive, lcd);
|
|
82
|
+ printStateLine('S', globalState.appState.water, globalState.uiState.state == WaterSetting, globalState.appState.water.isActive, lcd);
|
78
|
83
|
lcd.setCursor(0, 1);
|
79
|
|
- printStateLine('C', boilerState.heater, boilerState.uiState.state == HeaterSetting, boilerState.heater.isActive, lcd);
|
|
84
|
+ printStateLine('C', globalState.appState.heater, globalState.uiState.state == HeaterSetting, globalState.appState.heater.isActive, lcd);
|
|
85
|
+}
|
|
86
|
+
|
|
87
|
+void setState(GlobalState& boilerState, UiStateEnum state)
|
|
88
|
+{
|
|
89
|
+ char tmp[50];
|
|
90
|
+ snprintf(tmp, sizeof(tmp), "Changing state %i => %i", g_globalState.uiState.state, state);
|
|
91
|
+ Serial.println(tmp);
|
|
92
|
+
|
|
93
|
+ if (state == Lighting)
|
|
94
|
+ {
|
|
95
|
+ digitalWrite(PIN_LCD_LED, 1);
|
|
96
|
+ }
|
|
97
|
+ else if (state == Hibernate)
|
|
98
|
+ {
|
|
99
|
+ digitalWrite(PIN_LCD_LED, 0);
|
|
100
|
+ g_globalState.uiState.modeSequenceIndex = MODE_SEQUENCE_COUNT - 1;
|
|
101
|
+ }
|
|
102
|
+ g_globalState.uiState.state = state;
|
|
103
|
+ g_globalState.uiState.isUpdateNeeded = true;
|
|
104
|
+}
|
|
105
|
+
|
|
106
|
+void checkBoilerItem(BoilerItemState& boilerItemState, UiState uiState)
|
|
107
|
+{
|
|
108
|
+ if (!boilerItemState.isActive && (boilerItemState.current <= boilerItemState.setting - TEMP_TRIGGER))
|
|
109
|
+ {
|
|
110
|
+ boilerItemState.isActive = true;
|
|
111
|
+ uiState.isUpdateNeeded = true;
|
|
112
|
+ }
|
|
113
|
+ else if (boilerItemState.isActive && (boilerItemState.current >= boilerItemState.setting))
|
|
114
|
+ {
|
|
115
|
+ boilerItemState.isActive = false;
|
|
116
|
+ uiState.isUpdateNeeded = true;
|
|
117
|
+ }
|
80
|
118
|
}
|
81
|
119
|
|
82
|
120
|
void setup()
|
|
@@ -91,98 +129,83 @@ void setup()
|
91
|
129
|
|
92
|
130
|
g_lcd.begin(16, 2);
|
93
|
131
|
g_lcd.createChar(LCD_CHAR_SENSOR, g_sensorChar);
|
94
|
|
- printState(g_boilerState, g_lcd);
|
95
|
132
|
|
96
|
133
|
Serial.begin(9600);
|
97
|
134
|
}
|
98
|
135
|
|
99
|
136
|
void loop()
|
100
|
137
|
{
|
101
|
|
- bool needLcdUpdate = false;
|
102
|
|
- unsigned long currentMs = millis();
|
|
138
|
+ const auto& currentMs = millis();
|
103
|
139
|
|
104
|
140
|
for (unsigned i = 0; i < BUTTONS_COUNT; ++i)
|
105
|
141
|
{
|
106
|
142
|
g_buttons[i]->read();
|
107
|
143
|
if (g_buttons[i]->isPressed())
|
108
|
144
|
{
|
109
|
|
- g_boilerState.uiState.lastOpMs = currentMs;
|
|
145
|
+ g_globalState.uiState.lastOpMs = currentMs;
|
|
146
|
+ break;
|
110
|
147
|
}
|
111
|
148
|
}
|
112
|
149
|
|
113
|
150
|
|
114
|
|
- if (g_boilerState.uiState.state == Hibernate)
|
|
151
|
+ if (g_globalState.uiState.state == Hibernate)
|
115
|
152
|
{
|
116
|
153
|
for (unsigned i = 0; i < BUTTONS_COUNT; ++i)
|
117
|
154
|
{
|
118
|
155
|
if (g_buttons[i]->wasReleased())
|
119
|
156
|
{
|
120
|
|
- g_boilerState.uiState.state = Lighting;
|
121
|
|
- digitalWrite(PIN_LCD_LED, 1);
|
|
157
|
+ setState(g_globalState, Lighting);
|
122
|
158
|
break;
|
123
|
159
|
}
|
124
|
160
|
}
|
125
|
|
- needLcdUpdate = true;
|
126
|
161
|
}
|
127
|
162
|
else
|
128
|
163
|
{
|
129
|
|
- if (currentMs - g_boilerState.uiState.lastOpMs >= HIBERNATE_DELAY)
|
|
164
|
+ if (currentMs - g_globalState.uiState.lastOpMs >= HIBERNATE_DELAY)
|
130
|
165
|
{
|
131
|
|
- g_boilerState.uiState.state = Hibernate;
|
132
|
|
- digitalWrite(PIN_LCD_LED, 0);
|
133
|
|
- g_boilerState.uiState.modeSequenceIndex = MODE_SEQUENCE_COUNT - 1;
|
134
|
|
- needLcdUpdate = true;
|
|
166
|
+ setState(g_globalState, Hibernate);
|
135
|
167
|
}
|
136
|
168
|
else
|
137
|
169
|
{
|
138
|
|
- if (g_btnMode.wasPressed())
|
|
170
|
+ if (g_btnMode.wasReleased())
|
139
|
171
|
{
|
140
|
|
- g_boilerState.uiState.modeSequenceIndex =
|
141
|
|
- (g_boilerState.uiState.modeSequenceIndex + 1) % MODE_SEQUENCE_COUNT;
|
142
|
|
- g_boilerState.uiState.state = g_modeSequence[g_boilerState.uiState.modeSequenceIndex];
|
143
|
|
- needLcdUpdate = true;
|
|
172
|
+ g_globalState.uiState.modeSequenceIndex = (g_globalState.uiState.modeSequenceIndex + 1) % MODE_SEQUENCE_COUNT;
|
|
173
|
+ setState(g_globalState, g_modeSequence[g_globalState.uiState.modeSequenceIndex]);
|
144
|
174
|
}
|
145
|
|
- else
|
|
175
|
+ else if (g_btnMinus.wasReleased() || g_btnPlus.wasReleased())
|
146
|
176
|
{
|
147
|
|
- temp_t* setting = NULL;
|
148
|
|
- if (g_boilerState.uiState.state == WaterSetting)
|
|
177
|
+ BoilerItemState* itemState = NULL;
|
|
178
|
+ if (g_globalState.uiState.state == WaterSetting)
|
149
|
179
|
{
|
150
|
|
- setting = &g_boilerState.water.setting;
|
|
180
|
+ itemState = &g_globalState.appState.water;
|
151
|
181
|
}
|
152
|
|
- else if (g_boilerState.uiState.state == HeaterSetting)
|
|
182
|
+ else if (g_globalState.uiState.state == HeaterSetting)
|
153
|
183
|
{
|
154
|
|
- setting = &g_boilerState.heater.setting;
|
|
184
|
+ itemState = &g_globalState.appState.heater;
|
155
|
185
|
}
|
156
|
186
|
|
157
|
|
- if (setting)
|
|
187
|
+ if (itemState)
|
158
|
188
|
{
|
159
|
189
|
if (g_btnMinus.wasReleased())
|
160
|
190
|
{
|
161
|
|
- --(*setting);
|
|
191
|
+ --itemState->setting;
|
162
|
192
|
}
|
163
|
193
|
else if (g_btnPlus.wasReleased())
|
164
|
194
|
{
|
165
|
|
- ++(*setting);
|
|
195
|
+ ++itemState->setting;
|
166
|
196
|
}
|
167
|
|
- needLcdUpdate = true;
|
|
197
|
+ g_globalState.uiState.isUpdateNeeded = true;
|
168
|
198
|
}
|
169
|
199
|
}
|
170
|
200
|
}
|
171
|
201
|
}
|
172
|
202
|
|
173
|
|
- if (!g_boilerState.water.isActive && (g_boilerState.water.current <= g_boilerState.water.setting - TEMP_TRIGGER))
|
174
|
|
- {
|
175
|
|
- g_boilerState.water.isActive = true;
|
176
|
|
- needLcdUpdate = true;
|
177
|
|
- }
|
178
|
|
- else if (g_boilerState.water.isActive && (g_boilerState.water.current >= g_boilerState.water.setting))
|
179
|
|
- {
|
180
|
|
- g_boilerState.water.isActive = false;
|
181
|
|
- needLcdUpdate = true;
|
182
|
|
- }
|
|
203
|
+ checkBoilerItem(g_globalState.appState.water, g_globalState.uiState);
|
|
204
|
+ checkBoilerItem(g_globalState.appState.heater, g_globalState.uiState);
|
183
|
205
|
|
184
|
|
- if (needLcdUpdate)
|
|
206
|
+ if (g_globalState.uiState.isUpdateNeeded)
|
185
|
207
|
{
|
186
|
|
- printState(g_boilerState, g_lcd);
|
|
208
|
+ printState(g_globalState, g_lcd);
|
|
209
|
+ g_globalState.uiState.isUpdateNeeded = false;
|
187
|
210
|
}
|
188
|
211
|
}
|