changed to protocol.h/.cpp
This commit is contained in:
parent
9818b33e47
commit
961c5b8b29
|
@ -1,169 +0,0 @@
|
|||
#include <Arduino.h>
|
||||
#include "CFrame.h"
|
||||
|
||||
unsigned short
|
||||
CFrame::CalcCRC(int len)
|
||||
{
|
||||
// calculate a CRC-16/MODBUS checksum using the first 22 bytes of the data array
|
||||
unsigned short wCRCWord = 0xFFFF;
|
||||
|
||||
int wLength = len;
|
||||
unsigned char* pData = Data;
|
||||
while (wLength--)
|
||||
{
|
||||
unsigned char nTemp = *pData++ ^ wCRCWord;
|
||||
wCRCWord >>= 8;
|
||||
wCRCWord ^= wCRCTable[nTemp];
|
||||
}
|
||||
|
||||
return wCRCWord;
|
||||
}
|
||||
|
||||
void
|
||||
CFrame::setCRC()
|
||||
{
|
||||
setCRC(CalcCRC(22));
|
||||
}
|
||||
|
||||
void
|
||||
CFrame::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]
|
||||
}
|
||||
|
||||
CFrame&
|
||||
CFrame::operator=(CFrame& rhs)
|
||||
{
|
||||
memcpy(Data, rhs.Data, 24);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
unsigned short
|
||||
CFrame::getCRC()
|
||||
{
|
||||
unsigned short CRC;
|
||||
CRC = Data[22]; // MSB of CRC in Data[22]
|
||||
CRC <<= 8;
|
||||
CRC |= Data[23]; // LSB of CRC in Data[23]
|
||||
}
|
||||
|
||||
// return true for CRC match
|
||||
bool
|
||||
CFrame::verifyCRC()
|
||||
{
|
||||
unsigned short CRC = CalcCRC(22); // calculate CRC based on first 22 bytes
|
||||
return (getCRC() == CRC); // does it match the stored values?
|
||||
}
|
||||
|
||||
void
|
||||
CFrame::setFan_Min(short Speed)
|
||||
{
|
||||
// Minimum speed set
|
||||
Tx.MinFanRPM_MSB = (Speed >> 8) & 0xff;
|
||||
Tx.MinFanRPM_LSB = (Speed >> 0) & 0xff;
|
||||
}
|
||||
|
||||
void
|
||||
CFrame::setFan_Max(short Speed)
|
||||
{
|
||||
// Minimum speed set
|
||||
Tx.MaxFanRPM_MSB = (Speed >> 8) & 0xff;
|
||||
Tx.MaxFanRPM_LSB = (Speed >> 0) & 0xff;
|
||||
}
|
||||
|
||||
short
|
||||
CFrame::getFan_Min()
|
||||
{
|
||||
short retval;
|
||||
// Minimum speed get
|
||||
retval = Tx.MinFanRPM_MSB;
|
||||
retval <<= 8;
|
||||
retval |= Tx.MinFanRPM_LSB;
|
||||
return retval;
|
||||
}
|
||||
|
||||
short
|
||||
CFrame::getFan_Max()
|
||||
{
|
||||
short retval;
|
||||
// Maximum speed get
|
||||
retval = Tx.MaxFanRPM_MSB;
|
||||
retval <<= 8;
|
||||
retval |= Tx.MaxFanRPM_LSB;
|
||||
return retval;
|
||||
}
|
||||
|
||||
short
|
||||
CFrame::getFan_Actual()
|
||||
{
|
||||
// Rx side, actual
|
||||
short retval;
|
||||
retval = Rx.FanRPM_MSB;
|
||||
retval <<= 8;
|
||||
retval |= Rx.FanRPM_LSB;
|
||||
return retval;
|
||||
}
|
||||
|
||||
short
|
||||
CFrame::getTemperature_GlowPin() // temperature of glow pin
|
||||
{
|
||||
short retval;
|
||||
retval = Rx.GlowPinTemp_MSB;
|
||||
retval <<= 8;
|
||||
retval |= Rx.GlowPinPWMDuty_LSB;
|
||||
return retval;
|
||||
}
|
||||
|
||||
short
|
||||
CFrame::getTemperature_HeatExchg() // temperature of heat exchanger
|
||||
{
|
||||
short retval;
|
||||
retval = Rx.HeatExchgTemp_MSB;
|
||||
retval <<= 8;
|
||||
retval |= Rx.HeatExchgTemp_LSB;
|
||||
return retval;
|
||||
}
|
||||
|
||||
short
|
||||
CFrame::getTemperature_Inlet() // temperature near inlet
|
||||
{
|
||||
short retval;
|
||||
retval = Rx.InletTemp_MSB;
|
||||
retval <<= 8;
|
||||
retval |= Rx.InletTemp_LSB;
|
||||
return retval;
|
||||
}
|
||||
|
||||
void
|
||||
CFrame::Init(int Txmode)
|
||||
{
|
||||
if(Txmode) {
|
||||
Tx.Byte0 = 0x76;
|
||||
Tx.Len = 22;
|
||||
Tx.Command = 0; // NOP
|
||||
setTemperature_Actual(18); // 1degC / digit
|
||||
setTemperature_Desired(20); // 1degC / digit
|
||||
setPump_Min(14); // 0.1Hz/digit
|
||||
setPump_Max(43); // 0.1Hz/digit
|
||||
setFan_Min(1450); // 1RPM / digit
|
||||
setFan_Max(4500); // 1RPM / digit
|
||||
Tx.OperatingVoltage = 120; // 0.1V/digit
|
||||
Tx.FanSensor = 1; // SN-1 or SN-2
|
||||
Tx.OperatingMode = 0x32; // 0x32:Thermostat, 0xCD:Fixed
|
||||
setTemperature_Min(8); // Minimum settable temperature
|
||||
setTemperature_Max(35); // Maximum settable temperature
|
||||
Tx.MinTempRise = 5; // temp rise to sense fuel ignition
|
||||
Tx.Prime = 0; // 00: normal, 0x5A: fuel prime
|
||||
Tx.Unknown1_MSB = 0x01; // always 0x01
|
||||
Tx.Unknown1_LSB = 0x2c; // always 0x2c 16bit: "300 secs = max run without burn detected" ??
|
||||
Tx.Unknown2_MSB = 0x0d; // always 0x0d
|
||||
Tx.Unknown2_LSB = 0xac; // always 0xac 16bit: "3500" ??
|
||||
setCRC();
|
||||
}
|
||||
else {
|
||||
memset(Data, 0, 24);
|
||||
}
|
||||
}
|
||||
|
267
Arduino/SenderTrial2/Protocol.cpp
Normal file
267
Arduino/SenderTrial2/Protocol.cpp
Normal file
|
@ -0,0 +1,267 @@
|
|||
#include <Arduino.h>
|
||||
#include "Protocol.h"
|
||||
|
||||
unsigned short
|
||||
CFrame::CalcCRC(int len)
|
||||
{
|
||||
// calculate a CRC-16/MODBUS checksum using the first 22 bytes of the data array
|
||||
unsigned short wCRCWord = 0xFFFF;
|
||||
|
||||
int wLength = len;
|
||||
unsigned char* pData = Data;
|
||||
while (wLength--)
|
||||
{
|
||||
unsigned char nTemp = *pData++ ^ wCRCWord;
|
||||
wCRCWord >>= 8;
|
||||
wCRCWord ^= wCRCTable[nTemp];
|
||||
}
|
||||
|
||||
return wCRCWord;
|
||||
}
|
||||
|
||||
void
|
||||
CFrame::setCRC()
|
||||
{
|
||||
setCRC(CalcCRC(22));
|
||||
}
|
||||
|
||||
void
|
||||
CFrame::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
|
||||
CFrame::getCRC()
|
||||
{
|
||||
unsigned short CRC;
|
||||
CRC = Data[22]; // MSB of CRC in Data[22]
|
||||
CRC <<= 8;
|
||||
CRC |= Data[23]; // LSB of CRC in Data[23]
|
||||
}
|
||||
|
||||
// return true for CRC match
|
||||
bool
|
||||
CFrame::verifyCRC()
|
||||
{
|
||||
unsigned short CRC = CalcCRC(22); // calculate CRC based on first 22 bytes
|
||||
return (getCRC() == CRC); // does it match the stored values?
|
||||
}
|
||||
|
||||
CFrame&
|
||||
CFrame::operator=(const CFrame& rhs)
|
||||
{
|
||||
memcpy(Data, rhs.Data, 24);
|
||||
return *this;
|
||||
}
|
||||
|
||||
int
|
||||
CFrame::getCommand()
|
||||
{
|
||||
return Controller.Command;
|
||||
}
|
||||
|
||||
void
|
||||
CFrame::setCommand(int cmd)
|
||||
{
|
||||
Controller.Command = cmd;
|
||||
}
|
||||
|
||||
/*unsigned char getCommand();
|
||||
void setCommand(int mode);*/
|
||||
|
||||
|
||||
void
|
||||
CFrame::setFan_Min(short Speed)
|
||||
{
|
||||
// Minimum speed set
|
||||
Controller.MinFanRPM_MSB = (Speed >> 8) & 0xff;
|
||||
Controller.MinFanRPM_LSB = (Speed >> 0) & 0xff;
|
||||
}
|
||||
|
||||
void
|
||||
CFrame::setFan_Max(short Speed)
|
||||
{
|
||||
// Minimum speed set
|
||||
Controller.MaxFanRPM_MSB = (Speed >> 8) & 0xff;
|
||||
Controller.MaxFanRPM_LSB = (Speed >> 0) & 0xff;
|
||||
}
|
||||
|
||||
short
|
||||
CFrame::getFan_Min()
|
||||
{
|
||||
short retval;
|
||||
// Minimum speed get
|
||||
retval = Controller.MinFanRPM_MSB;
|
||||
retval <<= 8;
|
||||
retval |= Controller.MinFanRPM_LSB;
|
||||
return retval;
|
||||
}
|
||||
|
||||
short
|
||||
CFrame::getFan_Max()
|
||||
{
|
||||
short retval;
|
||||
// Maximum speed get
|
||||
retval = Controller.MaxFanRPM_MSB;
|
||||
retval <<= 8;
|
||||
retval |= Controller.MaxFanRPM_LSB;
|
||||
return retval;
|
||||
}
|
||||
|
||||
short
|
||||
CFrame::getFan_Actual()
|
||||
{
|
||||
// Rx side, actual
|
||||
short retval;
|
||||
retval = Heater.FanRPM_MSB;
|
||||
retval <<= 8;
|
||||
retval |= Heater.FanRPM_LSB;
|
||||
return retval;
|
||||
}
|
||||
|
||||
void
|
||||
CFrame::setFan_Actual(short Speed) // Heater side, actual
|
||||
{
|
||||
// actual speed set
|
||||
Heater.FanRPM_MSB = (Speed >> 8) & 0xff;
|
||||
Heater.FanRPM_LSB = (Speed >> 0) & 0xff;
|
||||
}
|
||||
|
||||
short
|
||||
CFrame::getGlowPlug_Current() // glow plug current
|
||||
{
|
||||
short retval;
|
||||
retval = Heater.GlowPlugCurrent_MSB;
|
||||
retval <<= 8;
|
||||
retval |= Heater.GlowPlugCurrent_LSB;
|
||||
return retval;
|
||||
}
|
||||
|
||||
void
|
||||
CFrame::setGlowPlug_Current(short ampsx100) // glow plug current
|
||||
{
|
||||
Heater.GlowPlugCurrent_MSB = (ampsx100 >> 8) & 0xff;
|
||||
Heater.GlowPlugCurrent_LSB = (ampsx100 >> 0) & 0xff;
|
||||
}
|
||||
|
||||
short
|
||||
CFrame::getGlowPlug_Voltage() // glow plug voltage
|
||||
{
|
||||
short retval;
|
||||
retval = Heater.GlowPlugVoltage_MSB;
|
||||
retval <<= 8;
|
||||
retval |= Heater.GlowPlugVoltage_LSB;
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CFrame::setGlowPlug_Voltage(short voltsx10) // glow plug voltage
|
||||
{
|
||||
Heater.GlowPlugVoltage_MSB = (voltsx10 >> 8) & 0xff;
|
||||
Heater.GlowPlugVoltage_LSB = (voltsx10 >> 0) & 0xff;
|
||||
}
|
||||
|
||||
short
|
||||
CFrame::getTemperature_HeatExchg() // temperature of heat exchanger
|
||||
{
|
||||
short retval;
|
||||
retval = Heater.HeatExchgTemp_MSB;
|
||||
retval <<= 8;
|
||||
retval |= Heater.HeatExchgTemp_LSB;
|
||||
return retval;
|
||||
}
|
||||
|
||||
void
|
||||
CFrame::setTemperature_HeatExchg(short degC) // temperature of heat exchanger
|
||||
{
|
||||
Heater.HeatExchgTemp_MSB = (degC >> 8) & 0xff;
|
||||
Heater.HeatExchgTemp_LSB = (degC >> 0) & 0xff;
|
||||
}
|
||||
|
||||
short
|
||||
CFrame::getFan_Voltage() // temperature near inlet
|
||||
{
|
||||
short retval;
|
||||
retval = Heater.FanVoltage_MSB;
|
||||
retval <<= 8;
|
||||
retval |= Heater.FanVoltage_LSB;
|
||||
return retval;
|
||||
}
|
||||
|
||||
void
|
||||
CFrame::setFan_Voltage(short voltsx10) // temperature near inlet
|
||||
{
|
||||
Heater.FanVoltage_MSB = (voltsx10 >> 8) & 0xff;
|
||||
Heater.FanVoltage_LSB = (voltsx10 >> 0) & 0xff;
|
||||
}
|
||||
|
||||
void
|
||||
CFrame::setVoltage_Supply(short voltsx10)
|
||||
{
|
||||
Heater.SupplyV_MSB = (voltsx10 >> 8) & 0xff;
|
||||
Heater.SupplyV_LSB = (voltsx10 >> 0) & 0xff;
|
||||
}
|
||||
|
||||
short
|
||||
CFrame::getVoltage_Supply()
|
||||
{
|
||||
short retval = 0;
|
||||
retval = Heater.SupplyV_MSB & 0xff;
|
||||
retval <<= 8;
|
||||
retval |= Heater.SupplyV_LSB & 0xff;
|
||||
}
|
||||
|
||||
void
|
||||
CFrame::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(14); // 0.1Hz/digit
|
||||
setPump_Max(43); // 0.1Hz/digit
|
||||
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
|
||||
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" ??
|
||||
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.ErrorCode = 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -30,24 +30,24 @@ public:
|
|||
unsigned char Unknown2_LSB; // [21] always 0xac "3500 ?"
|
||||
unsigned char CRC_MSB; // [22]
|
||||
unsigned char CRC_LSB; // [23]
|
||||
} Tx;
|
||||
} Controller;
|
||||
struct {
|
||||
unsigned char Byte0; // always 0x76
|
||||
unsigned char Len; // always 0x16 == 22
|
||||
unsigned char Len; // always 0x16 == 22 bytes
|
||||
unsigned char RunState; // operating state
|
||||
unsigned char OnOff; // 0: OFF, 1: ON
|
||||
unsigned char ErrState; // 0: OFF, 1: ON, 2+ (E-0n + 1)
|
||||
unsigned char SupplyV_MSB; // 16 bit - big endian MSB
|
||||
unsigned char SupplyV_LSB; // 16 bit - big endian MSB : 0.1V / digit
|
||||
unsigned char FanRPM_MSB; // 16 bit - big endian MSB
|
||||
unsigned char FanRPM_LSB; // 16 bit - big endian LSB : 1 RPM / digit
|
||||
unsigned char InletTemp_MSB; // 16 bit - big endian MSB
|
||||
unsigned char InletTemp_LSB; // 16 bit - big endian LSB : 1 degC / digit
|
||||
unsigned char FanVoltage_MSB; // 16 bit - big endian MSB
|
||||
unsigned char FanVoltage_LSB; // 16 bit - big endian LSB : 0.1V / digit
|
||||
unsigned char HeatExchgTemp_MSB; // 16 bit - big endian MSB
|
||||
unsigned char HeatExchgTemp_LSB; // 16 bit - big endian LSB : 1 degC / digit
|
||||
unsigned char GlowPinPWMDuty_MSB; // 16 bit - big endian MSB
|
||||
unsigned char GlowPinPWMDuty_LSB; // 16 bit - big endian LSB : 1% / digit
|
||||
unsigned char GlowPinTemp_MSB; // 16 bit - big endian MSB
|
||||
unsigned char GlowPinTemp_LSB; // 16 bit - big endian LSB : 1 degC / digit
|
||||
unsigned char GlowPlugVoltage_MSB; // 16 bit - big endian MSB
|
||||
unsigned char GlowPlugVoltage_LSB; // 16 bit - big endian LSB : 0.1V / digit
|
||||
unsigned char GlowPlugCurrent_MSB; // 16 bit - big endian MSB
|
||||
unsigned char GlowPlugCurrent_LSB; // 16 bit - big endian LSB : 10mA / digit
|
||||
unsigned char ActualPumpFreq; // fuel pump freq.: 0.1Hz / digit
|
||||
unsigned char ErrorCode; //
|
||||
unsigned char Unknown1; // always 0x00
|
||||
|
@ -56,9 +56,10 @@ public:
|
|||
unsigned char Unknown3; // always 0x00
|
||||
unsigned char CRC_MSB;
|
||||
unsigned char CRC_LSB;
|
||||
} Rx;
|
||||
} Heater;
|
||||
};
|
||||
static const int TxMode = 1;
|
||||
static const int CtrlMode = 1;
|
||||
static const int HeatMode = 2;
|
||||
const unsigned short wCRCTable[256] = {
|
||||
0X0000, 0XC0C1, 0XC181, 0X0140, 0XC301, 0X03C0, 0X0280, 0XC241,
|
||||
0XC601, 0X06C0, 0X0780, 0XC741, 0X0500, 0XC5C1, 0XC481, 0X0440,
|
||||
|
@ -99,35 +100,59 @@ public:
|
|||
CFrame(int TxMode) { Init(TxMode); };
|
||||
void Init(int Txmode);
|
||||
// CRC handlers
|
||||
unsigned short CalcCRC(int len); // calculate and set the CRC upon first 22 bytes
|
||||
unsigned short CalcCRC(int len); // calculate and set the CRC upon len bytes
|
||||
void setCRC(); // calculate and set the CRC in the buffer
|
||||
void setCRC(unsigned short CRC); // set the CRC in the buffer
|
||||
unsigned short getCRC(); // extract CRC value from buffer
|
||||
bool verifyCRC(); // return true for CRC match
|
||||
// command
|
||||
int getCommand();
|
||||
void setCommand(int mode);
|
||||
// Run state
|
||||
unsigned char getRunState() { return Heater.RunState; };
|
||||
void setRunState(unsigned char state) { Heater.RunState = state; };
|
||||
unsigned char getErrState() { return Heater.ErrState; };
|
||||
void setErrState(unsigned char state) { Heater.ErrState = state; };
|
||||
//
|
||||
short getVoltage_Supply();
|
||||
void setVoltage_Supply(short voltsx10);
|
||||
|
||||
// fan set/get
|
||||
short getFan_Actual(); // Rx side, actual
|
||||
short getFan_Min(); // Tx side, define min fan speed
|
||||
short getFan_Max(); // Tx side, define max fan speed
|
||||
void setFan_Min(short speed); // Tx side, define min fan speed
|
||||
void setFan_Max(short speed); // Tx side, define max fan speed
|
||||
short getFan_Actual(); // Heater side, actual
|
||||
short getFan_Min(); // Controller side, define min fan speed
|
||||
short getFan_Max(); // Controller side, define max fan speed
|
||||
void setFan_Actual(short speed); // Heater side, actual
|
||||
void setFan_Min(short speed); // Controller side, define min fan speed
|
||||
void setFan_Max(short speed); // Controller side, define max fan speed
|
||||
short getFan_Voltage(); // fan voltage
|
||||
void setFan_Voltage(short voltsx10); // fan voltage
|
||||
|
||||
// pump set/get
|
||||
void setPump_Min(unsigned short Freq) { Tx.MinPumpFreq = Freq; };
|
||||
void setPump_Max(unsigned short Freq) { Tx.MaxPumpFreq = Freq; };
|
||||
unsigned char getPump_Min() { return Tx.MinPumpFreq; }; // Tx side, min pump freq
|
||||
unsigned char getPump_Max() { return Tx.MaxPumpFreq; }; // Tx side, max pump freq
|
||||
unsigned char getPump_Actual() { return Rx.ActualPumpFreq; }; // Rx style, actual
|
||||
unsigned char getPump_Fixed() { return Rx.FixedPumpFreq; }; // Fixed mode pump frequency
|
||||
void setPump_Min(unsigned short Freq) { Controller.MinPumpFreq = Freq; };
|
||||
void setPump_Max(unsigned short Freq) { Controller.MaxPumpFreq = Freq; };
|
||||
void setPump_Actual(unsigned char Freq) { Heater.ActualPumpFreq = Freq; };
|
||||
void setPump_Fixed(unsigned char Freq) { Heater.FixedPumpFreq = Freq; };
|
||||
unsigned char getPump_Min() { return Controller.MinPumpFreq; }; // Tx side, min pump freq
|
||||
unsigned char getPump_Max() { return Controller.MaxPumpFreq; }; // Tx side, max pump freq
|
||||
unsigned char getPump_Actual() { return Heater.ActualPumpFreq; }; // Rx style, actual
|
||||
unsigned char getPump_Fixed() { return Heater.FixedPumpFreq; }; // Fixed mode pump frequency
|
||||
// temperature set/get
|
||||
void setTemperature_Desired(unsigned char degC) { Tx.DesiredTemperature = degC; };
|
||||
void setTemperature_Min(unsigned char degC) { Tx.MinTemperature = degC; };
|
||||
void setTemperature_Max(unsigned char degC) { Tx.MaxTemperature = degC; };
|
||||
void setTemperature_Actual(unsigned char degC) { Tx.ActualTemperature = degC; };
|
||||
unsigned char getTemperature_Desired() { return Tx.DesiredTemperature; };
|
||||
short getTemperature_GlowPin(); // temperature of glow pin
|
||||
void setTemperature_Desired(unsigned char degC) { Controller.DesiredTemperature = degC; };
|
||||
void setTemperature_Min(unsigned char degC) { Controller.MinTemperature = degC; };
|
||||
void setTemperature_Max(unsigned char degC) { Controller.MaxTemperature = degC; };
|
||||
void setTemperature_Actual(unsigned char degC) { Controller.ActualTemperature = degC; };
|
||||
unsigned char getTemperature_Desired() { return Controller.DesiredTemperature; };
|
||||
unsigned char getTemperature_Min() { return Controller.MinTemperature; };
|
||||
unsigned char getTemperature_Max() { return Controller.MaxTemperature; };
|
||||
short getGlowPlug_Current(); // glow plug current
|
||||
short getGlowPlug_Voltage(); // glow plug voltage
|
||||
void setGlowPlug_Current(short ampsx100); // glow plug current
|
||||
void setGlowPlug_Voltage(short voltsx10); // glow plug voltage
|
||||
short getTemperature_HeatExchg(); // temperature of heat exchanger
|
||||
short getTemperature_Inlet(); // temperature near inlet
|
||||
void setTemperature_HeatExchg(short degC); // temperature of heat exchanger
|
||||
|
||||
CFrame& operator=(CFrame& rhs);
|
||||
CFrame& operator=(const CFrame& rhs);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -1,55 +1,68 @@
|
|||
/*
|
||||
Chinese Heater Half Duplex Serial Data Send Test Tool
|
||||
Chinese Heater Half Duplex Serial Data Sending Tool
|
||||
|
||||
Connects to the blue wire of a Chinese heater, which is the half duplex serial link.
|
||||
Receives data from serial port 1.
|
||||
|
||||
Sends and receives data from serial port 1.
|
||||
|
||||
Terminology: Tx is to the heater unit, Rx is from the heater unit.
|
||||
|
||||
The binary data is received from the line.
|
||||
If it has been > 100ms since the last activity this indicates a new frame
|
||||
sequence is starting, synchronise as such then count off the next 48 bytes
|
||||
storing them in the Data array.
|
||||
|
||||
The "outer loop" then detects the count of 48 and packages the data to be sent
|
||||
over Serial to the USB attached PC.
|
||||
|
||||
Typical data frame timing on the blue wire is:
|
||||
__Tx_Rx____________________________Tx_Rx____________________________Tx_Rx___________
|
||||
|
||||
This software can connect to the blue wire in a normal OEM system, detecting the
|
||||
OEM controller and allowing extraction of the data or injecting on/off commands.
|
||||
|
||||
The binary data is received from the line.
|
||||
If it has been > 100ms since the last blue wire activity this indicates a new frame
|
||||
sequence is starting from the OEM controller.
|
||||
Synchronise as such then count off the next 24 bytes storing them in the Controller's
|
||||
data array. These bytes are then reported over USB to the PC in ASCII.
|
||||
|
||||
It is then expected the heater wil lrespond with it's 24 bytes.
|
||||
Capture those bytes and store them in the Heater1 data array.
|
||||
Once again these bytes are then reported over USB to the PC in ASCII.
|
||||
|
||||
If no activity is sensed in a second, it is assumed no controller is attached and we
|
||||
have full control over the heater.
|
||||
|
||||
Either way we can now inject a message onto the blue wire allowing our custom
|
||||
on/off control.
|
||||
We must remain synchronous with the OEM controller if it exists otherwise E-07
|
||||
faults will be caused.
|
||||
|
||||
Typical data frame timing on the blue wire is then:
|
||||
__OEMTx_HtrRx__OurTx_HtrRx____________OEMTx_HtrRx__OurTx_HtrRx____________OEMTx_HtrRx__OurTx_HtrRx_________
|
||||
|
||||
Rx to next Tx delay is always > 100ms and is paced by the controller.
|
||||
The delay before seeing Rx data after Tx is usually much less than 10ms.
|
||||
**The heater only ever sends Rx data in response to a data frame from the controller**
|
||||
The second HtrRx to the next OEMTx delay is always > 100ms and is paced by the OEM controller.
|
||||
The delay before seeing Heater Rx data after any Tx is usually much less than 10ms.
|
||||
But this does rise if new max/min or voltage settings are sent.
|
||||
**The heater only ever sends Rx data in response to a data frame from a controller**
|
||||
|
||||
Resultant data is tagged and sent out on serial port 0 (the default debug port),
|
||||
along with a timestamp for relative timing.
|
||||
|
||||
This example works only with boards with more than one serial port like Arduino
|
||||
|
||||
This code only works with boards that have more than one hardware serial port like Arduino
|
||||
Mega, Due, Zero etc.
|
||||
|
||||
|
||||
The circuit:
|
||||
- Blue wire connected to Serial 1 Rx input - preferably with series 680ohm resistor.
|
||||
- Serial logging software on Serial port 0 via USB link
|
||||
- a Tx Rx multiplexer is required to combine the Arduino's Tx1 And Rx1 pins onto the blue wire.
|
||||
- a Tx Enable signal from pin 20 controls the multiplexer
|
||||
- Serial logging software on Serial0 via USB link
|
||||
|
||||
created 24 Aug 2018 by Ray Jones
|
||||
|
||||
modified 25 Aug by Ray Jones
|
||||
- simplifed to read 48 bytes, synchronised by observing a long pause
|
||||
between characters. The heater only sends when prompted.
|
||||
No longer need to discrimate which packet of data would be present.
|
||||
created 23 Sep 2018 by Ray Jones
|
||||
|
||||
This example code is in the public domain.
|
||||
*/
|
||||
|
||||
#include "CFrame.h"
|
||||
#include "Protocol.h"
|
||||
#include "TxManage.h"
|
||||
|
||||
void SerialReport(const char* hdr, const unsigned char* pData, const char* ftr);
|
||||
|
||||
class CommStates {
|
||||
public:
|
||||
// comms states
|
||||
enum eCS {
|
||||
Idle, CtrlRx, CtrlRpt, HtrRx1, HtrRpt1, SelfTx, HtrRx2, HtrRpt2
|
||||
Idle, ControllerRx, ControllerReport, HeaterRx1, HeaterReport1, SelfTx, HeaterRx2, HeaterReport2
|
||||
};
|
||||
CommStates() {
|
||||
set(Idle);
|
||||
|
@ -61,7 +74,7 @@ class CommStates {
|
|||
bool is(eCS eState) {
|
||||
return m_State == eState;
|
||||
}
|
||||
bool rxData(unsigned char* pData, unsigned char val, int limit = 24) { // return true if buffer filled
|
||||
bool saveData(unsigned char* pData, unsigned char val, int limit = 24) { // returns true when buffer filled
|
||||
pData[m_Count++] = val;
|
||||
return m_Count == limit;
|
||||
}
|
||||
|
@ -70,17 +83,19 @@ private:
|
|||
int m_Count;
|
||||
};
|
||||
|
||||
const int TxEnbPin = 17;
|
||||
UARTClass& USB(Serial);
|
||||
UARTClass& BlueWire(Serial1);
|
||||
UARTClass& BlueTooth(Serial2);
|
||||
|
||||
const int TxEnbPin = 20;
|
||||
CommStates CommState;
|
||||
CFrame Controller(CFrame::TxMode);
|
||||
CFrame TxFrame(CFrame::TxMode);
|
||||
CTxManage TxManage(TxEnbPin, Serial1);
|
||||
CFrame Heater1;
|
||||
CFrame Heater2;
|
||||
long lastRxTime; // used to calculate inter character delay
|
||||
long TxEnbTime; // used to reset TxEnb low
|
||||
bool bOnEvent = false;
|
||||
bool bOffEvent = false;
|
||||
CFrame Controller; // most recent data packet received from OEM controller found on blue wire
|
||||
CFrame Heater1; // data packet received from heater in response to OEM controller packet
|
||||
CFrame Heater2; // data packet received from heater in response to our packet
|
||||
CFrame SelfParams(CFrame::CtrlMode); // holds our local parameters, used in case on no OEM controller
|
||||
long lastRxTime; // used to observe inter character delays
|
||||
|
||||
|
||||
|
||||
void setup()
|
||||
|
@ -88,16 +103,25 @@ void setup()
|
|||
// initialize listening serial port
|
||||
// 25000 baud, Tx and Rx channels of Chinese heater comms interface:
|
||||
// Tx/Rx data to/from heater, special baud rate for Chinese heater controllers
|
||||
Serial1.begin(25000);
|
||||
pinMode(19, INPUT_PULLUP);
|
||||
BlueWire.begin(25000);
|
||||
pinMode(19, INPUT_PULLUP); // required for MUX to work properly
|
||||
|
||||
// initialise serial monitor on serial port 0
|
||||
Serial.begin(115200);
|
||||
USB.begin(115200);
|
||||
|
||||
// prepare for first long delay detection
|
||||
lastRxTime = millis();
|
||||
|
||||
TxManage.begin();
|
||||
TxManage.begin(); // ensure Tx enable pin setup
|
||||
|
||||
// define defaults should heater controller be missing
|
||||
SelfParams.setTemperature_Desired(23);
|
||||
SelfParams.setTemperature_Actual(22);
|
||||
SelfParams.Controller.OperatingVoltage = 120;
|
||||
SelfParams.setPump_Min(16);
|
||||
SelfParams.setPump_Max(55);
|
||||
SelfParams.setFan_Min(1680);
|
||||
SelfParams.setFan_Max(4500);
|
||||
|
||||
}
|
||||
|
||||
|
@ -106,8 +130,8 @@ void loop()
|
|||
unsigned long timenow = millis();
|
||||
|
||||
// check for test commands received from PC Over USB
|
||||
if(Serial.available()) {
|
||||
char rxval = Serial.read();
|
||||
if(USB.available()) {
|
||||
char rxval = USB.read();
|
||||
if(rxval == '+') {
|
||||
TxManage.RequestOn();
|
||||
}
|
||||
|
@ -116,12 +140,11 @@ void loop()
|
|||
}
|
||||
}
|
||||
|
||||
// Handle time interval where we send data to the blue wire
|
||||
if(CommState.is(CommStates::SelfTx)) {
|
||||
// Interval where we should send data to the blue wire
|
||||
lastRxTime = timenow; // not expecting rx data, but we are pumping onto blue wire!
|
||||
TxManage.Tick(timenow); // keep trying to send our data
|
||||
if(!TxManage.isBusy()) { // until completed
|
||||
CommState.set(CommStates::HtrRx2); // then await heater repsonse
|
||||
lastRxTime = timenow; // we are pumping onto blue wire, track this activity!
|
||||
if(TxManage.CheckTx(timenow) ) { // monitor our data delivery
|
||||
CommState.set(CommStates::HeaterRx2); // then await heater repsonse
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -135,72 +158,71 @@ void loop()
|
|||
// OEM controller probably not connected.
|
||||
// Skip to SelfTx, sending our own settings.
|
||||
CommState.set(CommStates::SelfTx);
|
||||
bool bSelfParams = true;
|
||||
TxManage.Send(timenow, bSelfParams);
|
||||
bool bOurParams = true;
|
||||
TxManage.Start(SelfParams, timenow, bOurParams);
|
||||
}
|
||||
|
||||
// precaution if 24 bytes were not received whilst expecting them
|
||||
if(RxTimeElapsed > 50) {
|
||||
if( CommState.is(CommStates::CtrlRx) ||
|
||||
CommState.is(CommStates::HtrRx1) ||
|
||||
CommState.is(CommStates::HtrRx2) ) {
|
||||
// precaution action if all 24 bytes were not received whilst expecting them
|
||||
if(RxTimeElapsed > 150) {
|
||||
if( CommState.is(CommStates::ControllerRx) ||
|
||||
CommState.is(CommStates::HeaterRx1) ||
|
||||
CommState.is(CommStates::HeaterRx2) ) {
|
||||
|
||||
CommState.set(CommStates::Idle);
|
||||
}
|
||||
}
|
||||
|
||||
// read from port 1, the "blue wire" (to/from heater), store according to CommState
|
||||
if (Serial1.available()) {
|
||||
if (BlueWire.available()) {
|
||||
|
||||
lastRxTime = timenow;
|
||||
|
||||
if( CommState.is(CommStates::Idle) && (RxTimeElapsed > 100)) { // this indicates the start of a new frame sequence from another controller
|
||||
CommState.set(CommStates::CtrlRx);
|
||||
// detect start of a new frame sequence from OEM controller
|
||||
if( CommState.is(CommStates::Idle) && (RxTimeElapsed > 100)) {
|
||||
CommState.set(CommStates::ControllerRx);
|
||||
}
|
||||
|
||||
int inByte = Serial1.read(); // read hex byte
|
||||
int inByte = BlueWire.read(); // read hex byte
|
||||
|
||||
if( CommState.is(CommStates::CtrlRx) ) {
|
||||
if(CommState.rxData(Controller.Data, inByte) ) {
|
||||
CommState.set(CommStates::CtrlRpt);
|
||||
if( CommState.is(CommStates::ControllerRx) ) {
|
||||
if(CommState.saveData(Controller.Data, inByte) ) {
|
||||
CommState.set(CommStates::ControllerReport);
|
||||
}
|
||||
}
|
||||
|
||||
else if( CommState.is(CommStates::HtrRx1) ) {
|
||||
if( CommState.rxData(Heater1.Data, inByte) ) {
|
||||
CommState.set(CommStates::HtrRpt1);
|
||||
else if( CommState.is(CommStates::HeaterRx1) ) {
|
||||
if( CommState.saveData(Heater1.Data, inByte) ) {
|
||||
CommState.set(CommStates::HeaterReport1);
|
||||
}
|
||||
}
|
||||
|
||||
else if( CommState.is(CommStates::HtrRx2) ) {
|
||||
if( CommState.rxData(Heater2.Data, inByte) ) {
|
||||
CommState.set(CommStates::HtrRpt2);
|
||||
else if( CommState.is(CommStates::HeaterRx2) ) {
|
||||
if( CommState.saveData(Heater2.Data, inByte) ) {
|
||||
CommState.set(CommStates::HeaterReport2);
|
||||
}
|
||||
}
|
||||
|
||||
} // Serial1.available
|
||||
} // BlueWire.available
|
||||
|
||||
|
||||
if( CommState.is(CommStates::CtrlRpt) ) {
|
||||
if( CommState.is(CommStates::ControllerReport) ) {
|
||||
// filled controller frame, report
|
||||
SerialReport("Ctrl ", Controller.Data, " ");
|
||||
CommState.set(CommStates::HtrRx1);
|
||||
CommState.set(CommStates::HeaterRx1);
|
||||
}
|
||||
|
||||
else if(CommState.is(CommStates::HtrRpt1) ) {
|
||||
else if(CommState.is(CommStates::HeaterReport1) ) {
|
||||
// received heater frame (after controller message), report
|
||||
SerialReport("Htr1 ", Heater1.Data, "\r\n");
|
||||
|
||||
TxManage.Copy(Controller); // replicate last obtained controller data
|
||||
TxManage.Send(timenow, false);
|
||||
bool bOurParams = false;
|
||||
TxManage.Start(Controller, timenow, bOurParams);
|
||||
CommState.set(CommStates::SelfTx);
|
||||
}
|
||||
|
||||
else if( CommState.is(CommStates::HtrRpt2) ) {
|
||||
else if( CommState.is(CommStates::HeaterReport2) ) {
|
||||
// received heater frame (after our control message), report
|
||||
|
||||
SerialReport("Htr2 ", Heater2.Data, "\r\n");
|
||||
|
||||
CommState.set(CommStates::Idle);
|
||||
}
|
||||
|
||||
|
@ -208,11 +230,11 @@ void loop()
|
|||
|
||||
void SerialReport(const char* hdr, const unsigned char* pData, const char* ftr)
|
||||
{
|
||||
Serial.print(hdr); // header
|
||||
USB.print(hdr); // header
|
||||
for(int i=0; i<24; i++) {
|
||||
char str[16];
|
||||
sprintf(str, "%02X ", pData[i]); // build 2 dig hex values
|
||||
Serial.print(str); // and print
|
||||
sprintf(str, "%02X ", pData[i]); // build 2 dig hex values
|
||||
USB.print(str); // and print
|
||||
}
|
||||
Serial.print(ftr); // footer
|
||||
USB.print(ftr); // footer
|
||||
}
|
|
@ -5,12 +5,11 @@ extern void SerialReport(const char* hdr, const unsigned char* pData, const char
|
|||
|
||||
CTxManage::CTxManage(int TxEnbPin, USARTClass& serial) :
|
||||
m_Serial(serial),
|
||||
m_Frame(CFrame::TxMode)
|
||||
m_Frame(CFrame::CtrlMode)
|
||||
{
|
||||
m_bOnReq = false;
|
||||
m_bOffReq = false;
|
||||
m_bTxPending = false;
|
||||
m_bSelf = true;
|
||||
m_nStartTime = 0;
|
||||
m_nTxEnbPin = TxEnbPin;
|
||||
}
|
||||
|
@ -33,31 +32,23 @@ CTxManage::RequestOff()
|
|||
m_bOffReq = true;
|
||||
}
|
||||
|
||||
void
|
||||
CTxManage::Copy(CFrame& ref)
|
||||
void
|
||||
CTxManage::Start(const CFrame& ref, unsigned long timenow, bool self)
|
||||
{
|
||||
m_Frame = ref;
|
||||
}
|
||||
// 0x78 prevents the controller showing bum information when we parrot the OEM controller
|
||||
// heater is happy either way, the OEM controller has set the max/min stuff already
|
||||
m_Frame.Data[0] = self ? 0x76 : 0x78;
|
||||
|
||||
bool
|
||||
CTxManage::isBusy()
|
||||
{
|
||||
return m_nStartTime != 0;
|
||||
}
|
||||
|
||||
void
|
||||
CTxManage::Send(unsigned long timenow, bool self)
|
||||
{
|
||||
if(timenow == 0)
|
||||
timenow++;
|
||||
|
||||
m_nStartTime = timenow;
|
||||
m_bSelf = self;
|
||||
m_bTxPending = true;
|
||||
}
|
||||
|
||||
void
|
||||
CTxManage::Tick(unsigned long timenow)
|
||||
bool
|
||||
CTxManage::CheckTx(unsigned long timenow)
|
||||
{
|
||||
if(m_nStartTime) {
|
||||
|
||||
|
@ -78,38 +69,26 @@ CTxManage::Tick(unsigned long timenow)
|
|||
digitalWrite(m_nTxEnbPin, LOW);
|
||||
}
|
||||
}
|
||||
return m_nStartTime == 0;
|
||||
}
|
||||
|
||||
void
|
||||
CTxManage::_send()
|
||||
{
|
||||
if(m_bSelf) {
|
||||
m_Frame.Data[0] = 0x76; // required for heater to use the max min information
|
||||
m_Frame.Data[1] = 0x16;
|
||||
m_Frame.setTemperature_Desired(35);
|
||||
m_Frame.setTemperature_Actual(22);
|
||||
m_Frame.Tx.OperatingVoltage = 120;
|
||||
m_Frame.setPump_Min(16);
|
||||
m_Frame.setPump_Max(55);
|
||||
m_Frame.setFan_Min(1680);
|
||||
m_Frame.setFan_Max(4500);
|
||||
}
|
||||
else {
|
||||
m_Frame.Data[0] = 0x78; // this prevents the controller trying to show bum information, heater uses controller max/min settings
|
||||
}
|
||||
|
||||
// install on/off commands if required
|
||||
if(m_bOnReq) {
|
||||
m_bOnReq = false;
|
||||
m_Frame.Tx.Command = 0xa0;
|
||||
m_Frame.Controller.Command = 0xa0;
|
||||
}
|
||||
else if(m_bOffReq) {
|
||||
m_bOffReq = false;
|
||||
m_Frame.Tx.Command = 0x05;
|
||||
m_Frame.Controller.Command = 0x05;
|
||||
}
|
||||
else {
|
||||
m_Frame.Tx.Command = 0x00;
|
||||
m_Frame.Controller.Command = 0x00;
|
||||
}
|
||||
|
||||
// ensure CRC valid
|
||||
m_Frame.setCRC();
|
||||
|
||||
// send to heater - using binary
|
||||
|
|
|
@ -3,14 +3,16 @@
|
|||
|
||||
class CTxManage
|
||||
{
|
||||
const int m_nStartDelay = 20;
|
||||
const int m_nFrameTime = 14;
|
||||
const int m_nFrontPorch = 2;
|
||||
|
||||
public:
|
||||
CTxManage(int TxEnbPin, USARTClass& serial);
|
||||
void RequestOn();
|
||||
void RequestOff();
|
||||
void Copy(CFrame& ref);
|
||||
bool isBusy();
|
||||
void Tick(unsigned long timenow);
|
||||
void Send(unsigned long timenow, bool self);
|
||||
void Start(const CFrame& ref, unsigned long timenow, bool self);
|
||||
bool CheckTx(unsigned long timenow);
|
||||
void Report();
|
||||
void begin();
|
||||
|
||||
|
@ -19,15 +21,10 @@ private:
|
|||
bool m_bOnReq;
|
||||
bool m_bOffReq;
|
||||
bool m_bTxPending;
|
||||
bool m_bSelf;
|
||||
int m_nTxEnbPin;
|
||||
unsigned long m_nStartTime;
|
||||
USARTClass& m_Serial;
|
||||
|
||||
const int m_nStartDelay = 20;
|
||||
const int m_nFrameTime = 14;
|
||||
const int m_nFrontPorch = 2;
|
||||
|
||||
void _send();
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue