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/device_library.h b/src/device_library.h index 828a02ad2..3cbe47026 100644 --- a/src/device_library.h +++ b/src/device_library.h @@ -98,6 +98,7 @@ {207, DeviceType::CONTROLLER, F("Sense II/CS200"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x10 {209, DeviceType::CONTROLLER, F("ErP"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09 {218, DeviceType::CONTROLLER, F("M200/RFM200"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x50 +{224, DeviceType::CONTROLLER, F("Bosch 9000i"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09 {230, DeviceType::CONTROLLER, F("BC Base"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09 {241, DeviceType::CONTROLLER, F("Condens 5000i"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09 diff --git a/src/devices/boiler.cpp b/src/devices/boiler.cpp index 031b74333..19565c058 100644 --- a/src/devices/boiler.cpp +++ b/src/devices/boiler.cpp @@ -51,7 +51,6 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const // the telegram handlers... register_telegram_type(0x10, F("UBAErrorMessage1"), false, std::bind(&Boiler::process_UBAErrorMessage, this, _1)); register_telegram_type(0x11, F("UBAErrorMessage2"), false, std::bind(&Boiler::process_UBAErrorMessage, this, _1)); - register_telegram_type(0x12, F("UBAErrorMessage3"), false, std::bind(&Boiler::process_UBAErrorMessage, this, _1)); register_telegram_type(0x18, F("UBAMonitorFast"), false, std::bind(&Boiler::process_UBAMonitorFast, this, _1)); register_telegram_type(0x19, F("UBAMonitorSlow"), true, std::bind(&Boiler::process_UBAMonitorSlow, this, _1)); register_telegram_type(0x34, F("UBAMonitorWW"), false, std::bind(&Boiler::process_UBAMonitorWW, this, _1)); 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/helpers.cpp b/src/helpers.cpp index ae83cd0b6..6ac1d7341 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -104,7 +104,7 @@ char * Helpers::render_value(char * result, uint8_t value, uint8_t format) { return (result); } - static char s2[5] = {0}; + char s2[5] = {0}; switch (format) { case 2: @@ -226,7 +226,7 @@ char * Helpers::render_value(char * result, const uint32_t value, const uint8_t return (result); } - static char s[20] = {0}; + char s[20] = {0}; #ifndef EMSESP_STANDALONE if (format <= 1) { 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/uart/emsuart_esp32.cpp b/src/uart/emsuart_esp32.cpp index 091363cec..d4dc5d2b5 100644 --- a/src/uart/emsuart_esp32.cpp +++ b/src/uart/emsuart_esp32.cpp @@ -122,7 +122,12 @@ void EMSuart::start(uint8_t tx_mode) { .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, - }; + } + if (tx_mode_ == 5) { + EMS_UART.conf0.stop_bit_num = UART_STOP_BITS_1_5; + } else { + EMS_UART.conf0.stop_bit_num = UART_STOP_BITS_1; + } ESP_ERROR_CHECK(uart_param_config(EMSUART_UART, &uart_config)); ESP_ERROR_CHECK(uart_set_pin(EMSUART_UART, EMSUART_TXPIN, EMSUART_RXPIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); @@ -161,7 +166,12 @@ void EMSuart::restart() { EMS_UART.int_ena.brk_det = 1; // activate only break emsTxBufIdx = 0; emsTxBufLen = 0; -}; + if (tx_mode_ == 5) { + EMS_UART.conf0.stop_bit_num = UART_STOP_BITS_1_5; + } else { + EMS_UART.conf0.stop_bit_num = UART_STOP_BITS_1; + } +} /* * Sends a 1-byte poll, ending with a @@ -186,7 +196,7 @@ void EMSuart::send_poll(uint8_t data) { */ uint16_t EMSuart::transmit(uint8_t * buf, uint8_t len) { if (len == 0 || len > 32) { - return EMS_TX_STATUS_ERROR; + return EMS_TX_STATUS_ERR; } if (tx_mode_ == EMS_TXMODE_NEW || tx_mode_ == 5) { for (uint8_t i = 0; i < len; i++) { diff --git a/src/uart/emsuart_esp32.h b/src/uart/emsuart_esp32.h index 4e958469e..000a20c00 100644 --- a/src/uart/emsuart_esp32.h +++ b/src/uart/emsuart_esp32.h @@ -58,7 +58,7 @@ namespace emsesp { #define EMS_TX_STATUS_OK 1 -#define EMS_TX_STATUS_ERROR 0 +#define EMS_TX_STATUS_ERR 0 class EMSuart { public: diff --git a/src/uart/emsuart_esp8266.cpp b/src/uart/emsuart_esp8266.cpp index d77a77de3..1b1468f89 100644 --- a/src/uart/emsuart_esp8266.cpp +++ b/src/uart/emsuart_esp8266.cpp @@ -35,6 +35,7 @@ uint8_t phantomBreak = 0; uint8_t tx_mode_ = 0xFF; bool drop_next_rx = true; uint32_t emsRxTime; +// uint32_t emsTxTime = 0; uint8_t emsTxBuf[EMS_MAXBUFFERSIZE]; uint8_t emsTxBufIdx; uint8_t emsTxBufLen; @@ -88,7 +89,10 @@ void ICACHE_FLASH_ATTR EMSuart::emsuart_recvTask(os_event_t * events) { phantomBreak = 0; length--; // remove phantom break from Rx buffer } - + // if (emsTxTime > 0) { + // LOG_INFO(F("tx duration: %d ms"), uuid::get_uptime() - emsTxTime); + // emsTxTime = 0; + // } // it's a poll or status code, single byte and ok to send on, then quit if (length == 2) { EMSESP::incoming_telegram((uint8_t *)pCurrent->buffer, 1); @@ -124,7 +128,7 @@ void ICACHE_RAM_ATTR EMSuart::emsuart_tx_timer_intr_handler() { } else if (emsTxBufIdx == emsTxBufLen) { USC0(EMSUART_UART) |= (1 << UCBRK); // set if (tx_mode_ > 5 || tx_mode_ < 11) { - timer1_write(5 * EMSUART_TX_BIT_TIME * 11); + timer1_write(5 * EMSUART_TX_BIT_TIME * 12); USIE(EMSUART_UART) &= ~(1 << UIBD); // disable break interrupt } } else if (USC0(EMSUART_UART) & (1 << UCBRK)) { @@ -258,10 +262,10 @@ void ICACHE_FLASH_ATTR EMSuart::tx_brk() { ETS_UART_INTR_DISABLE(); USC0(EMSUART_UART) |= (1 << UCBRK); // set bit - 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 + if (tx_mode_ == EMS_TXMODE_EMSPLUS) { // EMS+ mode + delayMicroseconds(EMSUART_TX_WAIT_PLUS); // 2070 + } else { // junkers and EMS1.0 + delayMicroseconds(EMSUART_TX_WAIT_BRK); // 1144 } USC0(EMSUART_UART) &= ~(1 << UCBRK); // clear BRK bit @@ -283,10 +287,17 @@ void EMSuart::send_poll(uint8_t data) { } else if (tx_mode_ >= EMS_TXMODE_NEW) { // hardware controlled modes USF(EMSUART_UART) = data; USC0(EMSUART_UART) |= (1 << UCBRK); // send at the end - } else { // software controlled modes - // EMS1.0, EMS+ and HT3 + } else if (tx_mode_ == EMS_TXMODE_HT3) { USF(EMSUART_UART) = data; - delayMicroseconds(EMSUART_TX_BRK_WAIT); + delayMicroseconds(EMSUART_TX_WAIT_HT3); + tx_brk(); // send + } else if (tx_mode_ == EMS_TXMODE_EMSPLUS) { + USF(EMSUART_UART) = data; + delayMicroseconds(EMSUART_TX_WAIT_PLUS); + tx_brk(); // send + } else { // EMS1.0 + USF(EMSUART_UART) = data; + delayMicroseconds(EMSUART_TX_WAIT_BRK); tx_brk(); // send } } @@ -303,6 +314,7 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { #ifdef EMSESP_DEBUG // LOG_INFO(F("[DEBUG] UART Response time: %d ms"), uuid::get_uptime() - emsRxTime); #endif + // emsTxTime = uuid::get_uptime(); // if ((uuid::get_uptime() - emsRxTime) > EMS_RX_TO_TX_TIMEOUT)) { // send allowed within 20 ms // return EMS_TX_STATUS_ERR; // } @@ -317,6 +329,8 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { emsTxBufIdx = 0; emsTxBufLen = len; USF(EMSUART_UART) = buf[0]; + // timer1_attachInterrupt(emsuart_tx_timer_intr_handler); // Add ISR Function + // timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE); // 5 MHz timer timer1_write(emsTxWait); return EMS_TX_STATUS_OK; } @@ -334,7 +348,7 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { if (tx_mode_ == EMS_TXMODE_EMSPLUS) { // With extra tx delay for EMS+ for (uint8_t i = 0; i < len; i++) { USF(EMSUART_UART) = buf[i]; - delayMicroseconds(EMSUART_TX_BRK_WAIT); // 2070 + delayMicroseconds(EMSUART_TX_WAIT_PLUS); // 2070 } tx_brk(); // send return EMS_TX_STATUS_OK; @@ -350,7 +364,7 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { ; // wait until bits are sent on wire - delayMicroseconds(EMSUART_TX_BRK_WAIT_HT3); + delayMicroseconds(EMSUART_TX_WAIT_HT3); } tx_brk(); // send return EMS_TX_STATUS_OK; diff --git a/src/uart/emsuart_esp8266.h b/src/uart/emsuart_esp8266.h index 26ca2478c..1923b2f2e 100644 --- a/src/uart/emsuart_esp8266.h +++ b/src/uart/emsuart_esp8266.h @@ -42,13 +42,16 @@ // LEGACY #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_BRK (EMSUART_TX_BIT_TIME * 11) // 1144 // 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 +// HT3/Junkers - Time to send one Byte (8 Bits, 1 Start Bit, 1 Stop Bit) plus 7 bit delay. The -8 is for lag compensation. +#define EMSUART_TX_WAIT_HT3 (EMSUART_TX_BIT_TIME * 17) - 8 // 1760 + +// EMS+ - Time to send one Byte (8 Bits, 1 Start Bit, 1 Stop Bit) and delay of another Bytetime. +#define EMSUART_TX_WAIT_PLUS 2070 namespace emsesp { 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"