Merge branch 'SmartErrors' into 'master'

Smart errors

See merge request mrjones.id.au/bluetoothheater!6
This commit is contained in:
Ray Jones 2018-10-28 19:23:33 +00:00
commit 1b814cbf3f
8 changed files with 165 additions and 11 deletions

Binary file not shown.

Binary file not shown.

View file

@ -248,7 +248,7 @@ CProtocol::Init(int FrameMode)
setGlowPlug_Voltage(0);
setGlowPlug_Current(0);
Heater.ActualPumpFreq = 0; // fuel pump freq.: 0.1Hz / digit
Heater.ErrorCode = 0; //
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 ?"

View file

@ -49,7 +49,7 @@ public:
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 StoredErrorCode; //
unsigned char Unknown1; // always 0x00
unsigned char FixedPumpFreq; // fixed mode frequency set point: 0.1Hz / digit
unsigned char Unknown2; // always 0x64 "100 ?"
@ -121,6 +121,8 @@ public:
void setRunState(unsigned char state) { Heater.RunState = state; };
unsigned char getErrState() { return Heater.ErrState; };
void setErrState(unsigned char state) { Heater.ErrState = state; };
unsigned char getStoredErrCode() { return Heater.StoredErrorCode; };
void setStoredErrCode(unsigned char state) { Heater.StoredErrorCode = state; };
//
short getVoltage_Supply();
void setVoltage_Supply(short voltsx10);

View file

