Switched to HC-05.
quick push for James
This commit is contained in:
parent
a156062a94
commit
7be3424359
7 changed files with 271 additions and 34 deletions
2
Arduino/SenderTrial2/.vscode/arduino.json
vendored
2
Arduino/SenderTrial2/.vscode/arduino.json
vendored
|
@ -3,5 +3,5 @@
|
||||||
"port": "COM9",
|
"port": "COM9",
|
||||||
"sketch": "SenderTrial2.ino",
|
"sketch": "SenderTrial2.ino",
|
||||||
"output": "..\\build",
|
"output": "..\\build",
|
||||||
"configuration": "PSRAM=disabled,PartitionScheme=default,FlashMode=qio,FlashFreq=80,FlashSize=4M,UploadSpeed=921600,DebugLevel=warn"
|
"configuration": "PSRAM=disabled,PartitionScheme=default,FlashMode=qio,FlashFreq=80,FlashSize=4M,UploadSpeed=921600,DebugLevel=none"
|
||||||
}
|
}
|
|
@ -5,6 +5,7 @@ class CProtocol;
|
||||||
void Bluetooth_Init();
|
void Bluetooth_Init();
|
||||||
void Bluetooth_SendFrame(const char* pHdr, const CProtocol& Frame, bool lineterm=true);
|
void Bluetooth_SendFrame(const char* pHdr, const CProtocol& Frame, bool lineterm=true);
|
||||||
void Bluetooth_Check();
|
void Bluetooth_Check();
|
||||||
|
void Bluetooth_SendACK();
|
||||||
|
|
||||||
extern void Command_Interpret(const char* pLine); // decodes received command lines, implemented in main .ino file!
|
extern void Command_Interpret(const char* pLine); // decodes received command lines, implemented in main .ino file!
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,171 @@
|
||||||
|
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
|
|
||||||
|
#define ESP32_USE_HC05
|
||||||
|
|
||||||
const int LED = 2;
|
const int LED = 2;
|
||||||
|
|
||||||
// ESP32
|
// ESP32
|
||||||
|
|
||||||
sRxLine RxLine;
|
sRxLine RxLine;
|
||||||
|
|
||||||
|
#ifdef ESP32_USE_HC05
|
||||||
|
|
||||||
|
//static HardwareSerial& Bluetooth(Serial2); // TODO: make proper ESP32 BT client
|
||||||
|
|
||||||
|
bool Bluetooth_ATCommand(const char* cmd);
|
||||||
|
|
||||||
|
const int BTRates[] = {
|
||||||
|
9600, 38400, 115200, 19200, 57600, 2400, 4800, 1200
|
||||||
|
};
|
||||||
|
|
||||||
|
bool bHC05Available = false;
|
||||||
|
|
||||||
|
void Bluetooth_Init()
|
||||||
|
{
|
||||||
|
RxLine.clear();
|
||||||
|
|
||||||
|
// search for BlueTooth adapter, trying the common baud rates, then less common
|
||||||
|
// as the device cannot be guaranteed to power up with the key pin high
|
||||||
|
// we are at the mercy of the baud rate stored in the module.
|
||||||
|
digitalWrite(KeyPin, HIGH);
|
||||||
|
delay(5000);
|
||||||
|
Serial2.begin(9600, SERIAL_8N1, Rx2Pin, Tx2Pin); // need to explicitly specify pins for pin multiplexer!);
|
||||||
|
|
||||||
|
DebugPort.println("\r\n\r\nAttempting to detect HC-05 Bluetooth module...");
|
||||||
|
|
||||||
|
int BTidx = 0;
|
||||||
|
int maxTries = sizeof(BTRates)/sizeof(int);
|
||||||
|
for(BTidx = 0; BTidx < maxTries; BTidx++) {
|
||||||
|
DebugPort.print(" @ ");
|
||||||
|
DebugPort.print(BTRates[BTidx]);
|
||||||
|
DebugPort.print(" baud... ");
|
||||||
|
Serial2.begin(BTRates[BTidx], SERIAL_8N1, Rx2Pin, Tx2Pin); // open serial port at a certain baud rate
|
||||||
|
delay(100);
|
||||||
|
Serial2.print("\r\n");
|
||||||
|
Serial2.setTimeout(100);
|
||||||
|
|
||||||
|
if(Bluetooth_ATCommand("AT\r\n")) {
|
||||||
|
DebugPort.println(" OK.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(Bluetooth_ATCommand("AT\r\n")) {
|
||||||
|
DebugPort.println(" OK.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// failed, try another baud rate
|
||||||
|
DebugPort.println("");
|
||||||
|
Serial2.flush();
|
||||||
|
Serial2.end();
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugPort.println("");
|
||||||
|
if(BTidx == maxTries) {
|
||||||
|
DebugPort.println("FAILED to detect HC-05 Bluetooth module :-(");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/*// if(BTRates[BTidx] == 115200) {
|
||||||
|
if(BTRates[BTidx] == 9600) {
|
||||||
|
// DebugPort.println("HC-05 found and already set to 115200 baud, skipping Init.");
|
||||||
|
DebugPort.println("HC-05 found and already set to 9600 baud, skipping Init.");
|
||||||
|
bHC05Available = true;
|
||||||
|
}
|
||||||
|
else*/ {
|
||||||
|
do {
|
||||||
|
DebugPort.println("HC-05 found");
|
||||||
|
|
||||||
|
DebugPort.print(" Setting Name to \"Diesel Heater\"... ");
|
||||||
|
if(!Bluetooth_ATCommand("AT+NAME=\"Diesel Heater\"\r\n")) {
|
||||||
|
DebugPort.println("FAILED");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DebugPort.println("OK");
|
||||||
|
|
||||||
|
// DebugPort.print(" Setting baud rate to 115200N81...");
|
||||||
|
// if(!Bluetooth_ATCommand("AT+UART=115200,1,0\r\n")) {
|
||||||
|
DebugPort.print(" Setting baud rate to 9600N81...");
|
||||||
|
if(!Bluetooth_ATCommand("AT+UART=9600,1,0\r\n")) {
|
||||||
|
DebugPort.println("FAILED");
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
DebugPort.println("OK");
|
||||||
|
|
||||||
|
// Serial2.begin(115200, SERIAL_8N1, Rx2Pin, Tx2Pin);
|
||||||
|
Serial2.begin(9600, SERIAL_8N1, Rx2Pin, Tx2Pin);
|
||||||
|
bHC05Available = true;
|
||||||
|
|
||||||
|
} while(0);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
digitalWrite(KeyPin, LOW); // leave HC-05 command mode
|
||||||
|
|
||||||
|
delay(500);
|
||||||
|
|
||||||
|
if(!bHC05Available)
|
||||||
|
Serial2.end(); // close serial port if no module found
|
||||||
|
|
||||||
|
DebugPort.println("");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bluetooth_Check()
|
||||||
|
{
|
||||||
|
// check for data coming back over Bluetooth
|
||||||
|
if(bHC05Available) {
|
||||||
|
if(Serial2.available()) {
|
||||||
|
char rxVal = Serial2.read();
|
||||||
|
if(isControl(rxVal)) { // "End of Line"
|
||||||
|
Command_Interpret(RxLine.Line);
|
||||||
|
RxLine.clear();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
RxLine.append(rxVal); // append new char to our Rx buffer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Bluetooth_SendFrame(const char* pHdr, const CProtocol& Frame, bool lineterm)
|
||||||
|
{
|
||||||
|
DebugPort.print(millis());
|
||||||
|
DebugReportFrame(pHdr, Frame, lineterm ? "\r\n" : " ");
|
||||||
|
|
||||||
|
if(bHC05Available) {
|
||||||
|
if(Frame.verifyCRC()) {
|
||||||
|
digitalWrite(LED, !digitalRead(LED)); // toggle LED
|
||||||
|
Serial2.print(pHdr);
|
||||||
|
Serial2.write(Frame.Data, 24);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DebugPort.print("Bluetooth data not sent, CRC error ");
|
||||||
|
DebugPort.println(pHdr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DebugPort.println("No Bluetooth client");
|
||||||
|
digitalWrite(LED, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// local function, typically to perform Hayes commands with HC-05
|
||||||
|
bool Bluetooth_ATCommand(const char* cmd)
|
||||||
|
{
|
||||||
|
// if(bHC05Available) {
|
||||||
|
Serial2.print(cmd);
|
||||||
|
char RxBuffer[16];
|
||||||
|
memset(RxBuffer, 0, 16);
|
||||||
|
int read = Serial2.readBytesUntil('\n', RxBuffer, 16); // \n is not included in returned string!
|
||||||
|
if((read == 3) && (0 == strcmp(RxBuffer, "OK\r")) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
// }
|
||||||
|
// return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // ESP32_USE_HC05
|
||||||
#ifndef ESP32_USE_BLE_RLJ
|
#ifndef ESP32_USE_BLE_RLJ
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -49,13 +208,25 @@ void Bluetooth_Check()
|
||||||
|
|
||||||
void Bluetooth_SendFrame(const char* pHdr, const CProtocol& Frame, bool lineterm)
|
void Bluetooth_SendFrame(const char* pHdr, const CProtocol& Frame, bool lineterm)
|
||||||
{
|
{
|
||||||
|
char fullMsg[32];
|
||||||
|
|
||||||
|
DebugPort.print(millis());
|
||||||
DebugReportFrame(pHdr, Frame, lineterm ? "\r\n" : " ");
|
DebugReportFrame(pHdr, Frame, lineterm ? "\r\n" : " ");
|
||||||
|
delay(40);
|
||||||
if(SerialBT.hasClient()) {
|
if(SerialBT.hasClient()) {
|
||||||
|
|
||||||
if(Frame.verifyCRC()) {
|
if(Frame.verifyCRC()) {
|
||||||
digitalWrite(LED, !digitalRead(LED)); // toggle LED
|
digitalWrite(LED, !digitalRead(LED)); // toggle LED
|
||||||
SerialBT.print(pHdr);
|
int len = strlen(pHdr);
|
||||||
SerialBT.write(Frame.Data, 24);
|
if(len < 8) {
|
||||||
|
strcpy(fullMsg, pHdr);
|
||||||
|
memcpy(&fullMsg[len], Frame.Data, 24);
|
||||||
|
SerialBT.write((uint8_t*)fullMsg, 24+len);
|
||||||
|
}
|
||||||
|
/* SerialBT.print(pHdr);
|
||||||
|
delay(1);
|
||||||
|
SerialBT.write(Frame.Data, 24);*/
|
||||||
|
delay(10);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
DebugPort.println("Data not sent to Bluetooth, CRC error!");
|
DebugPort.println("Data not sent to Bluetooth, CRC error!");
|
||||||
|
@ -67,6 +238,14 @@ void Bluetooth_SendFrame(const char* pHdr, const CProtocol& Frame, bool lineterm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Bluetooth_SendACK()
|
||||||
|
{
|
||||||
|
/* if(SerialBT.hasClient()) {
|
||||||
|
SerialBT.print("[ACK]");
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ^
|
// ^
|
||||||
// |
|
// |
|
||||||
// CLASSIC BLUETOOTH
|
// CLASSIC BLUETOOTH
|
||||||
|
@ -216,4 +395,6 @@ void BLE_Send(std::string Data)
|
||||||
|
|
||||||
#endif // ESP32_USE_BLE_RLJ
|
#endif // ESP32_USE_BLE_RLJ
|
||||||
|
|
||||||
|
#endif // ESP32_USE_HC05
|
||||||
|
|
||||||
#endif // __ESP32__
|
#endif // __ESP32__
|
|
@ -45,6 +45,7 @@ void Bluetooth_Init()
|
||||||
DebugPort.print(" @ ");
|
DebugPort.print(" @ ");
|
||||||
DebugPort.print(BTRates[BTidx]);
|
DebugPort.print(BTRates[BTidx]);
|
||||||
DebugPort.print(" baud... ");
|
DebugPort.print(" baud... ");
|
||||||
|
Bluetooth.end();
|
||||||
Bluetooth.begin(BTRates[BTidx]); // open serial port at a certain baud rate
|
Bluetooth.begin(BTRates[BTidx]); // open serial port at a certain baud rate
|
||||||
Bluetooth.print("\r\n");
|
Bluetooth.print("\r\n");
|
||||||
Bluetooth.setTimeout(50);
|
Bluetooth.setTimeout(50);
|
||||||
|
@ -85,6 +86,7 @@ void Bluetooth_Init()
|
||||||
};
|
};
|
||||||
DebugPort.println("OK");
|
DebugPort.println("OK");
|
||||||
|
|
||||||
|
Bluetooth.end();
|
||||||
Bluetooth.begin(115200);
|
Bluetooth.begin(115200);
|
||||||
bHC05Available = true;
|
bHC05Available = true;
|
||||||
|
|
||||||
|
|
|
@ -228,12 +228,12 @@ CProtocol::Init(int FrameMode)
|
||||||
Controller.OperatingMode = 0x32; // 0x32:Thermostat, 0xCD:Fixed
|
Controller.OperatingMode = 0x32; // 0x32:Thermostat, 0xCD:Fixed
|
||||||
setTemperature_Min(8); // Minimum settable temperature
|
setTemperature_Min(8); // Minimum settable temperature
|
||||||
setTemperature_Max(35); // Maximum settable temperature
|
setTemperature_Max(35); // Maximum settable temperature
|
||||||
Controller.MinTempRise = 5; // temp rise to sense fuel ignition
|
Controller.MinTempRise = 5; // temp rise to sense fuel ignition - GLOW PLUG POWER?
|
||||||
Controller.Prime = 0; // 00: normal, 0x5A: fuel prime
|
Controller.Prime = 0; // 00: normal, 0x5A: fuel prime
|
||||||
Controller.Unknown1_MSB = 0x01; // always 0x01
|
Controller.Unknown1_MSB = 0x01; // always 0x01
|
||||||
Controller.Unknown1_LSB = 0x2c; // always 0x2c 16bit: "300 secs = max run without burn detected" ??
|
Controller.Unknown1_LSB = 0x2c; // always 0x2c 16bit: "300 secs = max run without burn detected" ??
|
||||||
Controller.Unknown2_MSB = 0x0d; // always 0x0d
|
Controller.Unknown2_MSB = 0x07; // always 0x0d
|
||||||
Controller.Unknown2_LSB = 0xac; // always 0xac 16bit: "3500" ??
|
Controller.Unknown2_LSB = 0xac; // always 0xac 16bit: "3500" ?? Ignition fan max RPM????
|
||||||
setCRC();
|
setCRC();
|
||||||
}
|
}
|
||||||
else if(FrameMode == HeatMode){
|
else if(FrameMode == HeatMode){
|
||||||
|
|
|
@ -88,7 +88,7 @@ class CommStates {
|
||||||
public:
|
public:
|
||||||
// comms states
|
// comms states
|
||||||
enum eCS {
|
enum eCS {
|
||||||
Idle, ControllerRx, ControllerReport, HeaterRx1, HeaterReport1, BTC_Tx, HeaterRx2, HeaterReport2
|
Idle, OEMCtrlRx, OEMCtrlReport, HeaterRx1, HeaterReport1, BTC_Tx, HeaterRx2, HeaterReport2
|
||||||
};
|
};
|
||||||
CommStates() {
|
CommStates() {
|
||||||
set(Idle);
|
set(Idle);
|
||||||
|
@ -100,8 +100,8 @@ class CommStates {
|
||||||
bool is(eCS eState) {
|
bool is(eCS eState) {
|
||||||
return m_State == eState;
|
return m_State == eState;
|
||||||
}
|
}
|
||||||
bool saveData(unsigned char* pData, unsigned char val, int limit = 24) { // returns true when buffer filled
|
bool collectData(CProtocol& Frame, unsigned char val, int limit = 24) { // returns true when buffer filled
|
||||||
pData[m_Count++] = val;
|
Frame.Data[m_Count++] = val;
|
||||||
return m_Count == limit;
|
return m_Count == limit;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
|
@ -112,11 +112,12 @@ private:
|
||||||
|
|
||||||
CommStates CommState;
|
CommStates CommState;
|
||||||
CTxManage TxManage(TxEnbPin, BlueWire);
|
CTxManage TxManage(TxEnbPin, BlueWire);
|
||||||
CProtocol OEMControllerFrame; // 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
|
CProtocol 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 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
|
CProtocol DefaultBTCParams(CProtocol::CtrlMode); // defines the default parameters, used in case of no OEM controller
|
||||||
long lastRxTime; // used to observe inter character delays
|
long lastRxTime; // used to observe inter character delays
|
||||||
|
int hasController = 0;
|
||||||
|
|
||||||
// setup Non Volatile storage
|
// setup Non Volatile storage
|
||||||
// this is very much hardware dependent, we can use the ESP32's FLASH
|
// this is very much hardware dependent, we can use the ESP32's FLASH
|
||||||
|
@ -127,12 +128,17 @@ CHeaterStorage NVStorage; // dummy, for now
|
||||||
#endif
|
#endif
|
||||||
CHeaterStorage* pNVStorage = NULL;
|
CHeaterStorage* pNVStorage = NULL;
|
||||||
|
|
||||||
|
void PrepareTxFrame(const CProtocol& basisFrame, CProtocol& TxFrame, bool isBTCmaster);
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
// initialize serial port to interact with the "blue wire"
|
// initialize serial port to interact with the "blue wire"
|
||||||
// 25000 baud, Tx and Rx channels of Chinese heater comms interface:
|
// 25000 baud, Tx and Rx channels of Chinese heater comms interface:
|
||||||
// Tx/Rx data to/from heater,
|
// Tx/Rx data to/from heater,
|
||||||
// Note special baud rate for Chinese heater controllers
|
// Note special baud rate for Chinese heater controllers
|
||||||
|
pinMode(Tx2Pin, OUTPUT);
|
||||||
|
digitalWrite(Tx2Pin, HIGH);
|
||||||
|
pinMode(Rx2Pin, INPUT_PULLUP);
|
||||||
pinMode(ListenOnlyPin, INPUT_PULLUP);
|
pinMode(ListenOnlyPin, INPUT_PULLUP);
|
||||||
pinMode(KeyPin, OUTPUT);
|
pinMode(KeyPin, OUTPUT);
|
||||||
digitalWrite(KeyPin, LOW);
|
digitalWrite(KeyPin, LOW);
|
||||||
|
@ -217,18 +223,22 @@ void loop()
|
||||||
// have not seen any receive data for a second.
|
// have not seen any receive data for a second.
|
||||||
// OEM controller is probably not connected.
|
// OEM controller is probably not connected.
|
||||||
// Skip state machine immediately to BTC_Tx, sending our own settings.
|
// Skip state machine immediately to BTC_Tx, sending our own settings.
|
||||||
|
hasController = 0;
|
||||||
CommState.set(CommStates::BTC_Tx);
|
CommState.set(CommStates::BTC_Tx);
|
||||||
bool isBTCmaster = true;
|
bool isBTCmaster = true;
|
||||||
TxManage.PrepareFrame(DefaultBTCParams, isBTCmaster); // use our parameters, and mix in NV storage values
|
TxManage.PrepareFrame(DefaultBTCParams, isBTCmaster); // use our parameters, and mix in NV storage values
|
||||||
TxManage.Start(timenow);
|
TxManage.Start(timenow);
|
||||||
#ifdef BLUETOOTH
|
#ifdef BLUETOOTH
|
||||||
Bluetooth_SendFrame("[BTC]", TxManage.getFrame(), false); // BTC => Bluetooth Controller :-)
|
// Bluetooth_SendFrame("[BTC]", TxManage.getFrame(), false); // BTC => Bluetooth Controller :-)
|
||||||
|
// Bluetooth_SendFrame("[BTC]", TxManage.getFrame(), true); // BTC => Bluetooth Controller :-)
|
||||||
|
#else
|
||||||
|
DebugReportFrame("BTC ", OEMCtrlFrame, " ");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// precautionary action if all 24 bytes were not received whilst expecting them
|
// precautionary action if all 24 bytes were not received whilst expecting them
|
||||||
if(RxTimeElapsed > 50) {
|
if(RxTimeElapsed > 50) {
|
||||||
if( CommState.is(CommStates::ControllerRx) ||
|
if( CommState.is(CommStates::OEMCtrlRx) ||
|
||||||
CommState.is(CommStates::HeaterRx1) ||
|
CommState.is(CommStates::HeaterRx1) ||
|
||||||
CommState.is(CommStates::HeaterRx2) ) {
|
CommState.is(CommStates::HeaterRx2) ) {
|
||||||
|
|
||||||
|
@ -236,32 +246,47 @@ void loop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// read data from Serial port 1, the "blue wire" (to/from heater), store according to CommState
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Blue wire data reception
|
||||||
|
// Reads data from the "blue wire" Serial port, (to/from heater)
|
||||||
|
// If an OEM controller exists we will also see it's data frames
|
||||||
|
//
|
||||||
if (BlueWire.available()) {
|
if (BlueWire.available()) {
|
||||||
|
|
||||||
|
// Data is avaialable, read and store according to CommState
|
||||||
|
// if not in a recognised data frame state, the data is deliberately lost
|
||||||
|
|
||||||
lastRxTime = timenow;
|
lastRxTime = timenow;
|
||||||
|
|
||||||
// detect start of a new frame sequence from OEM controller
|
// Detect the start of a new frame sequence from an OEM controller
|
||||||
|
// This when there has been no activity for a while on the blue wire
|
||||||
|
// the heater always responds to a controller frame, but not otherwise
|
||||||
if( CommState.is(CommStates::Idle) && (RxTimeElapsed > 100)) {
|
if( CommState.is(CommStates::Idle) && (RxTimeElapsed > 100)) {
|
||||||
CommState.set(CommStates::ControllerRx);
|
DebugPort.print(RxTimeElapsed);
|
||||||
|
DebugPort.println(" OEM Controller re-sync");
|
||||||
|
hasController = 1;
|
||||||
|
CommState.set(CommStates::OEMCtrlRx);
|
||||||
}
|
}
|
||||||
|
|
||||||
int inByte = BlueWire.read(); // read hex byte
|
int inByte = BlueWire.read(); // read hex byte
|
||||||
|
|
||||||
if( CommState.is(CommStates::ControllerRx) ) {
|
// collect OEM controller frame
|
||||||
if(CommState.saveData(OEMControllerFrame.Data, inByte) ) {
|
if( CommState.is(CommStates::OEMCtrlRx) ) {
|
||||||
CommState.set(CommStates::ControllerReport);
|
if(CommState.collectData(OEMCtrlFrame, inByte) ) {
|
||||||
|
CommState.set(CommStates::OEMCtrlReport);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// collect heater frame, in response to an OEM controller
|
||||||
else if( CommState.is(CommStates::HeaterRx1) ) {
|
else if( CommState.is(CommStates::HeaterRx1) ) {
|
||||||
if( CommState.saveData(HeaterFrame1.Data, inByte) ) {
|
if( CommState.collectData(HeaterFrame1, inByte) ) {
|
||||||
CommState.set(CommStates::HeaterReport1);
|
CommState.set(CommStates::HeaterReport1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// collect heater frame, in response to our control frame
|
||||||
else if( CommState.is(CommStates::HeaterRx2) ) {
|
else if( CommState.is(CommStates::HeaterRx2) ) {
|
||||||
if( CommState.saveData(HeaterFrame2.Data, inByte) ) {
|
if( CommState.collectData(HeaterFrame2, inByte) ) {
|
||||||
CommState.set(CommStates::HeaterReport2);
|
CommState.set(CommStates::HeaterReport2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -269,13 +294,13 @@ void loop()
|
||||||
} // BlueWire.available
|
} // BlueWire.available
|
||||||
|
|
||||||
|
|
||||||
if( CommState.is(CommStates::ControllerReport) ) {
|
if( CommState.is(CommStates::OEMCtrlReport) ) {
|
||||||
// filled controller frame, report
|
// filled controller frame, report
|
||||||
#ifdef BLUETOOTH
|
#ifdef BLUETOOTH
|
||||||
// echo received OEM controller frame over Bluetooth, using [OEM] header
|
// echo received OEM controller frame over Bluetooth, using [OEM] header
|
||||||
Bluetooth_SendFrame("[OEM]", OEMControllerFrame, false);
|
Bluetooth_SendFrame("[OEM]", OEMCtrlFrame, true);
|
||||||
#else
|
#else
|
||||||
DebugReportFrame("OEM ", OEMControllerFrame, " ");
|
DebugReportFrame("OEM ", OEMCtrlFrame, " ");
|
||||||
#endif
|
#endif
|
||||||
CommState.set(CommStates::HeaterRx1);
|
CommState.set(CommStates::HeaterRx1);
|
||||||
}
|
}
|
||||||
|
@ -291,7 +316,7 @@ void loop()
|
||||||
|
|
||||||
if(digitalRead(ListenOnlyPin)) {
|
if(digitalRead(ListenOnlyPin)) {
|
||||||
bool isBTCmaster = false;
|
bool isBTCmaster = false;
|
||||||
TxManage.PrepareFrame(OEMControllerFrame, isBTCmaster); // parrot OEM parameters, but block NV modes
|
TxManage.PrepareFrame(OEMCtrlFrame, isBTCmaster); // parrot OEM parameters, but block NV modes
|
||||||
TxManage.Start(timenow);
|
TxManage.Start(timenow);
|
||||||
CommState.set(CommStates::BTC_Tx);
|
CommState.set(CommStates::BTC_Tx);
|
||||||
}
|
}
|
||||||
|
@ -302,14 +327,21 @@ void loop()
|
||||||
|
|
||||||
else if( CommState.is(CommStates::HeaterReport2) ) {
|
else if( CommState.is(CommStates::HeaterReport2) ) {
|
||||||
// received heater frame (after our control message), report
|
// received heater frame (after our control message), report
|
||||||
|
delay(5);
|
||||||
#ifdef BLUETOOTH
|
#ifdef BLUETOOTH
|
||||||
|
if(!hasController) {
|
||||||
|
Bluetooth_SendFrame("[BTC]", TxManage.getFrame(), true); // BTC => Bluetooth Controller :-)
|
||||||
Bluetooth_SendFrame("[HTR]", HeaterFrame2); // pin not grounded, suppress duplicate to BT
|
Bluetooth_SendFrame("[HTR]", HeaterFrame2); // pin not grounded, suppress duplicate to BT
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
DebugReportFrame("Htr2 ", HeaterFrame2, "\r\n");
|
DebugReportFrame("Htr2 ", HeaterFrame2, "\r\n");
|
||||||
#endif
|
#endif
|
||||||
// if(!digitalRead(ListenOnlyPin)) {
|
// if(!digitalRead(ListenOnlyPin)) {
|
||||||
// }
|
// }
|
||||||
CommState.set(CommStates::Idle);
|
CommState.set(CommStates::Idle);
|
||||||
|
|
||||||
|
Serial.print("Free heap ");
|
||||||
|
Serial.println(ESP.getFreeHeap());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // loop
|
} // loop
|
||||||
|
@ -325,6 +357,7 @@ void DebugReportFrame(const char* hdr, const CProtocol& Frame, const char* ftr)
|
||||||
DebugPort.print(ftr); // footer
|
DebugPort.print(ftr); // footer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Command_Interpret(const char* pLine)
|
void Command_Interpret(const char* pLine)
|
||||||
{
|
{
|
||||||
unsigned char cVal;
|
unsigned char cVal;
|
||||||
|
@ -393,7 +426,7 @@ void Command_Interpret(const char* pLine)
|
||||||
pLine += 4;
|
pLine += 4;
|
||||||
cVal = !pNVStorage->getThermostatMode();
|
cVal = !pNVStorage->getThermostatMode();
|
||||||
pNVStorage->setThermostatMode(cVal);
|
pNVStorage->setThermostatMode(cVal);
|
||||||
DebugPort.print("Mode = ");
|
DebugPort.print("Mode now ");
|
||||||
DebugPort.println(cVal ? "Thermostat" : "Fixed Hz");
|
DebugPort.println(cVal ? "Thermostat" : "Fixed Hz");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -3,6 +3,26 @@
|
||||||
|
|
||||||
extern void DebugReportFrame(const char* hdr, const CProtocol&, const char* ftr);
|
extern void DebugReportFrame(const char* hdr, const CProtocol&, const char* ftr);
|
||||||
|
|
||||||
|
// CTxManage is used to send a data frame to the blue wire
|
||||||
|
//
|
||||||
|
// As the blue wire is bidirectional, we need to only allow our transmit data
|
||||||
|
// to reach the blue wire when we actually want to send data.
|
||||||
|
// At all other times we are listening to the blue wire, receiving any async data
|
||||||
|
//
|
||||||
|
// This requires external circuitry to toggle the Tx/Rx modes.
|
||||||
|
// A "Tx Gating" signal is used.
|
||||||
|
// when high, transmit data is sent to the blue wire
|
||||||
|
// when low, transmit data is blocked (Hi-Z)
|
||||||
|
//
|
||||||
|
// Ideally the circuit also prevents feeding back our own Tx data into the Rx pin
|
||||||
|
// but the main software loop handles this situation by only accepting Rx data when expected.
|
||||||
|
//
|
||||||
|
// Timing diagram
|
||||||
|
// ____________________
|
||||||
|
// Tx Gate ____________________| |___________________________
|
||||||
|
// _____________________________________________________________________
|
||||||
|
// Tx Data |||||||||||||||
|
||||||
|
|
||||||
CTxManage::CTxManage(int TxGatePin, HardwareSerial& serial) :
|
CTxManage::CTxManage(int TxGatePin, HardwareSerial& serial) :
|
||||||
m_BlueWireSerial(serial),
|
m_BlueWireSerial(serial),
|
||||||
m_TxFrame(CProtocol::CtrlMode)
|
m_TxFrame(CProtocol::CtrlMode)
|
||||||
|
@ -75,7 +95,7 @@ CTxManage::PrepareFrame(const CProtocol& basisFrame, bool isBTCmaster)
|
||||||
void
|
void
|
||||||
CTxManage::Start(unsigned long timenow)
|
CTxManage::Start(unsigned long timenow)
|
||||||
{
|
{
|
||||||
if(timenow == 0) // avoid a black hole if millis() wraps
|
if(timenow == 0) // avoid a black hole if millis() has wrapped to zero
|
||||||
timenow++;
|
timenow++;
|
||||||
|
|
||||||
m_nStartTime = timenow;
|
m_nStartTime = timenow;
|
||||||
|
@ -97,17 +117,17 @@ CTxManage::CheckTx(unsigned long timenow)
|
||||||
digitalWrite(m_nTxGatePin, HIGH);
|
digitalWrite(m_nTxGatePin, HIGH);
|
||||||
}
|
}
|
||||||
if(m_bTxPending && (diff > (m_nStartDelay + m_nFrontPorch))) {
|
if(m_bTxPending && (diff > (m_nStartDelay + m_nFrontPorch))) {
|
||||||
// begin serial transmission
|
// front porch expired, perform serial transmission
|
||||||
|
// Tx gate remains held high
|
||||||
m_bTxPending = false;
|
m_bTxPending = false;
|
||||||
m_BlueWireSerial.write(m_TxFrame.Data, 24); // write native binary values
|
m_BlueWireSerial.write(m_TxFrame.Data, 24); // write native binary values
|
||||||
// DebugReportFrame("BTC ", m_TxFrame, " "); // report frame to debug port
|
|
||||||
}
|
}
|
||||||
if(diff > (m_nStartDelay + m_nFrameTime)) {
|
if(diff > (m_nStartDelay + m_nFrameTime)) {
|
||||||
// conclude Tx gating
|
// conclude Tx gating after (emperical) delay
|
||||||
m_nStartTime = 0;
|
|
||||||
digitalWrite(m_nTxGatePin, LOW);
|
digitalWrite(m_nTxGatePin, LOW);
|
||||||
|
m_nStartTime = 0; // cancel, we are DONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m_nStartTime == 0;
|
return m_nStartTime == 0; // returns true when done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue