diff --git a/platformio.ini b/platformio.ini index 5485771da..cc2e10d73 100644 --- a/platformio.ini +++ b/platformio.ini @@ -2,9 +2,9 @@ ; For EMS-ESP [platformio] -default_envs = esp8266 +; default_envs = esp8266 ; default_envs = esp32 -;default_envs = esp32_d1 +default_envs = esp32_d1 # override any settings with your own local ones in pio_local.ini extra_configs = pio_local.ini @@ -26,7 +26,11 @@ debug_flags = ; -D EMSESP_SAFE_MODE ; -D ENABLE_CORS -D CORS_ORIGIN=\"http://localhost:3000\" -build_flags = -std=c++11 -Os -fno-exceptions +; default platformio compile flags are: +; -fno-rtti -std=c++11 -Os -mlongcalls -mtext-section-literals -falign-functions=4 -ffunction-sections -fdata-sections -fno-exceptions -Wall +; (note -flto doesn't make a different to flash) + +build_flags = -D ONEWIRE_CRC16=0 -D NO_GLOBAL_ARDUINOOTA -D ARDUINOJSON_ENABLE_STD_STRING=1 @@ -59,7 +63,7 @@ check_flags = clangtidy: --checks=-*,clang-analyzer-*,performance-* ; USB upload -; upload_protocol = esptool + ;upload_protocol = esptool ; example ports for OSX ;upload_port = /dev/cu.wchusbserial14403 ;upload_port = /dev/cu.usbserial-1440 @@ -70,7 +74,7 @@ upload_protocol = espota upload_flags = --port=8266 --auth=neo -upload_port = 192.168.0.20 +upload_port = 192.168.0.23 [env:esp8266] build_type = release @@ -80,9 +84,9 @@ board = esp12e ; board = d1_mini ; https://github.com/platformio/platform-espressif8266/blob/master/boards/d1_mini.json lib_deps = ${common.libs_core} ${common.libs_esp8266} board_build.f_cpu = 160000000L ; 160MHz -;board_build.ldscript = eagle.flash.4m1m.ld ; 1019 KB sketch, 1000 KB SPIFFS. 4KB EEPROM, 4KB RFCAL, 12KB WIFI stack, 2052 KB OTA & buffer -board_build.ldscript = eagle.flash.4m2m.ld ; 1019 KB sketch, 2024 KB SPIFFS. 4KB EEPROM, 4KB RFCAL, 12KB WIFI stack, 1028 KB OTA & buffer -build_flags = ${common.build_flags} ${common.debug_flags} -flto -D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY +board_build.ldscript = eagle.flash.4m1m.ld ; 1019 KB sketch, 1000 KB SPIFFS. 4KB EEPROM, 4KB RFCAL, 12KB WIFI stack, 2052 KB OTA & buffer +; board_build.ldscript = eagle.flash.4m2m.ld ; 1019 KB sketch, 2024 KB SPIFFS. 4KB EEPROM, 4KB RFCAL, 12KB WIFI stack, 1028 KB OTA & buffer +build_flags = ${common.build_flags} ${common.debug_flags} -D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY [env:esp32] build_type = release diff --git a/src/console.cpp b/src/console.cpp index 5ed1a9c78..5d6c68b59 100644 --- a/src/console.cpp +++ b/src/console.cpp @@ -431,7 +431,7 @@ void Console::start() { shell->log_level(uuid::log::Level::DEBUG); // order is: err, warning, notice, info, trace, debug, all } -// always start the telnet service +// always start the telnet service, except on an ESP8266 // default idle is 10 minutes, default write timeout is 0 (automatic) // note, this must be started after the network/wifi for ESP32 otherwise it'll crash #ifndef EMSESP_STANDALONE diff --git a/src/device_library.h b/src/device_library.h index 4ddcd93e4..dc0f76b86 100644 --- a/src/device_library.h +++ b/src/device_library.h @@ -58,9 +58,9 @@ // Switches - 0x11 { 71, DeviceType::SWITCH, F("WM10"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x11 -// Controllers - 0x09 / 0x10 +// Controllers - 0x09 / 0x10 / 0x50 { 68, DeviceType::CONTROLLER, F("BC10/RFM20"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09 -{ 89, DeviceType::CONTROLLER, F("BC"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09 +{ 89, DeviceType::CONTROLLER, F("BC10 GB142"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09 {218, DeviceType::CONTROLLER, F("M200/RFM200"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x50 {190, DeviceType::CONTROLLER, F("BC10"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09 {114, DeviceType::CONTROLLER, F("BC10"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09 @@ -79,7 +79,7 @@ // Gateways - 0x48 / 0x18 {189, DeviceType::GATEWAY, F("KM200"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x48 -{ 94, DeviceType::GATEWAY, F("RC"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x18 +{ 94, DeviceType::GATEWAY, F("RFM20 Remote Base for RC20RF"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x18 // Thermostat - not currently supporting write operations, like the Easy/100 types - 0x18 {202, DeviceType::THERMOSTAT, F("Logamatic TC100/Moduline Easy"), DeviceFlags::EMS_DEVICE_FLAG_EASY | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE}, // 0x18, cannot write diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index a588b9441..1a5a27942 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -169,6 +169,17 @@ void EMSdevice::fetch_values() { } } +// toggle on/off automatic fetch for a telegram id +void EMSdevice::toggle_fetch(uint16_t telegram_id, bool toggle) { + LOG_DEBUG(F("Toggling fetch for device ID 0x%02X, telegram ID 0x%02X to %d"), device_id(), telegram_id, toggle); + + for (auto & tf : telegram_functions_) { + if (tf.telegram_type_id_ == telegram_id) { + tf.fetch_ = toggle; + } + } +} + // list all the telegram type IDs for this device void EMSdevice::show_telegram_handlers(uuid::console::Shell & shell) { if (telegram_functions_.size() == 0) { @@ -227,9 +238,17 @@ std::string EMSdevice::telegram_type_name(std::shared_ptr telegr // take a telegram_type_id and call the matching handler // return true if match found -bool EMSdevice::process_telegram(std::shared_ptr telegram) { +bool EMSdevice::handle_telegram(std::shared_ptr telegram) { for (const auto & tf : telegram_functions_) { if (tf.telegram_type_id_ == telegram->type_id) { + // if the data block is empty, assume that this telegram is not recognized by the bus master + // so remove it from the automatic fetch list + if (telegram->message_length == 0) { + LOG_DEBUG(F("This telegram (%s) is not recognized by the EMS bus"), uuid::read_flash_string(tf.telegram_type_name_).c_str()); + toggle_fetch(tf.telegram_type_id_, false); + return false; + } + LOG_DEBUG(F("Processing %s..."), uuid::read_flash_string(tf.telegram_type_name_).c_str()); tf.process_function_(telegram); return true; diff --git a/src/emsdevice.h b/src/emsdevice.h index 94d58496e..405a1d3ad 100644 --- a/src/emsdevice.h +++ b/src/emsdevice.h @@ -99,7 +99,7 @@ class EMSdevice { using process_function_p = std::function)>; void register_telegram_type(const uint16_t telegram_type_id, const __FlashStringHelper * telegram_type_name, bool fetch, process_function_p cb); - bool process_telegram(std::shared_ptr telegram); + bool handle_telegram(std::shared_ptr telegram); void write_command(const uint16_t type_id, const uint8_t offset, uint8_t * message_data, const uint8_t message_length, const uint16_t validate_typeid); void write_command(const uint16_t type_id, const uint8_t offset, const uint8_t value, const uint16_t validate_typeid); @@ -118,6 +118,7 @@ class EMSdevice { std::string telegram_type_name(std::shared_ptr telegram); void fetch_values(); + void toggle_fetch(uint16_t telegram_id, bool toggle); void print_value(uuid::console::Shell & shell, uint8_t padding, const __FlashStringHelper * name, const __FlashStringHelper * prefix, const char * value); void print_value(uuid::console::Shell & shell, uint8_t padding, const __FlashStringHelper * name, const char * value); diff --git a/src/emsesp.cpp b/src/emsesp.cpp index 519e63755..7f7130424 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -422,7 +422,7 @@ bool EMSESP::process_telegram(std::shared_ptr telegram) { for (const auto & emsdevice : emsdevices) { if (emsdevice) { if (emsdevice->is_device_id(telegram->src)) { - found = emsdevice->process_telegram(telegram); + found = emsdevice->handle_telegram(telegram); // check to see if we need to force an MQTT publish if (found) { if (emsdevice->updated_values()) { @@ -702,6 +702,9 @@ void EMSESP::console_commands(Shell & shell, unsigned int context) { settings.ems_tx_mode(tx_mode); settings.commit(); shell.printfln(F_(tx_mode_fmt), settings.ems_tx_mode()); + // reset the UART + EMSuart::stop(); + EMSuart::start(tx_mode); } else { shell.println(F("Must be 1 for EMS generic, 2 for EMS+, 3 for HT3, 4 for experimental")); } diff --git a/src/helpers.cpp b/src/helpers.cpp index 0b4ef1d3a..4a0380358 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -152,7 +152,7 @@ char * Helpers::render_value(char * result, const int16_t value, const uint8_t f result[0] = '\0'; // remove errors or invalid values, 0x7D00 and higher - if ((value == EMS_VALUE_SHORT_NOTSET) || (value == EMS_VALUE_SHORT_INVALID)) { + if ((value == EMS_VALUE_SHORT_NOTSET) || (value == EMS_VALUE_SHORT_INVALID) || (value == EMS_VALUE_USHORT_NOTSET)) { strlcpy(result, "?", 10); return result; } diff --git a/src/mixing.cpp b/src/mixing.cpp index 198869adf..223ffe330 100644 --- a/src/mixing.cpp +++ b/src/mixing.cpp @@ -31,7 +31,7 @@ Mixing::Mixing(uint8_t device_type, uint8_t device_id, uint8_t product_id, const if (flags == EMSdevice::EMS_DEVICE_FLAG_MMPLUS) { if (device_id < 0x28) { // telegram handlers 0x20 - 0x27 for HC - register_telegram_type(device_id -0x20 + 0x02D7, F("MMPLUSStatusMessage_HC"), true, std::bind(&Mixing::process_MMPLUSStatusMessage_HC, this, _1)); + register_telegram_type(device_id - 0x20 + 0x02D7, F("MMPLUSStatusMessage_HC"), true, std::bind(&Mixing::process_MMPLUSStatusMessage_HC, this, _1)); } else { // telegram handlers for warm water/DHW 0x28, 0x29 register_telegram_type(device_id - 0x28 + 0x0331, F("MMPLUSStatusMessage_WWC"), true, std::bind(&Mixing::process_MMPLUSStatusMessage_WWC, this, _1)); @@ -54,6 +54,15 @@ Mixing::Mixing(uint8_t device_type, uint8_t device_id, uint8_t product_id, const void Mixing::add_context_menu() { } +// check to see if values have been updated +bool Mixing::updated_values() { + return false; +} + +// add console commands +void Mixing::console_commands() { +} + // display all values into the shell console void Mixing::show_values(uuid::console::Shell & shell) { EMSdevice::show_values(shell); // always call this to show header @@ -86,10 +95,10 @@ void Mixing::publish_values() { if (mqtt_format_ == Settings::MQTT_format::SINGLE) { switch (type_) { case Type::HC: - rootMixing["type"] = F("hc"); + rootMixing["type"] = "hc"; break; case Type::WWC: - rootMixing["type"] = F("wwc"); + rootMixing["type"] = "wwc"; break; case Type::NONE: default: @@ -141,15 +150,6 @@ void Mixing::publish_values() { Mqtt::publish(topic, doc); } -// check to see if values have been updated -bool Mixing::updated_values() { - return false; -} - -// add console commands -void Mixing::console_commands() { -} - // heating circuits 0x02D7, 0x02D8 etc... void Mixing::process_MMPLUSStatusMessage_HC(std::shared_ptr telegram) { type_ = Type::HC; diff --git a/src/network.cpp b/src/network.cpp index 7d11fcbf6..39394d473 100644 --- a/src/network.cpp +++ b/src/network.cpp @@ -73,14 +73,14 @@ void Network::sta_mode_start(WiFiEvent_t event, WiFiEventInfo_t info) { #if defined(ESP8266) void Network::sta_mode_connected(const WiFiEventStationModeConnected & event) { LOG_INFO(F("Connected to %s (%02X:%02X:%02X:%02X:%02X:%02X) on channel %u"), - event.ssid.c_str(), - event.bssid[0], - event.bssid[1], - event.bssid[2], - event.bssid[3], - event.bssid[4], - event.bssid[5], - event.channel); + event.ssid.c_str(), + event.bssid[0], + event.bssid[1], + event.bssid[2], + event.bssid[3], + event.bssid[4], + event.bssid[5], + event.channel); // turn off safe mode System::save_safe_mode(false); @@ -88,14 +88,14 @@ void Network::sta_mode_connected(const WiFiEventStationModeConnected & event) { #elif defined(ESP32) void Network::sta_mode_connected(WiFiEvent_t event, WiFiEventInfo_t info) { LOG_INFO(F("Connected to %s (%02X:%02X:%02X:%02X:%02X:%02X) on channel %u"), - info.connected.ssid, - info.sta_connected.mac[0], - info.sta_connected.mac[1], - info.sta_connected.mac[2], - info.sta_connected.mac[3], - info.sta_connected.mac[4], - info.sta_connected.mac[5], - info.connected.channel); + info.connected.ssid, + info.sta_connected.mac[0], + info.sta_connected.mac[1], + info.sta_connected.mac[2], + info.sta_connected.mac[3], + info.sta_connected.mac[4], + info.sta_connected.mac[5], + info.connected.channel); // turn off safe mode System::save_safe_mode(false); @@ -126,16 +126,16 @@ void Network::sta_mode_disconnected(WiFiEvent_t event, WiFiEventInfo_t info) { #if defined(ESP8266) void Network::sta_mode_got_ip(const WiFiEventStationModeGotIP & event) { LOG_INFO(F("Obtained IPv4 address %s/%s and gateway %s"), - uuid::printable_to_string(event.ip).c_str(), - uuid::printable_to_string(event.mask).c_str(), - uuid::printable_to_string(event.gw).c_str()); + uuid::printable_to_string(event.ip).c_str(), + uuid::printable_to_string(event.mask).c_str(), + uuid::printable_to_string(event.gw).c_str()); } #elif defined(ESP32) void Network::sta_mode_got_ip(WiFiEvent_t event, WiFiEventInfo_t info) { LOG_INFO(F("Obtained IPv4 address %s/%s and gateway %s"), - uuid::printable_to_string(IPAddress(info.got_ip.ip_info.ip.addr)).c_str(), - uuid::printable_to_string(IPAddress(info.got_ip.ip_info.netmask.addr)).c_str(), - uuid::printable_to_string(IPAddress(info.got_ip.ip_info.gw.addr)).c_str()); + uuid::printable_to_string(IPAddress(info.got_ip.ip_info.ip.addr)).c_str(), + uuid::printable_to_string(IPAddress(info.got_ip.ip_info.netmask.addr)).c_str(), + uuid::printable_to_string(IPAddress(info.got_ip.ip_info.gw.addr)).c_str()); } #endif @@ -148,11 +148,16 @@ void Network::connect() { #ifndef EMSESP_STANDALONE - // WiFi.mode(WIFI_STA); - if (!settings.hostname().empty()) { #if defined(ESP8266) + // experiment with fixed IP + // IPAddress ip(10, 10, 10, 140); + // IPAddress gateway(10, 10, 10, 1); + // IPAddress subnet(255, 255, 255, 0); + // WiFi.config(ip, gateway, subnet); + WiFi.config(INADDR_ANY, INADDR_ANY, INADDR_ANY); + WiFi.hostname(settings.hostname().c_str()); #elif defined(ESP32) WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); @@ -205,9 +210,11 @@ void Network::ota_setup() { ota_->onStart([this]() { LOG_DEBUG(F("OTA starting (send type %d)..."), ota_->getCommand()); - // turn off stuff to stop interference +// turn off UART stuff to stop interference on an ESP8266 only +#if defined(ESP8266) EMSuart::stop(); // UART stop - in_ota_ = true; // set flag so all other services stop +#endif + in_ota_ = true; // set flag so all other services stop }); ota_->onEnd([this]() { LOG_DEBUG(F("OTA done, automatically restarting")); }); diff --git a/src/settings.cpp b/src/settings.cpp index 7a5035eb6..4ac397edf 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -254,9 +254,9 @@ void Settings::show_settings(uuid::console::Shell & shell) { // format the FS. Wipes everything. void Settings::format(uuid::console::Shell & shell) { - EMSuart::stop(); #ifndef EMSESP_STANDALONE #if defined(ESP8266) + EMSuart::stop(); if (EMSESP_FS.begin()) { #elif defined(ESP32) if (EMSESP_FS.begin(true)) { @@ -275,8 +275,10 @@ void Settings::format(uuid::console::Shell & shell) { auto msg = F("Unable to mount filesystem"); shell.logger().alert(msg); } +#if defined(ESP8266) EMSuart::restart(); #endif +#endif } void Settings::syslog_host(const std::string & syslog_host) { diff --git a/src/system.cpp b/src/system.cpp index 5dafeb6b6..eacf4075b 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -45,8 +45,6 @@ uuid::log::Logger System::logger_{F_(logger_name), uuid::log::Facility::KERN}; uuid::syslog::SyslogService System::syslog_; #endif -EMSuart System::emsuart_; - #if defined(ESP8266) RTCVars System::state_; #endif @@ -87,7 +85,6 @@ void System::mqtt_commands(const char * message) { // restart EMS-ESP // mode = safe mode. true to enable on next boot void System::restart(bool mode) { - EMSuart::stop(); // check for safe mode if (mode) { @@ -171,7 +168,7 @@ void System::start() { if (safe_mode()) { } else { save_safe_mode(false); // next time boot up in normal mode - emsuart_.start(settings.ems_tx_mode()); + EMSuart::start(settings.ems_tx_mode()); } #endif } diff --git a/src/system.h b/src/system.h index 173bc0d64..01ac50afe 100644 --- a/src/system.h +++ b/src/system.h @@ -107,8 +107,6 @@ class System { static uint32_t heap_start_; static int reset_counter_; - static EMSuart emsuart_; - #if defined(ESP8266) static RTCVars state_; #endif diff --git a/src/telegram.cpp b/src/telegram.cpp index 73a90ee15..2461da50d 100644 --- a/src/telegram.cpp +++ b/src/telegram.cpp @@ -43,6 +43,7 @@ bool EMSbus::bus_connected_ = false; // start assuming the bus uint8_t EMSbus::ems_mask_ = EMS_MASK_UNSET; // unset so its triggered when booting, the its 0x00=buderus, 0x80=junker/ht3 uint8_t EMSbus::ems_bus_id_ = EMSESP_DEFAULT_BUS_ID; bool EMSbus::tx_waiting_ = false; +bool EMSbus::tx_active_ = false; uuid::log::Logger EMSbus::logger_{F_(logger_name), uuid::log::Facility::CONSOLE}; @@ -278,7 +279,7 @@ void RxService::add(uint8_t * data, uint8_t length) { // 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 + // 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; @@ -355,8 +356,8 @@ void TxService::loop() { #ifndef EMSESP_STANDALONE if ((uuid::get_uptime() - last_tx_check_) > TX_LOOP_WAIT) { last_tx_check_ = uuid::get_uptime(); - if ((tx_telegrams_.size() >= MAX_TX_TELEGRAMS - 1) && (EMSbus::bus_connected())) { - LOG_ERROR(F("Tx buffer full. Looks like Tx is not working?")); + if (!tx_active_ && (EMSbus::bus_connected())) { + LOG_ERROR(F("Tx is not active. Please check connection.")); } } #endif diff --git a/src/telegram.h b/src/telegram.h index 19c325fc9..8b6fa661f 100644 --- a/src/telegram.h +++ b/src/telegram.h @@ -139,8 +139,15 @@ class EMSbus { return tx_waiting_; } + static bool tx_active_; // whether Tx is active or not + static void tx_waiting(bool tx_waiting) { tx_waiting_ = tx_waiting; + + // if false, then it's been reset which means we have an active Tx + if (!tx_waiting) { + tx_active_ = true; + } } static uint8_t calculate_crc(const uint8_t * data, const uint8_t length); @@ -150,14 +157,14 @@ class EMSbus { static uint32_t last_bus_activity_; // timestamp of last time a valid Rx came in static bool bus_connected_; // start assuming the bus hasn't been connected - static uint8_t ems_mask_; // unset 0x00 buderus 0x80 junker/ht3 + static uint8_t ems_mask_; // unset 0x00 buderus 0x80 junkers/ht3 static uint8_t ems_bus_id_; // the bus id, which configurable and stored in settings static bool tx_waiting_; // state of the Tx queue (idle, waiting for ack) }; class RxService : public EMSbus { public: - static constexpr size_t MAX_RX_TELEGRAMS = 10; + static constexpr size_t MAX_RX_TELEGRAMS = 20; RxService() = default; ~RxService() = default; @@ -213,7 +220,7 @@ class RxService : public EMSbus { class TxService : public EMSbus { public: - static constexpr size_t MAX_TX_TELEGRAMS = 30; + static constexpr size_t MAX_TX_TELEGRAMS = 40; // size of Tx queue static constexpr uint8_t TX_WRITE_FAIL = 4; static constexpr uint8_t TX_WRITE_SUCCESS = 1; diff --git a/src/thermostat.cpp b/src/thermostat.cpp index 1f4492675..19faf83ae 100644 --- a/src/thermostat.cpp +++ b/src/thermostat.cpp @@ -35,7 +35,7 @@ uuid::log::Logger Thermostat::logger_{F_(logger_name), uuid::log::Facility::CONS Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand) : EMSdevice(device_type, device_id, product_id, version, name, flags, brand) { - // telegram handlers + // common telegram handlers register_telegram_type(EMS_TYPE_RCOutdoorTemp, F("RCOutdoorTemp"), false, std::bind(&Thermostat::process_RCOutdoorTemp, this, _1)); register_telegram_type(EMS_TYPE_RCTime, F("RCTime"), true, std::bind(&Thermostat::process_RCTime, this, _1)); // 0x06 @@ -44,8 +44,8 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i monitor_typeids = {0xB1}; set_typeids = {0xB0}; for (uint8_t i = 0; i < monitor_typeids.size(); i++) { - register_telegram_type(monitor_typeids[i], F("RC10Monitor"), true, std::bind(&Thermostat::process_RC10Monitor, this, _1)); - register_telegram_type(set_typeids[i], F("RC10Set"), true, std::bind(&Thermostat::process_RC10Set, this, _1)); + register_telegram_type(monitor_typeids[i], F("RC10Monitor"), false, std::bind(&Thermostat::process_RC10Monitor, this, _1)); + register_telegram_type(set_typeids[i], F("RC10Set"), false, std::bind(&Thermostat::process_RC10Set, this, _1)); } // RC35 @@ -53,8 +53,8 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i monitor_typeids = {0x3E, 0x48, 0x52, 0x5C}; set_typeids = {0x3D, 0x47, 0x51, 0x5B}; for (uint8_t i = 0; i < monitor_typeids.size(); i++) { - register_telegram_type(monitor_typeids[i], F("RC35Monitor"), true, std::bind(&Thermostat::process_RC35Monitor, this, _1)); - register_telegram_type(set_typeids[i], F("RC35Set"), true, std::bind(&Thermostat::process_RC35Set, this, _1)); + register_telegram_type(monitor_typeids[i], F("RC35Monitor"), false, std::bind(&Thermostat::process_RC35Monitor, this, _1)); + register_telegram_type(set_typeids[i], F("RC35Set"), false, std::bind(&Thermostat::process_RC35Set, this, _1)); } register_telegram_type(EMS_TYPE_IBASettings, F("IBASettings"), true, std::bind(&Thermostat::process_IBASettings, this, _1)); @@ -63,8 +63,8 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i monitor_typeids = {0x91}; set_typeids = {0xA8}; for (uint8_t i = 0; i < monitor_typeids.size(); i++) { - register_telegram_type(monitor_typeids[i], F("RC20Monitor"), true, std::bind(&Thermostat::process_RC20Monitor, this, _1)); - register_telegram_type(set_typeids[i], F("RC20Set"), true, std::bind(&Thermostat::process_RC20Set, this, _1)); + register_telegram_type(monitor_typeids[i], F("RC20Monitor"), false, std::bind(&Thermostat::process_RC20Monitor, this, _1)); + register_telegram_type(set_typeids[i], F("RC20Set"), false, std::bind(&Thermostat::process_RC20Set, this, _1)); } // RC20 newer @@ -72,8 +72,8 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i monitor_typeids = {0xAE}; set_typeids = {0xAD}; for (uint8_t i = 0; i < monitor_typeids.size(); i++) { - register_telegram_type(monitor_typeids[i], F("RC20Monitor"), true, std::bind(&Thermostat::process_RC20Monitor_2, this, _1)); - register_telegram_type(set_typeids[i], F("RC20Set"), true, std::bind(&Thermostat::process_RC20Set_2, this, _1)); + register_telegram_type(monitor_typeids[i], F("RC20Monitor"), false, std::bind(&Thermostat::process_RC20Monitor_2, this, _1)); + register_telegram_type(set_typeids[i], F("RC20Set"), false, std::bind(&Thermostat::process_RC20Set_2, this, _1)); } // RC30 @@ -81,23 +81,23 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i monitor_typeids = {0x41}; set_typeids = {0xA7}; for (uint8_t i = 0; i < monitor_typeids.size(); i++) { - register_telegram_type(monitor_typeids[i], F("RC30Monitor"), true, std::bind(&Thermostat::process_RC30Monitor, this, _1)); - register_telegram_type(set_typeids[i], F("RC30Set"), true, std::bind(&Thermostat::process_RC30Set, this, _1)); + register_telegram_type(monitor_typeids[i], F("RC30Monitor"), false, std::bind(&Thermostat::process_RC30Monitor, this, _1)); + register_telegram_type(set_typeids[i], F("RC30Set"), false, std::bind(&Thermostat::process_RC30Set, this, _1)); } // EASY } else if (flags == EMSdevice::EMS_DEVICE_FLAG_EASY) { monitor_typeids = {0x0A}; set_typeids = {}; - register_telegram_type(monitor_typeids[0], F("EasyMonitor"), true, std::bind(&Thermostat::process_EasyMonitor, this, _1)); + register_telegram_type(monitor_typeids[0], F("EasyMonitor"), false, std::bind(&Thermostat::process_EasyMonitor, this, _1)); // RC300/RC100 } else if ((flags == EMSdevice::EMS_DEVICE_FLAG_RC300) || (flags == EMSdevice::EMS_DEVICE_FLAG_RC100)) { monitor_typeids = {0x02A5, 0x02A6, 0x02A7, 0x02A8}; set_typeids = {0x02B9, 0x02BA, 0x02BB, 0x02BC}; for (uint8_t i = 0; i < monitor_typeids.size(); i++) { - register_telegram_type(monitor_typeids[i], F("RC300Monitor"), true, std::bind(&Thermostat::process_RC300Monitor, this, _1)); - register_telegram_type(set_typeids[i], F("RC300Set"), true, std::bind(&Thermostat::process_RC300Set, this, _1)); + register_telegram_type(monitor_typeids[i], F("RC300Monitor"), false, std::bind(&Thermostat::process_RC300Monitor, this, _1)); + register_telegram_type(set_typeids[i], F("RC300Set"), false, std::bind(&Thermostat::process_RC300Set, this, _1)); } // JUNKERS/HT3 @@ -105,16 +105,16 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i monitor_typeids = {0x6F, 0x70, 0x71, 0x72}; set_typeids = {0x65, 0x66, 0x67, 0x68}; for (uint8_t i = 0; i < monitor_typeids.size(); i++) { - register_telegram_type(monitor_typeids[i], F("JunkersMonitor"), true, std::bind(&Thermostat::process_JunkersMonitor, this, _1)); - register_telegram_type(set_typeids[i], F("JunkersSet"), true, std::bind(&Thermostat::process_JunkersSet, this, _1)); + register_telegram_type(monitor_typeids[i], F("JunkersMonitor"), false, std::bind(&Thermostat::process_JunkersMonitor, this, _1)); + register_telegram_type(set_typeids[i], F("JunkersSet"), false, std::bind(&Thermostat::process_JunkersSet, this, _1)); } } else if (flags == (EMSdevice::EMS_DEVICE_FLAG_JUNKERS | EMSdevice::EMS_DEVICE_FLAG_JUNKERS_2)) { monitor_typeids = {0x6F, 0x70, 0x71, 0x72}; set_typeids = {0x79, 0x7A, 0x7B, 0x7C}; for (uint8_t i = 0; i < monitor_typeids.size(); i++) { - register_telegram_type(monitor_typeids[i], F("JunkersMonitor"), true, std::bind(&Thermostat::process_JunkersMonitor, this, _1)); - register_telegram_type(set_typeids[i], F("JunkersSet"), true, std::bind(&Thermostat::process_JunkersSet, this, _1)); + register_telegram_type(monitor_typeids[i], F("JunkersMonitor"), false, std::bind(&Thermostat::process_JunkersMonitor, this, _1)); + register_telegram_type(set_typeids[i], F("JunkersSet"), false, std::bind(&Thermostat::process_JunkersSet, this, _1)); } } @@ -510,6 +510,7 @@ std::shared_ptr Thermostat::heating_circuit(const ui // determine which heating circuit the type ID is referring too // returns pointer to the HeatingCircuit or nullptr if it can't be found +// if its a new one, the object will be created and also the fetch flags set std::shared_ptr Thermostat::heating_circuit(std::shared_ptr telegram) { // look through the Monitor and Set arrays to see if there is a match uint8_t hc_num = 0; @@ -545,8 +546,12 @@ std::shared_ptr Thermostat::heating_circuit(std::sha } // create a new heating circuit object - // TODO do we need to create a new object if using emplace_back? heating_circuits_.emplace_back(new HeatingCircuit(hc_num, monitor_typeids[hc_num - 1], set_typeids[hc_num - 1])); + + // set the flag saying we want its data during the next auto fetch + toggle_fetch(monitor_typeids[hc_num - 1], true); + toggle_fetch(set_typeids[hc_num - 1], true); + return heating_circuits_.back(); } @@ -667,17 +672,16 @@ std::string Thermostat::mode_tostring(uint8_t mode) const { void Thermostat::show_values(uuid::console::Shell & shell) { EMSdevice::show_values(shell); // always call this to show header - char buffer[10]; // for formatting only + char buffer[10]; // for formatting only + uint8_t flags = (this->flags() & 0x0F); // specific thermostat characteristics, strip the option bits if (datetime_.size()) { shell.printfln(F(" Clock: %s"), datetime_.c_str()); - if (ibaClockOffset != EMS_VALUE_UINT_NOTSET) { + if (ibaClockOffset != EMS_VALUE_UINT_NOTSET && flags == EMS_DEVICE_FLAG_RC30_1) { print_value(shell, 2, F("Offset clock"), Helpers::render_value(buffer, ibaClockOffset, 1)); // offset (in sec) to clock, 0xff = -1 s, 0x02 = 2 s } } - uint8_t flags = (this->flags() & 0x0F); // specific thermostat characteristics, strip the option bits - if (flags == EMS_DEVICE_FLAG_RC35) { print_value(shell, 2, F("Damped Outdoor temperature"), F_(degrees), Helpers::render_value(buffer, dampedoutdoortemp, 1)); print_value(shell, 2, F("Tempsensor 1"), F_(degrees), Helpers::render_value(buffer, tempsensor1, 10)); @@ -719,7 +723,7 @@ void Thermostat::show_values(uuid::console::Shell & shell) { } } } - if (flags == EMS_DEVICE_FLAG_RC35 ||flags == EMS_DEVICE_FLAG_RC30_1) { + if (flags == EMS_DEVICE_FLAG_RC35 || flags == EMS_DEVICE_FLAG_RC30_1) { if (ibaCalIntTemperature != EMS_VALUE_INT_NOTSET) { print_value(shell, 2, F("Offset int. temperature"), F_(degrees), Helpers::render_value(buffer, ibaCalIntTemperature, 2)); diff --git a/src/uart/emsuart_esp32.cpp b/src/uart/emsuart_esp32.cpp index a8c4142a5..06d502113 100644 --- a/src/uart/emsuart_esp32.cpp +++ b/src/uart/emsuart_esp32.cpp @@ -29,15 +29,14 @@ namespace emsesp { static intr_handle_t uart_handle; -static RingbufHandle_t buf_handle = NULL; -static uint8_t rxbuf[UART_FIFO_LEN]; -static uint8_t rxlen; -bool drop_first_rx = true; +static RingbufHandle_t buf_handle = NULL; +static bool drop_first_rx = true; +static uint8_t tx_mode_ = 0xFF; /* * Task to handle the incoming data */ -void EMSuart::emsuart_recvTask(void * param) { +void EMSuart::emsuart_recvTask(void * para) { while (1) { size_t item_size; uint8_t * telegram = (uint8_t *)xRingbufferReceive(buf_handle, &item_size, portMAX_DELAY); @@ -52,24 +51,36 @@ void EMSuart::emsuart_recvTask(void * param) { /* * UART interrupt, on break read the fifo and put the whole telegram to ringbuffer */ -void IRAM_ATTR EMSuart::uart_intr_handle(void * arg) { +void IRAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) { + static uint8_t rxbuf[EMS_MAXBUFFERSIZE]; + static uint8_t length; + if (EMS_UART.int_st.brk_det) { - for (uint8_t rxlen = 0; EMS_UART.status.rxfifo_cnt > 0; rxlen++) { - rxbuf[rxlen] = EMS_UART.fifo.rw_byte; // read all bytes into buffer - } - if (!drop_first_rx && (rxlen == 2) || ((rxlen > 4) && (rxlen <= EMS_MAXBUFFERSIZE))) { - int baseType = 0; - xRingbufferSendFromISR(buf_handle, rxbuf, rxlen - 1, &baseType); - } - drop_first_rx = false; EMS_UART.int_clr.brk_det = 1; // clear flag EMS_UART.conf0.txd_brk = 0; // if it was break from sending, clear bit + length = 0; + while (EMS_UART.status.rxfifo_cnt) { + uint8_t rx = EMS_UART.fifo.rw_byte; // read all bytes into buffer + if (length < EMS_MAXBUFFERSIZE) { + rxbuf[length++] = rx; + } + } + if ((!drop_first_rx) && ((length == 2) || ((length > 4)))) { + int baseType = 0; + xRingbufferSendFromISR(buf_handle, rxbuf, length - 1, &baseType); + } + drop_first_rx = false; } } /* * init UART driver */ void EMSuart::start(uint8_t tx_mode) { + if (tx_mode_ != 0xFF) { // uart already initialized + restart(); + return; + } + tx_mode_ = tx_mode; uart_config_t uart_config = { .baud_rate = EMSUART_BAUD, .data_bits = UART_DATA_8_BITS, @@ -80,12 +91,13 @@ void EMSuart::start(uint8_t tx_mode) { 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)); - EMS_UART.int_ena.val = 0; // disable all intr. - EMS_UART.int_clr.val = 0xFFFFFFFF; // clear all intr. flags - buf_handle = xRingbufferCreate(128, RINGBUF_TYPE_NOSPLIT); - ESP_ERROR_CHECK(uart_isr_register(EMSUART_UART, uart_intr_handle, NULL, ESP_INTR_FLAG_IRAM, &uart_handle)); + EMS_UART.int_ena.val = 0; // disable all intr. + EMS_UART.int_clr.val = 0xFFFFFFFF; // clear all intr. flags + EMS_UART.idle_conf.tx_brk_num = 11; // breaklength 11 bit + drop_first_rx = true; + buf_handle = xRingbufferCreate(128, RINGBUF_TYPE_NOSPLIT); + ESP_ERROR_CHECK(uart_isr_register(EMSUART_UART, emsuart_rx_intr_handler, NULL, ESP_INTR_FLAG_IRAM, &uart_handle)); xTaskCreate(emsuart_recvTask, "emsuart_recvTask", 2048, NULL, 12, NULL); - drop_first_rx = true; EMS_UART.int_ena.brk_det = 1; // activate only break } @@ -100,8 +112,8 @@ void EMSuart::stop() { * Restart Interrupt */ void EMSuart::restart() { - if (EMS_UART.int_st.brk_det) { - EMS_UART.int.clr.brk_det = 1; // clear break if happend + if (EMS_UART.int_raw.brk_det) { + EMS_UART.int_clr.brk_det = 1; // clear flag drop_first_rx = true; // and drop first frame } EMS_UART.int_ena.brk_det = 1; // activate only break @@ -113,7 +125,7 @@ void EMSuart::restart() { void EMSuart::send_poll(uint8_t data) { EMS_UART.conf0.txd_brk = 0; // just to make sure the bit is cleared EMS_UART.fifo.rw_byte = data; - EMS_UART.idle_conf.tx_brk_num = 11; // breaklength 11 bit + //EMS_UART.idle_conf.tx_brk_num = 11; // breaklength 11 bit EMS_UART.conf0.txd_brk = 1; // sending ends in a break } @@ -129,7 +141,7 @@ EMSUART_STATUS EMSuart::transmit(uint8_t * buf, uint8_t len) { EMS_UART.fifo.rw_byte = buf[i]; } //uart_tx_chars(EMSUART_UART, (const char *)buf, len); - EMS_UART.idle_conf.tx_brk_num = 11; // breaklength 11 bit + //EMS_UART.idle_conf.tx_brk_num = 11; // breaklength 11 bit EMS_UART.conf0.txd_brk = 1; // sending ends in a break } return EMS_TX_STATUS_OK; diff --git a/src/uart/emsuart_esp32.h b/src/uart/emsuart_esp32.h index dea169d3c..38df2c212 100644 --- a/src/uart/emsuart_esp32.h +++ b/src/uart/emsuart_esp32.h @@ -27,7 +27,7 @@ #include "freertos/queue.h" #include -#define EMS_MAXBUFFERSIZE 33 // max size of the buffer. EMS packets are max 32 bytes, plus extra 2 for BRKs +#define EMS_MAXBUFFERSIZE 33 // max size of the buffer. EMS packets are max 32 bytes, plus extra for BRK #define EMSUART_UART UART_NUM_2 // on the ESP32 we're using UART2 #define EMS_UART UART2 // for intr setting @@ -57,7 +57,7 @@ class EMSuart { static EMSUART_STATUS transmit(uint8_t * buf, uint8_t len); private: - static void emsuart_recvTask(void * param); + static void emsuart_recvTask(void * para); static void IRAM_ATTR emsuart_rx_intr_handler(void * para); }; diff --git a/src/uart/emsuart_esp8266.cpp b/src/uart/emsuart_esp8266.cpp index 48ccf716e..5299d354d 100644 --- a/src/uart/emsuart_esp8266.cpp +++ b/src/uart/emsuart_esp8266.cpp @@ -30,7 +30,7 @@ EMSuart::EMSRxBuf_t * pEMSRxBuf; EMSuart::EMSRxBuf_t * paEMSRxBuf[EMS_MAXBUFFERS]; uint8_t emsRxBufIdx = 0; uint8_t phantomBreak = 0; -uint8_t tx_mode_ = EMS_TXMODE_DEFAULT; +uint8_t tx_mode_ = 0xFF; bool drop_first_rx = true; // @@ -127,8 +127,12 @@ void ICACHE_FLASH_ATTR EMSuart::emsuart_flush_fifos() { * init UART0 driver */ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) { + if (tx_mode_ != 0xFF) { // it's a restart no need to configure rx + tx_mode_ = tx_mode; + restart(); + return; + } tx_mode_ = tx_mode; - // allocate and preset EMS Receive buffers for (int i = 0; i < EMS_MAXBUFFERS; i++) { EMSRxBuf_t * p = (EMSRxBuf_t *)malloc(sizeof(EMSRxBuf_t)); @@ -205,6 +209,7 @@ void ICACHE_FLASH_ATTR EMSuart::restart() { drop_first_rx = true; } ETS_UART_INTR_ENABLE(); + // emsuart_flush_fifos(); } /* diff --git a/src/version.h b/src/version.h index 56a398129..0f71dbb50 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "2.0.0a9" +#define EMSESP_APP_VERSION "2.0.0a10"