[Serial] Simplify ESPEasy console code + reduce resource usage

This commit is contained in:
TD-er
2026-07-19 17:06:59 +02:00
parent 759285e9bd
commit 39f43f14f8
7 changed files with 189 additions and 210 deletions
@@ -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
+27 -14
View File
@@ -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 @@ public:
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 @@ private:
#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
+94 -33
View File
@@ -13,9 +13,12 @@
#include "../Helpers/Memory.h"
#include "../Helpers/StringConverter.h"
#include <ESPEasySerialPort.h>
#if FEATURE_DEFINE_SERIAL_CONSOLE_PORT
# include <ESPEasySerialPort.h>
# ifdef ESP32
# include <esp32-hal-periman.h>
# 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; }
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;
}
size_t nrLinesWritten = 0;
PrintToString str;
str.reserve(availableForWrite);
str.reserve(CONSOLE_MAX_WRITE_CHUNKSIZE);
if (!_serialWriteBuffer.process(&str, availableForWrite)) {
return false;
}
_serial->write(str.get().c_str(), str.length());
do
{
if (availableForWrite == 0) { return false; }
if (availableForWrite == 1) {
// For only a single byte, just write it directly
return _serialWriteBuffer.process(_serial, availableForWrite);
}
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) {
+18 -16
View File
@@ -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 @@ public:
Improv_Helper_t _improv;
#endif
#endif // if FEATURE_IMPROV
};
#endif
#endif // ifndef ESPEASYCORE_ESPEASY_CONSOLE_PORT_H
@@ -22,10 +22,6 @@
# include <ESPEasySerialPort.h>
# ifdef ESP32
# include <esp32-hal-periman.h>
# 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");
addLog(LOG_LEVEL_INFO, F("ESPEasy console fallback enabled"));
if (_mainSerial._serial != nullptr) {
addLog(LOG_LEVEL_INFO, F("ESPEasy console 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) {
@@ -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;
HardwareSerial * EspEasy_Console_t::getPort() { return _mainSerial._serial; }
return PluginCall(PLUGIN_SERIAL_IN, 0, dummy);
}
HardwareSerial * EspEasy_Console_t::getPort()
{
if (_mainSerial._serial != nullptr) {
return _mainSerial._serial;
}
return nullptr;
}
void EspEasy_Console_t::endPort()
void EspEasy_Console_t::endPort()
{
_mainSerial.endPort();
delay(10);
@@ -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<ESPEasySerialPort>(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<ESPEasySerialPort>(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) {