// VERSION 3
#include <EEPROM.h>
#include <CRC32.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define pinInpT 2
#define pinInpACOK 3
#define pinInpBatLow 4
#define pinInpAux 5
#define pinOutLedBat 6
#define pinOutLedPlc 7
#define pinOutBeep 8
#define pinOutBatCtrl 9
#define pinOutAcCtrl 10
#define pinOutAux 11
#define pinOutLedRun LED_BUILTIN
#define VERSION 3
#define REQUEST_LEN 15
#define REQUEST_TIMEOUT 100
#define DEFAULT_TIMEOUT_SERIAL 10
#define DEFAULT_TIMEOUT_BATCTRL 5
#define ADDR_SERIAL_CONNECTED 0
#define ADDR_BAT_CTRL 2
#define ADDR_BEEP_MODE 8
OneWire oneWire(pinInpT);
DallasTemperature dallasTemp(&oneWire);
int T;
boolean outBeep;
boolean outBatCtrl;
boolean outAcCtrl;
boolean outAux;
boolean outLedBat;
boolean outLedPlc;
boolean manual_BatCtrl;
int beep_mode;
int timeBatCtrl;
int cntBatCtrl;
int cntLedPlc;
long ms;
int cnt5000ms;
int cnt1000ms;
int cnt200ms;
boolean serConnected;
int timeoutSerialConnected;
long serms;
int sercnt;
uint8_t serbuf[REQUEST_LEN];
boolean plcHasBeenDetected;
int lastACOKSentToPlc;
void setup() {
pinMode(pinInpACOK, INPUT);
pinMode(pinInpBatLow, INPUT);
pinMode(pinInpAux, INPUT);
pinMode(pinOutLedBat, OUTPUT);
pinMode(pinOutLedPlc, OUTPUT);
pinMode(pinOutBeep, OUTPUT);
pinMode(pinOutBatCtrl, OUTPUT);
pinMode(pinOutAcCtrl, OUTPUT);
pinMode(pinOutAux, OUTPUT);
pinMode(pinOutLedRun, OUTPUT);
Serial.begin(9600);
dallasTemp.begin();
dallasTemp.setWaitForConversion(false);
dallasTemp.requestTemperatures();
manual_BatCtrl = false;
cnt5000ms = 0;
cnt1000ms = 0;
cnt200ms = 0;
cntLedPlc = 0;
cntBatCtrl = 0;
plcHasBeenDetected = false;
lastACOKSentToPlc = 0;
sercnt = 0;
serConnected = false;
ms = millis();
EEPROM.get(ADDR_SERIAL_CONNECTED, timeoutSerialConnected);
EEPROM.get(ADDR_BAT_CTRL, timeBatCtrl);
EEPROM.get(ADDR_BEEP_MODE, beep_mode);
outAux = 0;
digitalWrite(pinOutAux, outAux);
validate_vars();
greeting();
}
void greeting() {
Serial.print("UPS NANO version ");
Serial.println(VERSION);
Serial.print("SerTimeout = ");
Serial.println(timeoutSerialConnected);
Serial.print("BatCtrlTimeout = ");
Serial.println(timeBatCtrl);
}
void validate_vars() {
if(timeBatCtrl <= 0)
timeBatCtrl = 1;
if(timeoutSerialConnected <= 0)
timeoutSerialConnected = 1;
if(beep_mode < 0 || beep_mode > 2)
beep_mode = 0;
}
void loop() {
long msdelta = millis() - ms;
if( msdelta >= 100 ) {
ms += 100;
loop100ms();
} else
if( msdelta < 0 ) {
msdelta += 0x80000000L;
if( msdelta >= 100 ) {
ms += 100 + 0x80000000L;
loop100ms();
}
}
if( Serial ) {
if( Serial.available() == 0 ) {
msdelta = millis() - serms;
if( msdelta < 0 )
msdelta += 0x80000000L;
if( sercnt > 0 && msdelta > REQUEST_TIMEOUT ) {
sercnt = 0;
serConnected = false;
}
if( serConnected && (msdelta/1000) >= timeoutSerialConnected ) {
serConnected = false;
}
} else {
while( Serial.available() > 0 ) {
serbuf[sercnt++] = Serial.read();
if( sercnt == REQUEST_LEN ) {
onSerRequest();
sercnt = 0;
}
}
serms = millis();
}
}
}
void loop100ms() {
if( cnt5000ms++ >= 50 ) {
cnt5000ms = 0;
loop5000ms();
}
if( cnt1000ms++ >= 10 ) {
cnt1000ms = 0;
loop1000ms();
}
if( cnt200ms++ >= 2 ) {
cnt200ms = 0;
loop200ms();
}
// led plc
if( !serConnected ) {
if( cntLedPlc++ < 10 )
outLedPlc = cntLedPlc % 2;
else if( cntLedPlc >= 30 ) {
outLedPlc = false;
cntLedPlc = 0;
}
} else
cntLedPlc = 0;
digitalWrite(pinOutLedPlc, !outLedPlc);
digitalWrite(pinOutLedRun, !outLedPlc);
digitalWrite(pinOutLedBat, outLedBat);
}
void loop200ms() {
// led bat
if( !digitalRead(pinInpACOK) ) {
if( (digitalRead(pinInpBatLow)) == HIGH )
outLedBat = !outLedBat;
else
outLedBat = HIGH;
} else
outLedBat = LOW;
}
void loop1000ms() {
if( serConnected )
outLedPlc = !outLedPlc;
// bat control
if( !manual_BatCtrl ) {
outBatCtrl = 1;
if( timeBatCtrl > 0 && !serConnected ) {
if( !digitalRead(pinInpACOK) ) {
if( cntBatCtrl >= timeBatCtrl ) {
outBatCtrl = 0;
} else
cntBatCtrl++;
} else
cntBatCtrl = 0;
}
}
digitalWrite(pinOutBatCtrl, outBatCtrl);
// beep
if( !digitalRead(pinInpACOK) ) {
if( outBeep = !outBeep )
// second arg:
// 1200 - normal tone
// 40 - debug tone (very low)
if( beep_mode == 0 )
tone(pinOutBeep, 1200, 1000);
else if( beep_mode == 1 )
tone(pinOutBeep, 40, 1000);
else
noTone(pinOutBeep);
}
// acctrl
outAcCtrl = !serConnected && plcHasBeenDetected && (lastACOKSentToPlc == 0);
digitalWrite(pinOutAcCtrl, outAcCtrl);
// temperature
int t = (int)round(dallasTemp.getTempCByIndex(0) * 10);
dallasTemp.requestTemperatures();
if( t > -500 && t < 1200 )
T = t;
}
void loop5000ms() {
}
void onSerRequest() {
serConnected = false;
uint32_t cs1 = CRC32::calculate(serbuf, REQUEST_LEN-4);
uint32_t cs2 =
(((uint32_t)serbuf[REQUEST_LEN-4])<<24) +
(((uint32_t)serbuf[REQUEST_LEN-3])<<16) +
(((uint32_t)serbuf[REQUEST_LEN-2])<<8) +
(uint32_t)serbuf[REQUEST_LEN-1];
if( cs1 != cs2 ) {
return;
}
if( serbuf[0] != VERSION ) {
sendErrorVersion();
return;
}
getSerbufValues();
sendGoodAnswer();
serConnected = true;
plcHasBeenDetected = true;
}
void sendGoodAnswer() {
lastACOKSentToPlc = digitalRead(pinInpACOK);
serbuf[0] = 0;
serbuf[1] = lastACOKSentToPlc + (digitalRead(pinInpBatLow))*2 + (digitalRead(pinInpAux))*4;
serbuf[2] = (T >> 8) & 0xFF;
serbuf[3] = T & 0xFF;
addSerbufCrc(4);
Serial.write(serbuf, 8);
}
void sendErrorVersion() {
serbuf[0] = 0xFF;
serbuf[1] = VERSION;
serbuf[2] = serbuf[3] = 0;
addSerbufCrc(4);
Serial.write(serbuf, 8);
}
void addSerbufCrc(int len) {
uint32_t cs = CRC32::calculate(serbuf, len);
serbuf[len++] = cs >> 24;
serbuf[len++] = (cs %= 0x1000000) >> 16;
serbuf[len++] = (cs %= 0x10000) >> 8;
serbuf[len++] = cs %= 0x100;
}
void getSerbufValues() {
timeBatCtrl =
(serbuf[1] << 8) +
serbuf[2];
timeoutSerialConnected =
(serbuf[3] << 8) +
serbuf[4];
if( outAux != serbuf[9] ) {
outAux = serbuf[9];
digitalWrite(pinOutAux, outAux);
}
beep_mode = (serbuf[10] >> 4) & 0xF;
validate_vars();
EEPROM.put(ADDR_SERIAL_CONNECTED, timeoutSerialConnected);
EEPROM.put(ADDR_BAT_CTRL, timeBatCtrl);
EEPROM.put(ADDR_BEEP_MODE, beep_mode);
}