From 943b95a955a40546449c95e2e1281330eea79d59 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 18 Jul 2026 01:52:45 +0200 Subject: [PATCH 1/8] [Console] Split ESPEasy_console.cpp into dual/single/serial0-only --- ...le.cpp => ESPEasy_Console_dual_serial.cpp} | 184 +++--------- .../ESPEasy_Console_serial0_only.cpp | 166 +++++++++++ .../ESPEasy_Console_single_serial.cpp | 275 ++++++++++++++++++ 3 files changed, 475 insertions(+), 150 deletions(-) rename src/src/ESPEasyCore/{ESPEasy_Console.cpp => ESPEasy_Console_dual_serial.cpp} (63%) create mode 100644 src/src/ESPEasyCore/ESPEasy_Console_serial0_only.cpp create mode 100644 src/src/ESPEasyCore/ESPEasy_Console_single_serial.cpp diff --git a/src/src/ESPEasyCore/ESPEasy_Console.cpp b/src/src/ESPEasyCore/ESPEasy_Console_dual_serial.cpp similarity index 63% rename from src/src/ESPEasyCore/ESPEasy_Console.cpp rename to src/src/ESPEasyCore/ESPEasy_Console_dual_serial.cpp index bb91b36bbe..12fc8f4167 100644 --- a/src/src/ESPEasyCore/ESPEasy_Console.cpp +++ b/src/src/ESPEasyCore/ESPEasy_Console_dual_serial.cpp @@ -1,38 +1,39 @@ #include "../ESPEasyCore/ESPEasy_Console.h" +#ifdef ESP32 -#include "../Commands/ExecuteCommand.h" +// Only ESP32 does allow for multiple serial ports -#include "../DataStructs/TimingStats.h" +# if FEATURE_DEFINE_SERIAL_CONSOLE_PORT +# if USES_ESPEASY_CONSOLE_FALLBACK_PORT -#include "../DataTypes/ESPEasy_plugin_functions.h" +# include "../Commands/ExecuteCommand.h" -#include "../Globals/Cache.h" -#include "../Globals/Logging.h" -#include "../Globals/Plugins.h" -#include "../Globals/Settings.h" +# include "../DataStructs/TimingStats.h" -#include "../Helpers/Memory.h" +# include "../DataTypes/ESPEasy_plugin_functions.h" -#include +# include "../Globals/Cache.h" +# include "../Globals/Logging.h" +# include "../Globals/Plugins.h" +# include "../Globals/Settings.h" -#ifdef ESP32 -# include -#endif +# include "../Helpers/Memory.h" + +# include + +# ifdef ESP32 +# include +# endif EspEasy_Console_t::EspEasy_Console_t() : _mainSerial(LOG_TO_SERIAL) -#if FEATURE_DEFINE_SERIAL_CONSOLE_PORT -# if USES_ESPEASY_CONSOLE_FALLBACK_PORT , _fallbackSerial(LOG_TO_SERIAL_EXTRA) -# endif -#endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT { -#if FEATURE_DEFINE_SERIAL_CONSOLE_PORT const ESPEasySerialPort port = static_cast(_console_serial_port); -# if USES_USBCDC +# if USES_USBCDC /* if (port == ESPEasySerialPort::usb_cdc_0 || @@ -42,12 +43,8 @@ EspEasy_Console_t::EspEasy_Console_t() : USB.productName() } */ -# endif // if USES_USBCDC +# endif // if USES_USBCDC -# ifdef ESP8266 - constexpr size_t buffSize = 256; -# endif // ifdef ESP8266 -# ifdef ESP32 // Ideal buffer size is a trade-off between bootspeed // and not missing data when the ESP is busy processing stuff. @@ -55,7 +52,6 @@ EspEasy_Console_t::EspEasy_Console_t() : // it may just take less time in the background tasks to dump // any logs as larger chunks can be transferred at once. constexpr size_t buffSize = 512; -# endif // ifdef ESP32 ESPEasySerialConfig config; config.port = port; @@ -66,15 +62,7 @@ EspEasy_Console_t::EspEasy_Console_t() : config.rxBuffSize = 256; config.txBuffSize = buffSize; - { - # ifdef USE_SECOND_HEAP - HeapSelectDram ephemeral; - # endif // ifdef USE_SECOND_HEAP - - _mainSerial._serial = new (std::nothrow) ESPeasySerial(config); - } - -# if USES_ESPEASY_CONSOLE_FALLBACK_PORT + _mainSerial._serial = new (std::nothrow) ESPeasySerial(config); if (Settings.console_serial0_fallback && (port != ESPEasySerialPort::serial0)) { config.port = ESPEasySerialPort::serial0; @@ -83,33 +71,20 @@ EspEasy_Console_t::EspEasy_Console_t() : _fallbackSerial._serial = new (std::nothrow) ESPeasySerial(config); } -# endif // if USES_ESPEASY_CONSOLE_FALLBACK_PORT - - -#endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT } void EspEasy_Console_t::reInit() { updateActiveTaskUseSerial0(); - bool somethingChanged = false; -#if FEATURE_DEFINE_SERIAL_CONSOLE_PORT + bool somethingChanged = false; const ESPEasySerialPort port = static_cast(Settings.console_serial_port); - const bool consoleUseSerial0 = ( -# ifdef ESP8266 - (port == ESPEasySerialPort::serial0_swap) || -# endif // ifdef ESP8266 - port == ESPEasySerialPort::serial0); + const bool consoleUseSerial0 = port == ESPEasySerialPort::serial0; const bool canUseSerial0 = !activeTaskUseSerial0() && !log_to_serial_disabled; - bool mustHaveSerial = Settings.UseSerial && (!consoleUseSerial0 || canUseSerial0); - - -# if USES_ESPEASY_CONSOLE_FALLBACK_PORT - + bool mustHaveSerial = Settings.UseSerial && (!consoleUseSerial0 || canUseSerial0); bool mustHaveFallback = false; if (Settings.UseSerial) { @@ -132,8 +107,6 @@ void EspEasy_Console_t::reInit() somethingChanged = true; } } -# endif // if USES_ESPEASY_CONSOLE_FALLBACK_PORT - if ((_console_serial_port != Settings.console_serial_port) || (_console_serial_rxpin != Settings.console_serial_rxpin) || @@ -151,20 +124,16 @@ void EspEasy_Console_t::reInit() } if ((_mainSerial._serial == nullptr) && mustHaveSerial) { - # ifdef USE_SECOND_HEAP - HeapSelectDram ephemeral; - # endif // ifdef USE_SECOND_HEAP - unsigned int buffsize = 128; const ESPEasySerialPort mainSerialPort = static_cast(_console_serial_port); -# if USES_HWCDC +# if USES_HWCDC if (mainSerialPort == ESPEasySerialPort::usb_hw_cdc) { buffsize = 2048; } -# endif // if USES_HWCDC +# endif // if USES_HWCDC _mainSerial._serial = new (std::nothrow) ESPeasySerial( mainSerialPort, @@ -174,7 +143,6 @@ void EspEasy_Console_t::reInit() buffsize); somethingChanged = true; } -# if USES_ESPEASY_CONSOLE_FALLBACK_PORT if ((_fallbackSerial._serial == nullptr) && mustHaveFallback) { _fallbackSerial._serial = new (std::nothrow) ESPeasySerial( @@ -183,21 +151,14 @@ void EspEasy_Console_t::reInit() SOC_TX0); somethingChanged = true; } -# endif // if USES_ESPEASY_CONSOLE_FALLBACK_PORT - - -# if USES_ESPEASY_CONSOLE_FALLBACK_PORT if (_fallbackSerial._serial == nullptr) { _fallbackSerial._serialWriteBuffer.clear(); } -# endif // if USES_ESPEASY_CONSOLE_FALLBACK_PORT - if (_mainSerial._serial == nullptr) { _mainSerial._serialWriteBuffer.clear(); } -#endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT if (somethingChanged) { begin(Settings.BaudRate); @@ -210,67 +171,32 @@ void EspEasy_Console_t::begin(uint32_t baudrate) _baudrate = baudrate; if (_mainSerial._serial != nullptr) { -#if FEATURE_DEFINE_SERIAL_CONSOLE_PORT _mainSerial._serial->begin(baudrate); addLog(LOG_LEVEL_INFO, F("ESPEasy console using ESPEasySerial")); -#else // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT -# ifdef ESP8266 - _mainSerial._serial->begin(baudrate); -# ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_INFO, F("ESPEasy console using HW Serial")); -# endif -# endif // ifdef ESP8266 -# ifdef ESP32 - - // Allow to flush data from the serial buffers - // When not opening the USB serial port, the ESP may hang at boot. - delay(10); - _mainSerial._serial->end(); - delay(10); - _mainSerial._serial->begin(baudrate); - _mainSerial._serial->flush(); -# endif // ifdef ESP32 -#endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT } -#if USES_ESPEASY_CONSOLE_FALLBACK_PORT if (_fallbackSerial._serial != nullptr) { _fallbackSerial._serial->begin(baudrate); -# ifdef ESP32 - // Need to have this string as C-string, not F-string perimanSetPinBusExtraType(SOC_RX0, "Console"); perimanSetPinBusExtraType(SOC_TX0, "Console"); -# endif // ifdef ESP32 addLog(LOG_LEVEL_INFO, F("ESPEasy console fallback enabled")); } -#endif // if USES_ESPEASY_CONSOLE_FALLBACK_PORT } void EspEasy_Console_t::init() { -#if FEATURE_IMPROV +# if FEATURE_IMPROV _mainSerial._improv.init(); -# if FEATURE_DEFINE_SERIAL_CONSOLE_PORT -# if USES_ESPEASY_CONSOLE_FALLBACK_PORT _fallbackSerial._improv.init(); -# endif // if USES_ESPEASY_CONSOLE_FALLBACK_PORT -# endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT -#endif // if FEATURE_IMPROV +# endif // if FEATURE_IMPROV updateActiveTaskUseSerial0(); if (!Settings.UseSerial) { return; } -#if !FEATURE_DEFINE_SERIAL_CONSOLE_PORT - - if (activeTaskUseSerial0() || log_to_serial_disabled) { - return; - } -#endif // if !FEATURE_DEFINE_SERIAL_CONSOLE_PORT - begin(Settings.BaudRate); } @@ -280,12 +206,8 @@ void EspEasy_Console_t::loop() START_TIMER; -#if FEATURE_DEFINE_SERIAL_CONSOLE_PORT const bool consoleUsesSerial0 = (static_cast(_console_serial_port) == ESPEasySerialPort::serial0 -# ifdef ESP8266 - || static_cast(_console_serial_port) == ESPEasySerialPort::serial0_swap -# endif // ifdef ESP8266 ); if (handledByPluginSerialIn()) @@ -296,18 +218,9 @@ void EspEasy_Console_t::loop() } return; } -#else // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT - - if (handledByPluginSerialIn()) { - return; - } -#endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT readInput(_mainSerial); -#if USES_ESPEASY_CONSOLE_FALLBACK_PORT - readInput(_fallbackSerial); -#endif // if USES_ESPEASY_CONSOLE_FALLBACK_PORT STOP_TIMER(CONSOLE_LOOP); } @@ -320,16 +233,13 @@ bool EspEasy_Console_t::process_serialWriteBuffer() { res = true; } -#if USES_ESPEASY_CONSOLE_FALLBACK_PORT - if (_fallbackSerial.process_serialWriteBuffer()) { res = true; } -#endif // if USES_ESPEASY_CONSOLE_FALLBACK_PORT -#if FEATURE_TIMING_STATS +# if FEATURE_TIMING_STATS if (res) { STOP_TIMER(CONSOLE_WRITE_SERIAL); } -#endif // if FEATURE_TIMING_STATS +# endif // if FEATURE_TIMING_STATS return res; } @@ -347,19 +257,13 @@ String EspEasy_Console_t::getPortDescription() const return _mainSerial.getPortDescription(); } -#if USES_ESPEASY_CONSOLE_FALLBACK_PORT - String EspEasy_Console_t::getFallbackPortDescription() const { return _fallbackSerial.getPortDescription(); } -#endif // if USES_ESPEASY_CONSOLE_FALLBACK_PORT - bool EspEasy_Console_t::handledByPluginSerialIn() { -#if USES_ESPEASY_CONSOLE_FALLBACK_PORT - if ((_fallbackSerial._serial != nullptr) && _fallbackSerial._serial->available()) { @@ -367,16 +271,10 @@ bool EspEasy_Console_t::handledByPluginSerialIn() return PluginCall(PLUGIN_SERIAL_IN, 0, dummy); } -#endif // if USES_ESPEASY_CONSOLE_FALLBACK_PORT -#if FEATURE_DEFINE_SERIAL_CONSOLE_PORT if ((_mainSerial._serial != nullptr) && _mainSerial._serial->available() && (static_cast(_console_serial_port) == ESPEasySerialPort::serial0 -# ifdef ESP8266 - || static_cast(_console_serial_port) == ESPEasySerialPort::serial0_swap -# endif // ifdef ESP8266 )) -#endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT { String dummy; @@ -404,39 +302,25 @@ void EspEasy_Console_t::readInput(EspEasy_Console_Port& port) } } -#if FEATURE_DEFINE_SERIAL_CONSOLE_PORT - ESPeasySerial * EspEasy_Console_t::getPort() { if (_mainSerial._serial != nullptr) { return _mainSerial._serial; } -# if USES_ESPEASY_CONSOLE_FALLBACK_PORT if (_fallbackSerial._serial != nullptr) { return _fallbackSerial._serial; } -# endif // if USES_ESPEASY_CONSOLE_FALLBACK_PORT return nullptr; } -#else // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT - -HardwareSerial * EspEasy_Console_t::getPort() -{ - if (_mainSerial._serial != nullptr) { - return _mainSerial._serial; - } - return nullptr; -} - -#endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT - void EspEasy_Console_t::endPort() { _mainSerial.endPort(); -#if USES_ESPEASY_CONSOLE_FALLBACK_PORT _fallbackSerial.endPort(); -#endif // if USES_ESPEASY_CONSOLE_FALLBACK_PORT delay(10); } + +# endif // if USES_ESPEASY_CONSOLE_FALLBACK_PORT +# endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT +#endif // ifdef ESP32 diff --git a/src/src/ESPEasyCore/ESPEasy_Console_serial0_only.cpp b/src/src/ESPEasyCore/ESPEasy_Console_serial0_only.cpp new file mode 100644 index 0000000000..4e669b3f82 --- /dev/null +++ b/src/src/ESPEasyCore/ESPEasy_Console_serial0_only.cpp @@ -0,0 +1,166 @@ +#include "../ESPEasyCore/ESPEasy_Console.h" + +#if !FEATURE_DEFINE_SERIAL_CONSOLE_PORT + + +# include "../Commands/ExecuteCommand.h" + +# include "../DataStructs/TimingStats.h" + +# include "../DataTypes/ESPEasy_plugin_functions.h" + +# include "../Globals/Cache.h" +# include "../Globals/Logging.h" +# include "../Globals/Plugins.h" +# include "../Globals/Settings.h" + +# include "../Helpers/Memory.h" + +# include + +# ifdef ESP32 +# include +# endif + + +EspEasy_Console_t::EspEasy_Console_t() : + _mainSerial(LOG_TO_SERIAL) +{} + +void EspEasy_Console_t::reInit() +{ + updateActiveTaskUseSerial0(); + bool somethingChanged = false; + + if (somethingChanged) { + begin(Settings.BaudRate); + } +} + +void EspEasy_Console_t::begin(uint32_t baudrate) +{ + updateActiveTaskUseSerial0(); + _baudrate = baudrate; + + if (_mainSerial._serial != nullptr) { +# ifdef ESP8266 + _mainSerial._serial->begin(baudrate); +# ifndef BUILD_NO_DEBUG + addLog(LOG_LEVEL_INFO, F("ESPEasy console using HW Serial")); +# endif +# endif // ifdef ESP8266 +# ifdef ESP32 + + // Allow to flush data from the serial buffers + // When not opening the USB serial port, the ESP may hang at boot. + delay(10); + _mainSerial._serial->end(); + delay(10); + _mainSerial._serial->begin(baudrate); + _mainSerial._serial->flush(); +# endif // ifdef ESP32 + } +} + +void EspEasy_Console_t::init() { +# if FEATURE_IMPROV + _mainSerial._improv.init(); +# endif // if FEATURE_IMPROV + updateActiveTaskUseSerial0(); + + if (!Settings.UseSerial) { + return; + } + + if (activeTaskUseSerial0() || log_to_serial_disabled) { + return; + } + + begin(Settings.BaudRate); +} + +void EspEasy_Console_t::loop() +{ + if (!Settings.UseSerial) { return; } + + START_TIMER; + + if (handledByPluginSerialIn()) { + return; + } + + readInput(_mainSerial); + + STOP_TIMER(CONSOLE_LOOP); +} + +bool EspEasy_Console_t::process_serialWriteBuffer() { + START_TIMER; + bool res = false; + + if (_mainSerial.process_serialWriteBuffer()) { + res = true; + } + +# if FEATURE_TIMING_STATS + + if (res) { STOP_TIMER(CONSOLE_WRITE_SERIAL); } +# endif // if FEATURE_TIMING_STATS + return res; +} + +void EspEasy_Console_t::setDebugOutput(bool enable) +{ + auto port = getPort(); + + if (port != nullptr) { + port->setDebugOutput(enable); + } +} + +String EspEasy_Console_t::getPortDescription() const +{ + return _mainSerial.getPortDescription(); +} + +bool EspEasy_Console_t::handledByPluginSerialIn() +{ + String dummy; + + return PluginCall(PLUGIN_SERIAL_IN, 0, dummy); +} + +void EspEasy_Console_t::readInput(EspEasy_Console_Port& port) +{ + size_t bytesToRead = port.available(); + + while (bytesToRead > 0) + { + --bytesToRead; + delay(0); + const int SerialInByte = port.read(); + + if (SerialInByte >= 0) { + if (port.process_consoleInput(SerialInByte)) { + // Processed a full line + return; + } + } + } +} + +HardwareSerial * EspEasy_Console_t::getPort() +{ + if (_mainSerial._serial != nullptr) { + return _mainSerial._serial; + } + return nullptr; +} + +void EspEasy_Console_t::endPort() +{ + _mainSerial.endPort(); + delay(10); +} + +#endif // if !FEATURE_DEFINE_SERIAL_CONSOLE_PORT diff --git a/src/src/ESPEasyCore/ESPEasy_Console_single_serial.cpp b/src/src/ESPEasyCore/ESPEasy_Console_single_serial.cpp new file mode 100644 index 0000000000..aefce3543e --- /dev/null +++ b/src/src/ESPEasyCore/ESPEasy_Console_single_serial.cpp @@ -0,0 +1,275 @@ +#include "../ESPEasyCore/ESPEasy_Console.h" + +#if FEATURE_DEFINE_SERIAL_CONSOLE_PORT +# if !USES_ESPEASY_CONSOLE_FALLBACK_PORT + + +# include "../Commands/ExecuteCommand.h" + +# include "../DataStructs/TimingStats.h" + +# include "../DataTypes/ESPEasy_plugin_functions.h" + +# include "../Globals/Cache.h" +# include "../Globals/Logging.h" +# include "../Globals/Plugins.h" +# include "../Globals/Settings.h" + +# include "../Helpers/Memory.h" + +# include + +# ifdef ESP32 +# include +# endif + + +EspEasy_Console_t::EspEasy_Console_t() : + _mainSerial(LOG_TO_SERIAL) +{ + const ESPEasySerialPort port = static_cast(_console_serial_port); + +# if USES_USBCDC + + /* + if (port == ESPEasySerialPort::usb_cdc_0 || + port == ESPEasySerialPort::usb_cdc_1) + { + USB.manufacturerName(F("ESPEasy")); + USB.productName() + } + */ +# endif // if USES_USBCDC + +# ifdef ESP8266 + constexpr size_t buffSize = 256; +# endif // ifdef ESP8266 +# ifdef ESP32 + + // Ideal buffer size is a trade-off between bootspeed + // and not missing data when the ESP is busy processing stuff. + // Since we do have a separate buffer in the console, + // it may just take less time in the background tasks to dump + // any logs as larger chunks can be transferred at once. + constexpr size_t buffSize = 512; +# endif // ifdef ESP32 + + ESPEasySerialConfig config; + config.port = port; + config.baud = DEFAULT_SERIAL_BAUD; + config.receivePin = _console_serial_rxpin; + config.transmitPin = _console_serial_txpin; + config.inverse_logic = false; + config.rxBuffSize = 256; + config.txBuffSize = buffSize; + + { + # ifdef USE_SECOND_HEAP + HeapSelectDram ephemeral; + # endif // ifdef USE_SECOND_HEAP + + _mainSerial._serial = new (std::nothrow) ESPeasySerial(config); + } +} + +void EspEasy_Console_t::reInit() +{ + updateActiveTaskUseSerial0(); + bool somethingChanged = false; + const ESPEasySerialPort port = static_cast(Settings.console_serial_port); + + const bool consoleUseSerial0 = ( +# ifdef ESP8266 + (port == ESPEasySerialPort::serial0_swap) || +# endif // ifdef ESP8266 + port == ESPEasySerialPort::serial0); + + const bool canUseSerial0 = !activeTaskUseSerial0() && !log_to_serial_disabled; + + + bool mustHaveSerial = Settings.UseSerial && (!consoleUseSerial0 || canUseSerial0); + + + if ((_console_serial_port != Settings.console_serial_port) || + (_console_serial_rxpin != Settings.console_serial_rxpin) || + (_console_serial_txpin != Settings.console_serial_txpin) || + !mustHaveSerial) { + if (_mainSerial._serial != nullptr) { + delete _mainSerial._serial; + _mainSerial._serial = nullptr; + somethingChanged = true; + } + + _console_serial_port = Settings.console_serial_port; + _console_serial_rxpin = Settings.console_serial_rxpin; + _console_serial_txpin = Settings.console_serial_txpin; + } + + if ((_mainSerial._serial == nullptr) && mustHaveSerial) { + # ifdef USE_SECOND_HEAP + HeapSelectDram ephemeral; + # endif // ifdef USE_SECOND_HEAP + + unsigned int buffsize = 128; + + const ESPEasySerialPort mainSerialPort = static_cast(_console_serial_port); + +# if USES_HWCDC + + if (mainSerialPort == ESPEasySerialPort::usb_hw_cdc) { + buffsize = 2048; + } +# endif // if USES_HWCDC + + _mainSerial._serial = new (std::nothrow) ESPeasySerial( + mainSerialPort, + _console_serial_rxpin, + _console_serial_txpin, + false, + buffsize); + somethingChanged = true; + } + + + if (_mainSerial._serial == nullptr) { + _mainSerial._serialWriteBuffer.clear(); + } + + if (somethingChanged) { + begin(Settings.BaudRate); + } +} + +void EspEasy_Console_t::begin(uint32_t baudrate) +{ + updateActiveTaskUseSerial0(); + _baudrate = baudrate; + + if (_mainSerial._serial != nullptr) { + _mainSerial._serial->begin(baudrate); + addLog(LOG_LEVEL_INFO, F("ESPEasy console using ESPEasySerial")); + } +} + +void EspEasy_Console_t::init() { +# if FEATURE_IMPROV + _mainSerial._improv.init(); +# endif // if FEATURE_IMPROV + updateActiveTaskUseSerial0(); + + if (!Settings.UseSerial) { + return; + } + + begin(Settings.BaudRate); +} + +void EspEasy_Console_t::loop() +{ + if (!Settings.UseSerial) { return; } + + START_TIMER; + + const bool consoleUsesSerial0 = + (static_cast(_console_serial_port) == ESPEasySerialPort::serial0 +# ifdef ESP8266 + || static_cast(_console_serial_port) == ESPEasySerialPort::serial0_swap +# endif // ifdef ESP8266 + ); + + if (handledByPluginSerialIn()) + { + // Any serial0 data is already dealt with + if (!consoleUsesSerial0 && (_mainSerial._serial != nullptr)) { + readInput(_mainSerial); + } + return; + } + + readInput(_mainSerial); + + STOP_TIMER(CONSOLE_LOOP); +} + +bool EspEasy_Console_t::process_serialWriteBuffer() { + START_TIMER; + bool res = false; + + if (_mainSerial.process_serialWriteBuffer()) { + res = true; + } + +# if FEATURE_TIMING_STATS + + if (res) { STOP_TIMER(CONSOLE_WRITE_SERIAL); } +# endif // if FEATURE_TIMING_STATS + return res; +} + +void EspEasy_Console_t::setDebugOutput(bool enable) +{ + auto port = getPort(); + + if (port != nullptr) { + port->setDebugOutput(enable); + } +} + +String EspEasy_Console_t::getPortDescription() const +{ + return _mainSerial.getPortDescription(); +} + + +bool EspEasy_Console_t::handledByPluginSerialIn() +{ + if ((_mainSerial._serial != nullptr) && _mainSerial._serial->available() && + (static_cast(_console_serial_port) == ESPEasySerialPort::serial0 +# ifdef ESP8266 + || static_cast(_console_serial_port) == ESPEasySerialPort::serial0_swap +# endif // ifdef ESP8266 + )) + { + String dummy; + + return PluginCall(PLUGIN_SERIAL_IN, 0, dummy); + } + return false; +} + +void EspEasy_Console_t::readInput(EspEasy_Console_Port& port) +{ + size_t bytesToRead = port.available(); + + while (bytesToRead > 0) + { + --bytesToRead; + delay(0); + const int SerialInByte = port.read(); + + if (SerialInByte >= 0) { + if (port.process_consoleInput(SerialInByte)) { + // Processed a full line + return; + } + } + } +} + + +ESPeasySerial * EspEasy_Console_t::getPort() +{ + if (_mainSerial._serial != nullptr) { + return _mainSerial._serial; + } + return nullptr; +} + +void EspEasy_Console_t::endPort() +{ + _mainSerial.endPort(); + delay(10); +} + +# endif // if !USES_ESPEASY_CONSOLE_FALLBACK_PORT +#endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT From 72171b9500c1d2e63089f5dde4c96d193e345aed Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 18 Jul 2026 16:09:50 +0200 Subject: [PATCH 2/8] [ESPEasy Console] Simplify init of ESPEasy console + update IDF/Arduino --- lib/ESPEasySerial/ESPEasySerialConfig.cpp | 18 ++ lib/ESPEasySerial/ESPEasySerialConfig.h | 4 + platformio_core_defs.ini | 3 +- src/_P040_ID12.ino | 2 +- src/_P091_SerSwitch.ino | 2 +- src/src/ESPEasyCore/ESPEasy_Console.h | 9 +- src/src/ESPEasyCore/ESPEasy_Console_Port.cpp | 161 ++++++++++++-- src/src/ESPEasyCore/ESPEasy_Console_Port.h | 16 ++ .../ESPEasy_Console_dual_serial.cpp | 210 +++++------------- .../ESPEasy_Console_serial0_only.cpp | 46 +--- .../ESPEasy_Console_single_serial.cpp | 161 ++++---------- src/src/Helpers/Improv_Helper.cpp | 5 + src/src/Helpers/Improv_Helper.h | 2 + 13 files changed, 296 insertions(+), 343 deletions(-) diff --git a/lib/ESPEasySerial/ESPEasySerialConfig.cpp b/lib/ESPEasySerial/ESPEasySerialConfig.cpp index 67ad8359c4..48d6ffea09 100644 --- a/lib/ESPEasySerial/ESPEasySerialConfig.cpp +++ b/lib/ESPEasySerial/ESPEasySerialConfig.cpp @@ -2,6 +2,24 @@ #include "ESPEasySerialType.h" +bool ESPEasySerialConfig::operator==(const ESPEasySerialConfig& other) const +{ + return port == other.port + && baud == other.baud + && receivePin == other.receivePin + && transmitPin == other.transmitPin + && inverse_logic == other.inverse_logic + && rxBuffSize == other.rxBuffSize + && txBuffSize == other.txBuffSize + && forceSWserial == other.forceSWserial + && timeout_ms == other.timeout_ms + && config == other.config +#ifdef ESP8266 + && mode == other.mode +#endif + ; +} + void ESPEasySerialConfig::validate() { port = ESPeasySerialType::getSerialType(port, receivePin, transmitPin); diff --git a/lib/ESPEasySerial/ESPEasySerialConfig.h b/lib/ESPEasySerial/ESPEasySerialConfig.h index 690626537d..cb9fa4a4bb 100644 --- a/lib/ESPEasySerial/ESPEasySerialConfig.h +++ b/lib/ESPEasySerial/ESPEasySerialConfig.h @@ -24,6 +24,10 @@ struct ESPEasySerialConfig { ESPEasySerialConfig() = default; + bool operator==(const ESPEasySerialConfig& other) const; + + ESPEasySerialConfig& operator=(const ESPEasySerialConfig& other) = default; + void validate(); #ifdef ESP8266 diff --git a/platformio_core_defs.ini b/platformio_core_defs.ini index e46e72b697..671c039370 100644 --- a/platformio_core_defs.ini +++ b/platformio_core_defs.ini @@ -191,9 +191,10 @@ extra_scripts = ${esp82xx_common.extra_scripts} ;platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/2904-2115-5.5/framework-arduinoespressif32-release_v5.5-f2a3fa2b.tar.xz platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF55_gcc152 -platform_packages = +platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/1807-0842-5.5/framework-arduinoespressif32-release_v5.5-67336dba.tar.xz ;platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/2805-1324-5.5/framework-arduinoespressif32-release_v5.5-f3cdb9d0.tar.xz + custom_remove_include = true custom_component_remove = diff --git a/src/_P040_ID12.ino b/src/_P040_ID12.ino index 13dfaa8684..6d1af2bfd3 100644 --- a/src/_P040_ID12.ino +++ b/src/_P040_ID12.ino @@ -88,6 +88,7 @@ boolean Plugin_040(uint8_t function, struct EventStruct *event, String& string) { if (Plugin_040_init) { + success = true; uint8_t val = 0; uint8_t code[6]; uint8_t checksum = 0; @@ -187,7 +188,6 @@ boolean Plugin_040(uint8_t function, struct EventStruct *event, String& string) Scheduler.setPluginTaskTimer(500, event->TaskIndex, event->Par1); } } - success = true; } break; } diff --git a/src/_P091_SerSwitch.ino b/src/_P091_SerSwitch.ino index ebea3d752f..2fe2b0c0dc 100644 --- a/src/_P091_SerSwitch.ino +++ b/src/_P091_SerSwitch.ino @@ -319,6 +319,7 @@ boolean Plugin_091(uint8_t function, struct EventStruct *event, String& string) if (Plugin_091_init) { + success = true; while (ESPEASY_SERIAL_0.available() > 0) { yield(); @@ -533,7 +534,6 @@ boolean Plugin_091(uint8_t function, struct EventStruct *event, String& string) } } } // plugin initialized end - success = true; break; } diff --git a/src/src/ESPEasyCore/ESPEasy_Console.h b/src/src/ESPEasyCore/ESPEasy_Console.h index b266cc0d82..adc344d20f 100644 --- a/src/src/ESPEasyCore/ESPEasy_Console.h +++ b/src/src/ESPEasyCore/ESPEasy_Console.h @@ -37,8 +37,6 @@ class EspEasy_Console_t { bool handledByPluginSerialIn(); - void readInput(EspEasy_Console_Port& port); - #if FEATURE_DEFINE_SERIAL_CONSOLE_PORT ESPeasySerial * getPort(); #else // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT @@ -47,18 +45,13 @@ class EspEasy_Console_t { void endPort(); - uint32_t _baudrate = 115200u; EspEasy_Console_Port _mainSerial; #if FEATURE_DEFINE_SERIAL_CONSOLE_PORT # if USES_ESPEASY_CONSOLE_FALLBACK_PORT + // Serial port to be always used as HW Serial0 EspEasy_Console_Port _fallbackSerial; # endif - - // Cache the used settings, so we can check whether to change the console serial - uint8_t _console_serial_port = DEFAULT_CONSOLE_PORT; - int8_t _console_serial_rxpin = DEFAULT_CONSOLE_PORT_RXPIN; - int8_t _console_serial_txpin = DEFAULT_CONSOLE_PORT_TXPIN; #endif }; diff --git a/src/src/ESPEasyCore/ESPEasy_Console_Port.cpp b/src/src/ESPEasyCore/ESPEasy_Console_Port.cpp index a179a296b4..929d6425d6 100644 --- a/src/src/ESPEasyCore/ESPEasy_Console_Port.cpp +++ b/src/src/ESPEasyCore/ESPEasy_Console_Port.cpp @@ -105,6 +105,35 @@ size_t EspEasy_Console_Port::available() const return res; } +void EspEasy_Console_Port::begin(uint32_t baudrate) +{ + updateActiveTaskUseSerial0(); + + if (_serial != nullptr) { + # if FEATURE_IMPROV + _improv.init(); + #endif + +#if FEATURE_DEFINE_SERIAL_CONSOLE_PORT + _config.baud = baudrate; +#endif + _serial->begin(baudrate); + addLog(LOG_LEVEL_INFO, F("ESPEasy console using ESPEasySerial")); + + +# ifdef ESP32 + // Allow to flush data from the serial buffers + // When not opening the USB serial port, the ESP may hang at boot. + delay(10); + _serial->end(); + delay(10); + _serial->begin(baudrate); + _serial->flush(); +# endif // ifdef ESP32 + + } +} + void EspEasy_Console_Port::endPort() { if (_serial != nullptr) { @@ -112,38 +141,70 @@ void EspEasy_Console_Port::endPort() } } +void EspEasy_Console_Port::readInput() +{ + if (_serial == nullptr) return; + size_t bytesToRead = available(); + + while (bytesToRead > 0) + { + --bytesToRead; + delay(0); + const int SerialInByte = read(); + + if (SerialInByte >= 0) { + if (process_consoleInput(SerialInByte)) { + // Processed a full line + return; + } + } + } +} + +ESPEasySerialPort EspEasy_Console_Port::getPortType() const +{ + #if FEATURE_DEFINE_SERIAL_CONSOLE_PORT + + if (_serial == nullptr) { return ESPEasySerialPort::not_set; } + return _config.port; + #else // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT + + // TODO TD-er: Should I also try to see if we're using serial0_swapped? + return ESPEasySerialPort::serial0; + #endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT +} + bool EspEasy_Console_Port::process_serialWriteBuffer() { - if (_serial != nullptr) { + if (_serial == nullptr) { return false; } #ifdef ESP32 - if (!xPortCanYield()) { return false; } + if (!xPortCanYield()) { return false; } #endif // ifdef ESP32 - size_t availableForWrite = _serial->availableForWrite(); + size_t availableForWrite = _serial->availableForWrite(); - if (availableForWrite == 0) { return false; } + if (availableForWrite == 0) { return false; } - if (availableForWrite == 1) { - // For only a single byte, just write it directly - return _serialWriteBuffer.process(_serial, availableForWrite); - } + if (availableForWrite == 1) { + // For only a single byte, just write it directly + return _serialWriteBuffer.process(_serial, availableForWrite); + } - if (availableForWrite > 64) { - // Set to max. of 64 bytes as this is the optimum 'chunk size' for most - // serial ports, like the CDC ports and I2C to UART. - // Also it is relatively fast to allocate. - availableForWrite = 64; - } + if (availableForWrite > 64) { + // Set to max. of 64 bytes as this is the optimum 'chunk size' for most + // serial ports, like the CDC ports and I2C to UART. + // Also it is relatively fast to allocate. + availableForWrite = 64; + } - PrintToString str; - str.reserve(availableForWrite); + PrintToString str; + str.reserve(availableForWrite); - if (_serialWriteBuffer.process(&str, availableForWrite)) { - _serial->write(str.get().c_str(), str.length()); - return true; - } + if (!_serialWriteBuffer.process(&str, availableForWrite)) { + return false; } - return false; + _serial->write(str.get().c_str(), str.length()); + return true; } bool EspEasy_Console_Port::process_consoleInput(uint8_t SerialInByte) @@ -199,3 +260,61 @@ String EspEasy_Console_Port::getPortDescription() const return F("-"); } + +#if FEATURE_DEFINE_SERIAL_CONSOLE_PORT + +bool EspEasy_Console_Port::updateSerialPort( + const ESPEasySerialConfig& config) +{ + updateActiveTaskUseSerial0(); + bool somethingChanged = false; + + const bool consoleUseSerial0 = ( +# ifdef ESP8266 + (config.port == ESPEasySerialPort::serial0_swap) || +# endif // ifdef ESP8266 + config.port == ESPEasySerialPort::serial0); + + const bool canUseSerial0 = !activeTaskUseSerial0() && !log_to_serial_disabled; + + + bool mustHaveSerial = Settings.UseSerial && (!consoleUseSerial0 || canUseSerial0); + + if (!(_config == config) || + !mustHaveSerial) { + if (_serial != nullptr) { + delete _serial; + _serial = nullptr; + somethingChanged = true; + } + _config = config; + } + + if ((_serial == nullptr) && mustHaveSerial) { + # ifdef USE_SECOND_HEAP + HeapSelectDram ephemeral; + # endif // ifdef USE_SECOND_HEAP + + { + # ifdef USE_SECOND_HEAP + HeapSelectDram ephemeral; + # endif // ifdef USE_SECOND_HEAP + _serial = new (std::nothrow) ESPeasySerial(_config); + } + + somethingChanged = true; + } + + + if (_serial == nullptr) { + _serialWriteBuffer.clear(); + } + + if (somethingChanged) { + begin(_config.baud); + } + + return somethingChanged; +} + +#endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT diff --git a/src/src/ESPEasyCore/ESPEasy_Console_Port.h b/src/src/ESPEasyCore/ESPEasy_Console_Port.h index ec7db6fdaf..37b00f82a3 100644 --- a/src/src/ESPEasyCore/ESPEasy_Console_Port.h +++ b/src/src/ESPEasyCore/ESPEasy_Console_Port.h @@ -27,14 +27,30 @@ struct EspEasy_Console_Port { int read(); size_t available() const; + void begin(uint32_t baudrate); + void endPort(); + void readInput(); + + ESPEasySerialPort getPortType() const; + bool process_serialWriteBuffer(); bool process_consoleInput(uint8_t SerialInByte); String getPortDescription() const; +#if FEATURE_DEFINE_SERIAL_CONSOLE_PORT + bool updateSerialPort(const ESPEasySerialConfig& config); + +private: + // Cache the used settings, so we can check whether to change the console serial + ESPEasySerialConfig _config; + +public: +#endif + int SerialInByteCounter{}; char *InputBuffer_Serial{}; SerialWriteBuffer_t _serialWriteBuffer; diff --git a/src/src/ESPEasyCore/ESPEasy_Console_dual_serial.cpp b/src/src/ESPEasyCore/ESPEasy_Console_dual_serial.cpp index 12fc8f4167..c482bf88cb 100644 --- a/src/src/ESPEasyCore/ESPEasy_Console_dual_serial.cpp +++ b/src/src/ESPEasyCore/ESPEasy_Console_dual_serial.cpp @@ -31,152 +31,96 @@ EspEasy_Console_t::EspEasy_Console_t() : _mainSerial(LOG_TO_SERIAL) , _fallbackSerial(LOG_TO_SERIAL_EXTRA) { - const ESPEasySerialPort port = static_cast(_console_serial_port); - # if USES_USBCDC /* if (port == ESPEasySerialPort::usb_cdc_0 || - port == ESPEasySerialPort::usb_cdc_1) + port == ESPEasySerialPort::usb_cdc_1) { - USB.manufacturerName(F("ESPEasy")); - USB.productName() + USB.manufacturerName(F("ESPEasy")); + USB.productName() } */ # endif // if USES_USBCDC - - // Ideal buffer size is a trade-off between bootspeed - // and not missing data when the ESP is busy processing stuff. - // Since we do have a separate buffer in the console, - // it may just take less time in the background tasks to dump - // any logs as larger chunks can be transferred at once. - constexpr size_t buffSize = 512; - ESPEasySerialConfig config; - config.port = port; + config.port = static_cast(DEFAULT_CONSOLE_PORT); config.baud = DEFAULT_SERIAL_BAUD; - config.receivePin = _console_serial_rxpin; - config.transmitPin = _console_serial_txpin; + config.receivePin = DEFAULT_CONSOLE_PORT_RXPIN; + config.transmitPin = DEFAULT_CONSOLE_PORT_TXPIN; config.inverse_logic = false; config.rxBuffSize = 256; - config.txBuffSize = buffSize; +# if USES_HWCDC - _mainSerial._serial = new (std::nothrow) ESPeasySerial(config); + if (config.port == ESPEasySerialPort::usb_hw_cdc) { + config.txBuffSize = 2048; + } else { + config.txBuffSize = 512; + } +# else // if USES_HWCDC + config.txBuffSize = 512; +# endif // if USES_HWCDC + + if (config.port != ESPEasySerialPort::serial0) { + // We only use the _mainSerial for ports other than HW Serial0 + _mainSerial.updateSerialPort(config); + } - if (Settings.console_serial0_fallback && (port != ESPEasySerialPort::serial0)) { + if (Settings.console_serial0_fallback || + (config.port == ESPEasySerialPort::serial0)) + { config.port = ESPEasySerialPort::serial0; config.receivePin = SOC_RX0; config.transmitPin = SOC_TX0; - - _fallbackSerial._serial = new (std::nothrow) ESPeasySerial(config); + config.txBuffSize = 512; + _fallbackSerial.updateSerialPort(config); } } void EspEasy_Console_t::reInit() { - updateActiveTaskUseSerial0(); - bool somethingChanged = false; - const ESPEasySerialPort port = static_cast(Settings.console_serial_port); - - const bool consoleUseSerial0 = port == ESPEasySerialPort::serial0; - - const bool canUseSerial0 = !activeTaskUseSerial0() && !log_to_serial_disabled; - - - bool mustHaveSerial = Settings.UseSerial && (!consoleUseSerial0 || canUseSerial0); - bool mustHaveFallback = false; - - if (Settings.UseSerial) { - if (consoleUseSerial0 && canUseSerial0 && (_fallbackSerial._serial != nullptr)) { - // Should not destruct an already running fallback serial port - mustHaveFallback = true; - mustHaveSerial = false; - } else { - if (Settings.console_serial0_fallback && !consoleUseSerial0 && canUseSerial0) - { - mustHaveFallback = true; - } - } - } - - if (!mustHaveFallback) { - if (_fallbackSerial._serial != nullptr) { - delete _fallbackSerial._serial; - _fallbackSerial._serial = nullptr; - somethingChanged = true; - } - } - - if ((_console_serial_port != Settings.console_serial_port) || - (_console_serial_rxpin != Settings.console_serial_rxpin) || - (_console_serial_txpin != Settings.console_serial_txpin) || - !mustHaveSerial) { - if (_mainSerial._serial != nullptr) { - delete _mainSerial._serial; - _mainSerial._serial = nullptr; - somethingChanged = true; - } - - _console_serial_port = Settings.console_serial_port; - _console_serial_rxpin = Settings.console_serial_rxpin; - _console_serial_txpin = Settings.console_serial_txpin; - } - - if ((_mainSerial._serial == nullptr) && mustHaveSerial) { - unsigned int buffsize = 128; - - const ESPEasySerialPort mainSerialPort = static_cast(_console_serial_port); + ESPEasySerialConfig config; + config.port = static_cast(Settings.console_serial_port); + config.baud = Settings.BaudRate; + config.receivePin = Settings.console_serial_rxpin; + config.transmitPin = Settings.console_serial_txpin; + config.inverse_logic = false; + config.rxBuffSize = 256; # if USES_HWCDC - if (mainSerialPort == ESPEasySerialPort::usb_hw_cdc) { - buffsize = 2048; - } -# endif // if USES_HWCDC - - _mainSerial._serial = new (std::nothrow) ESPeasySerial( - mainSerialPort, - _console_serial_rxpin, - _console_serial_txpin, - false, - buffsize); - somethingChanged = true; - } - - if ((_fallbackSerial._serial == nullptr) && mustHaveFallback) { - _fallbackSerial._serial = new (std::nothrow) ESPeasySerial( - ESPEasySerialPort::serial0, - SOC_RX0, - SOC_TX0); - somethingChanged = true; + if (config.port == ESPEasySerialPort::usb_hw_cdc) { + config.txBuffSize = 2048; + } else { + config.txBuffSize = 512; } +# else // if USES_HWCDC + config.txBuffSize = 512; +# endif // if USES_HWCDC - if (_fallbackSerial._serial == nullptr) { - _fallbackSerial._serialWriteBuffer.clear(); - } - if (_mainSerial._serial == nullptr) { - _mainSerial._serialWriteBuffer.clear(); + if (config.port != ESPEasySerialPort::serial0) { + // We only use the _mainSerial for ports other than HW Serial0 + _mainSerial.updateSerialPort(config); } - if (somethingChanged) { - begin(Settings.BaudRate); + if (Settings.console_serial0_fallback || + (config.port == ESPEasySerialPort::serial0)) + { + config.port = ESPEasySerialPort::serial0; + config.receivePin = SOC_RX0; + config.transmitPin = SOC_TX0; + config.txBuffSize = 512; + _fallbackSerial.updateSerialPort(config); } } void EspEasy_Console_t::begin(uint32_t baudrate) { - updateActiveTaskUseSerial0(); - _baudrate = baudrate; - - if (_mainSerial._serial != nullptr) { - _mainSerial._serial->begin(baudrate); - addLog(LOG_LEVEL_INFO, F("ESPEasy console using ESPEasySerial")); - } + _mainSerial.begin(baudrate); + _fallbackSerial.begin(baudrate); if (_fallbackSerial._serial != nullptr) { - _fallbackSerial._serial->begin(baudrate); // Need to have this string as C-string, not F-string perimanSetPinBusExtraType(SOC_RX0, "Console"); @@ -206,22 +150,13 @@ void EspEasy_Console_t::loop() START_TIMER; - const bool consoleUsesSerial0 = - (static_cast(_console_serial_port) == ESPEasySerialPort::serial0 - ); + _mainSerial.readInput(); - if (handledByPluginSerialIn()) - { + if (!handledByPluginSerialIn()) { // Any serial0 data is already dealt with - if (!consoleUsesSerial0 && (_mainSerial._serial != nullptr)) { - readInput(_mainSerial); - } - return; + _fallbackSerial.readInput(); } - readInput(_mainSerial); - readInput(_fallbackSerial); - STOP_TIMER(CONSOLE_LOOP); } @@ -245,10 +180,12 @@ bool EspEasy_Console_t::process_serialWriteBuffer() { void EspEasy_Console_t::setDebugOutput(bool enable) { - auto port = getPort(); + if (_mainSerial._serial != nullptr) { + _mainSerial._serial->setDebugOutput(enable); + } - if (port != nullptr) { - port->setDebugOutput(enable); + if (_fallbackSerial._serial != nullptr) { + _fallbackSerial._serial->setDebugOutput(enable); } } @@ -272,36 +209,9 @@ bool EspEasy_Console_t::handledByPluginSerialIn() return PluginCall(PLUGIN_SERIAL_IN, 0, dummy); } - if ((_mainSerial._serial != nullptr) && _mainSerial._serial->available() && - (static_cast(_console_serial_port) == ESPEasySerialPort::serial0 - )) - { - String dummy; - - return PluginCall(PLUGIN_SERIAL_IN, 0, dummy); - } return false; } -void EspEasy_Console_t::readInput(EspEasy_Console_Port& port) -{ - size_t bytesToRead = port.available(); - - while (bytesToRead > 0) - { - --bytesToRead; - delay(0); - const int SerialInByte = port.read(); - - if (SerialInByte >= 0) { - if (port.process_consoleInput(SerialInByte)) { - // Processed a full line - return; - } - } - } -} - ESPeasySerial * EspEasy_Console_t::getPort() { if (_mainSerial._serial != nullptr) { diff --git a/src/src/ESPEasyCore/ESPEasy_Console_serial0_only.cpp b/src/src/ESPEasyCore/ESPEasy_Console_serial0_only.cpp index 4e669b3f82..63cda8fb41 100644 --- a/src/src/ESPEasyCore/ESPEasy_Console_serial0_only.cpp +++ b/src/src/ESPEasyCore/ESPEasy_Console_serial0_only.cpp @@ -30,6 +30,9 @@ EspEasy_Console_t::EspEasy_Console_t() : void EspEasy_Console_t::reInit() { updateActiveTaskUseSerial0(); + + // TODO TD-er: Must check whether a task uses serial 0 and then stop serial console + //activeTaskUseSerial0() bool somethingChanged = false; if (somethingChanged) { @@ -39,27 +42,7 @@ void EspEasy_Console_t::reInit() void EspEasy_Console_t::begin(uint32_t baudrate) { - updateActiveTaskUseSerial0(); - _baudrate = baudrate; - - if (_mainSerial._serial != nullptr) { -# ifdef ESP8266 - _mainSerial._serial->begin(baudrate); -# ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_INFO, F("ESPEasy console using HW Serial")); -# endif -# endif // ifdef ESP8266 -# ifdef ESP32 - - // Allow to flush data from the serial buffers - // When not opening the USB serial port, the ESP may hang at boot. - delay(10); - _mainSerial._serial->end(); - delay(10); - _mainSerial._serial->begin(baudrate); - _mainSerial._serial->flush(); -# endif // ifdef ESP32 - } + _mainSerial.begin(baudrate); } void EspEasy_Console_t::init() { @@ -89,7 +72,7 @@ void EspEasy_Console_t::loop() return; } - readInput(_mainSerial); + _mainSerial.readInput(); STOP_TIMER(CONSOLE_LOOP); } @@ -130,25 +113,6 @@ bool EspEasy_Console_t::handledByPluginSerialIn() return PluginCall(PLUGIN_SERIAL_IN, 0, dummy); } -void EspEasy_Console_t::readInput(EspEasy_Console_Port& port) -{ - size_t bytesToRead = port.available(); - - while (bytesToRead > 0) - { - --bytesToRead; - delay(0); - const int SerialInByte = port.read(); - - if (SerialInByte >= 0) { - if (port.process_consoleInput(SerialInByte)) { - // Processed a full line - return; - } - } - } -} - HardwareSerial * EspEasy_Console_t::getPort() { if (_mainSerial._serial != nullptr) { diff --git a/src/src/ESPEasyCore/ESPEasy_Console_single_serial.cpp b/src/src/ESPEasyCore/ESPEasy_Console_single_serial.cpp index aefce3543e..6b88fb81c3 100644 --- a/src/src/ESPEasyCore/ESPEasy_Console_single_serial.cpp +++ b/src/src/ESPEasyCore/ESPEasy_Console_single_serial.cpp @@ -27,9 +27,7 @@ EspEasy_Console_t::EspEasy_Console_t() : _mainSerial(LOG_TO_SERIAL) { - const ESPEasySerialPort port = static_cast(_console_serial_port); - -# if USES_USBCDC +# if USES_USBCDC /* if (port == ESPEasySerialPort::usb_cdc_0 || @@ -39,12 +37,12 @@ EspEasy_Console_t::EspEasy_Console_t() : USB.productName() } */ -# endif // if USES_USBCDC +# endif // if USES_USBCDC -# ifdef ESP8266 +# ifdef ESP8266 constexpr size_t buffSize = 256; -# endif // ifdef ESP8266 -# ifdef ESP32 +# endif // ifdef ESP8266 +# ifdef ESP32 // Ideal buffer size is a trade-off between bootspeed // and not missing data when the ESP is busy processing stuff. @@ -52,104 +50,48 @@ EspEasy_Console_t::EspEasy_Console_t() : // it may just take less time in the background tasks to dump // any logs as larger chunks can be transferred at once. constexpr size_t buffSize = 512; -# endif // ifdef ESP32 +# endif // ifdef ESP32 ESPEasySerialConfig config; - config.port = port; + config.port = static_cast(DEFAULT_CONSOLE_PORT); config.baud = DEFAULT_SERIAL_BAUD; - config.receivePin = _console_serial_rxpin; - config.transmitPin = _console_serial_txpin; + config.receivePin = DEFAULT_CONSOLE_PORT_RXPIN; + config.transmitPin = DEFAULT_CONSOLE_PORT_TXPIN; config.inverse_logic = false; config.rxBuffSize = 256; config.txBuffSize = buffSize; - { - # ifdef USE_SECOND_HEAP - HeapSelectDram ephemeral; - # endif // ifdef USE_SECOND_HEAP - - _mainSerial._serial = new (std::nothrow) ESPeasySerial(config); - } + _mainSerial.updateSerialPort(config); } void EspEasy_Console_t::reInit() { - updateActiveTaskUseSerial0(); - bool somethingChanged = false; - const ESPEasySerialPort port = static_cast(Settings.console_serial_port); - - const bool consoleUseSerial0 = ( -# ifdef ESP8266 - (port == ESPEasySerialPort::serial0_swap) || -# endif // ifdef ESP8266 - port == ESPEasySerialPort::serial0); - - const bool canUseSerial0 = !activeTaskUseSerial0() && !log_to_serial_disabled; - - - bool mustHaveSerial = Settings.UseSerial && (!consoleUseSerial0 || canUseSerial0); - - - if ((_console_serial_port != Settings.console_serial_port) || - (_console_serial_rxpin != Settings.console_serial_rxpin) || - (_console_serial_txpin != Settings.console_serial_txpin) || - !mustHaveSerial) { - if (_mainSerial._serial != nullptr) { - delete _mainSerial._serial; - _mainSerial._serial = nullptr; - somethingChanged = true; - } - - _console_serial_port = Settings.console_serial_port; - _console_serial_rxpin = Settings.console_serial_rxpin; - _console_serial_txpin = Settings.console_serial_txpin; - } - - if ((_mainSerial._serial == nullptr) && mustHaveSerial) { - # ifdef USE_SECOND_HEAP - HeapSelectDram ephemeral; - # endif // ifdef USE_SECOND_HEAP - - unsigned int buffsize = 128; - - const ESPEasySerialPort mainSerialPort = static_cast(_console_serial_port); - -# if USES_HWCDC - - if (mainSerialPort == ESPEasySerialPort::usb_hw_cdc) { - buffsize = 2048; - } -# endif // if USES_HWCDC - - _mainSerial._serial = new (std::nothrow) ESPeasySerial( - mainSerialPort, - _console_serial_rxpin, - _console_serial_txpin, - false, - buffsize); - somethingChanged = true; - } +# ifdef ESP8266 + constexpr size_t buffSize = 256; +# endif // ifdef ESP8266 +# ifdef ESP32 + // Ideal buffer size is a trade-off between bootspeed + // and not missing data when the ESP is busy processing stuff. + // Since we do have a separate buffer in the console, + // it may just take less time in the background tasks to dump + // any logs as larger chunks can be transferred at once. + constexpr size_t buffSize = 512; +# endif // ifdef ESP32 - if (_mainSerial._serial == nullptr) { - _mainSerial._serialWriteBuffer.clear(); - } + ESPEasySerialConfig config; + config.port = static_cast(Settings.console_serial_port); + config.baud = Settings.BaudRate; + config.receivePin = Settings.console_serial_rxpin; + config.transmitPin = Settings.console_serial_txpin; + config.inverse_logic = false; + config.rxBuffSize = 256; + config.txBuffSize = buffSize; - if (somethingChanged) { - begin(Settings.BaudRate); - } + _mainSerial.updateSerialPort(config); } -void EspEasy_Console_t::begin(uint32_t baudrate) -{ - updateActiveTaskUseSerial0(); - _baudrate = baudrate; - - if (_mainSerial._serial != nullptr) { - _mainSerial._serial->begin(baudrate); - addLog(LOG_LEVEL_INFO, F("ESPEasy console using ESPEasySerial")); - } -} +void EspEasy_Console_t::begin(uint32_t baudrate) { _mainSerial.begin(baudrate); } void EspEasy_Console_t::init() { # if FEATURE_IMPROV @@ -171,22 +113,22 @@ void EspEasy_Console_t::loop() START_TIMER; const bool consoleUsesSerial0 = - (static_cast(_console_serial_port) == ESPEasySerialPort::serial0 -# ifdef ESP8266 - || static_cast(_console_serial_port) == ESPEasySerialPort::serial0_swap -# endif // ifdef ESP8266 + (_mainSerial.getPortType() == ESPEasySerialPort::serial0 +# ifdef ESP8266 + || _mainSerial.getPortType() == ESPEasySerialPort::serial0_swap +# endif // ifdef ESP8266 ); if (handledByPluginSerialIn()) { // Any serial0 data is already dealt with if (!consoleUsesSerial0 && (_mainSerial._serial != nullptr)) { - readInput(_mainSerial); + _mainSerial.readInput(); } return; } - readInput(_mainSerial); + _mainSerial.readInput(); STOP_TIMER(CONSOLE_LOOP); } @@ -220,14 +162,13 @@ String EspEasy_Console_t::getPortDescription() const return _mainSerial.getPortDescription(); } - bool EspEasy_Console_t::handledByPluginSerialIn() { if ((_mainSerial._serial != nullptr) && _mainSerial._serial->available() && - (static_cast(_console_serial_port) == ESPEasySerialPort::serial0 -# ifdef ESP8266 - || static_cast(_console_serial_port) == ESPEasySerialPort::serial0_swap -# endif // ifdef ESP8266 + (_mainSerial.getPortType() == ESPEasySerialPort::serial0 +# ifdef ESP8266 + || _mainSerial.getPortType() == ESPEasySerialPort::serial0_swap +# endif // ifdef ESP8266 )) { String dummy; @@ -237,26 +178,6 @@ bool EspEasy_Console_t::handledByPluginSerialIn() return false; } -void EspEasy_Console_t::readInput(EspEasy_Console_Port& port) -{ - size_t bytesToRead = port.available(); - - while (bytesToRead > 0) - { - --bytesToRead; - delay(0); - const int SerialInByte = port.read(); - - if (SerialInByte >= 0) { - if (port.process_consoleInput(SerialInByte)) { - // Processed a full line - return; - } - } - } -} - - ESPeasySerial * EspEasy_Console_t::getPort() { if (_mainSerial._serial != nullptr) { diff --git a/src/src/Helpers/Improv_Helper.cpp b/src/src/Helpers/Improv_Helper.cpp index 477f8e34c6..d487c9ea15 100644 --- a/src/src/Helpers/Improv_Helper.cpp +++ b/src/src/Helpers/Improv_Helper.cpp @@ -71,6 +71,11 @@ void Improv_Helper_t::init() // FIXME TD-er: Implement callback to use ESPEasy functions to connect to WiFi // _improv.setCustomTryConnectToWiFi(OnImprovESPEasyConnectWiFi); + update(); +} + +void Improv_Helper_t::update() +{ String firmwareName = get_binary_filename(); const String buildString = getSystemBuildString(); diff --git a/src/src/Helpers/Improv_Helper.h b/src/src/Helpers/Improv_Helper.h index fc92654580..c2a3fe080f 100644 --- a/src/src/Helpers/Improv_Helper.h +++ b/src/src/Helpers/Improv_Helper.h @@ -17,6 +17,8 @@ class Improv_Helper_t { void init(); + void update(); + bool handle(uint8_t b, Stream *serialForWrite); bool getFromBuffer(uint8_t& b); From 759285e9bd85c8564395995db81effee29b20d67 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sat, 18 Jul 2026 20:53:07 +0200 Subject: [PATCH 3/8] [Serial] Fix failing build on minimal ESP8266 builds --- src/src/ESPEasyCore/ESPEasy_Console_Port.cpp | 2 ++ src/src/ESPEasyCore/ESPEasy_Console_Port.h | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasy_Console_Port.cpp b/src/src/ESPEasyCore/ESPEasy_Console_Port.cpp index 929d6425d6..62b451631b 100644 --- a/src/src/ESPEasyCore/ESPEasy_Console_Port.cpp +++ b/src/src/ESPEasyCore/ESPEasy_Console_Port.cpp @@ -161,6 +161,7 @@ void EspEasy_Console_Port::readInput() } } +#if FEATURE_DEFINE_SERIAL_CONSOLE_PORT ESPEasySerialPort EspEasy_Console_Port::getPortType() const { #if FEATURE_DEFINE_SERIAL_CONSOLE_PORT @@ -173,6 +174,7 @@ ESPEasySerialPort EspEasy_Console_Port::getPortType() const return ESPEasySerialPort::serial0; #endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT } +#endif bool EspEasy_Console_Port::process_serialWriteBuffer() { diff --git a/src/src/ESPEasyCore/ESPEasy_Console_Port.h b/src/src/ESPEasyCore/ESPEasy_Console_Port.h index 37b00f82a3..9e5fad0fcc 100644 --- a/src/src/ESPEasyCore/ESPEasy_Console_Port.h +++ b/src/src/ESPEasyCore/ESPEasy_Console_Port.h @@ -32,9 +32,9 @@ struct EspEasy_Console_Port { void endPort(); void readInput(); - +#if FEATURE_DEFINE_SERIAL_CONSOLE_PORT ESPEasySerialPort getPortType() const; - +#endif bool process_serialWriteBuffer(); bool process_consoleInput(uint8_t SerialInByte); From 39f43f14f85189a2687aac74e98bb9282c681c26 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 19 Jul 2026 17:06:59 +0200 Subject: [PATCH 4/8] [Serial] Simplify ESPEasy console code + reduce resource usage --- lib/ESPEasySerial/ESPEasySerialConfig.cpp | 5 + src/src/ESPEasyCore/ESPEasy_Console.h | 41 ++++-- src/src/ESPEasyCore/ESPEasy_Console_Port.cpp | 125 +++++++++++++----- src/src/ESPEasyCore/ESPEasy_Console_Port.h | 34 ++--- .../ESPEasy_Console_dual_serial.cpp | 69 +++------- .../ESPEasy_Console_serial0_only.cpp | 38 ++---- .../ESPEasy_Console_single_serial.cpp | 83 +++--------- 7 files changed, 187 insertions(+), 208 deletions(-) diff --git a/lib/ESPEasySerial/ESPEasySerialConfig.cpp b/lib/ESPEasySerial/ESPEasySerialConfig.cpp index 48d6ffea09..b4fa040574 100644 --- a/lib/ESPEasySerial/ESPEasySerialConfig.cpp +++ b/lib/ESPEasySerial/ESPEasySerialConfig.cpp @@ -36,6 +36,11 @@ void ESPEasySerialConfig::validate() # endif // if USES_I2C_SC16IS752 } #endif // if USES_SW_SERIAL +#if USES_HWCDC + if (port == ESPEasySerialPort::usb_hw_cdc) { + txBuffSize = 2048; + } +#endif } #ifdef ESP8266 diff --git a/src/src/ESPEasyCore/ESPEasy_Console.h b/src/src/ESPEasyCore/ESPEasy_Console.h index adc344d20f..bc68ce9230 100644 --- a/src/src/ESPEasyCore/ESPEasy_Console.h +++ b/src/src/ESPEasyCore/ESPEasy_Console.h @@ -5,26 +5,41 @@ #include "../ESPEasyCore/ESPEasy_Console_Port.h" -class EspEasy_Console_t { +#ifdef ESP8266 +# define ESPEASY_CONSOLE_TX_BUFFSIZE 256 +#endif // ifdef ESP8266 +#ifdef ESP32 + +// Ideal buffer size is a trade-off between bootspeed +// and not missing data when the ESP is busy processing stuff. +// Since we do have a separate buffer in the console, +// it may just take less time in the background tasks to dump +// any logs as larger chunks can be transferred at once. +# define ESPEASY_CONSOLE_TX_BUFFSIZE 1024 +#endif // ifdef ESP32 + + +class EspEasy_Console_t +{ public: EspEasy_Console_t(); // Typically called after settings have been loaded. - void reInit(); + void reInit(); - void begin(uint32_t baudrate); + void begin(uint32_t baudrate); - void init(); + void init(); // Process data from serial port - void loop(); + void loop(); // Return true when something got written, or when the buffer was already empty - bool process_serialWriteBuffer(); + bool process_serialWriteBuffer(); - void setDebugOutput(bool enable); + void setDebugOutput(bool enable); String getPortDescription() const; @@ -32,13 +47,10 @@ class EspEasy_Console_t { String getFallbackPortDescription() const; #endif - private: - bool handledByPluginSerialIn(); - #if FEATURE_DEFINE_SERIAL_CONSOLE_PORT - ESPeasySerial * getPort(); + ESPeasySerial* getPort(); #else // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT HardwareSerial* getPort(); #endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT @@ -49,11 +61,12 @@ class EspEasy_Console_t { #if FEATURE_DEFINE_SERIAL_CONSOLE_PORT # if USES_ESPEASY_CONSOLE_FALLBACK_PORT + // Serial port to be always used as HW Serial0 EspEasy_Console_Port _fallbackSerial; -# endif -#endif -}; +# endif // if USES_ESPEASY_CONSOLE_FALLBACK_PORT +#endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT +}; // class EspEasy_Console_t #endif // ifndef ESPEASYCORE_ESPEASY_CONSOLE_H diff --git a/src/src/ESPEasyCore/ESPEasy_Console_Port.cpp b/src/src/ESPEasyCore/ESPEasy_Console_Port.cpp index 62b451631b..d748d56a87 100644 --- a/src/src/ESPEasyCore/ESPEasy_Console_Port.cpp +++ b/src/src/ESPEasyCore/ESPEasy_Console_Port.cpp @@ -13,9 +13,12 @@ #include "../Helpers/Memory.h" #include "../Helpers/StringConverter.h" - -#include - +#if FEATURE_DEFINE_SERIAL_CONSOLE_PORT +# include +# ifdef ESP32 +# include +# endif +#endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT #ifdef ESP32 # define CONSOLE_INPUT_BUFFER_SIZE 1280 @@ -23,6 +26,10 @@ # define CONSOLE_INPUT_BUFFER_SIZE 128 #endif // ifdef ESP32 +// Set to max. of 64 bytes as this is the optimum 'chunk size' for most +// serial ports, like the CDC ports and I2C to UART. +// Also it is relatively fast to allocate. +#define CONSOLE_MAX_WRITE_CHUNKSIZE 64 /* #if FEATURE_DEFINE_SERIAL_CONSOLE_PORT @@ -110,18 +117,17 @@ void EspEasy_Console_Port::begin(uint32_t baudrate) updateActiveTaskUseSerial0(); if (_serial != nullptr) { - # if FEATURE_IMPROV + #if FEATURE_IMPROV _improv.init(); #endif + _serial->begin(baudrate); #if FEATURE_DEFINE_SERIAL_CONSOLE_PORT _config.baud = baudrate; #endif - _serial->begin(baudrate); - addLog(LOG_LEVEL_INFO, F("ESPEasy console using ESPEasySerial")); +#ifdef ESP32 -# ifdef ESP32 // Allow to flush data from the serial buffers // When not opening the USB serial port, the ESP may hang at boot. delay(10); @@ -129,8 +135,18 @@ void EspEasy_Console_Port::begin(uint32_t baudrate) delay(10); _serial->begin(baudrate); _serial->flush(); -# endif // ifdef ESP32 + +# if FEATURE_DEFINE_SERIAL_CONSOLE_PORT + + if (useGPIOpins(_config.port)) { + // Need to have this string as C-string, not F-string + perimanSetPinBusExtraType(_config.receivePin, "Console"); + perimanSetPinBusExtraType(_config.transmitPin, "Console"); + } +# endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT + +#endif // ifdef ESP32 } } @@ -143,9 +159,30 @@ void EspEasy_Console_Port::endPort() void EspEasy_Console_Port::readInput() { - if (_serial == nullptr) return; + if (_serial == nullptr) { return; } + size_t bytesToRead = available(); + if (bytesToRead == 0) { return; } + + +#if FEATURE_DEFINE_SERIAL_CONSOLE_PORT + + if (getPortType() == ESPEasySerialPort::serial0 +# ifdef ESP8266 + || getPortType() == ESPEasySerialPort::serial0_swap +# endif // ifdef ESP8266 + ) +#endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT + { + String dummy; + + if (PluginCall(PLUGIN_SERIAL_IN, 0, dummy)) { + // Any serial0 data is already dealt with + return; + } + } + while (bytesToRead > 0) { --bytesToRead; @@ -162,19 +199,21 @@ void EspEasy_Console_Port::readInput() } #if FEATURE_DEFINE_SERIAL_CONSOLE_PORT + ESPEasySerialPort EspEasy_Console_Port::getPortType() const { - #if FEATURE_DEFINE_SERIAL_CONSOLE_PORT + # if FEATURE_DEFINE_SERIAL_CONSOLE_PORT if (_serial == nullptr) { return ESPEasySerialPort::not_set; } return _config.port; - #else // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT + # else // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT // TODO TD-er: Should I also try to see if we're using serial0_swapped? return ESPEasySerialPort::serial0; - #endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT + # endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT } -#endif + +#endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT bool EspEasy_Console_Port::process_serialWriteBuffer() { @@ -183,29 +222,46 @@ bool EspEasy_Console_Port::process_serialWriteBuffer() if (!xPortCanYield()) { return false; } #endif // ifdef ESP32 + + // Only check for nr. available bytes left once + // This can be a relatively "expensive" call + // and when using high baud rates this processing may take up + // too much time blocking everything else. size_t availableForWrite = _serial->availableForWrite(); - if (availableForWrite == 0) { return false; } + size_t nrLinesWritten = 0; - if (availableForWrite == 1) { - // For only a single byte, just write it directly - return _serialWriteBuffer.process(_serial, availableForWrite); - } + PrintToString str; + str.reserve(CONSOLE_MAX_WRITE_CHUNKSIZE); - if (availableForWrite > 64) { - // Set to max. of 64 bytes as this is the optimum 'chunk size' for most - // serial ports, like the CDC ports and I2C to UART. - // Also it is relatively fast to allocate. - availableForWrite = 64; - } + do + { + if (availableForWrite == 0) { return false; } - PrintToString str; - str.reserve(availableForWrite); + if (availableForWrite == 1) { + // For only a single byte, just write it directly + return _serialWriteBuffer.process(_serial, availableForWrite); + } - if (!_serialWriteBuffer.process(&str, availableForWrite)) { - return false; - } - _serial->write(str.get().c_str(), str.length()); + size_t chunkSize = availableForWrite; + + if (chunkSize > CONSOLE_MAX_WRITE_CHUNKSIZE) { + chunkSize = CONSOLE_MAX_WRITE_CHUNKSIZE; + } + availableForWrite -= chunkSize; + + if (!_serialWriteBuffer.process(&str, chunkSize)) { + // Nothing left to write + return false; + } + + if (_serial->write(str.get().c_str(), str.length()) < chunkSize) { + // Try to end on a full log line to lower the chance of SDK debug logs + // interfering with console output. + ++nrLinesWritten; + } + str.clear(); + } while (availableForWrite > 0 && nrLinesWritten < 3); return true; } @@ -266,10 +322,11 @@ String EspEasy_Console_Port::getPortDescription() const #if FEATURE_DEFINE_SERIAL_CONSOLE_PORT bool EspEasy_Console_Port::updateSerialPort( - const ESPEasySerialConfig& config) + ESPEasySerialConfig& config) { updateActiveTaskUseSerial0(); bool somethingChanged = false; + config.validate(); const bool consoleUseSerial0 = ( # ifdef ESP8266 @@ -280,7 +337,7 @@ bool EspEasy_Console_Port::updateSerialPort( const bool canUseSerial0 = !activeTaskUseSerial0() && !log_to_serial_disabled; - bool mustHaveSerial = Settings.UseSerial && (!consoleUseSerial0 || canUseSerial0); + bool mustHaveSerial = Settings.UseSerial && (!consoleUseSerial0 || canUseSerial0) && config.port != ESPEasySerialPort::not_set; if (!(_config == config) || !mustHaveSerial) { @@ -290,6 +347,10 @@ bool EspEasy_Console_Port::updateSerialPort( somethingChanged = true; } _config = config; + + if (!mustHaveSerial) { + _config.port = ESPEasySerialPort::not_set; + } } if ((_serial == nullptr) && mustHaveSerial) { diff --git a/src/src/ESPEasyCore/ESPEasy_Console_Port.h b/src/src/ESPEasyCore/ESPEasy_Console_Port.h index 9e5fad0fcc..249f918092 100644 --- a/src/src/ESPEasyCore/ESPEasy_Console_Port.h +++ b/src/src/ESPEasyCore/ESPEasy_Console_Port.h @@ -13,7 +13,7 @@ #endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT #if FEATURE_IMPROV -#include "../Helpers/Improv_Helper.h" +# include "../Helpers/Improv_Helper.h" #endif @@ -24,39 +24,41 @@ struct EspEasy_Console_Port { operator bool() const; - int read(); - size_t available() const; + int read(); + size_t available() const; - void begin(uint32_t baudrate); + void begin(uint32_t baudrate); - void endPort(); + void endPort(); - void readInput(); + void readInput(); #if FEATURE_DEFINE_SERIAL_CONSOLE_PORT ESPEasySerialPort getPortType() const; #endif - bool process_serialWriteBuffer(); + bool process_serialWriteBuffer(); - bool process_consoleInput(uint8_t SerialInByte); + bool process_consoleInput(uint8_t SerialInByte); - String getPortDescription() const; + String getPortDescription() const; #if FEATURE_DEFINE_SERIAL_CONSOLE_PORT - bool updateSerialPort(const ESPEasySerialConfig& config); + bool updateSerialPort(ESPEasySerialConfig& config); private: + // Cache the used settings, so we can check whether to change the console serial ESPEasySerialConfig _config; public: -#endif - int SerialInByteCounter{}; - char *InputBuffer_Serial{}; +#endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT + + int SerialInByteCounter{}; + char *InputBuffer_Serial{}; SerialWriteBuffer_t _serialWriteBuffer; #if FEATURE_DEFINE_SERIAL_CONSOLE_PORT - ESPeasySerial *_serial = nullptr; + ESPeasySerial *_serial = nullptr; #else // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT # if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL) && ARDUINO_USB_CDC_ON_BOOT // Serial used for USB CDC HardwareSerial *_serial = &Serial0; @@ -68,9 +70,9 @@ struct EspEasy_Console_Port { Improv_Helper_t _improv; -#endif +#endif // if FEATURE_IMPROV }; -#endif \ No newline at end of file +#endif // ifndef ESPEASYCORE_ESPEASY_CONSOLE_PORT_H diff --git a/src/src/ESPEasyCore/ESPEasy_Console_dual_serial.cpp b/src/src/ESPEasyCore/ESPEasy_Console_dual_serial.cpp index c482bf88cb..84749649e2 100644 --- a/src/src/ESPEasyCore/ESPEasy_Console_dual_serial.cpp +++ b/src/src/ESPEasyCore/ESPEasy_Console_dual_serial.cpp @@ -22,10 +22,6 @@ # include -# ifdef ESP32 -# include -# endif - EspEasy_Console_t::EspEasy_Console_t() : _mainSerial(LOG_TO_SERIAL) @@ -50,16 +46,7 @@ EspEasy_Console_t::EspEasy_Console_t() : config.transmitPin = DEFAULT_CONSOLE_PORT_TXPIN; config.inverse_logic = false; config.rxBuffSize = 256; -# if USES_HWCDC - - if (config.port == ESPEasySerialPort::usb_hw_cdc) { - config.txBuffSize = 2048; - } else { - config.txBuffSize = 512; - } -# else // if USES_HWCDC - config.txBuffSize = 512; -# endif // if USES_HWCDC + config.txBuffSize = ESPEASY_CONSOLE_TX_BUFFSIZE; if (config.port != ESPEasySerialPort::serial0) { // We only use the _mainSerial for ports other than HW Serial0 @@ -72,7 +59,7 @@ EspEasy_Console_t::EspEasy_Console_t() : config.port = ESPEasySerialPort::serial0; config.receivePin = SOC_RX0; config.transmitPin = SOC_TX0; - config.txBuffSize = 512; + config.txBuffSize = ESPEASY_CONSOLE_TX_BUFFSIZE; _fallbackSerial.updateSerialPort(config); } } @@ -87,17 +74,7 @@ void EspEasy_Console_t::reInit() config.transmitPin = Settings.console_serial_txpin; config.inverse_logic = false; config.rxBuffSize = 256; -# if USES_HWCDC - - if (config.port == ESPEasySerialPort::usb_hw_cdc) { - config.txBuffSize = 2048; - } else { - config.txBuffSize = 512; - } -# else // if USES_HWCDC - config.txBuffSize = 512; -# endif // if USES_HWCDC - + config.txBuffSize = ESPEASY_CONSOLE_TX_BUFFSIZE; if (config.port != ESPEasySerialPort::serial0) { // We only use the _mainSerial for ports other than HW Serial0 @@ -110,7 +87,7 @@ void EspEasy_Console_t::reInit() config.port = ESPEasySerialPort::serial0; config.receivePin = SOC_RX0; config.transmitPin = SOC_TX0; - config.txBuffSize = 512; + config.txBuffSize = ESPEASY_CONSOLE_TX_BUFFSIZE; _fallbackSerial.updateSerialPort(config); } } @@ -120,21 +97,22 @@ void EspEasy_Console_t::begin(uint32_t baudrate) _mainSerial.begin(baudrate); _fallbackSerial.begin(baudrate); - if (_fallbackSerial._serial != nullptr) { +# ifndef BUILD_NO_DEBUG - // Need to have this string as C-string, not F-string - perimanSetPinBusExtraType(SOC_RX0, "Console"); - perimanSetPinBusExtraType(SOC_TX0, "Console"); + if (_mainSerial._serial != nullptr) { + addLog(LOG_LEVEL_INFO, F("ESPEasy console enabled")); + } - addLog(LOG_LEVEL_INFO, F("ESPEasy console fallback enabled")); + if (_fallbackSerial._serial != nullptr) { + addLog(LOG_LEVEL_INFO, + (_mainSerial._serial != nullptr) + ? F("ESPEasy console fallback enabled") + : F("ESPEasy console enabled")); } +# endif // ifndef BUILD_NO_DEBUG } void EspEasy_Console_t::init() { -# if FEATURE_IMPROV - _mainSerial._improv.init(); - _fallbackSerial._improv.init(); -# endif // if FEATURE_IMPROV updateActiveTaskUseSerial0(); if (!Settings.UseSerial) { @@ -151,11 +129,7 @@ void EspEasy_Console_t::loop() START_TIMER; _mainSerial.readInput(); - - if (!handledByPluginSerialIn()) { - // Any serial0 data is already dealt with - _fallbackSerial.readInput(); - } + _fallbackSerial.readInput(); STOP_TIMER(CONSOLE_LOOP); } @@ -199,19 +173,6 @@ String EspEasy_Console_t::getFallbackPortDescription() const return _fallbackSerial.getPortDescription(); } -bool EspEasy_Console_t::handledByPluginSerialIn() -{ - if ((_fallbackSerial._serial != nullptr) && - _fallbackSerial._serial->available()) - { - String dummy; - - return PluginCall(PLUGIN_SERIAL_IN, 0, dummy); - } - - return false; -} - ESPeasySerial * EspEasy_Console_t::getPort() { if (_mainSerial._serial != nullptr) { diff --git a/src/src/ESPEasyCore/ESPEasy_Console_serial0_only.cpp b/src/src/ESPEasyCore/ESPEasy_Console_serial0_only.cpp index 63cda8fb41..fa56f44cf7 100644 --- a/src/src/ESPEasyCore/ESPEasy_Console_serial0_only.cpp +++ b/src/src/ESPEasyCore/ESPEasy_Console_serial0_only.cpp @@ -32,7 +32,7 @@ void EspEasy_Console_t::reInit() updateActiveTaskUseSerial0(); // TODO TD-er: Must check whether a task uses serial 0 and then stop serial console - //activeTaskUseSerial0() + // activeTaskUseSerial0() bool somethingChanged = false; if (somethingChanged) { @@ -43,12 +43,12 @@ void EspEasy_Console_t::reInit() void EspEasy_Console_t::begin(uint32_t baudrate) { _mainSerial.begin(baudrate); +# ifndef BUILD_NO_DEBUG + addLog(LOG_LEVEL_INFO, F("ESPEasy console enabled")); +# endif } void EspEasy_Console_t::init() { -# if FEATURE_IMPROV - _mainSerial._improv.init(); -# endif // if FEATURE_IMPROV updateActiveTaskUseSerial0(); if (!Settings.UseSerial) { @@ -68,16 +68,14 @@ void EspEasy_Console_t::loop() START_TIMER; - if (handledByPluginSerialIn()) { - return; - } - _mainSerial.readInput(); STOP_TIMER(CONSOLE_LOOP); } bool EspEasy_Console_t::process_serialWriteBuffer() { + +# if FEATURE_TIMING_STATS START_TIMER; bool res = false; @@ -85,11 +83,12 @@ bool EspEasy_Console_t::process_serialWriteBuffer() { res = true; } -# if FEATURE_TIMING_STATS - if (res) { STOP_TIMER(CONSOLE_WRITE_SERIAL); } -# endif // if FEATURE_TIMING_STATS return res; + +# else // if FEATURE_TIMING_STATS + return _mainSerial.process_serialWriteBuffer(); +# endif // if FEATURE_TIMING_STATS } void EspEasy_Console_t::setDebugOutput(bool enable) @@ -106,22 +105,9 @@ String EspEasy_Console_t::getPortDescription() const return _mainSerial.getPortDescription(); } -bool EspEasy_Console_t::handledByPluginSerialIn() -{ - String dummy; - - return PluginCall(PLUGIN_SERIAL_IN, 0, dummy); -} - -HardwareSerial * EspEasy_Console_t::getPort() -{ - if (_mainSerial._serial != nullptr) { - return _mainSerial._serial; - } - return nullptr; -} +HardwareSerial * EspEasy_Console_t::getPort() { return _mainSerial._serial; } -void EspEasy_Console_t::endPort() +void EspEasy_Console_t::endPort() { _mainSerial.endPort(); delay(10); diff --git a/src/src/ESPEasyCore/ESPEasy_Console_single_serial.cpp b/src/src/ESPEasyCore/ESPEasy_Console_single_serial.cpp index 6b88fb81c3..584687c283 100644 --- a/src/src/ESPEasyCore/ESPEasy_Console_single_serial.cpp +++ b/src/src/ESPEasyCore/ESPEasy_Console_single_serial.cpp @@ -39,18 +39,6 @@ EspEasy_Console_t::EspEasy_Console_t() : */ # endif // if USES_USBCDC -# ifdef ESP8266 - constexpr size_t buffSize = 256; -# endif // ifdef ESP8266 -# ifdef ESP32 - - // Ideal buffer size is a trade-off between bootspeed - // and not missing data when the ESP is busy processing stuff. - // Since we do have a separate buffer in the console, - // it may just take less time in the background tasks to dump - // any logs as larger chunks can be transferred at once. - constexpr size_t buffSize = 512; -# endif // ifdef ESP32 ESPEasySerialConfig config; config.port = static_cast(DEFAULT_CONSOLE_PORT); @@ -59,44 +47,37 @@ EspEasy_Console_t::EspEasy_Console_t() : config.transmitPin = DEFAULT_CONSOLE_PORT_TXPIN; config.inverse_logic = false; config.rxBuffSize = 256; - config.txBuffSize = buffSize; + config.txBuffSize = ESPEASY_CONSOLE_TX_BUFFSIZE; _mainSerial.updateSerialPort(config); } void EspEasy_Console_t::reInit() { -# ifdef ESP8266 - constexpr size_t buffSize = 256; -# endif // ifdef ESP8266 -# ifdef ESP32 - - // Ideal buffer size is a trade-off between bootspeed - // and not missing data when the ESP is busy processing stuff. - // Since we do have a separate buffer in the console, - // it may just take less time in the background tasks to dump - // any logs as larger chunks can be transferred at once. - constexpr size_t buffSize = 512; -# endif // ifdef ESP32 - ESPEasySerialConfig config; + config.port = static_cast(Settings.console_serial_port); config.baud = Settings.BaudRate; config.receivePin = Settings.console_serial_rxpin; config.transmitPin = Settings.console_serial_txpin; config.inverse_logic = false; config.rxBuffSize = 256; - config.txBuffSize = buffSize; + config.txBuffSize = ESPEASY_CONSOLE_TX_BUFFSIZE; _mainSerial.updateSerialPort(config); } -void EspEasy_Console_t::begin(uint32_t baudrate) { _mainSerial.begin(baudrate); } +void EspEasy_Console_t::begin(uint32_t baudrate) { + _mainSerial.begin(baudrate); +# ifndef BUILD_NO_DEBUG + + if (_mainSerial._serial != nullptr) { + addLog(LOG_LEVEL_INFO, F("ESPEasy console enabled")); + } +# endif // ifndef BUILD_NO_DEBUG +} void EspEasy_Console_t::init() { -# if FEATURE_IMPROV - _mainSerial._improv.init(); -# endif // if FEATURE_IMPROV updateActiveTaskUseSerial0(); if (!Settings.UseSerial) { @@ -112,28 +93,13 @@ void EspEasy_Console_t::loop() START_TIMER; - const bool consoleUsesSerial0 = - (_mainSerial.getPortType() == ESPEasySerialPort::serial0 -# ifdef ESP8266 - || _mainSerial.getPortType() == ESPEasySerialPort::serial0_swap -# endif // ifdef ESP8266 - ); - - if (handledByPluginSerialIn()) - { - // Any serial0 data is already dealt with - if (!consoleUsesSerial0 && (_mainSerial._serial != nullptr)) { - _mainSerial.readInput(); - } - return; - } - _mainSerial.readInput(); STOP_TIMER(CONSOLE_LOOP); } bool EspEasy_Console_t::process_serialWriteBuffer() { +# if FEATURE_TIMING_STATS START_TIMER; bool res = false; @@ -141,11 +107,12 @@ bool EspEasy_Console_t::process_serialWriteBuffer() { res = true; } -# if FEATURE_TIMING_STATS - if (res) { STOP_TIMER(CONSOLE_WRITE_SERIAL); } -# endif // if FEATURE_TIMING_STATS return res; + +# else // if FEATURE_TIMING_STATS + return _mainSerial.process_serialWriteBuffer(); +# endif // if FEATURE_TIMING_STATS } void EspEasy_Console_t::setDebugOutput(bool enable) @@ -162,22 +129,6 @@ String EspEasy_Console_t::getPortDescription() const return _mainSerial.getPortDescription(); } -bool EspEasy_Console_t::handledByPluginSerialIn() -{ - if ((_mainSerial._serial != nullptr) && _mainSerial._serial->available() && - (_mainSerial.getPortType() == ESPEasySerialPort::serial0 -# ifdef ESP8266 - || _mainSerial.getPortType() == ESPEasySerialPort::serial0_swap -# endif // ifdef ESP8266 - )) - { - String dummy; - - return PluginCall(PLUGIN_SERIAL_IN, 0, dummy); - } - return false; -} - ESPeasySerial * EspEasy_Console_t::getPort() { if (_mainSerial._serial != nullptr) { From 50c52c3b9525796a716f54326ea1b2f5726bc7bb Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 19 Jul 2026 22:50:51 +0200 Subject: [PATCH 5/8] [ESPEasy console] reduce load when USB HWCDC is not connected --- .../Port_ESPEasySerial_USB_HWCDC.cpp | 31 ++++++++++++++----- .../Port_ESPEasySerial_USB_HWCDC.h | 3 ++ src/src/ESPEasyCore/ESPEasy_Console_Port.cpp | 28 +++++++++++------ .../ESPEasy_Console_serial0_only.cpp | 14 ++++----- .../ESPEasy_Console_single_serial.cpp | 7 ++--- 5 files changed, 54 insertions(+), 29 deletions(-) diff --git a/lib/ESPEasySerial/Port_ESPEasySerial_USB_HWCDC.cpp b/lib/ESPEasySerial/Port_ESPEasySerial_USB_HWCDC.cpp index 69da8b25f1..af89084794 100644 --- a/lib/ESPEasySerial/Port_ESPEasySerial_USB_HWCDC.cpp +++ b/lib/ESPEasySerial/Port_ESPEasySerial_USB_HWCDC.cpp @@ -48,6 +48,20 @@ static void hwcdcEventCallback(void *arg, esp_event_base_t event_base, int32_t e } } +bool Port_ESPEasySerial_USB_HWCDC_t::isConnected() const +{ + static bool connected_cache{}; + static uint32_t lastChecked{}; + if (!connected_cache) { + const int32_t timePassedSince = (int32_t) (millis() - lastChecked); + if (timePassedSince < 1000) return false; + lastChecked = millis(); + } + connected_cache = _hwcdc_serial != nullptr && _hwcdc_serial->isConnected(); + return connected_cache; +} + + Port_ESPEasySerial_USB_HWCDC_t::Port_ESPEasySerial_USB_HWCDC_t(const ESPEasySerialConfig& config) # if ARDUINO_USB_CDC_ON_BOOT // Serial used for USB CDC @@ -71,7 +85,7 @@ Port_ESPEasySerial_USB_HWCDC_t::Port_ESPEasySerial_USB_HWCDC_t(const ESPEasySeri // _hwcdc_serial->begin(); - // _hwcdc_serial->onEvent(hwcdcEventCallback); + // _hwcdc_serial->onEvent(hwcdcEventCallback); } } @@ -106,7 +120,7 @@ void Port_ESPEasySerial_USB_HWCDC_t::end() { int Port_ESPEasySerial_USB_HWCDC_t::available(void) { - if (_hwcdc_serial != nullptr && _hwcdc_serial->isConnected()) { + if (isConnected()) { return _hwcdc_serial->available(); } return 0; @@ -114,7 +128,7 @@ int Port_ESPEasySerial_USB_HWCDC_t::available(void) int Port_ESPEasySerial_USB_HWCDC_t::availableForWrite(void) { - if (_hwcdc_serial != nullptr && _hwcdc_serial->isConnected()) { + if (isConnected()) { return _hwcdc_serial->availableForWrite(); } return 0; @@ -122,7 +136,7 @@ int Port_ESPEasySerial_USB_HWCDC_t::availableForWrite(void) int Port_ESPEasySerial_USB_HWCDC_t::peek(void) { - if (_hwcdc_serial != nullptr && _hwcdc_serial->isConnected()) { + if (isConnected()) { return _hwcdc_serial->peek(); } return 0; @@ -130,7 +144,7 @@ int Port_ESPEasySerial_USB_HWCDC_t::peek(void) int Port_ESPEasySerial_USB_HWCDC_t::read(void) { - if (_hwcdc_serial != nullptr && _hwcdc_serial->isConnected()) { + if (isConnected()) { return _hwcdc_serial->read(); } return 0; @@ -139,7 +153,7 @@ int Port_ESPEasySerial_USB_HWCDC_t::read(void) size_t Port_ESPEasySerial_USB_HWCDC_t::read(uint8_t *buffer, size_t size) { - if (_hwcdc_serial != nullptr && _hwcdc_serial->isConnected()) { + if (isConnected()) { return _hwcdc_serial->read(buffer, size); } return 0; @@ -147,7 +161,7 @@ size_t Port_ESPEasySerial_USB_HWCDC_t::read(uint8_t *buffer, void Port_ESPEasySerial_USB_HWCDC_t::flush(void) { - if (_hwcdc_serial != nullptr && _hwcdc_serial->isConnected()) { + if (isConnected()) { return _hwcdc_serial->flush(); } } @@ -176,7 +190,7 @@ size_t Port_ESPEasySerial_USB_HWCDC_t::write(const uint8_t *buffer, Port_ESPEasySerial_USB_HWCDC_t::operator bool() const { - if (_hwcdc_serial != nullptr && _hwcdc_serial->isConnected()) { + if (isConnected()) { // return usbActive; return true; } @@ -212,4 +226,5 @@ bool Port_ESPEasySerial_USB_HWCDC_t::setRS485Mode(int8_t rtsPin, bool enableColl return false; } + #endif // if USES_HWCDC diff --git a/lib/ESPEasySerial/Port_ESPEasySerial_USB_HWCDC.h b/lib/ESPEasySerial/Port_ESPEasySerial_USB_HWCDC.h index 7de5565a5c..fa9fff5f73 100644 --- a/lib/ESPEasySerial/Port_ESPEasySerial_USB_HWCDC.h +++ b/lib/ESPEasySerial/Port_ESPEasySerial_USB_HWCDC.h @@ -43,6 +43,9 @@ class Port_ESPEasySerial_USB_HWCDC_t : public Port_ESPEasySerial_base { bool setRS485Mode(int8_t rtsPin, bool enableCollisionDetection = false); private: + + bool isConnected() const; + #if !ARDUINO_USB_CDC_ON_BOOT HWCDC myUsbSerial; #endif diff --git a/src/src/ESPEasyCore/ESPEasy_Console_Port.cpp b/src/src/ESPEasyCore/ESPEasy_Console_Port.cpp index d748d56a87..40f6826076 100644 --- a/src/src/ESPEasyCore/ESPEasy_Console_Port.cpp +++ b/src/src/ESPEasyCore/ESPEasy_Console_Port.cpp @@ -217,6 +217,7 @@ ESPEasySerialPort EspEasy_Console_Port::getPortType() const bool EspEasy_Console_Port::process_serialWriteBuffer() { + if (_serialWriteBuffer.getNrMessages() == 0) { return false; } if (_serial == nullptr) { return false; } #ifdef ESP32 @@ -234,35 +235,44 @@ bool EspEasy_Console_Port::process_serialWriteBuffer() PrintToString str; str.reserve(CONSOLE_MAX_WRITE_CHUNKSIZE); + size_t totalWritten = 0; + do { - if (availableForWrite == 0) { return false; } + if (availableForWrite == 0) { return totalWritten > 0; } if (availableForWrite == 1) { // For only a single byte, just write it directly - return _serialWriteBuffer.process(_serial, availableForWrite); + if (_serialWriteBuffer.process(_serial, availableForWrite)) { + ++totalWritten; + } + + return totalWritten > 0; } - size_t chunkSize = availableForWrite; + const size_t chunkSize = availableForWrite > CONSOLE_MAX_WRITE_CHUNKSIZE + ? CONSOLE_MAX_WRITE_CHUNKSIZE + : availableForWrite; - if (chunkSize > CONSOLE_MAX_WRITE_CHUNKSIZE) { - chunkSize = CONSOLE_MAX_WRITE_CHUNKSIZE; - } availableForWrite -= chunkSize; if (!_serialWriteBuffer.process(&str, chunkSize)) { // Nothing left to write - return false; + return totalWritten > 0; } - if (_serial->write(str.get().c_str(), str.length()) < chunkSize) { + const size_t lastWritten = _serial->write(str.get().c_str(), str.length()); + + totalWritten += lastWritten; + + if (lastWritten < chunkSize) { // Try to end on a full log line to lower the chance of SDK debug logs // interfering with console output. ++nrLinesWritten; } str.clear(); } while (availableForWrite > 0 && nrLinesWritten < 3); - return true; + return totalWritten > 0; } bool EspEasy_Console_Port::process_consoleInput(uint8_t SerialInByte) diff --git a/src/src/ESPEasyCore/ESPEasy_Console_serial0_only.cpp b/src/src/ESPEasyCore/ESPEasy_Console_serial0_only.cpp index fa56f44cf7..ac18b3069d 100644 --- a/src/src/ESPEasyCore/ESPEasy_Console_serial0_only.cpp +++ b/src/src/ESPEasyCore/ESPEasy_Console_serial0_only.cpp @@ -74,21 +74,19 @@ void EspEasy_Console_t::loop() } bool EspEasy_Console_t::process_serialWriteBuffer() { - -# if FEATURE_TIMING_STATS +# if FEATURE_TIMING_STATS START_TIMER; - bool res = false; if (_mainSerial.process_serialWriteBuffer()) { - res = true; + STOP_TIMER(CONSOLE_WRITE_SERIAL); + return true; } - if (res) { STOP_TIMER(CONSOLE_WRITE_SERIAL); } - return res; + return false; -# else // if FEATURE_TIMING_STATS +# else // if FEATURE_TIMING_STATS return _mainSerial.process_serialWriteBuffer(); -# endif // if FEATURE_TIMING_STATS +# endif // if FEATURE_TIMING_STATS } void EspEasy_Console_t::setDebugOutput(bool enable) diff --git a/src/src/ESPEasyCore/ESPEasy_Console_single_serial.cpp b/src/src/ESPEasyCore/ESPEasy_Console_single_serial.cpp index 584687c283..7f474cb633 100644 --- a/src/src/ESPEasyCore/ESPEasy_Console_single_serial.cpp +++ b/src/src/ESPEasyCore/ESPEasy_Console_single_serial.cpp @@ -101,14 +101,13 @@ void EspEasy_Console_t::loop() bool EspEasy_Console_t::process_serialWriteBuffer() { # if FEATURE_TIMING_STATS START_TIMER; - bool res = false; if (_mainSerial.process_serialWriteBuffer()) { - res = true; + STOP_TIMER(CONSOLE_WRITE_SERIAL); + return true; } - if (res) { STOP_TIMER(CONSOLE_WRITE_SERIAL); } - return res; + return false; # else // if FEATURE_TIMING_STATS return _mainSerial.process_serialWriteBuffer(); From 406a62421fa36d1438896373df3622f1e7bb65e4 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 20 Jul 2026 22:55:00 +0200 Subject: [PATCH 6/8] [Console] Prevent long delay when USB-HWCDC is plugged but not used --- .../Port_ESPEasySerial_USB_HWCDC.cpp | 10 +-- src/src/ESPEasyCore/ESPEasy_Console_Port.cpp | 63 ++++++++++++------- 2 files changed, 45 insertions(+), 28 deletions(-) diff --git a/lib/ESPEasySerial/Port_ESPEasySerial_USB_HWCDC.cpp b/lib/ESPEasySerial/Port_ESPEasySerial_USB_HWCDC.cpp index af89084794..957b16d4b3 100644 --- a/lib/ESPEasySerial/Port_ESPEasySerial_USB_HWCDC.cpp +++ b/lib/ESPEasySerial/Port_ESPEasySerial_USB_HWCDC.cpp @@ -162,7 +162,7 @@ size_t Port_ESPEasySerial_USB_HWCDC_t::read(uint8_t *buffer, void Port_ESPEasySerial_USB_HWCDC_t::flush(void) { if (isConnected()) { - return _hwcdc_serial->flush(); + _hwcdc_serial->flush(); } } @@ -190,16 +190,12 @@ size_t Port_ESPEasySerial_USB_HWCDC_t::write(const uint8_t *buffer, Port_ESPEasySerial_USB_HWCDC_t::operator bool() const { - if (isConnected()) { - // return usbActive; - return true; - } - return false; + return _hwcdc_serial != nullptr && _hwcdc_serial->isPlugged(); } void Port_ESPEasySerial_USB_HWCDC_t::setDebugOutput(bool enabled) { if (_hwcdc_serial != nullptr) { - return _hwcdc_serial->setDebugOutput(enabled); + _hwcdc_serial->setDebugOutput(enabled); } } diff --git a/src/src/ESPEasyCore/ESPEasy_Console_Port.cpp b/src/src/ESPEasyCore/ESPEasy_Console_Port.cpp index 40f6826076..e8d6e077fd 100644 --- a/src/src/ESPEasyCore/ESPEasy_Console_Port.cpp +++ b/src/src/ESPEasyCore/ESPEasy_Console_Port.cpp @@ -117,25 +117,28 @@ void EspEasy_Console_Port::begin(uint32_t baudrate) updateActiveTaskUseSerial0(); if (_serial != nullptr) { - #if FEATURE_IMPROV +#if FEATURE_IMPROV _improv.init(); - #endif +#endif _serial->begin(baudrate); #if FEATURE_DEFINE_SERIAL_CONSOLE_PORT _config.baud = baudrate; #endif + _serial->flush(); #ifdef ESP32 // Allow to flush data from the serial buffers // When not opening the USB serial port, the ESP may hang at boot. - delay(10); - _serial->end(); - delay(10); - _serial->begin(baudrate); - _serial->flush(); + /* + delay(10); + _serial->end(); + delay(10); + _serial->begin(baudrate); + _serial->flush(); + */ # if FEATURE_DEFINE_SERIAL_CONSOLE_PORT @@ -202,15 +205,15 @@ void EspEasy_Console_Port::readInput() ESPEasySerialPort EspEasy_Console_Port::getPortType() const { - # if FEATURE_DEFINE_SERIAL_CONSOLE_PORT +# if FEATURE_DEFINE_SERIAL_CONSOLE_PORT if (_serial == nullptr) { return ESPEasySerialPort::not_set; } return _config.port; - # else // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT +# else // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT // TODO TD-er: Should I also try to see if we're using serial0_swapped? return ESPEasySerialPort::serial0; - # endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT +# endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT } #endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT @@ -218,6 +221,7 @@ ESPEasySerialPort EspEasy_Console_Port::getPortType() const bool EspEasy_Console_Port::process_serialWriteBuffer() { if (_serialWriteBuffer.getNrMessages() == 0) { return false; } + if (_serial == nullptr) { return false; } #ifdef ESP32 @@ -251,8 +255,8 @@ bool EspEasy_Console_Port::process_serialWriteBuffer() } const size_t chunkSize = availableForWrite > CONSOLE_MAX_WRITE_CHUNKSIZE - ? CONSOLE_MAX_WRITE_CHUNKSIZE - : availableForWrite; +? CONSOLE_MAX_WRITE_CHUNKSIZE +: availableForWrite; availableForWrite -= chunkSize; @@ -317,13 +321,13 @@ bool EspEasy_Console_Port::process_consoleInput(uint8_t SerialInByte) String EspEasy_Console_Port::getPortDescription() const { if (_serial != nullptr) { - #if FEATURE_DEFINE_SERIAL_CONSOLE_PORT +#if FEATURE_DEFINE_SERIAL_CONSOLE_PORT return _serial->getPortDescription(); - #else // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT +#else // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT String res = F("HW Serial0 @ "); res += _serial->baudRate(); return res; - #endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT +#endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT } return F("-"); @@ -364,15 +368,32 @@ bool EspEasy_Console_Port::updateSerialPort( } if ((_serial == nullptr) && mustHaveSerial) { - # ifdef USE_SECOND_HEAP - HeapSelectDram ephemeral; - # endif // ifdef USE_SECOND_HEAP - { - # ifdef USE_SECOND_HEAP +# ifdef USE_SECOND_HEAP HeapSelectDram ephemeral; - # endif // ifdef USE_SECOND_HEAP +# endif // ifdef USE_SECOND_HEAP _serial = new (std::nothrow) ESPeasySerial(_config); + +# if USES_HWCDC + + // Check to see if the port is plugged. + // If not, we can remove it again and save resources. + if ((_config.port == ESPEasySerialPort::usb_hw_cdc) && (_serial != nullptr)) { + bool isPlugged{}; + + for (uint32_t i = 0; !isPlugged && i < 5; i++) { + isPlugged = _serial->operator bool(); + delay(50); + } + + if (!isPlugged) { + delete _serial; + _serial = nullptr; + } + } + +# endif // if USES_HWCDC + } somethingChanged = true; From 450ecb3116881bfc53e4a5db70affec2895a796d Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 20 Jul 2026 22:55:24 +0200 Subject: [PATCH 7/8] [Docs] Add ESP32-S31 datasheet to docs --- docs/source/ESPEasy/ESPchips.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/ESPEasy/ESPchips.rst b/docs/source/ESPEasy/ESPchips.rst index c1b7336950..287bad3196 100644 --- a/docs/source/ESPEasy/ESPchips.rst +++ b/docs/source/ESPEasy/ESPchips.rst @@ -679,6 +679,7 @@ Datasheets * `DS:ESP32 `_ * `DS:ESP32-S2 `_ * `DS:ESP32-S3 `_ +* `DS:ESP32-S31 `_ * `DS:ESP32-C2 `_ * `DS:ESP32-C3 `_ * `DS:ESP32-C5 `_ From d80bea94673b07576836e7344275fff9684e4938 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 20 Jul 2026 23:10:19 +0200 Subject: [PATCH 8/8] [Serial] Fix failing custom_IR_ESP8266_4M1M build --- src/src/Helpers/_Plugin_Helper_serial.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/src/Helpers/_Plugin_Helper_serial.cpp b/src/src/Helpers/_Plugin_Helper_serial.cpp index 556435a557..cf33635a48 100644 --- a/src/src/Helpers/_Plugin_Helper_serial.cpp +++ b/src/src/Helpers/_Plugin_Helper_serial.cpp @@ -294,9 +294,6 @@ void serialHelper_webformLoad(ESPEasySerialPort port, true); #endif // ifdef ESP32 - #if !USES_SW_SERIAL - allowSoftwareSerial = false; - #endif const int ids[] = { static_cast(ESPEasySerialPort::not_set) @@ -369,9 +366,11 @@ void serialHelper_webformLoad(ESPEasySerialPort port, if (!(allowedSerial & INCLUDE_HW_SERIAL) && isHWserial(serType)) { attr[i] = F("disabled"); } +#if USES_SW_SERIAL if (!(allowedSerial & INCLUDE_SW_SERIAL) && (serType == ESPEasySerialPort::software)) { attr[i] = F("disabled"); } +#endif #if USES_I2C_SC16IS752 if (!(allowedSerial & INCLUDE_I2C_SERIAL) && (serType == ESPEasySerialPort::sc16is752)) { attr[i] = F("disabled");