@ -67,6 +67,7 @@
#include "pins.h"
#include "NVStorage.h"
#include "debugport.h"
#include "SmartError.h"
#define DEBUG_BTRX
@ -129,13 +130,23 @@ public:
}
};
class CModeratedFrame : public CProtocol {
unsigned long lastTime;
public:
CModeratedFrame() { lastTime = 0; };
void setTime() { lastTime = millis(); };
unsigned long elapsedTime() { return millis() - lastTime; };
};
CommStates CommState;
CTxManage TxManage(TxEnbPin, BlueWireSerial);
CProtocol OEMCtrlFrame; // data packet received from heater in response to OEM controller packet
CProtocol HeaterFrame1; // data packet received from heater in response to OEM controller packet
//CProtocol OEMCtrlFrame; // data packet received from heater in response to OEM controller packet
//CProtocol HeaterFrame1; // data packet received from heater in response to OEM controller packet
CModeratedFrame OEMCtrlFrame; // data packet received from heater in response to OEM controller packet
CModeratedFrame HeaterFrame1; // data packet received from heater in response to OEM controller packet
CProtocol HeaterFrame2; // data packet received from heater in response to our packet
CProtocol DefaultBTCParams(CProtocol::CtrlMode); // defines the default parameters, used in case of no OEM controller
CSmartError SmartError;
long lastRxTime; // used to observe inter character delays
bool hasOEMController = false;
@ -152,10 +163,6 @@ void PrepareTxFrame(const CProtocol& basisFrame, CProtocol& TxFrame, bool isBTCm
void setup()
{
// initialize serial port to interact with the "blue wire"
// 25000 baud, Tx and Rx channels of Chinese heater comms interface:
// Tx/Rx data to/from heater,
// Note special baud rate for Chinese heater controllers
pinMode(Tx2Pin, OUTPUT);
digitalWrite(Tx2Pin, HIGH);
pinMode(Rx2Pin, INPUT_PULLUP);
@ -163,6 +170,10 @@ void setup()
pinMode(KeyPin, OUTPUT);
digitalWrite(KeyPin, LOW);
// initialize serial port to interact with the "blue wire"
// 25000 baud, Tx and Rx channels of Chinese heater comms interface:
// Tx/Rx data to/from heater,
// Note special baud rate for Chinese heater controllers
#if defined(__arm__) || defined(__AVR__)
BlueWireSerial.begin(25000);
pinMode(Rx1Pin, INPUT_PULLUP); // required for MUX to work properly
@ -181,7 +192,7 @@ void setup()
TxManage.begin(); // ensure Tx enable pin is setup
// define defaults should heater controller be missing
// define defaults should OEM controller be missing
DefaultBTCParams.setTemperature_Desired(23);
DefaultBTCParams.setTemperature_Actual(22);
DefaultBTCParams.Controller.OperatingVoltage = 120;
@ -233,6 +244,16 @@ void loop()
CommState.is(CommStates::HeaterRx1) ||
CommState.is(CommStates::HeaterRx2) ) {
if(CommState.is(CommStates::OEMCtrlRx)) {
DebugPort.println("Timeout collecting OEM controller data, returning to Idle State");
}
else if(CommState.is(CommStates::HeaterRx1)) {
DebugPort.println("Timeout collecting OEM heater response data, returning to Idle State");
}
else {
DebugPort.println("Timeout collecting BTC heater response data, returning to Idle State");
}
CommState.set(CommStates::Idle); // revert to idle mode
}
}
@ -295,7 +316,13 @@ void loop()
else if( CommState.is(CommStates::OEMCtrlReport) ) {
// filled OEM controller frame, report
// echo received OEM controller frame over Bluetooth, using [OEM] header
Bluetooth_SendFrame("[OEM]", OEMCtrlFrame, true);
if(OEMCtrlFrame.elapsedTime() > 700) {
Bluetooth_SendFrame("[OEM]", OEMCtrlFrame, true);
OEMCtrlFrame.setTime();
}
else {
DebugPort.println("Suppressed delivery of OEM frame");
}
CommState.set(CommStates::HeaterRx1);
}
@ -310,8 +337,19 @@ void loop()
else if(CommState.is(CommStates::HeaterReport1) ) {
// received heater frame (after controller message), report
// do some monitoring of the heater state variable
// if suspicious transitions, introduce a smart error!
SmartError.monitor(HeaterFrame1);
// echo heater reponse data to Bluetooth client
Bluetooth_SendFrame("[HTR]", HeaterFrame1);
if(HeaterFrame1.elapsedTime() > 700) {
Bluetooth_SendFrame("[HTR]", HeaterFrame1);
HeaterFrame1.setTime();
}
else {
DebugPort.println("Suppressed delivery of OEM heater response frame");
}
if(digitalRead(ListenOnlyPin)) {
bool isBTCmaster = false;
@ -343,6 +381,11 @@ void loop()
else if( CommState.is(CommStates::HeaterReport2) ) {
// received heater frame (after our control message), report
// do some monitoring of the heater state variable
// if suspicious transitions, introduce a smart error!
SmartError.monitor(HeaterFrame2);
delay(5);
if(!hasOEMController) {
// only convey these frames to Bluetooth when NOT using an OEM controller!
@ -391,10 +434,12 @@ void Command_Interpret(const char* pLine)
if(strncmp(pLine, "ON", 2) == 0) {
TxManage.queueOnRequest();
DebugPort.println("Heater ON");
SmartError.reset();
}
else if(strncmp(pLine, "OFF", 3) == 0) {
TxManage.queueOffRequest();
DebugPort.println("Heater OFF");
SmartError.inhibit();
}
else if(strncmp(pLine, "Pmin", 4) == 0) {
pLine += 4;

View file

@ -0,0 +1,93 @@
#include "SmartError.h"
CSmartError::CSmartError()
{
reset();
}
void
CSmartError::reset()
{
m_prevRunState = 0;
m_Error = 0;
m_bInhibit = false;
}
// we use inhibit when we manually command the heater off during preheat
// otherwise we'll register an ignition fail event
void
CSmartError::inhibit()
{
m_bInhibit = true;
m_Error = 0;
}
// accept a fresh heater frame
// inpsect the advertised run state, tracking when and how it transitions out
// of preheat especially.
// abnormal transitions are registered and becoem our smart m_Error
// In addition, the hetaer frame has the ErrState updated to track the
// smart error, providing no heater error exists!
void
CSmartError::monitor(CProtocol& heaterFrame)
{
if(heaterFrame.verifyCRC()) {
// only accept valid heater frames!
monitor(heaterFrame.getRunState());
unsigned char HtrErr = heaterFrame.getErrState();
if((HtrErr & 0xfe) == 0) {
// heater is Idle or Normal running state (E-0X + 1 in protocol!!)
unsigned char smartErr = getError();
if(smartErr) {
heaterFrame.setErrState(smartErr); // 10 = ign fail, 11 = retry
heaterFrame.setCRC(); // changed the message, fix the CRC!
}
}
}
}
// test the new run state value, comparing to previous
// detect abnormal transitions
void
CSmartError::monitor(unsigned char newRunState)
{
// check if moving away from heater Idle state (S0)
// especially useful if an OEM controller exists
if((m_prevRunState == 0) && newRunState) {
// reset the smart error
m_Error = 0;
m_bInhibit = false;
}
if(!m_bInhibit) {
if(m_prevRunState == 2) { // preheat state (S2)
if(newRunState == 4) {
// transitioned from preheat to ignited
// - all good!
m_Error = 0;
}
else if(newRunState > 5) {
// transitioned from preheat to post glow
// - second ignition attempt failed, heater is shutting down
m_Error = 11;
}
else if(newRunState == 3) {
// transitioned from preheat to retry
// - first ignition attempt failed, heater will retry
m_Error = 12;
}
}
}
m_prevRunState = newRunState;
}
// return our smart error, if it exists, as the registered code
unsigned char
CSmartError::getError()
{
if(m_Error) {
return m_Error;
}
return 0;
}

View file

@ -0,0 +1,14 @@
#include "Protocol.h"
class CSmartError {
unsigned char m_prevRunState;
unsigned char m_Error;
bool m_bInhibit;
public:
CSmartError();
void reset();
void inhibit();
void monitor(CProtocol& heaterFrame);
void monitor(unsigned char runstate);
unsigned char getError();
};