Skip to content

Instantly share code, notes, and snippets.

@ashevchuk
Last active March 10, 2024 18:48
Show Gist options
  • Save ashevchuk/e3ff135dc46874e62dc8c3bb966b7da5 to your computer and use it in GitHub Desktop.
Save ashevchuk/e3ff135dc46874e62dc8c3bb966b7da5 to your computer and use it in GitHub Desktop.
Rack chiller cooling system controller firmware
#include <MCP41xxx.h>
#include <SerialCommands.h>
#include <ArduinoUniqueID.h>
#include <DS18B20.h>
#define WDT
//#define MA_SMOOTH
//#define EWMA_SMOOTH
#define SIMPLE_SMOOTH
#define CALIBRATION
//#define LCD_BLINK
//#define CHECK_DEVICE_ADDR
//#define CHECK_DEVICE_ADDR_ARG
//#define VIBRATION_SENSOR
#define LCD
//#define LED // speed-sensitive LED flashing
//#define SERIAL_STATUS
#define SERIAL_CONTROL
enum PIN_CONFIG {
#ifdef LED
PIN_LED_STATUS = 13,
#endif
PIN_SENSOR_COMPRESSOR = A0,
PIN_SENSOR_CONDENSER = A1,
#ifdef SERIAL_CONTROL
PIN_PWM_FAN_EVAPORATOR = 10,
PIN_PWM_FAN_CONDENSER = 9,
//pin (ST_CP) of 74HC595
PIN_SHIFT_REG_LATCH = 8,
//pin (SH_CP) of 74HC595
PIN_SHIFT_REG_CLOCK = 7,
//pin (DS) of 74HC595
PIN_SHIFT_REG_DATA = 6,
#endif
PIN_CONDENSATE_LEVEL = 2,
PIN_SENSOR_TEMP = 3,
PIN_VFD_CS = 4,
#ifdef SERIAL_CONTROL
PIN_SER_TX_ENABLE_SERIAL0 = 5,
#endif
};
enum LCD_CHAR_BITMAP {
LCD_CHAR_TEMP = 0,
LCD_CHAR_HUMIDITY = 1,
LCD_CHAR_CLOCK = 2,
LCD_CHAR_HEART = 3,
LCD_CHAR_DUCK = 4,
LCD_CHAR_CHECK = 5,
LCD_CHAR_CROSS = 6,
LCD_CHAR_FAN = 7,
LCD_CHAR_GRAD = 0b11011111,
LCD_CHAR_BAR = 0b11111111,
LCD_CHAR_DASH = 0b10100101
// LCD_CHAR_DASH = 0b10110000
};
#define CMD_MAX_LENGTH 64
#ifdef EWMA_SMOOTH
#include <math.h>
#include <Ewma.h>
#include <EwmaT.h>
#endif
#ifdef MA_SMOOTH
#include <movingAvg.h>
#endif
#ifdef WDT
#include <avr/wdt.h>
#endif
#include <Shifty.h>
#include <EEPROM.h>
#ifdef VIBRATION_SENSOR
#include <LSM303.h>
LSM303 acceleration_sensor;
#endif
#ifdef LCD
// set the LCD address to 0x27 for a 16 chars and 2 line display
#define LCD_ADDRESS 0x27
#include <Wire.h>
#include <LiquidCrystal_PCF8574.h>
LiquidCrystal_PCF8574 lcd(LCD_ADDRESS);
#endif
#ifdef SERIAL_CONTROL
#define SERIAL_DEFAULT_BAUD_RATE 9600
#if defined(UDR0)
#define UART_SRA UCSR0A
#define UART_SRB UCSR0B
#define UART_SRC UCSR0C
#define UART_SRL UBRR0L
#define UART_UDR UDR0
#elif defined(UDR)
#define UART_SRA UCSRA
#define UART_SRB UCSRB
#define UART_SRC UCSRC
#define UART_SRL UBRRL
#define UART_UDR UDR
#endif
#define SERIAL_TX_FLUSH while (!(UART_SRA & _BV(UDRE0))) { }; while (!(UART_SRA & _BV(TXC0))) { }
#define SERIAL_TX_ENABLE digitalWrite(PIN_SER_TX_ENABLE_SERIAL0, HIGH); delayMicroseconds(120)
#define SERIAL_TX_DISABLE delayMicroseconds(120); digitalWrite(PIN_SER_TX_ENABLE_SERIAL0, LOW)
#define SERIAL_PORT Serial
#define PRINT(...) SERIAL_TX_ENABLE; SERIAL_PORT.print(__VA_ARGS__); SERIAL_TX_FLUSH
#define PRINTLN(...) SERIAL_TX_ENABLE; SERIAL_PORT.println(__VA_ARGS__); SERIAL_TX_FLUSH
char serial_command_buffer_[CMD_MAX_LENGTH];
SerialCommands serial_commands_(&SERIAL_PORT, serial_command_buffer_, sizeof(serial_command_buffer_), (char *)"<", (char *)"\r", (char *)":", PIN_SER_TX_ENABLE_SERIAL0);
void cmd_analog_read(SerialCommands* sender);
SerialCommand cmd_analog_read_("AREAD", cmd_analog_read);
void cmd_digital_read(SerialCommands* sender);
SerialCommand cmd_digital_read_("DREAD", cmd_digital_read);
void cmd_reg_on(SerialCommands* sender);
SerialCommand cmd_reg_on_("REGON", cmd_reg_on);
void cmd_reg_off(SerialCommands* sender);
SerialCommand cmd_reg_off_("REGOFF", cmd_reg_off);
void cmd_fan_pwm(SerialCommands* sender);
SerialCommand cmd_fan_pwm_("FAN", cmd_fan_pwm);
void cmd_temp(SerialCommands* sender);
SerialCommand cmd_temp_("TEMP", cmd_temp);
void cmd_ping(SerialCommands* sender);
SerialCommand cmd_ping_("PING", cmd_ping);
void cmd_mode(SerialCommands* sender);
SerialCommand cmd_mode_("MODE", cmd_mode);
void cmd_set_state(SerialCommands* sender);
SerialCommand cmd_set_state_("SET_STATE", cmd_set_state);
void cmd_vfd(SerialCommands* sender);
SerialCommand cmd_vfd_("VFD", cmd_vfd);
void cmd_uptime(SerialCommands* sender);
SerialCommand cmd_uptime_("UPTIME", cmd_uptime);
void cmd_reset(SerialCommands* sender);
SerialCommand cmd_reset_("RESET", cmd_reset);
void cmd_reboot(SerialCommands* sender);
SerialCommand cmd_reboot_("REBOOT", cmd_reboot);
void cmd_stop(SerialCommands* sender);
SerialCommand cmd_stop_("STOP", cmd_stop);
void cmd_start(SerialCommands* sender);
SerialCommand cmd_start_("START", cmd_start);
void cmd_discover(SerialCommands* sender);
SerialCommand cmd_discover_("DISCOVER", cmd_discover);
#endif
float get_compressor_temp();
float get_condenser_temp();
static bool is_running = true;
typedef enum state {
STATE_INITIAL = 0,
STATE_NORMAL = 1,
STATE_COOLING = 2,
STATE_UNFREEZING = 3,
STATE_CONDENSING = 4,
STATE_SUSPEND = 5,
STATE_RESUME = 6
} state;
enum shift_regs {
REG_EVAPORATOR_FAN = 1,
REG_CONDENSER_FAN = 2,
REG_COMPRESSOR = 6,
REG_CONDENSATE_PUMP = 4,
REG_EVAPORATOR_BLOW_FAN = 5,
REG_EVAPORATOR_HEATER = 7
};
typedef enum reset_cause {
RESET_UNKNOWN = 0,
RESET_WATCH_DOG = 1,
RESET_POWER_SUPERVISOR = 2,
RESET_EXTERNAL = 3,
RESET_ON_POWER = 4
} reset_cause;
typedef enum run_mode {
RUN_MODE_MASTER = 0,
RUN_MODE_SLAVE = 1,
} run_mode;
#define TRESHOLD_PWM_MIN 15
#define TRESHOLD_PWM_MAX 320
#define PWM_AS_PERCENT(a) (float)(100 - ( (100.0 / (TRESHOLD_PWM_MAX * 1.0)) * (a)))
#ifdef CALIBRATION
#define TIMER_RESOLUTION 1000
#else
#define TIMER_RESOLUTION 1
#endif
#define MSECONDS(a) (unsigned long)((a) * 1)
#define TIME_RESOLUTION (unsigned long)(MSECONDS(TIMER_RESOLUTION))
#define SECONDS(a) (unsigned long)((a) * (TIME_RESOLUTION))
#define MINUTES(a) (unsigned long)((SECONDS(a)) * 60)
#define HOURS(a) (unsigned long)((MINUTES(a)) * 60)
#define TIME_AS_SECONDS(a) (unsigned long)((a) / (TIME_RESOLUTION))
#define TIME_AS_MINUTES(a) (unsigned long)((TIME_AS_SECONDS(a)) / 60 )
#define TIME_AS_HOURS(a) (unsigned long)((TIME_AS_MINUTES(a)) / 60 )
#define HOURS_AS_SEC(a) (unsigned long)((a) * 60 * 60)
#define MINS_AS_SEC(a) (unsigned long)((a) * 60)
#define SEC_AS_HOURS(a) (unsigned long)((a) / 60 / 60)
#define MINS_AS_HOURS(a) (unsigned long)((a) / 60)
#define SEC_AS_MINS(a) (unsigned long)((a) / 60)
#define CURRENT_TIME millis()
#define TEMP_ADC_ADJ_CONDENSER -10
#define TEMP_C(a) (float)((a) * 1.0)
#define TEMP_ADC_C(a) (float)((1 / (0.001129148 + (0.000234125 + (0.0000000876741 * log(((10240000 / (a)) - 10000)) * log(((10240000 / (a)) - 10000)) )) * log(((10240000 / (a)) - 10000)) )) - 273.15)
#define TEMP_ADC_C_ADJ(a,b) (float)((TEMP_ADC_C(a)) + b)
#define TEMP_C_AS_F(a) (float)(((a) * 9.0) / 5.0 + 32.0)
#define TEMP_PRECISION 9
#define TEMP_FORMAT DEC
#define SHIFT_REGS 8
#define TRESHOLD_TEMP_COMPRESSOR_MAX (TEMP_C(85))
#define TRESHOLD_TEMP_COMPRESSOR_MIN (TEMP_C(70))
#define TIME_MAX_COMPRESSOR_RUN (HOURS(12))
#define TIME_MAX_CONDENSATE_PUMP_RUN (MINUTES(1))
#define TIME_CONDENSATE_EVAPORATION (HOURS(4))
#define TIME_UNFREEZE_EVAPORATOR (MINUTES(1))
#define TIME_UNFREEZE_EVAPORATOR_CONDENSING (MINUTES(1))
#define TIME_INTERVAL_STATUS_SERIAL (SECONDS(1))
#define TIME_INTERVAL_STATUS_LCD (SECONDS(1))
#define TIME_INTERVAL_MEASURE_SENSOR (SECONDS(1))
#define TIME_INTERVAL_LCD_BLINK (MSECONDS(750))
#define TIME_INTERVAL_LCD_CHAR (MSECONDS(450))
#define TIME_INTERVAL_PING_TIMEOUT (SECONDS(60))
#define PING_TIMEOUT ((CURRENT_TIME - lastPing) > TIME_INTERVAL_PING_TIMEOUT)
#define TIME_MAX_INITIAL_UNFREEZE (HOURS(1))
#define TIME_SECS_PER_MIN 60
#define TIME_SECS_PER_HOUR 3600
#define MAX_INITIAL_UNFREEZ_CYCLES 2
#define SMOOTH_GET_CONDENSER_TEMP_READINGS 64
#define SMOOTH_GET_COMPRESSOR_TEMP_READINGS 64
#ifdef VIBRATION_SENSOR
#define SMOOTH_GET_ACCELERATION_READINGS 64
#endif
#define PWM_PID(a) (unsigned int)(TRESHOLD_PWM_MAX - constrain(map(TEMP_C_AS_F(a), 50, 100, 0, TRESHOLD_PWM_MAX), TRESHOLD_PWM_MIN, TRESHOLD_PWM_MAX))
#define PWM_INVERT(a) (unsigned int)(TRESHOLD_PWM_MAX - (a))
#define PWM_EVAPORATOR(a) OCR1A = (a)
#define PWM_CONDENSER(a) OCR1B = (a)
#ifdef VIBRATION_SENSOR
#define ACCEL_RANGE_REG_2G 0b0000000
#define ACCEL_RANGE_REG_4G 0b0000100
#define ACCEL_RANGE_REG_8G 0b0001000
#define ACCEL_RANGE_REG_16G 0b0001100
#define ACCEL_RANGE_REG (ACCEL_RANGE_REG_8G)
#define ACCEL_BASE 1000 // mG
#define ACCEL_RANGE(mG) (((mG) * (ACCEL_BASE) * 2) / 65535)
#define ACCEL_RANGE_2G 0.061
#define ACCEL_RANGE_4G ACCEL_RANGE(4)
#define ACCEL_RANGE_8G 0.244
#define ACCEL_RANGE_16G ACCEL_RANGE(16)
#define ACCEL_VECTOR(x,y,z) sqrt(pow((x),2)+pow((y),2)+pow((z),2)) * (ACCEL_RANGE_8G) / (ACCEL_BASE)
#endif
#define TURN_OFF(a) SHIFT_REGS_STATE[(a)] = LOW; shift.writeBit((a), LOW)
#define TURN_ON(a) SHIFT_REGS_STATE[(a)] = HIGH; shift.writeBit((a), HIGH)
#define TURN_OFF_ALL shift.batchWriteBegin(); for (byte thisReg = 0; thisReg < SHIFT_REGS; thisReg++) { SHIFT_REGS_STATE[thisReg] = LOW; shift.writeBit(thisReg, LOW); } shift.batchWriteEnd()
#define RESET_REGS shift.batchWriteBegin(); for (byte thisReg = 0; thisReg < SHIFT_REGS; thisReg++) { shift.writeBit(thisReg, SHIFT_REGS_STATE[thisReg]); } shift.batchWriteEnd()
#define PRINT_TIME(a) char * time_str = (char*) malloc(20); big_time_from_sec(time_str, (a) * 60); PRINT(time_str); free(time_str)
#define PRINT_LCD_TIME(a) if (LCDavail) { char * time_str = (char*) malloc(9); time_from_sec(time_str, (a)); lcd.print(time_str); free(time_str); }
#define PRINT_LCD_BIG_TIME(a) if (LCDavail) { char * time_str = (char*) malloc(20); big_time_from_sec(time_str, (a) * 60); lcd.print(time_str); free(time_str); }
#define PRINT_LCD_TEXT(a) if (LCDavail) { lcd.print(F(a)); }
#define PRINT_LCD_VALUE(...) if (LCDavail) { lcd.print(__VA_ARGS__); }
#define PRINT_LCD_STATUS(a,b) if (LCDavail) { lcd.setCursor(0, 3); lcd.write((a)); lcd.print(F(b)); }
//#define PRINT_LCD_TIMING(a,b,c) if (LCDavail) { if (((a) > 0) || ((b) > 0)) { lcd.setCursor(0, 2); lcd.write(LCD_CHAR_CLOCK); lcd.setCursor(2, 2); if ((a) > 0) { PRINT_LCD_TIME((a)); } if (((a) > 0) && ((b) > 0)) { lcd.print("/"); } if ((b) > 0) { PRINT_LCD_TIME((b)); } } }
#define PRINT_LCD_TIMING(a) if (LCDavail) { if ((a) > 0) { lcd.setCursor(11, 3); lcd.write(LCD_CHAR_CLOCK); PRINT_LCD_TIME((a)); } }
#define PRINT_LCD_XY(a, x, y) if (LCDavail) { lcd.setCursor((x), (y)); lcd.print(a); }
#define PRINT_LCD_CHAR(a) if (LCDavail) { lcd.write((byte)a); }
#define CURSOR_LCD_XY(x,y) if (LCDavail) { lcd.setCursor((x), (y)); }
#define CLEAR_LCD if (LCDavail) { lcd.home(); lcd.clear(); lcd.setCursor(0, 0); }
#define BL_LCD_ON if (LCDavail) { lcd.setBacklight(255); }
#define BL_LCD_OFF if (LCDavail) { lcd.setBacklight(0); }
#define LCD_ON if (LCDavail) { lcd.display(); }
#define LCD_OFF if (LCDavail) { lcd.noDisplay(); }
#define CREATE_LCD_CHAR(a, b) if (LCDavail) { create_lcd_char((a), (b)); }
#ifdef LCD_BLINK
#define LCD_BL(a) LCDblink = (a)
#endif
#define STATE get_service_state()
#define IS_NEW_STATE(a) ((STATE) != (a))
#define EEPROM_BOOTLOADER_FLAG_OFFSET 0x42
#define EEPROM_BOOTLOADER_MAGIC_VALUE 0x42
#define EEPROM_BOOTLOADER_BORING_VALUE 0xFF
#define EEPROM_INIT_MAGIC B1101011
#define EEPROM_ADDR_STATE_INITIAL 0
#define EEPROM_ADDR_STATE_COMPRESSOR sizeof(byte)
#define EEPROM_VAL_STATE_COMPRESSOR_T unsigned long
extern const __FlashStringHelper* getBuildTime() __attribute__((weak));
const __FlashStringHelper* getBuildTime()
{
static const char __BuildTime__[] PROGMEM = "BUILD:" __TIMESTAMP__;
return reinterpret_cast<const __FlashStringHelper *> (&__BuildTime__[0]);
}
#ifdef LCD
static bool LCDavail = false;
#ifdef LCD_BLINK
static bool LCDblink = false;
static bool LCDblink_state = false;
static unsigned long LCDBlinkMillis = 0;
#endif
static bool LCDchar_state = false;
static unsigned long LCDBcharMillis = 0;
#endif
#ifdef LED
static unsigned long ledMillis = 0; // stores last time LED status was toggled
#endif
static state runtimeState = STATE_INITIAL;
static state prevState = STATE_INITIAL;
#ifdef SERIAL_STATUS
static unsigned long serialMillis = 0; // stores last time a serial message was sent
#endif
static unsigned long lcdMillis = 0;
static unsigned long measureMillis = 0;
static unsigned long CompressorStopTime = 0;
static unsigned long CompressorStartTime = 0;
static unsigned long UnfreezeStartTime = 0;
static unsigned long CondensingStartTime = 0;
static unsigned long CondensatePumpStopTime = 0;
static unsigned long CondensatePumpStartTime = 0;
static byte initialUnfreezeCycles = 0;
static byte runMode = RUN_MODE_MASTER;
static unsigned long lastPing = 0;
unsigned int lastStatusLEDvalue = 0;
static byte SHIFT_REGS_STATE[SHIFT_REGS];
Shifty shift;
#ifdef MA_SMOOTH
movingAvg compressor_sensor_filter(10);
movingAvg condenser_sensor_filter(10);
movingAvg acceleration_sensor_filter(10);
#endif
#ifdef EWMA_SMOOTH
EwmaT <unsigned int> compressor_sensor_filter(3, 100);
EwmaT <unsigned int> condenser_sensor_filter(3, 100);
EwmaT <unsigned int> acceleration_sensor_filter(3, 100);
#endif
#ifdef SIMPLE_SMOOTH
static float condenser_readings[SMOOTH_GET_CONDENSER_TEMP_READINGS] = { 0.0 }; // the readings from the analog input
static byte condenser_readIndex = 0; // the index of the current reading
static float condenser_total = 0.0; // the running total
static float condenser_average = 0.0; // the average
static float condenser_last = 45.0; // last reading
static float compressor_readings[SMOOTH_GET_COMPRESSOR_TEMP_READINGS] = { 0.0 }; // the readings from the analog input
static byte compressor_readIndex = 0; // the index of the current reading
static float compressor_total = 0.0; // the running total
static float compressor_average = 0.0; // the average
#ifdef VIBRATION_SENSOR
static float acceleration_readings[SMOOTH_GET_ACCELERATION_READINGS] = { 0.0 };
static byte acceleration_readIndex = 0; // the index of the current reading
static float acceleration_total = 0.0; // the running total
static float acceleration_average = 0.0; // the average
#endif
#endif
DS18B20 temp_sensors(PIN_SENSOR_TEMP);
uint8_t thermometer[8] = { 0 };
uint8_t condenserThermometer[8] = { 0x28, 0xff, 0x64, 0x1d, 0xcd, 0xf9, 0x84, 0x66 };
uint8_t compressorThermometer[8] = { 0x28, 0x7f, 0x64, 0x1d, 0xcd, 0xf4, 0xac, 0x0e };
MCP41xxx vfdSpeedPot(PIN_VFD_CS);
#ifdef LCD
const char c_duck[8] PROGMEM = {0x00, 0x0c, 0x1d, 0x0f, 0x0f, 0x06, 0x00};
const char c_retarrow[8] PROGMEM = {0x01, 0x01, 0x05, 0x09, 0x1f, 0x08, 0x04};
//clock icon
const char c_clock[8] PROGMEM = {
0b00000,
0b01110,
0b10101,
0b10111,
0b10001,
0b01110,
0b00000,
0b00000
};
//clock icon
const char c_clock_inv[8] PROGMEM = {
0b00000,
0b01110,
0b10001,
0b11101,
0b10101,
0b01110,
0b00000,
0b00000
};
//check icon
const char c_check[8] PROGMEM = {
0b00000,
0b10101,
0b01110,
0b11011,
0b01110,
0b10101,
0b00000,
0b00000
};
//check icon
const char c_check_inv[8] PROGMEM = {
0b00000,
0b01010,
0b11111,
0b01010,
0b11111,
0b01010,
0b00000,
0b00000
};
const char c_cross[8] PROGMEM = {
0b00000,
0b01110,
0b10101,
0b11011,
0b01110,
0b01110,
0b00000,
0b00000
};
const char c_cross_inv[8] PROGMEM = {
0b00000,
0b01110,
0b10101,
0b11011,
0b01110,
0b01010,
0b01110,
0b00000
};
//cross icon
const char c_cross2[8] PROGMEM = {
0b00000,
0b01110,
0b10101,
0b11111,
0b01110,
0b01010,
0b00100,
0b00000
};
//cross icon
const char c_cross_inv2[8] PROGMEM = {
0b00000,
0b01110,
0b10101,
0b11111,
0b01110,
0b01110,
0b00000,
0b00000
};
//heart icon
const char c_heart[8] PROGMEM = {
0b00000,
0b01010,
0b11111,
0b11111,
0b01110,
0b00100,
0b00000,
0b00000
};
//heart icon
const char c_heart_inv[8] PROGMEM = {
0b00000,
0b01010,
0b11111,
0b01110,
0b01110,
0b00100,
0b00000,
0b00000
};
//compressor icon
const char c_compressor[8] PROGMEM = {
0b11111,
0b10001,
0b11111,
0b10101,
0b00100,
0b01010,
0b00100,
0b00000
};
//compressor icon
const char c_compressor_inv[8] PROGMEM = {
0b11111,
0b11111,
0b10101,
0b10101,
0b00100,
0b01010,
0b00100,
0b00000
};
//fan icon
const char c_fan[8] PROGMEM = {
B00000,
B00000,
B10011,
B10100,
B01110,
B00101,
B11001,
B00000
};
//fan icon
const char c_fan_inv[8] PROGMEM = {
B00000,
B00000,
B00010,
B10100,
B01110,
B00101,
B01000,
B00000
};
//hum icon
const char c_hum[8] PROGMEM = {
B00100,
B00100,
B01010,
B01010,
B10001,
B10001,
B10001,
B01110
};
//hum icon
const char c_hum_inv[8] PROGMEM = {
B00100,
B00100,
B01010,
B01010,
B10011,
B10111,
B11111,
B01110
};
//temp icon
const char c_temp_inv[8] PROGMEM = {
B00100,
B01010,
B01010,
B01010,
B01010,
B11111,
B11111,
B01110
};
//temp icon
const char c_temp[8] PROGMEM = {
B00100,
B01010,
B01010,
B01110,
B01110,
B11111,
B11111,
B01110
};
#endif
const char hex[17] PROGMEM = "0123456789ABCDEF";
char* id;
char* start_str;
bool condensate_avail(void)
{
return (bool)(digitalRead(PIN_CONDENSATE_LEVEL) == 0);
}
void ID()
{
#ifdef SERIAL_CONTROL
PRINT(">ID:");
PRINT(id);
PRINT(F(":"));
PRINTLN(getBuildTime());
#endif
}
void reboot(void) {
eeprom_write_byte((uint8_t*)EEPROM_BOOTLOADER_FLAG_OFFSET, EEPROM_BOOTLOADER_MAGIC_VALUE);
cli();
TCCR0A = TCCR1A = TCCR2A = 0; // make sure interrupts are off and timers are reset.
#ifdef WDT
wdt_enable(WDTO_1S);
while (1);
#endif
}
void restart_code(void) {
#ifdef WDT
wdt_enable(WDTO_1S);
while (1);
#endif
}
uint16_t crc16_update(uint16_t crc, uint8_t a)
{
int i;
crc ^= a;
for (i = 0; i < 8; ++i)
{
if (crc & 1)
crc = (crc >> 1) ^ 0xA001;
else
crc = (crc >> 1);
}
return crc;
}
char * uint_with_crc(uint16_t value) {
char * int_str = (char*) malloc(8);
sprintf(int_str, "%u", value);
realloc(int_str, strlen(int_str) + 1);
uint16_t crc = 0;
char * int_str_p = int_str;
// char * int_str_hex = (char*) malloc(strlen(int_str)*2+1);
// char * int_str_hex_ = int_str_hex;
while (*int_str_p != '\0') {
// *int_str_hex_++ = pgm_read_byte( &hex[(((*int_str_p) >> 4) & 0x0F)] );
// *int_str_hex_++ = pgm_read_byte( &hex[((*int_str_p) & 0x0F)] );
crc = crc16_update(crc, (uint8_t) * int_str_p++);
}
// *int_str_hex_ = '\0';
char * crc_str = (char*) malloc(8);
sprintf(crc_str, "%u", crc);
realloc(crc_str, strlen(crc_str) + 1);
// char * crc_str_p = crc_str;
// char * crc_str_hex = (char*) malloc(strlen(crc_str)*2+1);
// char * crc_str_hex_ = crc_str_hex;
// while(*crc_str_p++ != '\0') {
// *crc_str_hex_++ = pgm_read_byte( &hex[(*crc_str_p >> 4) & 0x0F] );
// *crc_str_hex_++ = pgm_read_byte( &hex[*crc_str_p & 0x0F] );
// }
// *crc_str_hex_ = '\0';
char * out_str = (char*) malloc(18);
// sprintf(out_str, "0x%s:0x%s", int_str_hex, crc_str_hex);
sprintf(out_str, "%s:%s", int_str, crc_str);
realloc(out_str, strlen(out_str) + 1);
free(int_str);
// free(int_str_hex);
free(crc_str);
// free(crc_str_hex);
return out_str;
}
char * str_crc(char * value) {
uint16_t crc = 0;
char * str_p = value;
while (*str_p != '\0') {
crc = crc16_update(crc, (uint8_t) * str_p++);
}
char * crc_str = (char*) malloc(8);
sprintf(crc_str, "%u", crc);
realloc(crc_str, strlen(crc_str) + 1);
return crc_str;
}
char * float_with_crc(float value) {
char * int_str = (char*) malloc(8);
dtostrf(value, -5, 1, int_str);
char * int_str_p = int_str;
while (*int_str_p++ != '\0') {
if (*int_str_p == 0x20) {
*int_str_p = '\0';
}
}
realloc(int_str, strlen(int_str) + 1);
uint16_t crc = 0;
int_str_p = int_str;
while (*int_str_p != '\0') {
crc = crc16_update(crc, (uint8_t) * int_str_p++);
}
char * crc_str = (char*) malloc(8);
sprintf(crc_str, "%u", crc);
realloc(crc_str, strlen(crc_str) + 1);
char * out_str = (char*) malloc(20);
sprintf(out_str, "%s:%s", int_str, crc_str);
realloc(out_str, strlen(out_str) + 1);
free(int_str);
free(crc_str);
return out_str;
}
#ifdef WDT
uint8_t mcusr_mirror __attribute__ ((section (".noinit")));
void get_mcusr(void) __attribute__((naked)) __attribute__((section(".init3")));
void get_mcusr(void) {
mcusr_mirror = MCUSR;
MCUSR = 0;
wdt_disable();
}
#endif
inline void big_time_from_sec(char * buffer, unsigned long seconds) {
if (seconds > 0) {
unsigned long hours = seconds / TIME_SECS_PER_HOUR;
unsigned long minutes = seconds / TIME_SECS_PER_MIN;
unsigned long mins_left = minutes % TIME_SECS_PER_MIN;
sprintf (buffer, "%02lu:%02lu", hours, mins_left);
} else {
sprintf (buffer, "00:00");
}
}
inline void time_from_sec(char * buffer, unsigned long seconds) {
if (seconds > 0) {
unsigned long hours = seconds / TIME_SECS_PER_HOUR;
unsigned long minutes = seconds / TIME_SECS_PER_MIN;
unsigned long mins_left = minutes % TIME_SECS_PER_MIN;
unsigned long secs_left = seconds % TIME_SECS_PER_MIN;
if (hours > 99) {
hours = 99;
}
sprintf (buffer, "%02lu:%02lu:%02lu", hours, mins_left, secs_left);
} else {
sprintf (buffer, "00:00:00");
}
}
void setup_eeprom() {
byte eeprom_state = 0;
//EEPROM.get(EEPROM_ADDR_STATE_INITIAL, eeprom_state);
if (eeprom_state == EEPROM_INIT_MAGIC) {
//PRINT_LCD_XY(F("ROM: OK"), 12, 3);
} else {
eeprom_state = EEPROM_INIT_MAGIC;
//EEPROM.put(EEPROM_ADDR_STATE_INITIAL, eeprom_state);
EEPROM_VAL_STATE_COMPRESSOR_T last_running_time = 0;
//EEPROM.put(EEPROM_ADDR_STATE_COMPRESSOR, last_running_time);
//PRINT_LCD_XY(F("ROM: INT"), 12, 3);
}
//delay(5000);
}
void setVFDspeed(uint16_t value) {
vfdSpeedPot.analogWrite(0, value);
}
EEPROM_VAL_STATE_COMPRESSOR_T get_compressor_runtime() {
EEPROM_VAL_STATE_COMPRESSOR_T last_running_time = 0;
// EEPROM.get(EEPROM_ADDR_STATE_COMPRESSOR, last_running_time);
// PRINT_LCD_XY("R ", 11, 0);
// PRINT_LCD_VALUE(last_running_time);
return last_running_time;
}
EEPROM_VAL_STATE_COMPRESSOR_T update_compressor_runtime(EEPROM_VAL_STATE_COMPRESSOR_T running_time) {
EEPROM_VAL_STATE_COMPRESSOR_T last_running_time = get_compressor_runtime();
if (running_time > 0) {
last_running_time += running_time;
#ifndef CALIBRATION
//PRINT_LCD_XY("W ", 0, 0);
//PRINT_LCD_VALUE(last_running_time);
//CURSOR_LCD_XY(0, 1);
//PRINT_LCD_BIG_TIME(get_compressor_runtime());
#endif
// EEPROM.put(EEPROM_ADDR_STATE_COMPRESSOR, last_running_time);
}
return last_running_time;
}
void turn_on_condensate_pump() {
TURN_ON(REG_CONDENSATE_PUMP);
CondensatePumpStopTime = 0;
CondensatePumpStartTime = TIME_AS_SECONDS(CURRENT_TIME);
#ifdef SERIAL_STATUS
PRINTLN(F("Condensate pump: ON"));
#endif
}
void turn_off_condensate_pump() {
TURN_OFF(REG_CONDENSATE_PUMP);
CondensatePumpStopTime = TIME_AS_SECONDS(CURRENT_TIME);
CondensatePumpStartTime = 0;
#ifdef SERIAL_STATUS
PRINTLN(F("Condensate pump: OFF"));
#endif
}
void turn_on_compressor() {
TURN_ON(REG_COMPRESSOR);
CompressorStopTime = 0;
CompressorStartTime = TIME_AS_SECONDS(CURRENT_TIME);
#ifdef SERIAL_STATUS
PRINTLN(F("Compressor: ON"));
#endif
}
void turn_off_compressor() {
TURN_OFF(REG_COMPRESSOR);
CompressorStopTime = TIME_AS_SECONDS(CURRENT_TIME);
if (CompressorStartTime > 0) {
update_compressor_runtime(SEC_AS_MINS(TIME_AS_SECONDS(CURRENT_TIME) - CompressorStartTime));
}
CompressorStartTime = 0;
#ifdef SERIAL_STATUS
PRINTLN(F("Compressor: OFF"));
#endif
}
void turn_on_condenser_fan() {
TURN_ON(REG_CONDENSER_FAN);
#ifdef SERIAL_STATUS
PRINTLN(F("Condenser Fan: ON"));
#endif
}
void turn_off_condenser_fan() {
TURN_OFF(REG_CONDENSER_FAN);
#ifdef SERIAL_STATUS
PRINTLN(F("Condenser Fan: OFF"));
#endif
}
void turn_on_evaporator_fan() {
TURN_ON(REG_EVAPORATOR_FAN);
TURN_ON(REG_EVAPORATOR_BLOW_FAN);
#ifdef SERIAL_STATUS
PRINTLN(F("Evaporator Fan: ON"));
#endif
}
void turn_off_evaporator_fan() {
TURN_OFF(REG_EVAPORATOR_FAN);
TURN_OFF(REG_EVAPORATOR_BLOW_FAN);
#ifdef SERIAL_STATUS
PRINTLN(F("Evaporator Fan: OFF"));
#endif
}
void turn_on_evaporator_heater() {
TURN_ON(REG_EVAPORATOR_HEATER);
#ifdef SERIAL_STATUS
PRINTLN(F("Evaporator Heater: ON"));
#endif
}
void turn_off_evaporator_heater() {
TURN_OFF(REG_EVAPORATOR_HEATER);
#ifdef SERIAL_STATUS
PRINTLN(F("Evaporator Heater: OFF"));
#endif
}
state set_service_state(state State) {
//EEPROM.update(EEPROM_ADDR_STATE_COMPRESSOR, State);
if (!IS_NEW_STATE(State)) {
return State;
}
lcd_update_state(State);
prevState = runtimeState;
runtimeState = State;
if ( State == STATE_NORMAL ) {
turn_off_evaporator_heater();
turn_on_evaporator_fan();
turn_on_compressor();
turn_on_condenser_fan();
UnfreezeStartTime = 0;
CondensingStartTime = 0;
#ifdef SERIAL_STATUS
PRINTLN(F("State: NORMAL"));
#endif
#ifdef LCD_BLINK
LCD_BL(false);
#endif
}
else if ( State == STATE_COOLING ) {
turn_off_condensate_pump();
turn_on_evaporator_fan();
turn_off_compressor();
turn_on_condenser_fan();
UnfreezeStartTime = 0;
CondensingStartTime = 0;
#ifdef SERIAL_STATUS
PRINTLN(F("State: COOLING"));
#endif
#ifdef LCD_BLINK
LCD_BL(true);
#endif
}
else if ( State == STATE_UNFREEZING ) {
turn_on_evaporator_heater();
turn_off_condensate_pump();
turn_on_evaporator_fan();
turn_off_compressor();
turn_on_condenser_fan();
UnfreezeStartTime = TIME_AS_SECONDS(CURRENT_TIME);
CondensingStartTime = 0;
#ifdef SERIAL_STATUS
PRINTLN(F("State: UNFREEZING"));
#endif
#ifdef LCD_BLINK
LCD_BL(true);
#endif
}
else if ( State == STATE_CONDENSING ) {
turn_on_evaporator_heater();
turn_off_condensate_pump();
turn_off_compressor();
turn_off_evaporator_fan();
turn_on_condenser_fan();
UnfreezeStartTime = 0;
CondensingStartTime = TIME_AS_SECONDS(CURRENT_TIME);
#ifdef SERIAL_STATUS
PRINTLN(F("State: CONDENSING"));
#endif
#ifdef LCD_BLINK
LCD_BL(true);
#endif
}
else if ( State == STATE_SUSPEND ) {
turn_off_evaporator_heater();
turn_off_condensate_pump();
//turn_off_compressor();
turn_off_evaporator_fan();
//turn_on_condenser_fan();
#ifdef SERIAL_STATUS
PRINTLN(F("State: SUSPEND"));
#endif
#ifdef LCD_BLINK
LCD_BL(true);
#endif
}
else if ( State == STATE_RESUME ) {
turn_off_evaporator_heater();
turn_off_condensate_pump();
//turn_off_compressor();
turn_on_evaporator_fan();
//turn_on_condenser_fan();
#ifdef SERIAL_STATUS
PRINTLN(F("State: RESUME"));
#endif
#ifdef LCD_BLINK
LCD_BL(false);
#endif
}
return State;
}
state get_service_state() {
//state State;
//EEPROM.get(EEPROM_ADDR_STATE_COMPRESSOR, State);
return runtimeState;
//return State;
}
state check_service_state(float Temp) {
//if ( Temp < 0 ) {
//turn_off_compressor();
//return STATE;
//}
if ( STATE == STATE_INITIAL ) {
turn_off_compressor();
turn_on_condenser_fan();
// if ( Temp <= TRESHOLD_TEMP_COMPRESSOR_MIN ) {
// return set_service_state(STATE_NORMAL);
// } else {
return set_service_state(STATE_UNFREEZING);
// }
}
else if ( STATE == STATE_NORMAL ) {
//if (CompressorStartTime > 0) {
// if (((TIME_AS_SECONDS(CURRENT_TIME) - lastStateSaveTime) / HOURS_AS_SEC(1)) > 0) {
// update_compressor_runtime(SEC_AS_MINS(TIME_AS_SECONDS(CURRENT_TIME) - CompressorStartTime));
// }
//}
if (initialUnfreezeCycles < MAX_INITIAL_UNFREEZ_CYCLES) {
if ( TIME_AS_SECONDS(CURRENT_TIME) - CompressorStartTime >= TIME_AS_SECONDS(TIME_MAX_INITIAL_UNFREEZE) ) {
initialUnfreezeCycles++;
turn_off_compressor();
return set_service_state(STATE_UNFREEZING);
}
}
if ( Temp >= TRESHOLD_TEMP_COMPRESSOR_MAX ) {
turn_off_compressor();
return set_service_state(STATE_COOLING);
}
else {
if ( TIME_AS_SECONDS(CURRENT_TIME) - CompressorStartTime >= TIME_AS_SECONDS(TIME_MAX_COMPRESSOR_RUN) ) {
turn_off_compressor();
return set_service_state(STATE_UNFREEZING);
}
else {
TURN_ON(REG_CONDENSER_FAN);
TURN_ON(REG_COMPRESSOR);
TURN_ON(REG_EVAPORATOR_FAN);
TURN_ON(REG_EVAPORATOR_BLOW_FAN);
if (CondensatePumpStartTime > 0) {
if ( TIME_AS_SECONDS(CURRENT_TIME) - CondensatePumpStartTime >= TIME_AS_SECONDS(TIME_MAX_CONDENSATE_PUMP_RUN) ) {
turn_off_condensate_pump();
}
} else {
if (CondensatePumpStopTime > 0) {
//if ( TIME_AS_SECONDS(CURRENT_TIME) - CondensatePumpStopTime >= TIME_AS_SECONDS(TIME_CONDENSATE_EVAPORATION) ) {
if ( condensate_avail() ) {
turn_on_condensate_pump();
}
}
}
}
}
}
else if ( STATE == STATE_COOLING ) {
turn_off_compressor();
if ( Temp <= TRESHOLD_TEMP_COMPRESSOR_MIN ) {
return set_service_state(STATE_UNFREEZING);
}
}
else if ( STATE == STATE_UNFREEZING ) {
turn_off_compressor();
if ( TIME_AS_SECONDS(CURRENT_TIME) - UnfreezeStartTime >= TIME_AS_SECONDS(TIME_UNFREEZE_EVAPORATOR) ) {
return set_service_state(STATE_CONDENSING);
}
}
else if ( STATE == STATE_CONDENSING ) {
turn_off_compressor();
if ( (TIME_AS_SECONDS(CURRENT_TIME) - CondensingStartTime) >= TIME_AS_SECONDS(TIME_UNFREEZE_EVAPORATOR_CONDENSING) ) {
return set_service_state(STATE_NORMAL);
}
}
else if ( STATE == STATE_SUSPEND ) {
return set_service_state(STATE_SUSPEND);
}
else if ( STATE == STATE_RESUME ) {
//turn_on_compressor();
//turn_on_condenser_fan();
turn_on_evaporator_fan();
return set_service_state(STATE_NORMAL);
}
else {
turn_off_compressor();
return set_service_state(STATE_INITIAL);
}
return STATE_INITIAL;
}
#ifdef LCD
void create_lcd_char(int char_code, const char * lcd_char PROGMEM) {
int lcd_char_buff[8];
for (byte i = 0; i < 8; i++) lcd_char_buff[i] = pgm_read_byte( &lcd_char[i] );
lcd.createChar(char_code, lcd_char_buff);
}
#endif
#ifdef LCD
int setup_lcd()
{
Wire.begin();
Wire.beginTransmission(LCD_ADDRESS);
lcd.begin(20, 4);
int lcd_status = Wire.endTransmission();
LCDavail = (lcd_status == 0);
CREATE_LCD_CHAR(LCD_CHAR_TEMP, c_temp);
CREATE_LCD_CHAR(LCD_CHAR_HUMIDITY, c_hum);
CREATE_LCD_CHAR(LCD_CHAR_CLOCK, c_clock);
CREATE_LCD_CHAR(LCD_CHAR_HEART, c_heart);
CREATE_LCD_CHAR(LCD_CHAR_DUCK, c_duck);
CREATE_LCD_CHAR(LCD_CHAR_CHECK, c_check);
CREATE_LCD_CHAR(LCD_CHAR_CROSS, c_cross);
CREATE_LCD_CHAR(LCD_CHAR_FAN, c_fan);
BL_LCD_ON;
CLEAR_LCD;
return lcd_status;
}
#endif
void setup_fan_pwm()
{
digitalWrite(PIN_PWM_FAN_EVAPORATOR, HIGH);
digitalWrite(PIN_PWM_FAN_CONDENSER, HIGH);
// PWM output @ 25 kHz, only on pins 9 and 10.
// Configure Timer 1 for PWM @ 25 kHz.
TCCR1A = 0; // undo the configuration done by...
TCCR1B = 0; // ...the Arduino core library
TCNT1 = 0; // reset timer
TCCR1A = _BV(COM1A1) // non-inverted PWM on ch. A
| _BV(COM1B1) // same on ch; B
| _BV(WGM11); // mode 10: ph. correct PWM, TOP = ICR1
TCCR1B = _BV(WGM13) // ditto
| _BV(CS10); // prescaler = 1
ICR1 = 320; // TOP = 320
// Set the PWM pins as output. Only pins 9 and 10 will work.
pinMode(PIN_PWM_FAN_EVAPORATOR, OUTPUT);
}
void setup_regs()
{
digitalWrite(PIN_SHIFT_REG_LATCH, HIGH);
digitalWrite(PIN_SHIFT_REG_CLOCK, HIGH);
digitalWrite(PIN_SHIFT_REG_DATA, HIGH);
shift.setBitCount(SHIFT_REGS);
shift.setPins(PIN_SHIFT_REG_DATA, PIN_SHIFT_REG_CLOCK, PIN_SHIFT_REG_LATCH);
TURN_OFF_ALL;
}
#ifdef VIBRATION_SENSOR
void init_accelerometer() {
acceleration_sensor.init(LSM303::device_DLHC);
acceleration_sensor.enableDefault();
acceleration_sensor.writeAccReg(LSM303::CTRL_REG2_A, ACCEL_RANGE_REG); //8G range
}
#endif
#ifdef SERIAL_CONTROL
void cmd_unrecognized(SerialCommands* sender, const char* cmd)
{
#ifdef CHECK_DEVICE_ADDR_ARG
char* addr_str = sender->Next();
if (addr_str == NULL || strcmp(id, addr_str) != 0)
return;
#endif
PRINT(">");
#ifdef CHECK_DEVICE_ADDR
PRINT(id);
PRINT(":");
#endif
PRINT(F("ERROR:UNKNOWN_COMMAND:"));
PRINTLN(cmd);
}
#endif
#ifdef SERIAL_CONTROL
void cmd_digital_read(SerialCommands* sender)
{
#ifdef CHECK_DEVICE_ADDR_ARG
char* addr_str = sender->Next();
if (addr_str == NULL || strcmp(id, addr_str) != 0)
return;
#endif
char* port_str = sender->Next();
if (port_str == NULL)
{
PRINT(">");
#ifdef CHECK_DEVICE_ADDR
PRINT(id);
PRINT(":");
#endif
PRINTLN(F("DREAD:ERROR:NO_PORT"));
return;
}
#ifdef CHECK_CRC
char* port_crc_str = sender->Next();
if (port_crc_str == NULL)
{
PRINT(">");
#ifdef CHECK_DEVICE_ADDR
PRINT(id);
PRINT(":");
#endif
PRINTLN(F("AREAD:ERROR:NO_PORT_CRC"));
return;
}
#endif
int port = atoi(port_str);
int value = -1;
switch (port)
{
case 2:
value = digitalRead(2);
break;
default:
PRINT(">");
#ifdef CHECK_DEVICE_ADDR
PRINT(id);
PRINT(":");
#endif
PRINTLN(F("DREAD:ERROR:INVALID_PORT"));
return;
}
PRINT(">");
#ifdef CHECK_DEVICE_ADDR
PRINT(id);
PRINT(":");
#endif
PRINT(F("DREAD:"));
PRINT(port);
PRINT(":");
char * value_str = uint_with_crc(value);
PRINTLN(value_str);
free(value_str);
}
#endif
#ifdef SERIAL_CONTROL
void cmd_analog_read(SerialCommands* sender)
{
#ifdef CHECK_DEVICE_ADDR_ARG
char* addr_str = sender->Next();
if (addr_str == NULL || strcmp(id, addr_str) != 0)
return;
#endif
char* port_str = sender->Next();
if (port_str == NULL)
{
PRINT(">");
#ifdef CHECK_DEVICE_ADDR
PRINT(id);
PRINT(":");
#endif
PRINTLN(F("ERROR:NO_PORT"));
return;
}
int port = atoi(port_str);
int value = -1;
switch (port)
{
case 0:
value = analogRead(A0);
break;
case 1:
value = analogRead(A1);
break;
case 2:
value = analogRead(A2);
break;
}
PRINT(">");
#ifdef CHECK_DEVICE_ADDR
PRINT(id);
PRINT(":");
#endif
PRINT(F("ANALOG_READ:"));
PRINT(port);
PRINT(":");
char * value_str = uint_with_crc(value);
PRINTLN(value_str);
free(value_str);
}
#endif
#ifdef SERIAL_CONTROL
void cmd_reg_on(SerialCommands* sender)
{
#ifdef CHECK_DEVICE_ADDR_ARG
char* addr_str = sender->Next();
if (addr_str == NULL || strcmp(id, addr_str) != 0)
return;
#endif
char* reg_str = sender->Next();
if (reg_str == NULL)
{
PRINT(">");
#ifdef CHECK_DEVICE_ADDR
PRINT(id);
PRINT(":");
#endif
PRINTLN(F("ERROR:NO_REG"));
return;
}
int reg = atoi(reg_str);
TURN_ON(reg);
PRINT(">");
#ifdef CHECK_DEVICE_ADDR
PRINT(id);
PRINT(":");
#endif
PRINT(F("REG_ON:"));
PRINT(reg);
PRINT(":");
PRINTLN("1");
}
#endif
#ifdef SERIAL_CONTROL
void cmd_reg_off(SerialCommands* sender)
{
#ifdef CHECK_DEVICE_ADDR_ARG
char* addr_str = sender->Next();
if (addr_str == NULL || strcmp(id, addr_str) != 0)
return;
#endif
char* reg_str = sender->Next();
if (reg_str == NULL)
{
PRINT(">");
#ifdef CHECK_DEVICE_ADDR
PRINT(id);
PRINT(":");
#endif
PRINTLN(F("ERROR:NO_REG"));
return;
}
int reg = atoi(reg_str);
TURN_OFF(reg);
PRINT(">");
#ifdef CHECK_DEVICE_ADDR
PRINT(id);
PRINT(":");
#endif
PRINT(F("REG_OFF:"));
PRINT(reg);
PRINT(":");
PRINTLN("0");
}
#endif
#ifdef SERIAL_CONTROL
void cmd_fan_pwm(SerialCommands* sender)
{
#ifdef CHECK_DEVICE_ADDR_ARG
char* addr_str = sender->Next();
if (addr_str == NULL || strcmp(id, addr_str) != 0)
return;
#endif
char* pwm_str = sender->Next();
if (pwm_str == NULL)
{
PRINT(">");
#ifdef CHECK_DEVICE_ADDR
PRINT(id);
PRINT(":");
#endif
PRINTLN(F("ERROR:NO_PWM"));
return;
}
int pwm = atoi(pwm_str);
int fan_pwm = constrain(map(pwm, 0, 100, TRESHOLD_PWM_MIN, TRESHOLD_PWM_MAX), TRESHOLD_PWM_MIN, TRESHOLD_PWM_MAX);
PWM_EVAPORATOR(fan_pwm);
PWM_CONDENSER(fan_pwm);
PRINT(">");
#ifdef CHECK_DEVICE_ADDR
PRINT(id);
PRINT(":");
#endif
PRINT(F("FAN_PWM:"));
PRINT(pwm);
PRINT(":");
PRINTLN(fan_pwm);
}
#endif
#ifdef SERIAL_CONTROL
void cmd_temp(SerialCommands* sender)
{
#ifdef CHECK_DEVICE_ADDR_ARG
char* addr_str = sender->Next();
if (addr_str == NULL || strcmp(id, addr_str) != 0)
return;
#endif
while (temp_sensors.selectNext())
{
float tempC = temp_sensors.getTempC();
PRINT(">");
#ifdef CHECK_DEVICE_ADDR
PRINT(id);
PRINT(":");
#endif
PRINT(F("TEMP:LIST:"));
temp_sensors.getAddress(thermometer);
for (uint8_t i = 0; i < 8; i++)
{
if (thermometer[i] < 0x10) { PRINT("0"); }
PRINT(thermometer[i], HEX);
}
PRINT(":");
char * value_str = float_with_crc(tempC);
PRINTLN(value_str);
free(value_str);
}
}
#endif
#ifdef SERIAL_CONTROL
void cmd_stop(SerialCommands* sender)
{
#ifdef CHECK_DEVICE_ADDR_ARG
char* addr_str = sender->Next();
if (addr_str == NULL || strcmp(id, addr_str) != 0)
return;
#endif
is_running = false;
set_service_state(STATE_COOLING);
TURN_OFF_ALL;
PRINT(">");
#ifdef CHECK_DEVICE_ADDR
PRINT(id);
PRINT(":");
#endif
PRINTLN(F("STOP"));
}
#endif
#ifdef SERIAL_CONTROL
void cmd_start(SerialCommands* sender)
{
#ifdef CHECK_DEVICE_ADDR_ARG
char* addr_str = sender->Next();
if (addr_str == NULL || strcmp(id, addr_str) != 0)
return;
#endif
is_running = true;
set_service_state(STATE_COOLING);
PRINT(">");
#ifdef CHECK_DEVICE_ADDR
PRINT(id);
PRINT(":");
#endif
PRINTLN(F("START"));
}
#endif
#ifdef SERIAL_CONTROL
void cmd_ping(SerialCommands* sender)
{
#ifdef CHECK_DEVICE_ADDR_ARG
char* addr_str = sender->Next();
if (addr_str == NULL || strcmp(id, addr_str) != 0)
return;
#endif
lastPing = CURRENT_TIME;
PRINT(">");
#ifdef CHECK_DEVICE_ADDR
PRINT(id);
PRINT(":");
#endif
PRINTLN(F("PONG"));
}
#endif
#ifdef SERIAL_CONTROL
void cmd_uptime(SerialCommands* sender)
{
#ifdef CHECK_DEVICE_ADDR_ARG
char* addr_str = sender->Next();
if (addr_str == NULL || strcmp(id, addr_str) != 0)
return;
#endif
PRINT(">");
#ifdef CHECK_DEVICE_ADDR
PRINT(id);
PRINT(":");
#endif
PRINT(F("UPTIME:"));
PRINT_TIME(get_compressor_runtime());
PRINTLN();
}
#endif
#ifdef SERIAL_CONTROL
void cmd_mode(SerialCommands* sender)
{
#ifdef CHECK_DEVICE_ADDR_ARG
char* addr_str = sender->Next();
if (addr_str == NULL || strcmp(id, addr_str) != 0)
return;
#endif
char* mode_str = sender->Next();
if (mode_str == NULL)
{
PRINT(">");
#ifdef CHECK_DEVICE_ADDR
PRINT(id);
PRINT(":");
#endif
PRINTLN(F("ERROR:NO_MODE"));
return;
}
runMode = atoi(mode_str);
PRINT(">");
#ifdef CHECK_DEVICE_ADDR
PRINT(id);
PRINT(":");
#endif
PRINT(F("MODE:"));
PRINTLN(runMode);
}
#endif
#ifdef SERIAL_CONTROL
void cmd_set_state(SerialCommands* sender)
{
#ifdef CHECK_DEVICE_ADDR_ARG
char* addr_str = sender->Next();
if (addr_str == NULL || strcmp(id, addr_str) != 0)
return;
#endif
char* state_str = sender->Next();
if (state_str == NULL)
{
PRINT(">");
#ifdef CHECK_DEVICE_ADDR
PRINT(id);
PRINT(":");
#endif
PRINTLN(F("ERROR:NO_STATE"));
return;
}
byte run_state = atoi(state_str);
set_service_state((state)run_state);
PRINT(">");
#ifdef CHECK_DEVICE_ADDR
PRINT(id);
PRINT(":");
#endif
PRINT(F("STATE:"));
PRINTLN(run_state);
}
#endif
#ifdef SERIAL_CONTROL
void cmd_vfd(SerialCommands* sender)
{
#ifdef CHECK_DEVICE_ADDR_ARG
char* addr_str = sender->Next();
if (addr_str == NULL || strcmp(id, addr_str) != 0)
return;
#endif
char* value_str = sender->Next();
if (value_str == NULL)
{
PRINT(">");
#ifdef CHECK_DEVICE_ADDR
PRINT(id);
PRINT(":");
#endif
PRINTLN(F("ERROR:NO_VALUE"));
return;
}
uint16_t value = atoi(value_str);
setVFDspeed(value);
PRINT(">");
#ifdef CHECK_DEVICE_ADDR
PRINT(id);
PRINT(":");
#endif
PRINT(F("VFD:"));
PRINTLN(value);
}
#endif
#ifdef SERIAL_CONTROL
void cmd_reboot(SerialCommands* sender)
{
#ifdef CHECK_DEVICE_ADDR_ARG
char* addr_str = sender->Next();
if (addr_str == NULL || strcmp(id, addr_str) != 0)
return;
#endif
TURN_OFF_ALL;
digitalWrite(13, HIGH);
PRINT(">");
#ifdef CHECK_DEVICE_ADDR
PRINT(id);
PRINT(":");
#endif
PRINTLN(F("REBOOT"));
digitalWrite(13, LOW);
reboot();
}
#endif
#ifdef SERIAL_CONTROL
void cmd_reset(SerialCommands* sender)
{
#ifdef CHECK_DEVICE_ADDR_ARG
char* addr_str = sender->Next();
if (addr_str == NULL || strcmp(id, addr_str) != 0)
return;
#endif
TURN_OFF_ALL;
digitalWrite(13, HIGH);
PRINT(">");
#ifdef CHECK_DEVICE_ADDR
PRINT(id);
PRINT(":");
#endif
PRINTLN(F("RESET"));
digitalWrite(13, LOW);
restart_code();
}
#endif
#ifdef SERIAL_CONTROL
void cmd_discover(SerialCommands* sender)
{
PRINT(">ID:");
PRINT(id);
PRINT(F(":"));
PRINTLN(getBuildTime());
}
#endif
float get_compressor_temp()
{
if(temp_sensors.select(compressorThermometer)) {
#ifdef MA_SMOOTH
//return compressor_sensor_filter.reading(TEMP_ADC_C(analogRead(PIN_SENSOR_COMPRESSOR)));
return compressor_sensor_filter.reading(temp_sensors.getTempC());
#endif
#ifdef EWMA_SMOOTH
//return TEMP_ADC_C(compressor_sensor_filter.filter(analogRead(PIN_SENSOR_COMPRESSOR)));
return compressor_sensor_filter.filter(temp_sensors.getTempC());
#endif
#ifdef SIMPLE_SMOOTH
// subtract the last reading:
compressor_total -= compressor_readings[compressor_readIndex];
// read from the sensor:
compressor_readings[compressor_readIndex] = temp_sensors.getTempC();
// add the reading to the total:
compressor_total += compressor_readings[compressor_readIndex];
// advance to the next position in the array:
if (++compressor_readIndex >= SMOOTH_GET_COMPRESSOR_TEMP_READINGS) {
compressor_readIndex = 0;
}
// calculate the average:
return (compressor_total / SMOOTH_GET_COMPRESSOR_TEMP_READINGS);
#endif
} else {
return 0.0;
}
}
float get_condenser_temp() {
//return 30.0;
if (temp_sensors.select(condenserThermometer)) {
#ifdef MA_SMOOTH
//return condenser_sensor_filter.reading(TEMP_ADC_C_ADJ(analogRead(PIN_SENSOR_CONDENSER), TEMP_ADC_ADJ_CONDENSER));
return condenser_sensor_filter.reading(temp_sensors.getTempC());
#endif
#ifdef EWMA_SMOOTH
//return TEMP_ADC_C_ADJ(condenser_sensor_filter.filter(analogRead(PIN_SENSOR_CONDENSER)), TEMP_ADC_ADJ_CONDENSER);
return condenser_sensor_filter.filter(temp_sensors.getTempC());
#endif
#ifdef SIMPLE_SMOOTH
// subtract the last reading:
condenser_total -= condenser_readings[condenser_readIndex];
// read from the sensor:
condenser_readings[condenser_readIndex] = temp_sensors.getTempC();
// add the reading to the total:
condenser_total += condenser_readings[condenser_readIndex];
// advance to the next position in the array:
if (++condenser_readIndex >= SMOOTH_GET_CONDENSER_TEMP_READINGS) {
condenser_readIndex = 0;
}
// calculate the average:
condenser_last = (condenser_total / SMOOTH_GET_CONDENSER_TEMP_READINGS);
#endif
}
return condenser_last;
}
#ifdef LED
void update_status_led(unsigned int fanPower) {
// flash the LED corresponding to the sensor value
if (CURRENT_TIME - ledMillis >= fanPower) {
ledMillis = CURRENT_TIME; // save the last time you toggled the LED
byte ledPinStatus = digitalRead(PIN_LED_STATUS);
digitalWrite(PIN_LED_STATUS, byte(!ledPinStatus)); // toggle the PIN_LED_STATUS
if (bool(ledPinStatus)) {
CREATE_LCD_CHAR(LCD_CHAR_FAN, c_fan_inv);
} else {
CREATE_LCD_CHAR(LCD_CHAR_FAN, c_fan);
}
}
}
#endif
#ifdef LCD
void lcd_update_values(float compressorTemp, float condenserTemp, unsigned int pwmValue)
{
CURSOR_LCD_XY(0, 0);
// PRINT_LCD_XY("P ", 0, 0);
PRINT_LCD_CHAR(LCD_CHAR_TEMP);
// PRINT_LCD_TEXT(" ");
PRINT_LCD_VALUE(compressorTemp, 1);
PRINT_LCD_CHAR(LCD_CHAR_GRAD);
PRINT_LCD_TEXT(" ");
CURSOR_LCD_XY(7, 0);
// PRINT_LCD_XY("C ", 10, 0);
PRINT_LCD_CHAR(LCD_CHAR_TEMP);
// PRINT_LCD_TEXT(" ");
PRINT_LCD_VALUE(condenserTemp, 1);
PRINT_LCD_CHAR(LCD_CHAR_GRAD);
PRINT_LCD_TEXT(" ");
CURSOR_LCD_XY(14, 0);
// PRINT_LCD_XY("F ", 0, 1);
PRINT_LCD_CHAR(LCD_CHAR_FAN);
// PRINT_LCD_TEXT(" ");
PRINT_LCD_VALUE(PWM_AS_PERCENT(pwmValue), 1);
PRINT_LCD_TEXT(" ");
for (byte thisReg = 0; thisReg < SHIFT_REGS; thisReg++) {
CURSOR_LCD_XY(((20 - (SHIFT_REGS / 2)) + thisReg) - ((thisReg / (SHIFT_REGS / 2)) * (SHIFT_REGS / 2)), 1 + (thisReg / (SHIFT_REGS / 2)));
if (SHIFT_REGS_STATE[thisReg] == LOW) {
PRINT_LCD_CHAR(LCD_CHAR_CROSS);
} else {
PRINT_LCD_CHAR(LCD_CHAR_HEART);
}
}
lcd_bar(0, 1, 16, 100, PWM_AS_PERCENT(pwmValue));
}
#endif
#ifdef LCD
void lcd_bar(byte bar_x, byte bar_y, byte bar_len, unsigned long max_val, unsigned long val) {
byte len = bar_len - 2;
unsigned long time_cells = val / (max_val / len);
byte x = bar_x + 1;
PRINT_LCD_XY("[", bar_x, bar_y);
PRINT_LCD_XY("]", bar_x + bar_len - 1, bar_y);
for (byte i = 0; i < time_cells; i++) {
CURSOR_LCD_XY(x + i, bar_y);
PRINT_LCD_CHAR(LCD_CHAR_BAR);
}
for (byte i = time_cells; i < len; i++) {
CURSOR_LCD_XY(x + i, bar_y);
PRINT_LCD_CHAR(LCD_CHAR_DASH);
}
}
#endif
#ifdef LCD
void lcd_update_status()
{
if (LCDavail) {
if (CURRENT_TIME - lcdMillis >= TIME_INTERVAL_STATUS_LCD) {
// save the last time you sent a message
lcdMillis = CURRENT_TIME;
if (runMode == RUN_MODE_MASTER) {
if ( STATE == STATE_NORMAL ) {
if (initialUnfreezeCycles < MAX_INITIAL_UNFREEZ_CYCLES) {
//PRINT_LCD_TIMING((TIME_AS_SECONDS(CURRENT_TIME) - CompressorStartTime), (TIME_AS_SECONDS(TIME_MAX_INITIAL_UNFREEZE) - (TIME_AS_SECONDS(CURRENT_TIME) - CompressorStartTime)));
PRINT_LCD_TIMING((TIME_AS_SECONDS(TIME_MAX_INITIAL_UNFREEZE) - (TIME_AS_SECONDS(CURRENT_TIME) - CompressorStartTime)));
lcd_bar(0, 2, 16, (TIME_AS_SECONDS(TIME_MAX_INITIAL_UNFREEZE)), (TIME_AS_SECONDS(TIME_MAX_INITIAL_UNFREEZE) - (TIME_AS_SECONDS(CURRENT_TIME) - CompressorStartTime)));
} else {
//PRINT_LCD_TIMING((TIME_AS_SECONDS(CURRENT_TIME) - CompressorStartTime), (TIME_AS_SECONDS(TIME_MAX_COMPRESSOR_RUN) - (TIME_AS_SECONDS(CURRENT_TIME) - CompressorStartTime)));
PRINT_LCD_TIMING((TIME_AS_SECONDS(TIME_MAX_COMPRESSOR_RUN) - (TIME_AS_SECONDS(CURRENT_TIME) - CompressorStartTime)));
lcd_bar(0, 2, 16, (TIME_AS_SECONDS(TIME_MAX_COMPRESSOR_RUN)), (TIME_AS_SECONDS(TIME_MAX_COMPRESSOR_RUN) - (TIME_AS_SECONDS(CURRENT_TIME) - CompressorStartTime)));
}
}
else if ( STATE == STATE_UNFREEZING ) {
//PRINT_LCD_TIMING((TIME_AS_SECONDS(CURRENT_TIME) - UnfreezeStartTime), (TIME_AS_SECONDS(TIME_UNFREEZE_EVAPORATOR) - (TIME_AS_SECONDS(CURRENT_TIME) - UnfreezeStartTime)));
PRINT_LCD_TIMING((TIME_AS_SECONDS(TIME_UNFREEZE_EVAPORATOR) - (TIME_AS_SECONDS(CURRENT_TIME) - UnfreezeStartTime)));
lcd_bar(0, 2, 16, (TIME_AS_SECONDS(TIME_UNFREEZE_EVAPORATOR)), ((TIME_AS_SECONDS(TIME_UNFREEZE_EVAPORATOR)) - (TIME_AS_SECONDS(CURRENT_TIME) - UnfreezeStartTime)));
}
else if ( STATE == STATE_CONDENSING ) {
//PRINT_LCD_TIMING((TIME_AS_SECONDS(CURRENT_TIME) - CondensingStartTime), (TIME_AS_SECONDS(TIME_UNFREEZE_EVAPORATOR_CONDENSING) - (TIME_AS_SECONDS(CURRENT_TIME) - CondensingStartTime)));
PRINT_LCD_TIMING((TIME_AS_SECONDS(TIME_UNFREEZE_EVAPORATOR_CONDENSING) - (TIME_AS_SECONDS(CURRENT_TIME) - CondensingStartTime)));
lcd_bar(0, 2, 16, (TIME_AS_SECONDS(TIME_UNFREEZE_EVAPORATOR_CONDENSING)), (TIME_AS_SECONDS(TIME_UNFREEZE_EVAPORATOR_CONDENSING) - (TIME_AS_SECONDS(CURRENT_TIME) - CondensingStartTime)));
}
else if ( STATE == STATE_COOLING ) {
PRINT_LCD_TIMING((TIME_AS_SECONDS(CURRENT_TIME) - CompressorStopTime));
}
else if ( STATE == STATE_INITIAL ) {
CURSOR_LCD_XY(0, 3);
PRINT_LCD_CHAR(LCD_CHAR_CLOCK);
CURSOR_LCD_XY(2, 3);
PRINT_LCD_BIG_TIME(get_compressor_runtime());
}
else if ( STATE == STATE_SUSPEND ) {
CURSOR_LCD_XY(0, 3);
PRINT_LCD_CHAR(LCD_CHAR_CLOCK);
CURSOR_LCD_XY(2, 3);
PRINT_LCD_BIG_TIME(get_compressor_runtime());
}
else if ( STATE == STATE_RESUME ) {
CURSOR_LCD_XY(0, 3);
PRINT_LCD_CHAR(LCD_CHAR_CLOCK);
CURSOR_LCD_XY(2, 3);
PRINT_LCD_BIG_TIME(get_compressor_runtime());
}
else {
}
} else if (runMode == RUN_MODE_SLAVE) {
if ( STATE == STATE_NORMAL ) {
PRINT_LCD_TIMING((TIME_AS_SECONDS(CURRENT_TIME) - CompressorStartTime));
}
else if ( STATE == STATE_UNFREEZING ) {
PRINT_LCD_TIMING((TIME_AS_SECONDS(CURRENT_TIME) - UnfreezeStartTime));
}
else if ( STATE == STATE_CONDENSING ) {
PRINT_LCD_TIMING((TIME_AS_SECONDS(CURRENT_TIME) - CondensingStartTime));
}
else if ( STATE == STATE_COOLING ) {
PRINT_LCD_TIMING((TIME_AS_SECONDS(CURRENT_TIME) - CompressorStopTime));
}
else if ( STATE == STATE_INITIAL ) {
}
else if ( STATE == STATE_SUSPEND ) {
}
else if ( STATE == STATE_RESUME ) {
}
else {
}
}
}
}
}
#endif
#ifdef LCD
void lcd_update_state(state State)
{
if (LCDavail) {
if (runMode == RUN_MODE_MASTER) {
if ( State == STATE_NORMAL ) {
PRINT_LCD_STATUS(LCD_CHAR_CHECK, "CHILL ");
}
else if ( State == STATE_UNFREEZING ) {
PRINT_LCD_STATUS(LCD_CHAR_HUMIDITY, "DEFROST ");
}
else if ( State == STATE_CONDENSING ) {
PRINT_LCD_STATUS(LCD_CHAR_HUMIDITY, "CONDENSE");
}
else if ( State == STATE_COOLING ) {
PRINT_LCD_STATUS(LCD_CHAR_CROSS, "OVERHEAT");
}
else if ( State == STATE_INITIAL ) {
PRINT_LCD_STATUS(LCD_CHAR_CHECK, "INIT ");
}
else if ( State == STATE_SUSPEND ) {
PRINT_LCD_STATUS(LCD_CHAR_CHECK, "STANDBY ");
}
else if ( State == STATE_RESUME ) {
PRINT_LCD_STATUS(LCD_CHAR_CHECK, "RESUME ");
}
else {
PRINT_LCD_STATUS(LCD_CHAR_CHECK, "CONFIG ");
}
} else {
PRINT_LCD_STATUS(LCD_CHAR_CHECK, "SLAVE ");
}
}
}
#endif
#ifdef SERIAL_STATUS
void serial_send_state(float compressorTemp, float condenserTemp, unsigned int pwmValue)
{
if (CURRENT_TIME - serialMillis >= TIME_INTERVAL_STATUS_SERIAL) {
// save the last time you sent a message
serialMillis = CURRENT_TIME;
PRINT(F("Compressor: "));
PRINT(compressorTemp, TEMP_FORMAT); // display Celsius
PRINT(F("C Condenser: "));
PRINT(condenserTemp, TEMP_FORMAT); // display Celsius
PRINT(F("C Condenser Fan: "));
PRINT(pwmValue, TEMP_FORMAT);
// PRINT(" Evaporator Fan: ");
// PRINT(pwmValue, TEMP_FORMAT);
if ( STATE == STATE_NORMAL ) {
unsigned long comressor_start = TIME_AS_SECONDS(CURRENT_TIME) - CompressorStartTime;
unsigned long comressor_stoped = TIME_AS_SECONDS(TIME_MAX_COMPRESSOR_RUN) - comressor_start;
PRINT(F(" Compressor runtime: "));
PRINT(comressor_start, TEMP_FORMAT); // display Celsius
PRINT(F("s run / "));
PRINT(comressor_stoped, TEMP_FORMAT); // display Celsius
PRINT(F("s to stop"));
}
else if ( STATE == STATE_UNFREEZING ) {
unsigned long unfreeze_start = TIME_AS_SECONDS(CURRENT_TIME) - UnfreezeStartTime;
unsigned long unfreeze_stoped = TIME_AS_SECONDS(TIME_UNFREEZE_EVAPORATOR) - unfreeze_start;
PRINT(F(" Unfreeze runtime: "));
PRINT(unfreeze_start, TEMP_FORMAT); // display Celsius
PRINT(F("s run / "));
PRINT(unfreeze_stoped, TEMP_FORMAT); // display Celsius
PRINT(F("s to stop"));
}
else if ( STATE == STATE_CONDENSING ) {
unsigned long condensing_start = TIME_AS_SECONDS(CURRENT_TIME) - CondensingStartTime;
unsigned long condensing_stoped = TIME_AS_SECONDS(TIME_UNFREEZE_EVAPORATOR_CONDENSING) - condensing_start;
PRINT(F(" Condensing runtime: "));
PRINT(condensing_start, TEMP_FORMAT); // display Celsius
PRINT(F("s run / "));
PRINT(condensing_stoped, TEMP_FORMAT); // display Celsius
PRINT(F("s to stop"));
}
else if ( STATE == STATE_COOLING ) {
PRINT(F(" State: cooling"));
}
else if ( STATE == STATE_INITIAL ) {
PRINT(F(" State: initial"));
}
else {
PRINT(F(" State: unknown"));
}
PRINTLN("");
}
}
#endif
#ifdef VIBRATION_SENSOR
float get_acceleration_velocity() {
acceleration_sensor.readAcc();
#ifdef MA_SMOOTH
return acceleration_sensor_filter.reading(ACCEL_VECTOR(acceleration_sensor.a.x, acceleration_sensor.a.y, acceleration_sensor.a.z));
#endif
#ifdef EWMA_SMOOTH
return acceleration_sensor_filter.filter(ACCEL_VECTOR(acceleration_sensor.a.x, acceleration_sensor.a.y, acceleration_sensor.a.z));
#endif
#ifdef SIMPLE_SMOOTH
// subtract the last reading:
acceleration_total -= acceleration_readings[acceleration_readIndex];
// read from the sensor:
acceleration_readings[acceleration_readIndex] = ACCEL_VECTOR(acceleration_sensor.a.x, acceleration_sensor.a.y, acceleration_sensor.a.z);
// add the reading to the total:
acceleration_total += acceleration_readings[acceleration_readIndex];
// advance to the next position in the array:
if (++acceleration_readIndex >= SMOOTH_GET_ACCELERATION_READINGS) {
acceleration_readIndex = 0;
}
// calculate the average:
return (acceleration_total / SMOOTH_GET_ACCELERATION_READINGS);
#endif
}
#endif
#ifdef VIBRATION_SENSOR
void measure_vibration() {
float acceleration = get_acceleration_velocity();
#ifdef LCD
CURSOR_LCD_XY(14, 2);
PRINT_LCD_CHAR(LCD_CHAR_DUCK);
PRINT_LCD_VALUE(acceleration);
#endif
}
#endif
void setup_id() {
id = (char*) malloc(sizeof(char) * (UniqueIDsize * 2 + 1));
start_str = (char*) malloc(sizeof(char) * (UniqueIDsize * 2 + 2));
char *id_ = id;
char *start_str_ = start_str;
for (size_t i = 0; i < UniqueIDsize; i++)
{
*id_++ = pgm_read_byte( &hex[(UniqueID[i] >> 4) & 0x0F] );
*id_++ = pgm_read_byte( &hex[UniqueID[i] & 0x0F] );
}
*id_ = '\0';
*start_str_ = '\0';
char *id_crc = str_crc(id);
free(id);
id = id_crc;
strcat(start_str, id);
strcat(start_str, ":");
realloc(start_str, strlen(start_str) + 1);
//serial_commands_.SetStart(start_str);
}
void setup_vfd() {
vfdSpeedPot.begin();
setVFDspeed(0);
}
void setup()
{
#ifdef WDT
wdt_disable();
#endif
setup_regs();
setup_fan_pwm();
setup_eeprom();
setup_id();
setup_vfd();
pinMode(3, OUTPUT);
digitalWrite(3, HIGH);
#ifdef LED
// declare the PIN_LED_STATUS as an output:
pinMode(PIN_LED_STATUS, OUTPUT);
#endif
pinMode(PIN_CONDENSATE_LEVEL, INPUT);
//analogReference(EXTERNAL);
#ifdef SERIAL_CONTROL
// initialize the serial port
pinMode(PIN_SER_TX_ENABLE_SERIAL0, OUTPUT);
digitalWrite(PIN_SER_TX_ENABLE_SERIAL0, LOW);
SERIAL_PORT.begin(SERIAL_DEFAULT_BAUD_RATE);
ID();
serial_commands_.SetDefaultHandler(cmd_unrecognized);
serial_commands_.AddCommand(&cmd_analog_read_);
serial_commands_.AddCommand(&cmd_digital_read_);
serial_commands_.AddCommand(&cmd_reg_on_);
serial_commands_.AddCommand(&cmd_reg_off_);
serial_commands_.AddCommand(&cmd_fan_pwm_);
serial_commands_.AddCommand(&cmd_temp_);
serial_commands_.AddCommand(&cmd_ping_);
serial_commands_.AddCommand(&cmd_mode_);
serial_commands_.AddCommand(&cmd_set_state_);
serial_commands_.AddCommand(&cmd_vfd_);
serial_commands_.AddCommand(&cmd_uptime_);
serial_commands_.AddCommand(&cmd_reset_);
serial_commands_.AddCommand(&cmd_reboot_);
serial_commands_.AddCommand(&cmd_stop_);
serial_commands_.AddCommand(&cmd_start_);
serial_commands_.AddCommand(&cmd_discover_);
#endif
#ifdef LCD
if (setup_lcd() == 0) {
#ifdef SERIAL_STATUS
PRINTLN(F("LCD found."));
#endif
} else {
#ifdef SERIAL_STATUS
PRINTLN(F("LCD not found."));
#endif
} // if
#endif
#ifdef VIBRATION_SENSOR
init_accelerometer();
#endif
#ifdef WDT
//check_last_wdt_cause();
#endif
#ifdef LCD
PRINT_LCD_XY(F("CALIBRATION..."), 3, 0);
PRINT_LCD_XY("R ", 0, 3);
PRINT_LCD_CHAR(LCD_CHAR_CLOCK);
CURSOR_LCD_XY(4, 3);
PRINT_LCD_BIG_TIME(get_compressor_runtime());
#endif
if(temp_sensors.select(compressorThermometer)) {
temp_sensors.setResolution(TEMP_PRECISION);
}
if (temp_sensors.select(condenserThermometer)) {
temp_sensors.setResolution(TEMP_PRECISION);
}
#ifdef CALIBRATION
float calibration_temp = 0.0;
if(temp_sensors.select(compressorThermometer)) {
calibration_temp = temp_sensors.getTempC();
}
#ifdef SIMPLE_SMOOTH
for (int thisReading = 0; thisReading < SMOOTH_GET_COMPRESSOR_TEMP_READINGS; thisReading++) {
compressor_readings[thisReading] = compressor_average = calibration_temp;//analogRead(PIN_SENSOR_COMPRESSOR);
compressor_total += compressor_average;
//delay(10);
#ifdef LCD
PRINT_LCD_XY("P ", 0, 1);
PRINT_LCD_VALUE(TEMP_ADC_C(compressor_average), 1);
#endif
}
calibration_temp = 35.0;
if(temp_sensors.select(condenserThermometer)) {
calibration_temp = temp_sensors.getTempC();
}
for (int thisReading = 0; thisReading < SMOOTH_GET_CONDENSER_TEMP_READINGS; thisReading++) {
condenser_readings[thisReading] = condenser_average = calibration_temp;//analogRead(PIN_SENSOR_CONDENSER);
condenser_total += condenser_average;
//delay(10);
#ifdef LCD
PRINT_LCD_XY("C ", 0, 2);
PRINT_LCD_VALUE(TEMP_ADC_C_ADJ(condenser_average, TEMP_ADC_ADJ_CONDENSER), 1);
#endif
}
#ifdef VIBRATION_SENSOR
for (int thisReading = 0; thisReading < SMOOTH_GET_ACCELERATION_READINGS; thisReading++) {
acceleration_readings[thisReading] = acceleration_average = get_acceleration_velocity();
acceleration_total += acceleration_average;
#ifdef LCD
PRINT_LCD_XY("C ", 0, 3);
PRINT_LCD_VALUE(acceleration_average, 1);
#endif
}
#endif
#endif
#endif
#ifdef LCD
BL_LCD_ON;
CLEAR_LCD;
#endif
#ifdef WDT
wdt_enable(WDTO_8S);
#endif
}
void loop()
{
#ifdef WDT
wdt_reset();
#endif
SERIAL_TX_DISABLE;
serial_commands_.ReadSerial();
if (is_running) {
if ((runMode != RUN_MODE_MASTER) && PING_TIMEOUT) {
runMode = RUN_MODE_MASTER;
}
#ifdef VIBRATION_SENSOR
measure_vibration();
#endif
if (CURRENT_TIME - measureMillis >= TIME_INTERVAL_MEASURE_SENSOR) {
measureMillis = CURRENT_TIME;
//temp_sensors.requestTemperatures();
float compressorTemp = get_compressor_temp();
float condenserTemp = get_condenser_temp();
// temp to fan speed
unsigned int fanPower = PWM_PID(condenserTemp);
// set the fan speed (PWM output at 25 kHz) per the sensor value
// this may need to be changed to (320 - sensorValue) or less
if (runMode == RUN_MODE_MASTER) {
PWM_EVAPORATOR(PWM_INVERT(fanPower));
PWM_CONDENSER(fanPower);
check_service_state(compressorTemp);
}
lastStatusLEDvalue = fanPower;
#ifdef LCD
#ifdef CALIBRATION
lcd_update_values(compressorTemp, condenserTemp, fanPower);
#endif
#endif
#ifdef SERIAL_STATUS
serial_send_state(compressorTemp, condenserTemp, fanPower);
#endif
}
#ifdef LED
update_status_led(lastStatusLEDvalue);
#endif
// check_switches();
RESET_REGS;
#ifdef LCD
if (CURRENT_TIME - LCDBcharMillis >= TIME_INTERVAL_LCD_CHAR) {
LCDBcharMillis = CURRENT_TIME;
if ((LCDchar_state = (bool)(!LCDchar_state))) {
//CREATE_LCD_CHAR(LCD_CHAR_FAN, c_fan_inv);
CREATE_LCD_CHAR(LCD_CHAR_HUMIDITY, c_hum_inv);
CREATE_LCD_CHAR(LCD_CHAR_HEART, c_heart_inv);
CREATE_LCD_CHAR(LCD_CHAR_TEMP, c_temp_inv);
CREATE_LCD_CHAR(LCD_CHAR_CROSS, c_cross_inv);
CREATE_LCD_CHAR(LCD_CHAR_CHECK, c_check_inv);
CREATE_LCD_CHAR(LCD_CHAR_CLOCK, c_clock_inv);
} else {
//CREATE_LCD_CHAR(LCD_CHAR_FAN, c_fan);
CREATE_LCD_CHAR(LCD_CHAR_HUMIDITY, c_hum);
CREATE_LCD_CHAR(LCD_CHAR_HEART, c_heart);
CREATE_LCD_CHAR(LCD_CHAR_TEMP, c_temp);
CREATE_LCD_CHAR(LCD_CHAR_CROSS, c_cross);
CREATE_LCD_CHAR(LCD_CHAR_CHECK, c_check);
CREATE_LCD_CHAR(LCD_CHAR_CLOCK, c_clock);
}
}
lcd_update_status();
#ifdef LCD_BLINK
if (runMode == RUN_MODE_MASTER) {
if (LCDavail) {
if (CURRENT_TIME - LCDBlinkMillis >= TIME_INTERVAL_LCD_BLINK) {
LCDBlinkMillis = CURRENT_TIME;
if (LCDblink) {
if ((LCDblink_state = (bool)(!LCDblink_state))) {
BL_LCD_ON;
} else {
BL_LCD_OFF;
}
} else {
BL_LCD_ON;
}
}
}
} else {
if ((bool)(!LCDblink_state)) BL_LCD_ON;
}
#endif
#endif
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment