-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathaDSEngine.h
411 lines (350 loc) · 18.1 KB
/
aDSEngine.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
///
/// \copyright Copyright (C) 2015-2017 F1RMB, Daniel Caujolle-Bert <[email protected]>
///
/// \license
/// This program is free software; you can redistribute it and/or
/// modify it under the terms of the GNU General Public License
/// as published by the Free Software Foundation; either version 2
/// of the License, or (at your option) any later version.<br><br>
/// This program is distributed in the hope that it will be useful,
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/// GNU General Public License for more details.<br><br>
/// You should have received a copy of the GNU General Public License
/// along with this program; if not, write to the Free Software
/// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///
#ifndef ADSENGINE_H
#define ADSENGINE_H
#include <Arduino.h>
#include <src/LiquidCrystal.h>
#include <src/EEPROM.h>
#include "TimerOne.h"
#include "ClickEncoder.h"
///
/// \file aDSEngine.h
/// \author F1RMB, Daniel Caujolle-Bert <[email protected]>
///
//#define SIMU 1 ///< Define this to run in simulation mode (temperature will raise/lower automatically, !! DO NOT PLUG ANY IRON TIP !!)
//#define CHANNEL_COUNTING 1 ///< Define this to trace channel counting, debug purpose
//#define LCD_CHANNELS_LEDS 1 ///< Define this if you want channels LEDs displayed on the LCD
#define DOUBLE_AVERAGE 1 ///< Define this if you want to use averaging based on double values (more SRAM used)
static const uint8_t CHANNEL2_ENABLE_PIN = 13; ///< Pin to check from if channel 2 is wired
static const uint8_t LCD_RS_PIN = 7; ///< LCD RS pin
static const uint8_t LCD_ENABLE_PIN = 8; ///< LCD Enable pin
static const uint8_t LCD_D4_PIN = 9; ///< LCD D4 pin
static const uint8_t LCD_D5_PIN = 10; ///< LCD D5 pin
static const uint8_t LCD_D6_PIN = 11; ///< LCD D6 pin
static const uint8_t LCD_D7_PIN = 12; ///< LCD D7 pin
static const uint8_t LCD_COLS = 16; ///< LCD columns
static const uint8_t LCD_ROWS = 2; ///< LCD rows
static const uint8_t ENCODER_A_PIN = 2; ///< Encoder A pin
static const uint8_t ENCODER_B_PIN = 3; ///< Encoder B pin
static const uint8_t ENCODER_PB_PIN = 4; ///< Encoder push button pin
static const uint8_t ENCODER_STEPS_PER_NOTCH = 4; ///< Number of steps per notch (indent)
static const uint8_t PWM_CHANNEL1_PIN = 5; ///< PWM pin of channel 1
static const uint8_t PWM_CHANNEL2_PIN = 6; ///< PWM pin of channel 2
static const uint8_t TEMP_SENSOR_CHANNEL1_PIN = A1; ///< Temp sensor pin of channel 1
static const uint8_t TEMP_SENSOR_CHANNEL2_PIN = A0; ///< Temp sensor pin of channel 2
static const uint8_t LED_CHANNEL1_PIN = A2; ///< LED pin of channel 1
static const uint8_t LED_CHANNEL2_PIN = A3; ///< LED pin of channel 2
static const uint8_t PROGRAM_VERSION_MAJOR = 1; ///< Major program version
static const uint8_t PROGRAM_VERSION_MINOR = 6; ///< Minor program version
static const uint16_t PROGRAM_YEAR = 2017; ///< Release year
/// \brief Operation Mode enumeration
///
///
typedef enum
{
OPERATION_MODE_READ, ///< Reading values
OPERATION_MODE_SET, ///< Settings values
OPERATION_MODE_UNKNOWN ///< Unset (internal)
} OperationMode_t;
/// \brief ValueAveraging class
///
#ifdef DOUBLE_AVERAGE
class ValueAveraging
{
protected:
static const uint16_t ARRAY_SIZE_MAX = 10; ///< Averaging is performed using n values
public:
ValueAveraging();
~ValueAveraging();
template<typename T>
void StackValue(T value);
template<typename T>
T GetValue();
bool SetAverage(uint16_t v);
uint16_t GetAverage();
uint16_t GetMaxAverage();
void ResetValues();
private:
double m_values[ARRAY_SIZE_MAX]; ///< values array storage
uint16_t m_offset; ///< offset in m_values[]
uint16_t m_average; ///< max values used from m_values[] to build average value
};
#else
class ValueAveraging
{
protected:
static const uint16_t ARRAY_SIZE_MAX = 10; ///< Averaging is performed using n values
public:
ValueAveraging();
~ValueAveraging();
void StackValue(int16_t value);
int16_t GetValue();
bool SetAverage(uint16_t v);
uint16_t GetAverage();
uint16_t GetMaxAverage();
void ResetValues();
private:
int16_t m_values[ARRAY_SIZE_MAX]; ///< values array storage
uint16_t m_offset; ///< offset in m_values[]
uint16_t m_average; ///< max values used from m_values[] to build average value
};
#endif
/// \brief aDSChannel class
///
class aDSChannel
{
public:
#ifdef SIMU
static const int16_t TEMPERATURE_MIN = 10;
#else
static const int16_t TEMPERATURE_MIN = 100; ///< Minimum temperature
#endif
static const int16_t TEMPERATURE_MAX = 450; ///< Maximum temperature
static const int16_t TEMPERATURE_STANDBY = 150; ///< Standby temperature
static const unsigned long BLINK_UPDATE_RATE = 400; ///< Update rate for LED blinking, in ms
static const int16_t TEMPERATURE_TOLERANCE = 3; ///< Temperature tolerance for REACHED state, +/- 2 °C
static const float DEFAULT_TEMPERATURE_SLOPE = 0.3947387545; ///< Default slope value, used for ADC to Temp correction
static const float DEFAULT_TEMPERATURE_OFFSET = 43.8279285472; ///< Default offset value, used for ADC to Temp correction
static const int16_t PWM_MAX_VALUE = 150; ///< Maximum PWM value
/// \brief Heating State enumeration
///
///
typedef enum
{
HEATING_STATE_HEATING, ///< Heating
HEATING_STATE_COOLING, ///< Cooling
HEATING_STATE_REACHED, ///< Target temperature reached
HEATING_STATE_STANDBY ///< In standby mode
} HeatingState_t;
/// \brief Calibration values
///
/// Contains Slope and Offset float values
///
typedef struct
{
float slope; ///< Slope value
float offset; ///< Offset value
} CalibrationData_t;
protected:
/// \brief Our pin structure
///
///
typedef struct
{
uint8_t pin; ///< "Arduino" pin
uint8_t timer; ///< Timer of the pin
uint8_t mask; ///< Bit mask of the pin
uint8_t port; ///< Port of the pin
volatile uint8_t *outputRegister; ///< Output register of the pin
} aPin_t;
public:
aDSChannel();
virtual ~aDSChannel();
void setup(uint8_t, uint8_t, uint8_t);
void setFocus(bool);
bool hasFocus();
uint16_t getTemperature(OperationMode_t);
bool setTemperature(OperationMode_t, int16_t);
bool service(unsigned long);
void setStandbyMode(bool);
bool getStandbyMode();
bool isTempHasChanged();
void syncTempChange();
uint8_t updateLEDState(unsigned long);
uint8_t getLEDState();
HeatingState_t getHeatState();
bool isPlugged();
void setCalibration(float, float);
const CalibrationData_t getCalibration() const;
int16_t getADCValue();
void setBrother(aDSChannel *);
protected:
void _turnOffPWM(aPin_t);
void _turnPWM(bool);
int8_t _digitalRead(aPin_t);
void _digitalWrite(aPin_t, uint8_t);
uint16_t _analogRead(aPin_t);
void _analogWrite(aPin_t, uint8_t);
private:
aPin_t m_pwmPin;
aPin_t m_sensorPin;
aPin_t m_ledPin;
bool m_hasFocus;
int16_t m_targetTemp;
int16_t m_currentTemp;
int8_t m_pwmValue;
int16_t m_adcValue;
bool m_inStandby;
HeatingState_t m_heatState;
uint8_t m_ledState;
unsigned long m_nextPass;
bool m_tempHasChanged;
unsigned long m_nextBlink;
uint8_t m_blinkStandby;
CalibrationData_t m_cal;
#ifdef SIMU
unsigned long m_nextTempStep;
unsigned long m_nextLowering;
#endif // SIMU
#if CHANNEL_COUNTING
uint8_t m_channel;
#endif
bool m_isPlugged;
aDSChannel *m_brother;
ValueAveraging m_avrTemp;
};
class aDSEngine;
/// \brief aDSChannels class
///
class aDSChannels
{
friend aDSEngine;
public:
static const uint8_t OFFSET_VALUE = 2; ///< Value column LCD offset
static const uint8_t OFFSET_MARKER_LEFT = 0; ///< Column LCD offset for left marker '['
static const uint8_t OFFSET_MARKER_RIGHT = 10; ///< Column LCD offset for right marker ']'
// Settings to Operation mode switch timeout
static const unsigned long OPERATION_SET_TIMEOUT = 3000; ///< Automatic toggle settings->reading timeout (3 seconds), in ms
static const unsigned long DISPLAY_UPDATE_RATE = 200; ///< Display update rate, in ms
static const unsigned long MEASURE_UPDATE_RATE = 200; ///< Measurement (for aDSChannel) rate, in ms
static const unsigned long TEMP_SETTING_INACTIVITY = 30000; ///< Timeout in ms, after which the new target temperature will be stored in the EEPROM.
/// \brief Channels enumeration
///
///
///
typedef enum
{
CHANNEL_ONE,
CHANNEL_TWO,
CHANNEL_MAX
} Channel_t;
static const uint16_t DATA_CHANNEL2_ENABLED = 1; ///< Bitfield: Channel 2 is enabled
static const uint16_t DATA_CHANNELS_JOINDED = 1 << 1; ///< Bitfield: Channel 1 & 2 are joinded
static const uint16_t DATA_OPERATION = 1 << 2; ///< Bitfield: Operation mode has changed
static const uint16_t DATA_CHANNEL1_TEMP_SET = 1 << 3; ///< Bitfield: Target temperature of channel 1 has changed
static const uint16_t DATA_CHANNEL1_TEMP_READ = 1 << 4; ///< Bitfield: Readed temperature of channel 1 has changed
static const uint16_t DATA_CHANNEL1_LED_STATE = 1 << 5; ///< Bitfield: LED state of channel 1 has changed
static const uint16_t DATA_CHANNEL2_TEMP_SET = 1 << 6; ///< Bitfield: Target temperature of channel 1 has changed
static const uint16_t DATA_CHANNEL2_TEMP_READ = 1 << 7; ///< Bitfield: Readed temperature of channel 1 has changed
static const uint16_t DATA_CHANNEL2_LED_STATE = 1 << 8; ///< Bitfield: LED state of channel 1 has changed
static const uint16_t DATA_DISPLAY = 1 << 9; ///< Bitfield: Display should be refreshed
static const uint16_t DATA_STANDBY = 1 << 10; ///< Bitfield: Standby state
static const uint16_t DATA_DISPLAY_STANDBY = 1 << 11; ///< Bitfield: Standby state has changed
static const uint16_t DATA_FOCUS = 1 << 12; ///< Bitfield: Focus has changed
static const uint16_t DATA_IN_CALIBRATION = 1 << 13; ///< Bitfield: in Calibration
private:
/** \brief Union to manipulate float/uint8_t [] calibration values
*
*/
union _eepromCalibrationValue_t
{
float v;
uint8_t c[sizeof(float)];
};
static const int16_t EEPROM_ADDR_MAGIC = 0; ///< EEPROM offset storage start for magic numbers (0xDEAD)
static const int16_t EEPROM_STORAGE_STARTING = 5; ///< EEPROM starting address for program datas
static const int16_t EEPROM_TEMP_SIZE = sizeof(uint16_t) + sizeof(uint8_t); ///< EEPROM temperature size (temperature + crc)
static const int16_t EEPROM_ADDR_CHANNEL_JOINED = EEPROM_STORAGE_STARTING + 1; ///< Channels are joinded
static const int16_t EEPROM_ADDR_TEMP_CHANNEL_ONE = EEPROM_ADDR_CHANNEL_JOINED + EEPROM_TEMP_SIZE; ///< Target temp for Channel 1
static const int16_t EEPROM_ADDR_TEMP_CHANNEL_TWO = EEPROM_ADDR_TEMP_CHANNEL_ONE + EEPROM_TEMP_SIZE; ///< Target temp for Channel 2
static const int16_t EEPROM_CALIBRATION_SIZE = (sizeof(float) * 2) + sizeof(uint8_t); ///< EEPROM calibration size: 2 float (slope & offset), and one uint8_t for crc
static const int16_t EEPROM_ADDR_CALIBRATION_CHAN_1 = EEPROM_ADDR_TEMP_CHANNEL_TWO + EEPROM_TEMP_SIZE; ///< EEPROM start offset for Channel 1 calibration values
static const int16_t EEPROM_ADDR_CALIBRATION_CHAN_2 = EEPROM_ADDR_CALIBRATION_CHAN_1 + EEPROM_CALIBRATION_SIZE; ///< EEPROM start offset for Channel 2 calibration values
public:
aDSChannels(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t);
virtual ~aDSChannels();
void setup(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t);
void setOperationMode(OperationMode_t);
OperationMode_t getOperationMode();
void updateOperationMode();
void pingOperationMode();
#define IS_DATA_ENABLED(bit) ((m_datas & bit))
//bool isDataEnabled(uint16_t);
void syncData(uint16_t);
void incEncoderPosition(uint16_t);
void service();
void toggleJoined();
bool isJoinded();
void setFocusToNextChannel();
void toggleStandbyMode();
bool isInStandby();
void setCalibrationValues(Channel_t, aDSChannel::CalibrationData_t);
aDSChannel::CalibrationData_t getCalibrationValues(Channel_t);
void restoreCalibationValues();
void saveCalibrationValues(Channel_t);
bool isInCalibration();
void setCalibrationMode(bool);
protected:
void _enableData(uint16_t, bool);
void _enableDataCheck(uint16_t, bool);
void _updateDisplay();
void _displayBigDigit(uint8_t, uint8_t, uint8_t = 0);
void _displayBigDigits(int16_t, uint8_t, uint8_t = 0);
void _clearValue(uint8_t, int = 0);
void _updateField(OperationMode_t, int16_t, uint8_t);
void _wakeupFromStandby();
void _showBanner();
// EEPROM related functions
bool _checkForMagicNumbers();
void _writeMagicNumbers();
uint8_t _crc8(const uint8_t *, uint8_t);
template <typename T>
bool _write(T const, int16_t &);
template <typename T>
bool _read(T &, int16_t &);
template <typename T>
void _scissor(T v, uint8_t *, size_t &);
bool _getTempFromEEPROM(int16_t, uint16_t &);
void _setTempToEEPROM(int16_t, uint16_t);
void _restoreCalibrationFromEEPROM(int16_t, aDSChannel &);
void _backupCalibrationFromEEPROM(int16_t, aDSChannel &);
private:
LiquidCrystal m_lcd;
aDSChannel m_channels[CHANNEL_MAX];
OperationMode_t m_operationMode;
unsigned long m_operationTick;
uint16_t m_datas;
uint8_t m_lcdCols;
uint8_t m_lcdRows;
unsigned long m_nextDisplayUpdate;
unsigned long m_nextMeasureUpdate;
unsigned long m_lastTempChange;
bool m_isValidEEPROM;
bool m_storedToEEPROM;
};
/// \brief aDSEngine class
///
class aDSEngine
{
private:
static const uint8_t RXBUFFER_MAXLEN = 64; ///< USB input communication buffer's max size
public:
aDSEngine();
virtual ~aDSEngine();
void setup();
void run();
protected:
void _handleSerialInput();
private:
aDSChannels m_channels;
ClickEncoder m_encoder;
uint16_t m_datas;
uint8_t m_RXbuffer[RXBUFFER_MAXLEN]; ///< USB rx buffer
uint8_t m_RXoffset; ///< USB rx buffer offset counter
unsigned long m_serialInputTick;
};
#endif // ADSENGINE_H