ESP32_ChinaDieselHeater_Con.../Arduino/BTCDieselHeater/Protocol.cpp

395 lines
9.7 KiB
C++

/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
*
* 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 3 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include <Arduino.h>
#include "Protocol.h"
#include "debugport.h"
#include "helpers.h"
unsigned short
CProtocol::CalcCRC(int len) const
{
// calculate a CRC-16/MODBUS checksum using the first 22 bytes of the data array
unsigned short wCRCWord = 0xFFFF;
int wLength = len;
const unsigned char* pData = Data;
while (wLength--)
{
unsigned char nTemp = *pData++ ^ wCRCWord;
wCRCWord >>= 8;
wCRCWord ^= wCRCTable[nTemp];
}
return wCRCWord;
}
void
CProtocol::setCRC()
{
setCRC(CalcCRC(22));
}
void
CProtocol::setCRC(unsigned short CRC)
{
Data[22] = (CRC >> 8) & 0xff; // MSB of CRC in Data[22]
Data[23] = (CRC >> 0) & 0xff; // LSB of CRC in Data[23]
}
unsigned short
CProtocol::getCRC() const
{
unsigned short CRC;
CRC = Data[22]; // MSB of CRC in Data[22]
CRC <<= 8;
CRC |= Data[23]; // LSB of CRC in Data[23]
return CRC;
}
// return true for CRC match
bool
CProtocol::verifyCRC(bool bSilent) const
{
unsigned short CRC = CalcCRC(22); // calculate CRC based on first 22 bytes
unsigned short FrameCRC = getCRC();
bool bOK = (FrameCRC == CRC);
if(!bOK && !bSilent) {
DebugPort.print("verifyCRC FAILED: calc:");
DebugPort.print(CRC, HEX);
DebugPort.print(" data:");
DebugPort.println(FrameCRC, HEX);
}
return bOK; // does it match the stored values?
}
CProtocol&
CProtocol::operator=(const CProtocol& rhs)
{
memcpy(Data, rhs.Data, 24);
return *this;
}
void
CProtocol::setFan_Min(short Speed)
{
// Minimum speed set
Controller.MinFanRPM_MSB = (Speed >> 8) & 0xff;
Controller.MinFanRPM_LSB = (Speed >> 0) & 0xff;
}
void
CProtocol::setFan_Max(short Speed)
{
// Minimum speed set
Controller.MaxFanRPM_MSB = (Speed >> 8) & 0xff;
Controller.MaxFanRPM_LSB = (Speed >> 0) & 0xff;
}
short
CProtocol::getFan_Min() const
{
short retval;
// Minimum speed get
retval = Controller.MinFanRPM_MSB;
retval <<= 8;
retval |= Controller.MinFanRPM_LSB;
return retval;
}
short
CProtocol::getFan_Max() const
{
short retval;
// Maximum speed get
retval = Controller.MaxFanRPM_MSB;
retval <<= 8;
retval |= Controller.MaxFanRPM_LSB;
return retval;
}
short
CProtocol::getFan_Actual() const
{
// Rx side, actual
short retval;
retval = Heater.FanRPM_MSB;
retval <<= 8;
retval |= Heater.FanRPM_LSB;
return retval;
}
void
CProtocol::setFan_Actual(short Speed) // Heater side, actual
{
// actual speed set
Heater.FanRPM_MSB = (Speed >> 8) & 0xff;
Heater.FanRPM_LSB = (Speed >> 0) & 0xff;
}
float
CProtocol::getGlowPlug_Current() const // glow plug current
{
short val;
val = Heater.GlowPlugCurrent_MSB;
val <<= 8;
val |= Heater.GlowPlugCurrent_LSB;
return float(val) * 0.01f; // 10mA / digit
}
void
CProtocol::setGlowPlug_Current(short ampsx100) // glow plug current
{
Heater.GlowPlugCurrent_MSB = (ampsx100 >> 8) & 0xff;
Heater.GlowPlugCurrent_LSB = (ampsx100 >> 0) & 0xff;
}
float
CProtocol::getGlowPlug_Voltage() const // glow plug voltage
{
short val;
val = Heater.GlowPlugVoltage_MSB;
val <<= 8;
val |= Heater.GlowPlugVoltage_LSB;
return float(val) * 0.1f; // 0.1V / digit
}
void
CProtocol::setGlowPlug_Voltage(short voltsx10) // glow plug voltage
{
Heater.GlowPlugVoltage_MSB = (voltsx10 >> 8) & 0xff;
Heater.GlowPlugVoltage_LSB = (voltsx10 >> 0) & 0xff;
}
short
CProtocol::getTemperature_HeatExchg() const // temperature of heat exchanger
{
short retval;
retval = Heater.HeatExchgTemp_MSB;
retval <<= 8;
retval |= Heater.HeatExchgTemp_LSB;
return retval;
}
void
CProtocol::setTemperature_HeatExchg(short degC) // temperature of heat exchanger
{
Heater.HeatExchgTemp_MSB = (degC >> 8) & 0xff;
Heater.HeatExchgTemp_LSB = (degC >> 0) & 0xff;
}
float
CProtocol::getFan_Voltage() const // fan voltage
{
if(getRunState()) { // fan volatge sensing goes stupid when main heater relay turns off!
short val;
val = Heater.FanVoltage_MSB;
val <<= 8;
val |= Heater.FanVoltage_LSB;
return float(val) * 0.1;
}
return 0;
}
void
CProtocol::setFan_Voltage(float volts) // fan voltage
{
short val = short(volts * 10);
Heater.FanVoltage_MSB = (val >> 8) & 0xff;
Heater.FanVoltage_LSB = (val >> 0) & 0xff;
}
void
CProtocol::setVoltage_Supply(float volts)
{
short val = short(volts * 10);
Heater.SupplyV_MSB = (val >> 8) & 0xff;
Heater.SupplyV_LSB = (val >> 0) & 0xff;
}
float
CProtocol::getVoltage_SupplyRaw() const
{
short val = 0;
val = Heater.SupplyV_MSB & 0xff;
val <<= 8;
val |= Heater.SupplyV_LSB & 0xff;
float voltage = float(val) * 0.1f;
return voltage;
}
float
CProtocol::getVoltage_Supply() const
{
return getVoltage_SupplyRaw() + 0.6; // compensate for series protection diode
}
void
CProtocol::Init(int FrameMode)
{
if(FrameMode == CtrlMode) {
Controller.Byte0 = 0x76;
Controller.Len = 22;
Controller.Command = 0; // NOP
setTemperature_Actual(18); // 1degC / digit
setTemperature_Desired(20); // 1degC / digit
setPump_Min(1.4f); // Hz
setPump_Max(4.3f); // Hz
setFan_Min(1450); // 1RPM / digit
setFan_Max(4500); // 1RPM / digit
Controller.OperatingVoltage = 120; // 0.1V/digit
Controller.FanSensor = 1; // SN-1 or SN-2
Controller.OperatingMode = 0x32; // 0x32:Thermostat, 0xCD:Fixed
setTemperature_Min(8); // Minimum settable temperature
setTemperature_Max(35); // Maximum settable temperature
Controller.MinTempRise = 5; // temp rise to sense fuel ignition - GLOW PLUG POWER?
Controller.Prime = 0; // 00: normal, 0x5A: fuel prime
Controller.Unknown1_MSB = 0x01; // always 0x01
Controller.Unknown1_LSB = 0x2c; // always 0x2c 16bit: "300 secs = max run without burn detected" ??
Controller.Unknown2_MSB = 0x0d; // always 0x0d
Controller.Unknown2_LSB = 0xac; // always 0xac 16bit: "3500" ?? Ignition fan max RPM????
setCRC();
}
else if(FrameMode == HeatMode){
Heater.Byte0 = 0x76;
Heater.Len = 22;
setRunState(0);
setErrState(0);
setVoltage_Supply(133);
setFan_Actual(0);
setFan_Voltage(0);
setTemperature_HeatExchg(18);
setGlowPlug_Voltage(0);
setGlowPlug_Current(0);
Heater.ActualPumpFreq = 0; // fuel pump freq.: 0.1Hz / digit
Heater.StoredErrorCode = 0; //
Heater.Unknown1 = 0; // always 0x00
Heater.FixedPumpFreq = 23; // fixed mode frequency set point: 0.1Hz / digit
Heater.Unknown2 = 100; // always 0x64 "100 ?"
Heater.Unknown3 = 0; // always 0x00
setCRC();
}
else {
memset(Data, 0, 24);
}
}
void
CProtocol::DebugReport(const char* hdr, const char* ftr)
{
DebugPort.print(hdr); // header
for(int i=0; i<24; i++) {
char str[16];
sprintf(str, " %02X", Data[i]); // build 2 dig hex values
DebugPort.print(str); // and print
}
DebugPort.print(ftr); // footer
}
void
CProtocol::setThermostatMode(unsigned on)
{
Controller.OperatingMode = on ? 0x32 : 0xCD;
if(!on)
setTemperature_Actual(0); // if using fixed mode, actual must be reported as 0
};
const char* Runstates [] PROGMEM = {
" Stopped/Ready ",
"Starting...",
"Igniting...",
"Ignition retry pause",
"Ignited",
"Running",
"Stopping",
"Shutting down",
"Cooling",
"Heating glow plug",
"Unknown run state"
};
const char*
CProtocolPackage::getRunStateStr() const
{
uint8_t runstate = Heater.getRunState();
UPPERLIMIT(runstate, 10);
if(runstate == 2 && getPump_Actual() == 0) { // split runstate 2 - glow, then fuel
runstate = 9;
}
return Runstates[runstate];
}
const char* Errstates [] PROGMEM = {
"",
"",
"Low voltage", // E-01
"High voltage", // E-02
"Glow plug fault", // E-03
"Pump fault", // E-04
"Overheat", // E-05
"Motor fault", // E-06
"Comms fault", // E-07
"Flame out", // E-08
"Temp sense", // E-09
"Ignition fail", // E-10
"Failed 1st ignition attempt", // E-11
"Unknown error?" // mystery code!
};
const char* ErrstatesEx [] PROGMEM = {
"E-00: OK",
"E-00: OK",
"E-01: Low voltage", // E-01
"E-02: High voltage", // E-02
"E-03: Glow plug fault", // E-03
"E-04: Pump fault", // E-04
"E-05: Overheat", // E-05
"E-06: Motor fault", // E-06
"E-07: Comms fault", // E-07
"E-08: Flame out", // E-08
"E-09: Temp sense", // E-09
"E-10: Ignition fail", // E-10
"E-11: Failed 1st ignition attempt", // E-11
"Unknown error?" // mystery code!
};
const char*
CProtocolPackage::getErrStateStr() const
{
uint8_t errstate = Heater.getErrState();
UPPERLIMIT(errstate, 13);
return Errstates[errstate];
}
const char*
CProtocolPackage::getErrStateStrEx() const
{
uint8_t errstate = Heater.getErrState();
UPPERLIMIT(errstate, 13);
return ErrstatesEx[errstate];
}