merge Junkers Tx logic

This commit is contained in:
proddy
2019-05-26 12:23:50 +02:00
parent 65bd9b96d4
commit 1d7310411f
8 changed files with 76 additions and 41 deletions

View File

@@ -5,20 +5,25 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.8.0dev] 2019- ## [1.8.0dev] 2019-05-26
### Added ### Added
- MM50 Mixer - MM50 Mixer
- tx_delay takes a value from 0 to 3 for the different Tx logic
0 = original classic ems logic
1 = @kwertie01 ems+ logic (https://github.com/proddy/EMS-ESP/issues/23#issuecomment-476872291)
2 = @susisstrolch logic [(pull request 113)](https://github.com/proddy/EMS-ESP/pull/113)
3 = @philrich logic for Junkers (https://github.com/proddy/EMS-ESP/files/3190563/ems-delay-rev-poll.patch.txt)
### Fixed ### Fixed
- runtime exceptions with latest 2.5.1 arduino core - runtime exceptions with latest 2.5.1 arduino core
### Changed
- Improved Tx code, by @Susis Strolch [(pull request 113)](https://github.com/proddy/EMS-ESP/pull/113). Use `set_txdelay 2`
## [1.7.0] 2019-05-11 ## [1.7.0] 2019-05-11
### Added ### Added

View File

@@ -496,7 +496,7 @@ void MyESP::_consoleShowHelp() {
} else { } else {
myDebug_P(PSTR("* Hostname: %s (%s)"), _getESPhostname().c_str(), WiFi.localIP().toString().c_str()); myDebug_P(PSTR("* Hostname: %s (%s)"), _getESPhostname().c_str(), WiFi.localIP().toString().c_str());
myDebug_P(PSTR("* WiFi SSID: %s (signal %d%%)"), WiFi.SSID().c_str(), getWifiQuality()); myDebug_P(PSTR("* WiFi SSID: %s (signal %d%%)"), WiFi.SSID().c_str(), getWifiQuality());
myDebug_P(PSTR("* MQTT is %s"), mqttClient.connected() ? "connected" : "disconnected"); myDebug_P(PSTR("* MQTT %s"), mqttClient.connected() ? "connected" : "disconnected");
} }
myDebug_P(PSTR("*")); myDebug_P(PSTR("*"));

View File

@@ -106,7 +106,7 @@ command_t project_cmds[] = {
{true, "shower_alert <on | off>", "send a warning of cold water after shower time is exceeded"}, {true, "shower_alert <on | off>", "send a warning of cold water after shower time is exceeded"},
{true, "publish_wait <seconds>", "set frequency for publishing to MQTT"}, {true, "publish_wait <seconds>", "set frequency for publishing to MQTT"},
{true, "heating_circuit <1 | 2>", "set the thermostat HC to work with if using multiple heating circuits"}, {true, "heating_circuit <1 | 2>", "set the thermostat HC to work with if using multiple heating circuits"},
{true, "tx_delay <n>", "0=normal, 1=ems+, 2=new logic"}, {true, "tx_delay <n>", "0=classic ems logic, 1=@kwertie01 ems+ logic, 2=@susisstrolch logic, 3=@philrich logic for Junkers"},
{false, "info", "show data captured on the EMS bus"}, {false, "info", "show data captured on the EMS bus"},
{false, "log <n | b | t | r | v>", "set logging mode to none, basic, thermostat only, raw or verbose"}, {false, "log <n | b | t | r | v>", "set logging mode to none, basic, thermostat only, raw or verbose"},
@@ -339,10 +339,10 @@ void showInfo() {
if (ems_getBusConnected()) { if (ems_getBusConnected()) {
myDebug_P(PSTR(" Bus is connected")); myDebug_P(PSTR(" Bus is connected"));
myDebug_P(PSTR(" Rx: Poll=%d microsecs, # Rx telegrams read=%d, # CRC errors=%d"), ems_getPollFrequency(), EMS_Sys_Status.emsRxPgks, EMS_Sys_Status.emxCrcErr); myDebug_P(PSTR(" Rx: Poll=%d microseconds, # Rx telegrams read=%d, # CRC errors=%d"), ems_getPollFrequency(), EMS_Sys_Status.emsRxPgks, EMS_Sys_Status.emxCrcErr);
if (ems_getTxCapable()) { if (ems_getTxCapable()) {
myDebug_P(PSTR(" Tx: available, Tx delay is %d, # Tx telegrams sent=%d"), ems_getTxDelay(), EMS_Sys_Status.emsTxPkgs); myDebug_P(PSTR(" Tx: available, Tx delay is %d, # successful write commands=%d"), ems_getTxDelay(), EMS_Sys_Status.emsTxPkgs);
} else { } else {
myDebug_P(PSTR(" Tx: no signal")); myDebug_P(PSTR(" Tx: no signal"));
} }

View File

@@ -221,6 +221,7 @@ void ems_init() {
EMS_Sys_Status.emsPollFrequency = 0; EMS_Sys_Status.emsPollFrequency = 0;
EMS_Sys_Status.txRetryCount = 0; EMS_Sys_Status.txRetryCount = 0;
EMS_Sys_Status.emsTxDelay = 0; EMS_Sys_Status.emsTxDelay = 0;
EMS_Sys_Status.emsReverse = false;
// thermostat // thermostat
EMS_Thermostat.setpoint_roomTemp = EMS_VALUE_SHORT_NOTSET; EMS_Thermostat.setpoint_roomTemp = EMS_VALUE_SHORT_NOTSET;
@@ -331,6 +332,13 @@ bool ems_getPoll() {
void ems_setTxDelay(uint8_t delay) { void ems_setTxDelay(uint8_t delay) {
EMS_Sys_Status.emsTxDelay = delay; EMS_Sys_Status.emsTxDelay = delay;
// special case for Junkers. If tx_delay is 3 then set the reverse poll flag
// https://github.com/proddy/EMS-ESP/issues/103#issuecomment-495945850
if (delay == 3) {
EMS_Sys_Status.emsReverse = true;
myDebug_P(PSTR("Setting for Tx Junkers logic and enabled the poll reverse flag"));
}
} }
uint8_t ems_getTxDelay() { uint8_t ems_getTxDelay() {
@@ -557,8 +565,9 @@ void _ems_sendTelegram() {
return; return;
} }
// create header // create the header
EMS_TxTelegram.data[0] = EMS_ID_ME; // src EMS_TxTelegram.data[0] = (EMS_Sys_Status.emsReverse) ? EMS_ID_ME | 0x80 : EMS_ID_ME; // src
// dest // dest
if (EMS_TxTelegram.action == EMS_TX_TELEGRAM_WRITE) { if (EMS_TxTelegram.action == EMS_TX_TELEGRAM_WRITE) {
EMS_TxTelegram.data[1] = EMS_TxTelegram.dest; EMS_TxTelegram.data[1] = EMS_TxTelegram.dest;
@@ -672,6 +681,7 @@ void _ems_readTelegram(uint8_t * telegram, uint8_t length) {
// create the Rx package // create the Rx package
static _EMS_RxTelegram EMS_RxTelegram; static _EMS_RxTelegram EMS_RxTelegram;
static uint32_t _last_emsPollFrequency = 0; static uint32_t _last_emsPollFrequency = 0;
EMS_RxTelegram.telegram = telegram; EMS_RxTelegram.telegram = telegram;
EMS_RxTelegram.timestamp = millis(); EMS_RxTelegram.timestamp = millis();
EMS_RxTelegram.length = length; EMS_RxTelegram.length = length;
@@ -684,12 +694,11 @@ void _ems_readTelegram(uint8_t * telegram, uint8_t length) {
EMS_Sys_Status.emsPollFrequency = (timenow_microsecs - _last_emsPollFrequency); EMS_Sys_Status.emsPollFrequency = (timenow_microsecs - _last_emsPollFrequency);
_last_emsPollFrequency = timenow_microsecs; _last_emsPollFrequency = timenow_microsecs;
// check first for a Poll for us
uint8_t value = telegram[0]; // 1st byte of data package uint8_t value = telegram[0]; // 1st byte of data package
if ((value & 0x7F) == EMS_ID_ME) { // check first for a Poll for us
EMS_Sys_Status.emsTxCapable = true; // the poll has the MSB set - seems to work on both EMS and Junkers
if (value == (EMS_ID_ME | 0x80)) {
// do we have something to send thats waiting in the Tx queue? // do we have something to send thats waiting in the Tx queue?
// if so send it if the Queue is not in a wait state // if so send it if the Queue is not in a wait state
if ((!EMS_TxQueue.isEmpty()) && (EMS_Sys_Status.emsTxStatus == EMS_TX_STATUS_IDLE)) { if ((!EMS_TxQueue.isEmpty()) && (EMS_Sys_Status.emsTxStatus == EMS_TX_STATUS_IDLE)) {

View File

@@ -95,6 +95,7 @@ typedef struct {
bool emsTxDisabled; // true to prevent all Tx bool emsTxDisabled; // true to prevent all Tx
uint8_t txRetryCount; // # times the last Tx was re-sent uint8_t txRetryCount; // # times the last Tx was re-sent
uint8_t emsTxDelay; // handles Tx logic uint8_t emsTxDelay; // handles Tx logic
bool emsReverse; // if true, poll logic is reversed
} _EMS_Sys_Status; } _EMS_Sys_Status;
// The Tx send package // The Tx send package

View File

@@ -175,7 +175,11 @@ void ICACHE_FLASH_ATTR emsuart_tx_brk() {
// automatically be sent when the tx fifo is empty // automatically be sent when the tx fifo is empty
tmp = (1 << UCBRK); tmp = (1 << UCBRK);
USC0(EMSUART_UART) |= (tmp); // set bit USC0(EMSUART_UART) |= (tmp); // set bit
delayMicroseconds(EMSUART_TX_BRK_WAIT); if (EMS_Sys_Status.emsTxDelay <= 2) {
delayMicroseconds(EMSUART_TX_BRK_WAIT); // classic mode
} else if (EMS_Sys_Status.emsTxDelay == 3) {
delayMicroseconds(EMSUART_TX_WAIT_BRK - EMSUART_TX_LAG); // 1144 (11 Bits)
}
USC0(EMSUART_UART) &= ~(tmp); // clear bit USC0(EMSUART_UART) &= ~(tmp); // clear bit
} }
@@ -193,21 +197,32 @@ static inline void ICACHE_FLASH_ATTR emsuart_loopback(bool enable) {
* Send to Tx, ending with a <BRK> * Send to Tx, ending with a <BRK>
*/ */
void ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len) { void ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len) {
// backwards compatibility if (EMS_Sys_Status.emsTxDelay == 0) { // Classic logic
if (EMS_Sys_Status.emsTxDelay < 2) { for (uint8_t i = 0; i < len; i++) {
USF(EMSUART_UART) = buf[i];
}
emsuart_tx_brk(); // send <BRK>
} else if (EMS_Sys_Status.emsTxDelay == 1) { // With extra tx delay for EMS+
for (uint8_t i = 0; i < len; i++) {
USF(EMSUART_UART) = buf[i];
delayMicroseconds(EMSUART_TX_BRK_WAIT); // https://github.com/proddy/EMS-ESP/issues/23#
}
emsuart_tx_brk(); // send <BRK>
} else if (EMS_Sys_Status.emsTxDelay == 3) { // Junkers logic by @philrich
for (uint8_t i = 0; i < len; i++) { for (uint8_t i = 0; i < len; i++) {
USF(EMSUART_UART) = buf[i]; USF(EMSUART_UART) = buf[i];
// check if we need to force a delay to slow down Tx // just to be safe wait for tx fifo empty (needed?)
// https://github.com/proddy/EMS-ESP/issues/23# while (((USS(EMSUART_UART) >> USTXC) & 0xff) != 0)
if (EMS_Sys_Status.emsTxDelay == 1) { ;
delayMicroseconds(EMSUART_TX_BRK_WAIT);
} // wait until bits are sent on wire
delayMicroseconds(EMSUART_TX_WAIT_BYTE - EMSUART_TX_LAG + EMSUART_TX_WAIT_GAP);
} }
emsuart_tx_brk(); // send <BRK> emsuart_tx_brk(); // send <BRK>
} else { } else if (EMS_Sys_Status.emsTxDelay == 2) { // smart Tx - take two - https://github.com/proddy/EMS-ESP/issues/103 by @susisstrolch
/* smart Tx - take two - https://github.com/proddy/EMS-ESP/issues/103 by @susisstrolch
* changed logic... /*
* we emit the whole telegram, with Rx interrupt disabled, collecting busmaster response in FIFO. * we emit the whole telegram, with Rx interrupt disabled, collecting busmaster response in FIFO.
* after sending the last char we poll the Rx status until either * after sending the last char we poll the Rx status until either
* - size(Rx FIFO) == size(Tx-Telegram) * - size(Rx FIFO) == size(Tx-Telegram)
@@ -227,8 +242,7 @@ void ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len) {
} }
// wait until we received sizeof(telegram) or RxBRK (== collision detect) // wait until we received sizeof(telegram) or RxBRK (== collision detect)
// while ((((USS(EMSUART_UART) >> USRXC) & 0xFF) < len) || !(USIS(EMSUART_UART) & (1 << UIBD))) while ((((USS(EMSUART_UART) >> USRXC) & 0xFF) < len) || (USIS(EMSUART_UART) & (1 << UIBD))) {
while ((((USS(EMSUART_UART) >> USRXC) & 0xFF) < len) || (U0IS & (1 << UIBD))) {
delayMicroseconds(11 * EMSUART_BIT_TIME); // burn CPU cycles... delayMicroseconds(11 * EMSUART_BIT_TIME); // burn CPU cycles...
} }
@@ -236,7 +250,7 @@ void ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len) {
// on Rx-BRK (bus collision), we simply enable Rx and leave // on Rx-BRK (bus collision), we simply enable Rx and leave
// otherwise, we send the final Tx-BRK in loopback and enable Rx-INT. // otherwise, we send the final Tx-BRK in loopback and enable Rx-INT.
// worst case, we'll see an additional Rx-BRK... // worst case, we'll see an additional Rx-BRK...
if (!(U0IS & (1 << UIBD))) { if (!(USIS(EMSUART_UART) & (1 << UIBD))) {
// no bus collision - send terminating BRK signal // no bus collision - send terminating BRK signal
emsuart_loopback(true); emsuart_loopback(true);
USC0(EMSUART_UART) |= (1 << UCBRK); // set <BRK> USC0(EMSUART_UART) |= (1 << UCBRK); // set <BRK>
@@ -260,6 +274,11 @@ void ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len) {
* Send the Poll (our own ID) to Tx as a single byte and end with a <BRK> * Send the Poll (our own ID) to Tx as a single byte and end with a <BRK>
*/ */
void ICACHE_FLASH_ATTR emsuart_tx_poll() { void ICACHE_FLASH_ATTR emsuart_tx_poll() {
static uint8_t buf[] = {EMS_ID_ME}; static uint8_t buf[1];
if (EMS_Sys_Status.emsReverse) {
buf[0] = {EMS_ID_ME | 0x80};
} else {
buf[0] = {EMS_ID_ME};
}
emsuart_tx_buffer(buf, 1); emsuart_tx_buffer(buf, 1);
} }

View File

@@ -16,11 +16,12 @@
#define EMS_MAXBUFFERS 10 // 4 buffers for circular filling to avoid collisions #define EMS_MAXBUFFERS 10 // 4 buffers for circular filling to avoid collisions
#define EMS_MAXBUFFERSIZE 32 // max size of the buffer. packets are max 32 bytes #define EMS_MAXBUFFERSIZE 32 // max size of the buffer. packets are max 32 bytes
// this is how long we drop the Tx signal to create a 11-bit Break of zeros (BRK) #define EMSUART_TX_BRK_WAIT 2070 // the BRK from Boiler master is roughly 1.039ms, so accounting for hardware lag using around 2078 (for half-duplex) - 8 (lag)
// At 9600 baud, 11 bits will be 1144 microseconds
// the BRK from Boiler master is roughly 1.039ms, so accounting for hardware lag using around 2078 (for half-duplex) - 8 (lag)
#define EMSUART_TX_BRK_WAIT 2070
#define EMSUART_BIT_TIME 104 // bit time @9600 baud #define EMSUART_BIT_TIME 104 // bit time @9600 baud
#define EMSUART_TX_WAIT_BYTE EMSUART_BIT_TIME * 10 // Time to send one Byte (8 Bits, 1 Start Bit, 1 Stop Bit)
#define EMSUART_TX_WAIT_BRK EMSUART_BIT_TIME * 11 // Time to send a BRK Signal (11 Bit)
#define EMSUART_TX_WAIT_GAP EMSUART_BIT_TIME * 7 // Gap between to Bytes
#define EMSUART_TX_LAG 8 // Assumed Lag
#define EMSUART_recvTaskPrio 1 #define EMSUART_recvTaskPrio 1
#define EMSUART_recvTaskQueueLen 64 #define EMSUART_recvTaskQueueLen 64

View File

@@ -6,5 +6,5 @@
#pragma once #pragma once
#define APP_NAME "EMS-ESP" #define APP_NAME "EMS-ESP"
#define APP_VERSION "1.8.0b3" #define APP_VERSION "1.8.0b4"
#define APP_HOSTNAME "ems-esp" #define APP_HOSTNAME "ems-esp"