From 20ce017686719859b45682886b4f275ac84e5ad5 Mon Sep 17 00:00:00 2001 From: proddy Date: Sat, 13 Jun 2020 15:46:49 +0200 Subject: [PATCH 1/7] fixed order of debug & trace according to spec --- lib/uuid-log/src/format_level_char.cpp | 2 +- lib/uuid-log/src/format_level_lowercase.cpp | 2 +- lib/uuid-log/src/format_level_uppercase.cpp | 2 +- lib/uuid-log/src/levels.cpp | 2 +- lib/uuid-log/src/levels_lowercase.cpp | 2 +- lib/uuid-log/src/levels_uppercase.cpp | 2 +- lib/uuid-log/src/uuid/log.h | 4 ++-- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/uuid-log/src/format_level_char.cpp b/lib/uuid-log/src/format_level_char.cpp index 39f7848ea..264e88083 100644 --- a/lib/uuid-log/src/format_level_char.cpp +++ b/lib/uuid-log/src/format_level_char.cpp @@ -23,7 +23,7 @@ namespace uuid { namespace log { char format_level_char(Level level) { - constexpr char log_level_chars[(int)Level::ALL - (int)Level::OFF + 1] = {' ', 'P', 'A', 'C', 'E', 'W', 'N', 'I', 'T', 'D', ' '}; // changed by proddy + constexpr char log_level_chars[(int)Level::ALL - (int)Level::OFF + 1] = {' ', 'P', 'A', 'C', 'E', 'W', 'N', 'I', 'D', 'T', ' '}; return log_level_chars[(int)level + 1]; } diff --git a/lib/uuid-log/src/format_level_lowercase.cpp b/lib/uuid-log/src/format_level_lowercase.cpp index 4cd603590..61dc124fb 100644 --- a/lib/uuid-log/src/format_level_lowercase.cpp +++ b/lib/uuid-log/src/format_level_lowercase.cpp @@ -47,8 +47,8 @@ PROGMEM = {reinterpret_cast(pstr_level_lowercase_of reinterpret_cast(pstr_level_lowercase_warning), reinterpret_cast(pstr_level_lowercase_notice), reinterpret_cast(pstr_level_lowercase_info), - reinterpret_cast(pstr_level_lowercase_trace), // switched by proddy reinterpret_cast(pstr_level_lowercase_debug), + reinterpret_cast(pstr_level_lowercase_trace), reinterpret_cast(pstr_level_lowercase_all)}; const __FlashStringHelper * format_level_lowercase(Level level) { diff --git a/lib/uuid-log/src/format_level_uppercase.cpp b/lib/uuid-log/src/format_level_uppercase.cpp index 9379b378a..480e2e7a8 100644 --- a/lib/uuid-log/src/format_level_uppercase.cpp +++ b/lib/uuid-log/src/format_level_uppercase.cpp @@ -47,8 +47,8 @@ PROGMEM = {reinterpret_cast(pstr_level_uppercase_of reinterpret_cast(pstr_level_uppercase_warning), reinterpret_cast(pstr_level_uppercase_notice), reinterpret_cast(pstr_level_uppercase_info), - reinterpret_cast(pstr_level_uppercase_trace), // switched by proddy reinterpret_cast(pstr_level_uppercase_debug), + reinterpret_cast(pstr_level_uppercase_trace), reinterpret_cast(pstr_level_uppercase_all)}; const __FlashStringHelper * format_level_uppercase(Level level) { diff --git a/lib/uuid-log/src/levels.cpp b/lib/uuid-log/src/levels.cpp index e5bd51281..232067785 100644 --- a/lib/uuid-log/src/levels.cpp +++ b/lib/uuid-log/src/levels.cpp @@ -33,8 +33,8 @@ std::vector levels() { Level::WARNING, Level::NOTICE, Level::INFO, + Level::DEBUG, Level::TRACE, - Level::DEBUG, // switched by proddy Level::ALL}; } diff --git a/lib/uuid-log/src/levels_lowercase.cpp b/lib/uuid-log/src/levels_lowercase.cpp index c54512db7..30b3a4c29 100644 --- a/lib/uuid-log/src/levels_lowercase.cpp +++ b/lib/uuid-log/src/levels_lowercase.cpp @@ -35,8 +35,8 @@ std::vector levels_lowercase() { uuid::read_flash_string(format_level_lowercase(Level::WARNING)), uuid::read_flash_string(format_level_lowercase(Level::NOTICE)), uuid::read_flash_string(format_level_lowercase(Level::INFO)), - uuid::read_flash_string(format_level_lowercase(Level::TRACE)), // switched by proddy uuid::read_flash_string(format_level_lowercase(Level::DEBUG)), + uuid::read_flash_string(format_level_lowercase(Level::TRACE)), uuid::read_flash_string(format_level_lowercase(Level::ALL))}; } diff --git a/lib/uuid-log/src/levels_uppercase.cpp b/lib/uuid-log/src/levels_uppercase.cpp index 9f86f1476..b7d546603 100644 --- a/lib/uuid-log/src/levels_uppercase.cpp +++ b/lib/uuid-log/src/levels_uppercase.cpp @@ -35,8 +35,8 @@ std::vector levels_uppercase() { uuid::read_flash_string(format_level_uppercase(Level::WARNING)), uuid::read_flash_string(format_level_uppercase(Level::NOTICE)), uuid::read_flash_string(format_level_uppercase(Level::INFO)), - uuid::read_flash_string(format_level_uppercase(Level::TRACE)), // switched by proddy uuid::read_flash_string(format_level_uppercase(Level::DEBUG)), + uuid::read_flash_string(format_level_uppercase(Level::TRACE)), uuid::read_flash_string(format_level_uppercase(Level::ALL))}; } diff --git a/lib/uuid-log/src/uuid/log.h b/lib/uuid-log/src/uuid/log.h index 48ee3f727..8fa64f31d 100644 --- a/lib/uuid-log/src/uuid/log.h +++ b/lib/uuid-log/src/uuid/log.h @@ -71,7 +71,7 @@ namespace uuid { namespace log { /** - * Severity level of log messages. Proddy switches trace & debug + * Severity level of log messages. * * @since 1.0.0 */ @@ -84,8 +84,8 @@ enum Level : int8_t { WARNING, /*!< Warning conditions. @since 1.0.0 */ NOTICE, /*!< Normal but significant conditions. @since 1.0.0 */ INFO, /*!< Informational messages. @since 1.0.0 */ - TRACE, /*!< Trace messages. @since 1.0.0 */ DEBUG, /*!< Debug-level messages. @since 1.0.0 */ + TRACE, /*!< Trace messages. @since 1.0.0 */ ALL, /*!< Meta level representing all log messages. @since 1.0.0 */ }; From 56ffe76638e5caafa108bc1aecceca88f701ee1a Mon Sep 17 00:00:00 2001 From: proddy Date: Sat, 13 Jun 2020 15:47:29 +0200 Subject: [PATCH 2/7] new command called 'watch'. telegrams are no longer shown in log debug --- src/console.cpp | 34 +--------------------- src/console.h | 7 ++--- src/emsesp.cpp | 76 +++++++++++++++++++++++++++++++++++++++---------- src/emsesp.h | 22 +++++++------- 4 files changed, 75 insertions(+), 64 deletions(-) diff --git a/src/console.cpp b/src/console.cpp index 7dce00224..419eb8082 100644 --- a/src/console.cpp +++ b/src/console.cpp @@ -225,9 +225,8 @@ void Console::load_standard_commands(unsigned int context) { context, CommandFlags::USER, flash_string_vector{F_(log)}, - flash_string_vector{F_(log_level_optional), F_(trace_format_optional), F_(traceid_optional)}, + flash_string_vector{F_(log_level_optional)}, [](Shell & shell, const std::vector & arguments) { - uint16_t watch_id; if (!arguments.empty()) { uuid::log::Level level; @@ -237,41 +236,10 @@ void Console::load_standard_commands(unsigned int context) { shell.printfln(F_(invalid_log_level)); return; } - - // trace logic - if (level == uuid::log::Level::TRACE || level == uuid::log::Level::DEBUG) { - watch_id = LOG_TRACE_WATCH_NONE; // no watch ID set - if (arguments.size() > 1) { - // next argument is raw or full - if (arguments[1] == read_flash_string(F_(raw))) { - emsesp::EMSESP::trace_raw(true); - } else if (arguments[1] == read_flash_string(F_(pretty))) { - emsesp::EMSESP::trace_raw(false); - } else { - emsesp::EMSESP::trace_watch_id(Helpers::hextoint(arguments[1].c_str())); - } - - // get the watch_id if its set - if (arguments.size() == 3) { - emsesp::EMSESP::trace_watch_id(Helpers::hextoint(arguments[2].c_str())); - } - } else { - // it was "log trace" so reset the watch id and switch back to pretty - emsesp::EMSESP::trace_raw(false); - emsesp::EMSESP::trace_watch_id(LOG_TRACE_WATCH_NONE); - } - } } // print out logging settings shell.printfln(F_(log_level_fmt), uuid::log::format_level_uppercase(shell.log_level())); - watch_id = emsesp::EMSESP::trace_watch_id(); - if (watch_id == LOG_TRACE_WATCH_NONE) { - shell.printfln(F("Tracing all telegrams")); - } else { - shell.printfln(F("Tracing only telegrams that match a device ID or telegram type of 0x%02X"), watch_id); - } - shell.printfln(F_(trace_raw_fmt), emsesp::EMSESP::trace_raw() ? F("as raw bytes") : F("in decoded format")); }, [](Shell & shell __attribute__((unused)), const std::vector & arguments __attribute__((unused))) -> std::vector { return uuid::log::levels_lowercase(); diff --git a/src/console.h b/src/console.h index 640326926..69ad657f4 100644 --- a/src/console.h +++ b/src/console.h @@ -42,8 +42,8 @@ using uuid::log::Level; // clang-format off #define LOG_DEBUG(...) if (logger_.enabled(Level::DEBUG)) {logger_.debug(__VA_ARGS__);} -#define LOG_TRACE(...) if (logger_.enabled(Level::TRACE)) {logger_.trace(__VA_ARGS__);} #define LOG_INFO(...) logger_.info(__VA_ARGS__) +#define LOG_TRACE(...) logger_.trace(__VA_ARGS__) #define LOG_NOTICE(...) logger_.notice(__VA_ARGS__) #define LOG_WARNING(...) logger_.warning(__VA_ARGS__) #define LOG_ERROR(...) logger_.err(__VA_ARGS__) @@ -90,7 +90,7 @@ MAKE_PSTR_WORD(restart) MAKE_PSTR_WORD(reconnect) MAKE_PSTR_WORD(format) MAKE_PSTR_WORD(raw) -MAKE_PSTR_WORD(pretty) +MAKE_PSTR_WORD(watch) // context menus MAKE_PSTR_WORD(mqtt) @@ -102,9 +102,6 @@ MAKE_PSTR(degrees_mandatory, "") MAKE_PSTR(asterisks, "********") MAKE_PSTR(n_mandatory, "") MAKE_PSTR(n_optional, "[n]") -MAKE_PSTR(traceid_optional, "[trace ID]") -MAKE_PSTR(trace_raw_fmt, "Displaying telegrams %s") -MAKE_PSTR(trace_format_optional, "[pretty | raw]") MAKE_PSTR(bool_mandatory, "") MAKE_PSTR(typeid_mandatory, "") MAKE_PSTR(deviceid_mandatory, "") diff --git a/src/emsesp.cpp b/src/emsesp.cpp index f015e3568..422f92c21 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -32,6 +32,10 @@ MAKE_PSTR(tx_mode_fmt, "Tx mode = %d") MAKE_PSTR(bus_id_fmt, "Bus ID = %02X") MAKE_PSTR(read_only_fmt, "Read-only mode is %s") +MAKE_PSTR(watchid_optional, "[ID]") +MAKE_PSTR(watch_format_mandatory, "") +MAKE_PSTR(invalid_watch, "Invalid watch type") + MAKE_PSTR(logger_name, "emsesp") namespace emsesp { @@ -56,8 +60,8 @@ Shower EMSESP::shower_; // Shower logic // static/common variables uint8_t EMSESP::actual_master_thermostat_ = EMSESP_DEFAULT_MASTER_THERMOSTAT; // which thermostat leads when multiple found -uint16_t EMSESP::trace_watch_id_ = LOG_TRACE_WATCH_NONE; // for when log is TRACE. 0 means no trace set -bool EMSESP::trace_raw_ = false; // not showing raw when in trace logging +uint16_t EMSESP::watch_id_ = WATCH_NONE; // for when log is TRACE. 0 means no trace set +uint8_t EMSESP::watch_ = 0; // trace off bool EMSESP::tap_water_active_ = false; // for when Boiler states we having running warm water. used in Shower() bool EMSESP::ems_read_only_; uint32_t EMSESP::last_fetch_ = 0; @@ -97,12 +101,12 @@ uint8_t EMSESP::actual_master_thermostat() { } // to watch both type IDs and device IDs -void EMSESP::trace_watch_id(uint16_t trace_watch_id) { +void EMSESP::watch_id(uint16_t watch_id) { // if it's a device ID, which is a single byte, remove the MSB so to support both Buderus and HT3 protocols - if (trace_watch_id <= 0xFF) { - trace_watch_id_ = (trace_watch_id & 0x7F); + if (watch_id <= 0xFF) { + watch_id_ = (watch_id & 0x7F); } else { - trace_watch_id_ = trace_watch_id; + watch_id_ = watch_id; } } @@ -389,10 +393,9 @@ void EMSESP::process_version(std::shared_ptr telegram) { // We also check for common telgram types, like the Version(0x02) // returns false if there are none found bool EMSESP::process_telegram(std::shared_ptr telegram) { - if ((logger_.enabled(Level::TRACE)) && !trace_raw()) { - if ((trace_watch_id_ == LOG_TRACE_WATCH_NONE) || (telegram->src == trace_watch_id_) || (telegram->dest == trace_watch_id_) - || (telegram->type_id == trace_watch_id_)) { - LOG_TRACE(pretty_telegram(telegram).c_str()); + if (watch() == 1) { + if ((watch_id_ == WATCH_NONE) || (telegram->src == watch_id_) || (telegram->dest == watch_id_) || (telegram->type_id == watch_id_)) { + LOG_INFO(pretty_telegram(telegram).c_str()); } } @@ -562,14 +565,14 @@ void EMSESP::send_write_request(const uint16_t type_id, // this is main entry point when data is received on the Rx line, via emsuart library // we check if its a complete telegram or just a single byte (which could be a poll or a return status) void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) { + // LOG_DEBUG(F("Rx: %s"), Helpers::data_to_hex(data, length).c_str()); // check first for echo - //LOG_TRACE(F("Rx: %s"), Helpers::data_to_hex(data, length).c_str()); uint8_t first_value = data[0]; if (((first_value & 0x7F) == txservice_.ems_bus_id()) && (length > 1)) { - // if we ask ourself at roomcontrol for version e.g. 0B 98 02 ... + // if we ask ourself at roomcontrol for version e.g. 0B 98 02 00 20 Roomctrl::check((data[1] ^ 0x80 ^ rxservice_.ems_mask()), data); #ifdef EMSESP_DEBUG - rxservice_.add(data, length); // just for logging, if compiled with additional debugging + LOG_DEBUG(F("[DEBUG] Echo: %s"), Helpers::data_to_hex(data, length).c_str()); #endif return; // it's an echo } @@ -613,7 +616,7 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) { // So re-send the last Tx and increment retry count uint8_t retries = txservice_.retry_tx(); // returns 0 if exceeded count #ifdef EMSESP_DEBUG - LOG_DEBUG(F("Last Tx operation failed. Retry #%d. Sent: %s, received: %s"), + LOG_DEBUG(F("[DEBUG] Last Tx operation failed. Retry #%d. Sent: %s, received: %s"), retries, txservice_.last_tx_to_string().c_str(), Helpers::data_to_hex(data, length).c_str()); @@ -823,6 +826,50 @@ void EMSESP::console_commands(Shell & shell, unsigned int context) { shell.printfln(F_(read_only_fmt), settings.ems_read_only() ? F_(on) : F_(off)); }); + + + EMSESPShell::commands->add_command(ShellContext::EMS, + CommandFlags::USER, + flash_string_vector{F_(watch)}, + flash_string_vector{F_(watch_format_mandatory), F_(watchid_optional)}, + [](Shell & shell, const std::vector & arguments) { + // get raw/pretty + if (arguments[0] == read_flash_string(F_(raw))) { + emsesp::EMSESP::watch(2); // raw + } else if (arguments[0] == read_flash_string(F_(on))) { + emsesp::EMSESP::watch(1); // on + } else if (arguments[0] == read_flash_string(F_(off))) { + emsesp::EMSESP::watch(0); // off + } else { + shell.printfln(F_(invalid_watch)); + return; + } + + uint16_t watch_id; + if (arguments.size() == 2) { + // get the watch_id if its set + watch_id = Helpers::hextoint(arguments[1].c_str()); + } else { + watch_id = WATCH_NONE; + } + + emsesp::EMSESP::watch_id(watch_id); + + uint8_t watch = emsesp::EMSESP::watch(); + if (watch == 0) { + shell.printfln(F("Watch is off")); + } else if (watch == 1) { + shell.printfln(F("Watching incoming telegrams, displayed in decoded format")); + } else { + shell.printfln(F("Watching incoming telegrams, displayed as raw bytes")); + } + + watch_id = emsesp::EMSESP::watch_id(); + if (watch_id != WATCH_NONE) { + shell.printfln(F("Filtering only telegrams that match a device ID or telegram type of 0x%02X"), watch_id); + } + }); + // enter the context Console::enter_custom_context(shell, context); } @@ -838,7 +885,6 @@ void EMSESP::start() { network_.start(); console_.start(); sensors_.start(); - rxservice_.start(); txservice_.start(); shower_.start(); mqtt_.start(); diff --git a/src/emsesp.h b/src/emsesp.h index 5ebceed26..a2c862df1 100644 --- a/src/emsesp.h +++ b/src/emsesp.h @@ -46,7 +46,7 @@ #include "devices/boiler.h" -#define LOG_TRACE_WATCH_NONE 0 // no watch id set +#define WATCH_NONE 0 // no watch id set namespace emsesp { @@ -99,18 +99,18 @@ class EMSESP { return sensors_.devices(); } - static void trace_watch_id(uint16_t id); + static void watch_id(uint16_t id); - static uint16_t trace_watch_id() { - return trace_watch_id_; + static uint16_t watch_id() { + return watch_id_; } - static void trace_raw(bool trace_raw) { - trace_raw_ = trace_raw; + static void watch(uint8_t watch) { + watch_ = watch; // 0=off, 1=on, 2=raw } - static bool trace_raw() { - return trace_raw_; + static uint8_t watch() { + return watch_; // 0=off, 1=on, 2=raw } static bool tap_water_active() { @@ -131,7 +131,7 @@ class EMSESP { static void fetch_device_values(const uint8_t device_id = 0); - static bool add_device(const uint8_t device_id, const uint8_t product_id, std::string & version, const uint8_t brand); + static bool add_device(const uint8_t device_id, const uint8_t product_id, std::string & version, const uint8_t brand); static Mqtt mqtt_; static System system_; @@ -166,8 +166,8 @@ class EMSESP { static std::vector device_library_; static uint8_t actual_master_thermostat_; - static uint16_t trace_watch_id_; - static bool trace_raw_; + static uint16_t watch_id_; + static uint8_t watch_; static bool tap_water_active_; static bool ems_read_only_; }; From 1fc276a1e28d6ffdfde9b68b0409211dd05d80d3 Mon Sep 17 00:00:00 2001 From: proddy Date: Sat, 13 Jun 2020 15:47:51 +0200 Subject: [PATCH 3/7] michaels' uart code. working tx_mode 1 on ESP8266 --- src/uart/emsuart_esp8266.cpp | 120 +++++++++++++++++++++-------------- src/uart/emsuart_esp8266.h | 35 +++++----- 2 files changed, 90 insertions(+), 65 deletions(-) diff --git a/src/uart/emsuart_esp8266.cpp b/src/uart/emsuart_esp8266.cpp index 2e7135f83..c3b81a297 100644 --- a/src/uart/emsuart_esp8266.cpp +++ b/src/uart/emsuart_esp8266.cpp @@ -35,6 +35,11 @@ uint8_t phantomBreak = 0; uint8_t tx_mode_ = 0xFF; bool drop_next_rx = true; uint32_t emsRxTime; +uint8_t emsTxBuf[EMS_MAXBUFFERSIZE]; +uint8_t emsTxBufIdx; +uint8_t emsTxBufLen; +uint32_t emsTxWait; + // // Main interrupt handler @@ -45,7 +50,13 @@ void ICACHE_RAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) { static uint8_t uart_buffer[EMS_MAXBUFFERSIZE + 2]; if (USIS(EMSUART_UART) & ((1 << UIBD))) { // BREAK detection = End of EMS data block - length = 0; + USC0(EMSUART_UART) &= ~(1 << UCBRK); // reset tx-brk + // while((USS(EMSUART_UART) >> USRXD) == 0); // wait for idle state of pin + // if((USS(EMSUART_UART) >> USRXD) == 0) { // if rx is not idle wait one bittime + // delayMicroseconds(EMSUART_TX_BIT_TIME); + // } + USIC(EMSUART_UART) = (1 << UIBD); // INT clear the BREAK detect interrupt + length = 0; while ((USS(EMSUART_UART) >> USRXC) & 0x0FF) { // read fifo into buffer uint8_t rx = USF(EMSUART_UART); if (length < EMS_MAXBUFFERSIZE) { @@ -54,8 +65,6 @@ void ICACHE_RAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) { drop_next_rx = true; } } - USIC(EMSUART_UART) = (1 << UIBD); // INT clear the BREAK detect interrupt - USC0(EMSUART_UART) &= ~(1 << UCBRK); // reset tx-brk if (!drop_next_rx) { pEMSRxBuf->length = length; os_memcpy((void *)pEMSRxBuf->buffer, (void *)&uart_buffer, pEMSRxBuf->length); // copy data into transfer buffer, including the BRK 0x00 at the end @@ -105,6 +114,20 @@ void ICACHE_FLASH_ATTR EMSuart::emsuart_flush_fifos() { USC0(EMSUART_UART) &= ~(tmp); // clear bits } +// ISR to Fire when Timer is triggered +void ICACHE_RAM_ATTR EMSuart::emsuart_tx_timer_intr_handler() { + emsTxBufIdx++; + if (emsTxBufIdx < emsTxBufLen) { + USF(EMSUART_UART) = emsTxBuf[emsTxBufIdx]; + timer1_write(emsTxWait); + } else if (emsTxBufIdx == emsTxBufLen) { + USC0(EMSUART_UART) |= (1 << UCBRK); // set + // timer1_write(emsTxWait); + timer1_write(5 * EMSUART_TX_BRK_WAIT); + } else { + USC0(EMSUART_UART) &= ~(1 << UCBRK); // clear + } +} /* * init UART0 driver */ @@ -146,8 +169,9 @@ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) { // change: we set UCFFT to 1 to get an immediate indicator about incoming traffic. // Otherwise, we're only noticed by UCTOT or RxBRK! // change: don't care, we do not use these interrupts - //USC1(EMSUART_UART) = 0; // reset config first - //USC1(EMSUART_UART) = (0x01 << UCFFT) | (0x01 << UCTOT) | (0 << UCTOE); // enable interupts + // change proddy 13-june-2020: add back USC1(EMSUART_UART) = 0; + USC1(EMSUART_UART) = 0; // reset config first + // USC1(EMSUART_UART) = (0x7F << UCFFT) | (0x04 << UCTOT) | (1 << UCTOE); // enable interupts // set interrupts for triggers USIC(EMSUART_UART) = 0xFFFF; // clear all interupts @@ -172,6 +196,13 @@ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) { ETS_UART_INTR_ENABLE(); drop_next_rx = true; // LOG_INFO(F("UART service for Rx/Tx started")); + + // for sending with large delay in EMS+ mode we use a timer interrupt + timer1_attachInterrupt(emsuart_tx_timer_intr_handler); // Add ISR Function + timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE); // 5 MHz timer + + // emsTxWait = 5 * EMSUART_TX_BIT_TIME * 20; // 20 bittimes for tx_mode 2 + emsTxWait = 5 * EMSUART_TX_BIT_TIME * 11; // 20 bittimes for tx_mode 2 } /* @@ -180,6 +211,7 @@ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) { */ void ICACHE_FLASH_ATTR EMSuart::stop() { ETS_UART_INTR_DISABLE(); + timer1_disable(); } /* @@ -191,6 +223,9 @@ void ICACHE_FLASH_ATTR EMSuart::restart() { drop_next_rx = true; } ETS_UART_INTR_ENABLE(); + emsTxBufIdx = 0; + emsTxBufLen = 0; + timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE); } /* @@ -213,13 +248,13 @@ void ICACHE_FLASH_ATTR EMSuart::tx_brk() { tmp = (1 << UCBRK); USC0(EMSUART_UART) |= (tmp); // set bit - if (tx_mode_ == EMS_TXMODE_EMSPLUS) { // EMS+ mode - delayMicroseconds(EMSUART_TX_BRK_WAIT); - } else if (tx_mode_ == EMS_TXMODE_HT3) { // junkers mode - delayMicroseconds(EMSUART_TX_WAIT_BRK - EMSUART_TX_LAG); // 1144 (11 Bits) + if (tx_mode_ == EMS_TXMODE_EMSPLUS) { // EMS+ mode + delayMicroseconds(EMSUART_TX_BRK_WAIT); // 2070 + } else if (tx_mode_ == EMS_TXMODE_HT3) { // junkers mode + delayMicroseconds(EMSUART_TX_BRK_WAIT_HT3); // 1144 } - USC0(EMSUART_UART) &= ~(tmp); // clear bit + USC0(EMSUART_UART) &= ~(tmp); // clear BRK bit } /* @@ -227,17 +262,21 @@ void ICACHE_FLASH_ATTR EMSuart::tx_brk() { * It's a bit dirty. there is no special wait logic per tx_mode type, fifo flushes or error checking */ void EMSuart::send_poll(uint8_t data) { - noInterrupts(); if (tx_mode_ == EMS_TXMODE_NEW) { USC0(EMSUART_UART) &= ~(1 << UCBRK); // reset tx-brk USF(EMSUART_UART) = data; USC0(EMSUART_UART) |= (1 << UCBRK); // send at the end + } else if (tx_mode_ == EMS_TXMODE_EMSPLUS) { + USF(EMSUART_UART) = data; + emsTxBufIdx = 0; + emsTxBufLen = 1; + timer1_write(emsTxWait); } else { + // EMS1.0 and HT3 USF(EMSUART_UART) = data; delayMicroseconds(EMSUART_TX_BRK_WAIT); tx_brk(); // send } - interrupts(); } /* @@ -245,44 +284,44 @@ void EMSuart::send_poll(uint8_t data) { * buf contains the CRC and len is #bytes including the CRC * returns code, 0=success, 1=brk error, 2=watchdog timeout */ -EMSUART_STATUS ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { +uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { if (len == 0) { - return EMS_TX_STATUS_OK; // nothing to send + return EMS_TX_STATUS_ERR; // nothing to send } #ifdef EMSESP_DEBUG - LOG_INFO(F("(debug) UART Response time: %d ms"), uuid::get_uptime() - emsRxTime); + // LOG_INFO(F("[DEBUG] UART Response time: %d ms"), uuid::get_uptime() - emsRxTime); #endif // if ((uuid::get_uptime() - emsRxTime) > EMS_RX_TO_TX_TIMEOUT)) { // send allowed within 20 ms - // return EMS_TX_WTD_TIMEOUT; + // return EMS_TX_STATUS_ERR; // } // new code from Michael. See https://github.com/proddy/EMS-ESP/issues/380 if (tx_mode_ == EMS_TXMODE_NEW) { USC0(EMSUART_UART) &= ~(1 << UCBRK); // reset tx-brk - noInterrupts(); for (uint8_t i = 0; i < len; i++) { USF(EMSUART_UART) = buf[i]; } USC0(EMSUART_UART) |= (1 << UCBRK); // send at the end - interrupts(); return EMS_TX_STATUS_OK; } // EMS+ https://github.com/proddy/EMS-ESP/issues/23# if (tx_mode_ == EMS_TXMODE_EMSPLUS) { // With extra tx delay for EMS+ - noInterrupts(); for (uint8_t i = 0; i < len; i++) { - USF(EMSUART_UART) = buf[i]; - delayMicroseconds(EMSUART_TX_BRK_WAIT); // 2070 + emsTxBuf[i] = buf[i]; + // USF(EMSUART_UART) = buf[i]; + // delayMicroseconds(EMSUART_TX_WAIT_EMSPLUS); // 2070 } - tx_brk(); // send - interrupts(); + emsTxBufIdx = 0; + emsTxBufLen = len; + USF(EMSUART_UART) = buf[0]; + timer1_write(emsTxWait); + // tx_brk(); // send return EMS_TX_STATUS_OK; } // Junkers logic by @philrich if (tx_mode_ == EMS_TXMODE_HT3) { - noInterrupts(); for (uint8_t i = 0; i < len; i++) { USF(EMSUART_UART) = buf[i]; @@ -291,15 +330,14 @@ EMSUART_STATUS ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { ; // wait until bits are sent on wire - delayMicroseconds(EMSUART_TX_WAIT_BYTE - EMSUART_TX_LAG + EMSUART_TX_WAIT_GAP); // 1760 + delayMicroseconds(EMSUART_TX_BRK_WAIT_HT3); } tx_brk(); // send - interrupts(); return EMS_TX_STATUS_OK; } /* - * Logic for tx_mode of 0 (EMS_TXMODE_DEFAULT) + * Logic for tx_mode of 1 * based on code from https://github.com/proddy/EMS-ESP/issues/103 by @susisstrolch * * Logic: @@ -314,7 +352,7 @@ EMSUART_STATUS ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { * 2. Busmaster cancel telegram by sending a BRK * * Case 1. is handled by a watchdog counter which is reset on each - * Tx attempt. The timeout should be 20x EMSUART_BIT_TIME plus + * Tx attempt. The timeout should be 20x EMSUART_TX_BIT_TIME plus * some smart guess for processing time on targeted EMS device. * We set Status to EMS_TX_WTD_TIMEOUT and return * @@ -325,30 +363,18 @@ EMSUART_STATUS ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { // disable rx interrupt // clear Rx status register, resetting the Rx FIFO and flush it - noInterrupts(); - // ETS_UART_INTR_DISABLE(); + // noInterrupts(); + ETS_UART_INTR_DISABLE(); // USC0(EMSUART_UART) |= (1 << UCRXRST); // reset uart rx fifo emsuart_flush_fifos(); // send the bytes along the serial line for (uint8_t i = 0; i < len; i++) { - uint16_t wdc = EMS_TX_TO_COUNT; // 1760 volatile uint8_t _usrxc = (USS(EMSUART_UART) >> USRXC) & 0xFF; USF(EMSUART_UART) = buf[i]; // send each Tx byte // wait for echo from the busmaster while (((USS(EMSUART_UART) >> USRXC) & 0xFF) == _usrxc) { - delayMicroseconds(EMSUART_BUSY_WAIT); // burn CPU cycles... - if (--wdc == 0) { - interrupts(); - // ETS_UART_INTR_ENABLE(); - return EMS_TX_WTD_TIMEOUT; - } - if (USIR(EMSUART_UART) & (1 << UIBD)) { - USIC(EMSUART_UART) = (1 << UIBD); // clear BRK detect IRQ - interrupts(); - // ETS_UART_INTR_ENABLE(); - return EMS_TX_BRK_DETECT; - } + delayMicroseconds(EMSUART_TX_BUSY_WAIT); // burn CPU cycles... } } @@ -363,7 +389,7 @@ EMSUART_STATUS ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { // wait until BRK detected... while (!(USIR(EMSUART_UART) & (1 << UIBD))) { - delayMicroseconds(EMSUART_BIT_TIME); + delayMicroseconds(EMSUART_TX_BIT_TIME); } USC0(EMSUART_UART) &= ~((1 << UCBRK) | (1 << UCLBE)); // disable loopback & clear @@ -371,12 +397,12 @@ EMSUART_STATUS ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { phantomBreak = 1; } - interrupts(); - // ETS_UART_INTR_ENABLE(); // open up the FIFO again to start receiving + // interrupts(); + ETS_UART_INTR_ENABLE(); // open up the FIFO again to start receiving return EMS_TX_STATUS_OK; // send the Tx ok status back } } // namespace emsesp -#endif +#endif \ No newline at end of file diff --git a/src/uart/emsuart_esp8266.h b/src/uart/emsuart_esp8266.h index 81a2009ec..e66912b13 100644 --- a/src/uart/emsuart_esp8266.h +++ b/src/uart/emsuart_esp8266.h @@ -15,6 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +#if defined(ESP8266) #ifndef EMSESP_EMSUART_H #define EMSESP_EMSUART_H @@ -40,34 +41,30 @@ #define EMS_TXMODE_NEW 4 // for michael's testing // LEGACY -#define EMSUART_BIT_TIME 104 // bit time @9600 baud +#define EMSUART_TX_BIT_TIME 104 // bit time @9600 baud #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) -#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 -#define EMSUART_BUSY_WAIT (EMSUART_BIT_TIME / 8) -#define EMS_TX_TO_CHARS (2 + 20) -#define EMS_TX_TO_COUNT ((EMS_TX_TO_CHARS)*8) + +// EMS 1.0 +#define EMSUART_TX_BUSY_WAIT (EMSUART_TX_BIT_TIME / 8) // 13 + +// HT3/Junkers - Time to send one Byte (8 Bits, 1 Start Bit, 1 Stop Bit). The -8 is for lag compensation. +#define EMSUART_TX_BRK_WAIT_HT3 (EMSUART_TX_BIT_TIME * 11) - 8 // 1136 namespace emsesp { -typedef enum { - EMS_TX_STATUS_OK = 1, - EMS_TX_WTD_TIMEOUT, // watchdog timeout during send - EMS_TX_BRK_DETECT, // incoming BRK during Tx -} EMSUART_STATUS; +#define EMS_TX_STATUS_ERR 0 +#define EMS_TX_STATUS_OK 1 class EMSuart { public: EMSuart() = default; ~EMSuart() = default; - static void ICACHE_FLASH_ATTR start(uint8_t tx_mode); - static void ICACHE_FLASH_ATTR stop(); - static void ICACHE_FLASH_ATTR restart(); - static void ICACHE_FLASH_ATTR send_poll(uint8_t data); - static EMSUART_STATUS ICACHE_FLASH_ATTR transmit(uint8_t * buf, uint8_t len); + static void ICACHE_FLASH_ATTR start(uint8_t tx_mode); + static void ICACHE_FLASH_ATTR stop(); + static void ICACHE_FLASH_ATTR restart(); + static void ICACHE_FLASH_ATTR send_poll(uint8_t data); + static uint16_t ICACHE_FLASH_ATTR transmit(uint8_t * buf, uint8_t len); typedef struct { uint8_t length; @@ -81,8 +78,10 @@ class EMSuart { static void ICACHE_FLASH_ATTR emsuart_recvTask(os_event_t * events); static void ICACHE_FLASH_ATTR emsuart_flush_fifos(); static void ICACHE_FLASH_ATTR tx_brk(); + static void ICACHE_RAM_ATTR emsuart_tx_timer_intr_handler(); }; } // namespace emsesp #endif +#endif \ No newline at end of file From b7fd8d3ee26e4f51bdca3e8f02553f4d302d7896 Mon Sep 17 00:00:00 2001 From: proddy Date: Sat, 13 Jun 2020 15:48:05 +0200 Subject: [PATCH 4/7] bump to a17 --- src/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h b/src/version.h index 01841a477..5393f3853 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "2.0.0a17" +#define EMSESP_APP_VERSION "2.0.0a18" From 803505b1da7e8ee9c7e0cb893581887c269660dc Mon Sep 17 00:00:00 2001 From: proddy Date: Sat, 13 Jun 2020 15:48:18 +0200 Subject: [PATCH 5/7] update to show watch command --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3349b059a..ec6d85222 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ Note: Version 2.0 is not backward compatible with v1.0. The File system structur common commands available in all contexts: exit help - log [level] [pretty | raw] [trace ID] + log [level] su (top root level) @@ -86,6 +86,7 @@ ems show devices show emsbus show values + watch [ID] mqtt publish From 10b66828423829b8f75f68c024d34ef723c7b907 Mon Sep 17 00:00:00 2001 From: proddy Date: Sat, 13 Jun 2020 15:49:38 +0200 Subject: [PATCH 6/7] fixed type_id for EMS+, cleaned up code, added watch, added option for Tx at top of queue --- src/system.h | 5 -- src/telegram.cpp | 167 ++++++++++++++++++++++++----------------------- src/telegram.h | 18 +++-- 3 files changed, 97 insertions(+), 93 deletions(-) diff --git a/src/system.h b/src/system.h index 06fd5c32f..d8f16c930 100644 --- a/src/system.h +++ b/src/system.h @@ -29,12 +29,7 @@ #include "telegram.h" #if defined(ESP8266) -#include "uart/emsuart_esp8266.h" #include -#elif defined(ESP32) -#include "uart/emsuart_esp32.h" -#elif defined(EMSESP_STANDALONE) -#include #endif #ifndef EMSESP_STANDALONE diff --git a/src/telegram.cpp b/src/telegram.cpp index 6e4a6262e..154b9e892 100644 --- a/src/telegram.cpp +++ b/src/telegram.cpp @@ -68,8 +68,8 @@ Telegram::Telegram(uint8_t operation, uint8_t src, uint8_t dest, uint16_t type_i , type_id(type_id) , offset(offset) , message_length(message_length) { - // copy complete telegram data over - for (uint8_t i = 0; i < message_length; i++) { + // copy complete telegram data over, preventing buffer overflow + for (uint8_t i = 0; ((i < message_length) && (i != EMS_MAX_TELEGRAM_MESSAGE_LENGTH - 1)); i++) { message_data[i] = data[i]; } } @@ -211,36 +211,26 @@ void RxService::flush_rx_queue() { rx_telegram_id_ = 0; } -// start and initialize the Rx incoming buffer -void RxService::start() { - // LOG_DEBUG(F("RxStart")); - // function not currently used -} - // Rx loop, run as many times as you can // processes all telegrams on the queue. Assumes there are valid (i.e. CRC checked) void RxService::loop() { + /* #ifndef EMSESP_STANDALONE - // give rx some breathing space - //if ((uuid::get_uptime() - last_rx_check_) < RX_LOOP_WAIT) { - // return; - //} - //last_rx_check_ = uuid::get_uptime(); + give rx some breathing space if ((uuid::get_uptime() - last_rx_check_) < RX_LOOP_WAIT) { + return; + } + last_rx_check_ = uuid::get_uptime(); #endif +*/ while (!rx_telegrams_.empty()) { auto telegram = rx_telegrams_.front().telegram_; - // rx_telegrams_overflow_ = false; - (void)EMSESP::process_telegram(telegram); // further process the telegram increment_telegram_count(); // increase count - // remove it from the queue - // if (!rx_telegrams_overflow_) { - rx_telegrams_.pop_front(); - // } + rx_telegrams_.pop_front(); // remove it from the queue } } @@ -249,10 +239,15 @@ void RxService::loop() { // length includes the CRC // for EMS+ the type_id has the value + 256. We look for these type of telegrams with F7, F9 and FF in 3rd byte void RxService::add(uint8_t * data, uint8_t length) { + if (length < 2) { + return; + } + // validate the CRC uint8_t crc = calculate_crc(data, length - 1); - if (data[length - 1] != crc) { - LOG_TRACE(F("Rx: %s %s(BAD, CRC %02X != %02X)%s"), Helpers::data_to_hex(data, length).c_str(), COLOR_RED, data[length - 1], crc, COLOR_RESET); + + if ((data[length - 1] != crc) && (EMSESP::watch() != 0)) { + LOG_ERROR(F("Rx: %s %s(BAD, CRC %02X != %02X)%s"), Helpers::data_to_hex(data, length).c_str(), COLOR_RED, data[length - 1], crc, COLOR_RESET); increment_telegram_error_count(); return; } @@ -270,42 +265,36 @@ void RxService::add(uint8_t * data, uint8_t length) { uint8_t dest = data[1] & 0x7F; // strip MSB, don't care if its read or write for processing uint8_t offset = data[3]; // offset is always 4th byte - uint16_t type_id = 0; // this could be 2 bytes for ems+ - uint8_t * message_data; - uint8_t message_length; + // set default values, which will be adjusted depending on the EMS1.0/2.0 logic below + uint16_t type_id = 0; + uint8_t * message_data = data; + uint8_t message_length = length; // work out depending on the type where the data message block starts if (data[2] < 0xF0 || length < 6) { // EMS 1.0 - type_id = data[2]; - message_data = data + 4; // message block starts at 5th byte - message_length = length - 5; // remove 4 bytes header plus CRC + type_id = data[2]; + message_data += 4; // message block starts at 5th byte + message_length -= 5; // remove 4 bytes header plus CRC } else { // EMS 2.0 / EMS+ if (data[2] == 0xFF) { // check for empty data // special broadcast telegrams on ems+ have no data values, some even don't have a type ID, e.g. "21 0B FF 00" - if (length <= 7) { - message_data = data; // bogus pointer, will not be used - message_length = 0; - if (length <= 5) { - type_id = 0; // has also an empty type_id - } else { - type_id = (data[4] << 8) + data[5] + 256; - } - } else { - message_length = length - 7; // remove 6 byte header plus CRC - message_data = data + 6; // message block starts at 7th position + if (length > 8) { + message_length -= 7; // remove 6 byte header plus CRC + message_data += 6; // message block starts at 7th position + } + if (length > 5) { + type_id = (data[4] << 8) + data[5] + 256; // set type_id if there is one } } else { // its F9 or F7 uint8_t shift = (data[4] != 0xFF); // true (1) if 5th byte is not 0xFF, then telegram is 1 byte longer type_id = (data[5 + shift] << 8) + data[6 + shift] + 256; - message_data = data + 6 + shift; // there is a special byte after the typeID which we ignore for now - if (length <= (9 + shift)) { - message_length = 0; // special broadcast on ems+ have no data values - } else { - message_length = length - (9 + shift); + message_data += 6 + shift; // there is a special byte after the typeID which we ignore for now + if (length > (9 + shift)) { + message_length -= (9 + shift); } } } @@ -315,26 +304,27 @@ void RxService::add(uint8_t * data, uint8_t length) { return; } + // if we're in "trace" and "raw" print out actual telegram as bytes to the console + if (EMSESP::watch() == 2) { + uint16_t trace_watch_id = EMSESP::watch_id(); + if ((trace_watch_id == WATCH_NONE) || (src == trace_watch_id) || (dest == trace_watch_id) || (type_id == trace_watch_id)) { + LOG_INFO(F("Rx: %s"), Helpers::data_to_hex(data, length).c_str()); + } + } + +#ifdef EMSESP_DEBUG + LOG_DEBUG(F("[DEBUG] New Rx [#%d] telegram, message length %d"), rx_telegram_id_, message_length); +#endif + // create the telegram auto telegram = std::make_shared(Telegram::Operation::RX, src, dest, type_id, offset, message_data, message_length); // check if queue is full, if so remove top item to make space if (rx_telegrams_.size() >= MAX_RX_TELEGRAMS) { - // rx_telegrams_overflow_ = true; rx_telegrams_.pop_front(); } - // add to queue - LOG_DEBUG(F("New Rx [#%d] telegram, length %d"), rx_telegram_id_, message_length); - rx_telegrams_.emplace_back(rx_telegram_id_++, std::move(telegram)); - - // if we're in "trace" and "raw" print out actual telegram as bytes to the console - if (logger_.enabled(Level::TRACE) && EMSESP::trace_raw()) { - uint16_t trace_watch_id = EMSESP::trace_watch_id(); - if ((trace_watch_id == LOG_TRACE_WATCH_NONE) || (src == trace_watch_id) || (dest == trace_watch_id) || (type_id == trace_watch_id)) { - LOG_TRACE(F("Rx: %s"), Helpers::data_to_hex(data, length).c_str()); - } - } + rx_telegrams_.emplace_back(rx_telegram_id_++, std::move(telegram)); // add to queue } @@ -379,7 +369,7 @@ void TxService::loop() { // sends a 1 byte poll which is our own device ID void TxService::send_poll() { - //LOG_TRACE(F("Ack %02X"),ems_bus_id() ^ ems_mask()); + //LOG_DEBUG(F("Ack %02X"),ems_bus_id() ^ ems_mask()); EMSuart::send_poll(ems_bus_id() ^ ems_mask()); } @@ -476,24 +466,20 @@ void TxService::send_telegram(const QueuedTxTelegram & tx_telegram) { tx_telegram.id_, telegram->to_string(telegram_raw, length).c_str()); - // if we're watching an ID, then always show the full telegram - if ((logger_.enabled(Level::TRACE)) - && ((telegram->src == EMSESP::trace_watch_id()) || (telegram->dest == EMSESP::trace_watch_id()) || (telegram->type_id == EMSESP::trace_watch_id()))) { - logger_.trace(F("Sending %s Tx [#%d], telegram: %s"), - (telegram->operation == Telegram::Operation::TX_WRITE) ? F("write") : F("read"), - tx_telegram.id_, - telegram->to_string(telegram_raw, length).c_str()); - } - // send the telegram to the UART Tx - EMSUART_STATUS status = EMSuart::transmit(telegram_raw, length); + uint16_t status = EMSuart::transmit(telegram_raw, length); + #ifdef EMSESP_DEBUG - LOG_TRACE(F("Tx: %s"), Helpers::data_to_hex(telegram_raw, length).c_str()); + // if watching in 'raw' mode + if (EMSESP::watch() == 2) { + LOG_INFO(F("[DEBUG] Tx: %s"), Helpers::data_to_hex(telegram_raw, length).c_str()); + } #endif - if (status != EMS_TX_STATUS_OK) { - LOG_ERROR(F("Failed to transmit Tx via UART. Error: %s"), status == EMS_TX_WTD_TIMEOUT ? F("Timeout") : F("BRK")); - tx_waiting(false); // nothing send, tx not in wait state + if (status == EMS_TX_STATUS_ERR) { + LOG_ERROR(F("Failed to transmit Tx via UART.")); + increment_telegram_fail_count(); // another Tx fail + tx_waiting(false); // nothing send, tx not in wait state return; } @@ -513,11 +499,15 @@ void TxService::send_telegram(const uint8_t * data, const uint8_t length) { LOG_DEBUG(F("Sending Raw telegram: %s (length=%d)"), Helpers::data_to_hex(telegram_raw, length).c_str(), length); + tx_waiting(false); // no post validation + // send the telegram to the UART Tx - EMSUART_STATUS status = EMSuart::transmit(telegram_raw, length); - //LOG_TRACE(F("Tx: %s"), Helpers::data_to_hex(telegram_raw, length).c_str()); - if (status != EMS_TX_STATUS_OK) { - LOG_ERROR(F("Failed to transmit Tx via UART. Error: %s"), status == EMS_TX_WTD_TIMEOUT ? F("Timeout") : F("BRK")); + uint16_t status = EMSuart::transmit(telegram_raw, length); + //LOG_DEBUG(F("Tx: %s"), Helpers::data_to_hex(telegram_raw, length).c_str()); + + if (status == EMS_TX_STATUS_ERR) { + LOG_ERROR(F("Failed to transmit Tx via UART.")); + increment_telegram_fail_count(); // another Tx fail } } @@ -525,7 +515,9 @@ void TxService::send_telegram(const uint8_t * data, const uint8_t length) { // given some details like the destination, type, offset and message block void TxService::add(const uint8_t operation, const uint8_t dest, const uint16_t type_id, const uint8_t offset, uint8_t * message_data, const uint8_t message_length) { auto telegram = std::make_shared(operation, ems_bus_id(), dest, type_id, offset, message_data, message_length); - LOG_DEBUG(F("New Tx [#%d] telegram, length %d"), tx_telegram_id_, message_length); +#ifdef EMSESP_DEBUG + LOG_DEBUG(F("[DEBUG] New Tx [#%d] telegram, length %d"), tx_telegram_id_, message_length); +#endif // if the queue is full, make room but removing the last one if (tx_telegrams_.size() >= MAX_TX_TELEGRAMS) { @@ -536,14 +528,17 @@ void TxService::add(const uint8_t operation, const uint8_t dest, const uint16_t } // builds a Tx telegram and adds to queue, using only raw data +// format is EMS 1.0 (src, dest, type_id, offset, data) // length is the length of the whole telegram data -void TxService::add(uint8_t * data, const uint8_t length) { - uint8_t message_length = length - 4; - if (!message_length) { - LOG_ERROR(F("Bad Tx telegram, too short (message length is %d)"), message_length); +// front = true if adding to the front of queue, e.g. with an Tx retry. Default is false. +void TxService::add(uint8_t * data, const uint8_t length, bool front) { + if (length < 5) { + LOG_ERROR(F("Tx telegram too short (telegram length is %d)"), length); return; } + uint8_t message_length = length - 4; + // build header uint8_t src = data[0]; uint8_t dest = data[1]; @@ -558,8 +553,16 @@ void TxService::add(uint8_t * data, const uint8_t length) { tx_telegrams_.pop_front(); } - LOG_DEBUG(F("New Tx [#%d] telegram, length %d"), tx_telegram_id_, message_length); - tx_telegrams_.emplace_back(tx_telegram_id_++, std::move(telegram)); +#ifdef EMSESP_DEBUG + LOG_DEBUG(F("[DEBUG] New Tx [#%d] telegram, length %d"), tx_telegram_id_, message_length); +#endif + + // add to either front or back of queue + if (front) { + tx_telegrams_.emplace_front(tx_telegram_id_++, std::move(telegram)); + } else { + tx_telegrams_.emplace_back(tx_telegram_id_++, std::move(telegram)); + } } // send a Tx telegram to request data from an EMS device @@ -622,7 +625,7 @@ uint8_t TxService::retry_tx() { return 0; } - add(telegram_last_, telegram_last_length_); // add the last Tx telegram to the tx queue, at the top + add(telegram_last_, telegram_last_length_, true); // add the last Tx telegram to the front of the tx queue, at the top return retry_count_; } diff --git a/src/telegram.h b/src/telegram.h index 4c8608d82..b0d7192e9 100644 --- a/src/telegram.h +++ b/src/telegram.h @@ -23,7 +23,15 @@ #include #include // for unique ptrs #include -// #include // for overflow + +// UART drivers +#if defined(ESP8266) +#include "uart/emsuart_esp8266.h" +#elif defined(ESP32) +#include "uart/emsuart_esp32.h" +#elif defined(EMSESP_STANDALONE) +#include +#endif #include @@ -43,8 +51,8 @@ static constexpr int16_t EMS_VALUE_SHORT_INVALID = 0x8000; static constexpr uint32_t EMS_VALUE_ULONG_NOTSET = 0xFFFFFFFF; // for 3-byte and 4-byte longs static constexpr uint32_t EMS_VALUE_ULONG_INVALID = 0x80000000; -static constexpr uint8_t EMS_MAX_TELEGRAM_LENGTH = 32; // max length of a telegram -static constexpr uint8_t EMS_MAX_TELEGRAM_MESSAGE_LENGTH = EMS_MAX_TELEGRAM_LENGTH - 5; // max length of message block +static constexpr uint8_t EMS_MAX_TELEGRAM_LENGTH = 32; // max length of a complete EMS telegram +static constexpr uint8_t EMS_MAX_TELEGRAM_MESSAGE_LENGTH = 27; // max length of message block, assuming EMS1.0 namespace emsesp { @@ -170,7 +178,6 @@ class RxService : public EMSbus { RxService() = default; ~RxService() = default; - void start(); void loop(); void add(uint8_t * data, uint8_t length); @@ -210,7 +217,6 @@ class RxService : public EMSbus { static constexpr uint32_t RX_LOOP_WAIT = 800; // delay in processing Rx queue uint32_t last_rx_check_ = 0; - // std::atomic rx_telegrams_overflow_{false}; uint8_t rx_telegram_id_ = 0; // queue counter uint16_t telegram_count_ = 0; // # Rx received @@ -234,7 +240,7 @@ class TxService : public EMSbus { void send(); void add(const uint8_t operation, const uint8_t dest, const uint16_t type_id, const uint8_t offset, uint8_t * message_data, const uint8_t message_length); - void add(uint8_t * data, const uint8_t length); + void add(uint8_t * data, const uint8_t length, bool front = false); void read_request(const uint16_t type_id, const uint8_t dest, const uint8_t offset = 0); From 43d8bb280892aca916bf18962223ecc41530b6a9 Mon Sep 17 00:00:00 2001 From: proddy Date: Sat, 13 Jun 2020 15:49:58 +0200 Subject: [PATCH 7/7] text changes --- src/mqtt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mqtt.cpp b/src/mqtt.cpp index 5954bb79b..b02898efd 100644 --- a/src/mqtt.cpp +++ b/src/mqtt.cpp @@ -340,7 +340,7 @@ void Mqtt::on_message(char * topic, char * payload, size_t len) { strlcpy(message, payload, len + 1); #ifdef EMSESP_DEBUG - LOG_DEBUG(F("Received %s => %s (length %d)"), topic, message, len); + LOG_DEBUG(F("[DEBUG] Received %s => %s (length %d)"), topic, message, len); #endif // strip out everything until the last /