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 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 */ }; 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 571c2388e..4152eaf71 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()); } } @@ -568,9 +571,9 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) { if (((first_value & 0x7F) == txservice_.ems_bus_id()) && (length > 1)) { // 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 - LOG_DEBUG(F("Echo: %s"), Helpers::data_to_hex(data, length).c_str()); -//#endif +#ifdef EMSESP_DEBUG + 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()); @@ -725,7 +728,6 @@ void EMSESP::console_commands(Shell & shell, unsigned int context) { flash_string_vector{F_(set), F_(tx_mode)}, flash_string_vector{F_(n_mandatory)}, [](Shell & shell, const std::vector & arguments) { - // uint8_t tx_mode = (arguments[0]).at(0) - '0'; uint8_t tx_mode = std::strtol(arguments[0].c_str(), nullptr, 10); if ((tx_mode > 0) && (tx_mode <= 30)) { Settings settings; @@ -824,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); } @@ -839,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_; }; 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 / 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 6ae4907a0..a393093bc 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,43 +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 { - type_id = (data[4] << 8) + data[5] + 256; - 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) ? 1 : 0; // 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); } } } @@ -316,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 } @@ -380,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()); } @@ -477,24 +466,19 @@ 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 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) { + if (status == EMS_TX_STATUS_ERR) { LOG_ERROR(F("Failed to transmit Tx via UART.")); - tx_waiting(false); // nothing send, tx not in wait state + increment_telegram_fail_count(); // another Tx fail + tx_waiting(false); // nothing send, tx not in wait state return; } @@ -514,11 +498,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 uint16_t 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")); + //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 } } @@ -526,7 +514,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) { @@ -537,14 +527,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]; @@ -559,8 +552,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 @@ -626,25 +627,8 @@ uint8_t TxService::retry_tx() { increment_telegram_fail_count(); // another Tx fail return 0; } - // if the queue is full, throw away - if (tx_telegrams_.size() >= MAX_TX_TELEGRAMS) { - reset_retry_count(); // give up - increment_telegram_fail_count(); // another Tx fail - return 0; - } - uint8_t message_length = telegram_last_length_ - 4; - - // build header - uint8_t src = telegram_last_[0]; - uint8_t dest = telegram_last_[1]; - uint8_t type_id = telegram_last_[2]; - uint8_t offset = telegram_last_[3]; - uint8_t * message_data = telegram_last_ + 4; - - auto telegram = std::make_shared(Telegram::Operation::TX_RAW, src, dest, type_id, offset, message_data, message_length); - - tx_telegrams_.emplace_front(tx_telegram_id_++, std::move(telegram)); + 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); 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"