2018-11-26 11:58:15 +00:00
|
|
|
/*
|
|
|
|
* 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/>.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2018-09-23 06:31:09 +00:00
|
|
|
#include "TxManage.h"
|
2018-10-20 07:11:23 +00:00
|
|
|
#include "NVStorage.h"
|
2018-09-23 06:31:09 +00:00
|
|
|
|
2018-10-20 07:11:23 +00:00
|
|
|
extern void DebugReportFrame(const char* hdr, const CProtocol&, const char* ftr);
|
2018-09-23 06:31:09 +00:00
|
|
|
|
2018-10-27 06:35:17 +00:00
|
|
|
// 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 |||||||||||||||
|
|
|
|
|
2018-10-20 07:11:23 +00:00
|
|
|
CTxManage::CTxManage(int TxGatePin, HardwareSerial& serial) :
|
|
|
|
m_BlueWireSerial(serial),
|
|
|
|
m_TxFrame(CProtocol::CtrlMode)
|
2018-09-23 06:31:09 +00:00
|
|
|
{
|
|
|
|
m_bOnReq = false;
|
|
|
|
m_bOffReq = false;
|
|
|
|
m_bTxPending = false;
|
|
|
|
m_nStartTime = 0;
|
2018-10-20 07:11:23 +00:00
|
|
|
m_nTxGatePin = TxGatePin;
|
2018-11-06 09:43:54 +00:00
|
|
|
_rawCommand = 0;
|
2018-09-23 06:31:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CTxManage::begin()
|
|
|
|
{
|
2018-10-20 07:11:23 +00:00
|
|
|
pinMode(m_nTxGatePin, OUTPUT);
|
2018-11-19 19:31:20 +00:00
|
|
|
digitalWrite(m_nTxGatePin, LOW); // default to receive mode
|
2018-09-23 06:31:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2018-11-07 10:31:00 +00:00
|
|
|
CTxManage::queueOnRequest(bool set)
|
2018-09-23 06:31:09 +00:00
|
|
|
{
|
2018-11-19 19:31:20 +00:00
|
|
|
m_bOnReq = set; // allow cancellation via heater response frame decode
|
2018-11-07 10:31:00 +00:00
|
|
|
m_bOffReq = false;
|
2018-09-23 06:31:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2018-11-07 10:31:00 +00:00
|
|
|
CTxManage::queueOffRequest(bool set)
|
2018-09-23 06:31:09 +00:00
|
|
|
{
|
2018-11-19 19:31:20 +00:00
|
|
|
m_bOffReq = set; // allow cancellation via heater response frame decode
|
2018-11-07 10:31:00 +00:00
|
|
|
m_bOnReq = false;
|
2018-09-23 06:31:09 +00:00
|
|
|
}
|
|
|
|
|
2018-11-06 09:43:54 +00:00
|
|
|
void
|
|
|
|
CTxManage::queueRawCommand(unsigned char val)
|
|
|
|
{
|
|
|
|
_rawCommand = val;
|
|
|
|
}
|
|
|
|
|
2018-10-20 07:11:23 +00:00
|
|
|
void
|
|
|
|
CTxManage::PrepareFrame(const CProtocol& basisFrame, bool isBTCmaster)
|
2018-09-23 06:31:09 +00:00
|
|
|
{
|
2018-10-20 07:11:23 +00:00
|
|
|
// copy supplied frame, typically this will be the values an OEM controller delivered
|
|
|
|
// which means we parrot that data by default.
|
|
|
|
// When parroting, we must especially avoid ping ponging "set temperature"!
|
|
|
|
// Otherwise we are supplied with the default params for standalone mode, which we
|
|
|
|
// then instil the NV parameters
|
|
|
|
m_TxFrame = basisFrame;
|
|
|
|
|
|
|
|
// ALWAYS install on/off commands if required
|
|
|
|
m_TxFrame.resetCommand(); // no command upon blue wire initially, unless a request is pending
|
2018-11-06 09:43:54 +00:00
|
|
|
if(_rawCommand) {
|
|
|
|
m_TxFrame.setRawCommand(_rawCommand);
|
|
|
|
_rawCommand = 0;
|
2018-10-20 07:11:23 +00:00
|
|
|
}
|
2018-11-06 09:43:54 +00:00
|
|
|
else {
|
|
|
|
if(m_bOnReq) {
|
2018-11-07 10:31:00 +00:00
|
|
|
// m_bOnReq = false; // requires cancel via queueOnRequest(false)
|
2018-11-06 09:43:54 +00:00
|
|
|
m_TxFrame.onCommand();
|
|
|
|
}
|
|
|
|
if(m_bOffReq) {
|
2018-11-07 10:31:00 +00:00
|
|
|
// m_bOffReq = false; // requires cancel via queueOffRequest(false)
|
2018-11-06 09:43:54 +00:00
|
|
|
m_TxFrame.offCommand();
|
|
|
|
}
|
2018-10-20 07:11:23 +00:00
|
|
|
}
|
|
|
|
|
2018-09-23 08:59:19 +00:00
|
|
|
// 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
|
2018-10-20 07:11:23 +00:00
|
|
|
if(isBTCmaster) {
|
2018-11-13 11:02:14 +00:00
|
|
|
m_TxFrame.setActiveMode(); // this allows heater to save the tuning params to EEPROM
|
2018-11-28 11:15:23 +00:00
|
|
|
m_TxFrame.setFan_Min(NVstore.getFmin());
|
|
|
|
m_TxFrame.setFan_Max(NVstore.getFmax());
|
|
|
|
m_TxFrame.setPump_Min(NVstore.getPmin());
|
|
|
|
m_TxFrame.setPump_Max(NVstore.getPmax());
|
|
|
|
m_TxFrame.setThermostatMode(NVstore.getThermostatMode());
|
2018-12-15 09:34:58 +00:00
|
|
|
m_TxFrame.setTemperature_Desired(NVstore.getDesiredTemperature());
|
2018-10-20 07:11:23 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
m_TxFrame.setPassiveMode(); // this prevents the tuning parameters being saved by heater
|
|
|
|
}
|
|
|
|
|
|
|
|
// ensure CRC valid
|
|
|
|
m_TxFrame.setCRC();
|
|
|
|
}
|
2018-09-23 06:31:09 +00:00
|
|
|
|
2018-10-20 07:11:23 +00:00
|
|
|
void
|
|
|
|
CTxManage::Start(unsigned long timenow)
|
|
|
|
{
|
2018-10-27 06:35:17 +00:00
|
|
|
if(timenow == 0) // avoid a black hole if millis() has wrapped to zero
|
2018-09-23 06:31:09 +00:00
|
|
|
timenow++;
|
|
|
|
|
|
|
|
m_nStartTime = timenow;
|
|
|
|
m_bTxPending = true;
|
|
|
|
}
|
|
|
|
|
2018-10-20 07:11:23 +00:00
|
|
|
// generate a Tx Gate, then send the TxFrame to the Blue wire
|
|
|
|
// Note the serial data is ISR driven, we need to hold off
|
|
|
|
// for a while to let teh buffewred dat clear before closing the Tx Gate.
|
2018-09-23 08:59:19 +00:00
|
|
|
bool
|
|
|
|
CTxManage::CheckTx(unsigned long timenow)
|
2018-09-23 06:31:09 +00:00
|
|
|
{
|
|
|
|
if(m_nStartTime) {
|
|
|
|
|
|
|
|
long diff = timenow - m_nStartTime;
|
|
|
|
|
|
|
|
if(diff > m_nStartDelay) {
|
|
|
|
// begin front porch of Tx gating pulse
|
2018-10-20 07:11:23 +00:00
|
|
|
digitalWrite(m_nTxGatePin, HIGH);
|
2018-09-23 06:31:09 +00:00
|
|
|
}
|
|
|
|
if(m_bTxPending && (diff > (m_nStartDelay + m_nFrontPorch))) {
|
2018-10-27 06:35:17 +00:00
|
|
|
// front porch expired, perform serial transmission
|
|
|
|
// Tx gate remains held high
|
2018-09-23 06:31:09 +00:00
|
|
|
m_bTxPending = false;
|
2018-10-20 07:11:23 +00:00
|
|
|
m_BlueWireSerial.write(m_TxFrame.Data, 24); // write native binary values
|
2018-09-23 06:31:09 +00:00
|
|
|
}
|
|
|
|
if(diff > (m_nStartDelay + m_nFrameTime)) {
|
2018-10-27 06:35:17 +00:00
|
|
|
// conclude Tx gating after (emperical) delay
|
2018-10-20 07:11:23 +00:00
|
|
|
digitalWrite(m_nTxGatePin, LOW);
|
2018-10-27 06:35:17 +00:00
|
|
|
m_nStartTime = 0; // cancel, we are DONE
|
2018-09-23 06:31:09 +00:00
|
|
|
}
|
|
|
|
}
|
2018-10-27 06:35:17 +00:00
|
|
|
return m_nStartTime == 0; // returns true when done
|
2018-09-23 06:31:09 +00:00
|
|
|
}
|
|
|
|
|