From f71ca3e0a251acb1adcdb900aa6e4e3bc6aa4a53 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 23 Mar 2025 17:34:44 +0100 Subject: [PATCH] Fix ESP32 telnet response --- tasmota/include/tasmota_globals.h | 5 +- tasmota/tasmota_support/support.ino | 24 ++++-- .../xdrv_08_serial_bridge.ino | 49 ++++++++---- .../xdrv_52_3_berry_tasmota.ino | 5 +- .../tasmota_xdrv_driver/xdrv_78_telnet.ino | 78 +++++++++++++------ 5 files changed, 113 insertions(+), 48 deletions(-) diff --git a/tasmota/include/tasmota_globals.h b/tasmota/include/tasmota_globals.h index 7c02d9f7f..4d2603e66 100644 --- a/tasmota/include/tasmota_globals.h +++ b/tasmota/include/tasmota_globals.h @@ -47,8 +47,11 @@ extern "C" int startWaveformClockCycles(uint8_t pin, uint32_t highCcys, uint32_t uint32_t runTimeCcys, int8_t alignPhase, uint32_t phaseOffsetCcys, bool autoPwm); extern "C" void setTimer1Callback(uint32_t (*fn)()); #ifdef USE_SERIAL_BRIDGE -void SerialBridgePrintf(PGM_P formatP, ...); +void SerialBridgeWrite(char *line, uint32_t len); #endif +#ifdef USE_TELNET +void TelnetWrite(char *line, uint32_t len); +#endif // USE_TELNET #ifdef USE_INFLUXDB void InfluxDbProcess(bool use_copy = false); #endif diff --git a/tasmota/tasmota_support/support.ino b/tasmota/tasmota_support/support.ino index 38de49991..1e9195600 100755 --- a/tasmota/tasmota_support/support.ino +++ b/tasmota/tasmota_support/support.ino @@ -2656,9 +2656,6 @@ void AddLogData(uint32_t loglevel, const char* log_data, const char* log_data_pa if ((loglevel <= TasmotaGlobal.seriallog_level) && (TasmotaGlobal.masterlog_level <= TasmotaGlobal.seriallog_level)) { TasConsole.printf("%s%s%s%s\r\n", mxtime, log_data, log_data_payload, log_data_retained); -#ifdef USE_SERIAL_BRIDGE - SerialBridgePrintf("%s%s%s%s\r\n", mxtime, log_data, log_data_payload, log_data_retained); -#endif // USE_SERIAL_BRIDGE } if (!TasmotaGlobal.log_buffer) { return; } // Leave now if there is no buffer available @@ -2680,27 +2677,40 @@ void AddLogData(uint32_t loglevel, const char* log_data, const char* log_data_pa log_data_payload = empty; log_data_retained = empty; } + log_data_len = strlen(mxtime) + strlen(log_data) + strlen(log_data_payload) + strlen(log_data_retained); TasmotaGlobal.log_buffer_pointer &= 0xFF; if (!TasmotaGlobal.log_buffer_pointer) { TasmotaGlobal.log_buffer_pointer++; // Index 0 is not allowed as it is the end of char string } while (TasmotaGlobal.log_buffer_pointer == TasmotaGlobal.log_buffer[0] || // If log already holds the next index, remove it - strlen(TasmotaGlobal.log_buffer) + strlen(log_data) + strlen(log_data_payload) + strlen(log_data_retained) + strlen(mxtime) + 4 > LOG_BUFFER_SIZE) // 4 = log_buffer_pointer + '\1' + '\0' - { + strlen(TasmotaGlobal.log_buffer) + log_data_len +4 > LOG_BUFFER_SIZE) { // 4 = log_buffer_pointer + '\1' + '\0' char* it = TasmotaGlobal.log_buffer; it++; // Skip log_buffer_pointer it += strchrspn(it, '\1'); // Skip log line it++; // Skip delimiting "\1" memmove(TasmotaGlobal.log_buffer, it, LOG_BUFFER_SIZE -(it-TasmotaGlobal.log_buffer)); // Move buffer forward to remove oldest log line } - snprintf_P(TasmotaGlobal.log_buffer, LOG_BUFFER_SIZE, PSTR("%s%c%c%s%s%s%s\1"), - TasmotaGlobal.log_buffer, TasmotaGlobal.log_buffer_pointer++, '0'+loglevel, mxtime, log_data, log_data_payload, log_data_retained); + char *log_line = TasmotaGlobal.log_buffer + strlen(TasmotaGlobal.log_buffer); // Ponter to next entry + snprintf_P(log_line, log_data_len +4, PSTR("%c%c%s%s%s%s\1"), + TasmotaGlobal.log_buffer_pointer++, '0'+loglevel, mxtime, log_data, log_data_payload, log_data_retained); if (too_long) { free(too_long); } TasmotaGlobal.log_buffer_pointer &= 0xFF; if (!TasmotaGlobal.log_buffer_pointer) { TasmotaGlobal.log_buffer_pointer++; // Index 0 is not allowed as it is the end of char string } + + // These calls fail to show initial logging + log_line += 2; // Skip log_buffer_pointer and loglevel +#ifdef USE_SERIAL_BRIDGE + SerialBridgeWrite(log_line, log_data_len); +#endif // USE_SERIAL_BRIDGE +#ifdef USE_TELNET +#ifdef ESP32 + TelnetWrite(log_line, log_data_len); // This uses too much heap on ESP8266 +#endif // ESP32 +#endif // USE_TELNET + } } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_08_serial_bridge.ino b/tasmota/tasmota_xdrv_driver/xdrv_08_serial_bridge.ino index 0e6bbf279..783ca8fd8 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_08_serial_bridge.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_08_serial_bridge.ino @@ -80,6 +80,7 @@ struct { uint32_t polling_window; int in_byte_counter = 0; float temperature; + uint8_t log_index; bool raw = false; } SBridge; @@ -99,31 +100,51 @@ void SetSSerialConfig(uint32_t serial_config) { } } -void SerialBridgePrintf(PGM_P formatP, ...) { +void SerialBridgeWrite(char *line, uint32_t len) { #ifdef USE_SERIAL_BRIDGE_TEE if ((SB_TEE == Settings->sserial_mode) && serial_bridge_buffer) { - va_list arg; - va_start(arg, formatP); - char* data = ext_vsnprintf_malloc_P(formatP, arg); - va_end(arg); - if (data == nullptr) { return; } - -// SerialBridgeSerial->printf(data); // This resolves "MqttClientMask":"DVES_%06X" into "DVES_000002" - SerialBridgeSerial->print(data); // This does not resolve "DVES_%06X" - free(data); + if (0 == SBridge.log_index) { +// SerialBridgeSerial->write("\r\n"); + SerialBridgeGetLog(); + } else { + SerialBridgeSerial->write(line, len); // This does not resolve "DVES_%06X" + SerialBridgeSerial->write("\r\n"); + } } #endif // USE_SERIAL_BRIDGE_TEE } +#ifdef USE_SERIAL_BRIDGE_TEE +bool SerialBridgeGetLog(void) { + bool any_line = false; + if (SB_TEE == Settings->sserial_mode) { + uint32_t index = SBridge.log_index; // Dump log buffer + char* line; + size_t len; + while (GetLog(TasmotaGlobal.seriallog_level, &index, &line, &len)) { + any_line = true; + SBridge.log_index = index; + SerialBridgeWrite(line, len -1); // This does not resolve "DVES_%06X" + } + } + return any_line; +} +#endif // USE_SERIAL_BRIDGE_TEE + /********************************************************************************************/ -void SerialBridgeInput(void) { +void SerialBridgeLoop(void) { +/* +#ifdef USE_SERIAL_BRIDGE_TEE + if (SerialBridgeGetLog()) { return; } +#endif // USE_SERIAL_BRIDGE_TEE +*/ while (SerialBridgeSerial->available()) { yield(); uint8_t serial_in_byte = SerialBridgeSerial->read(); #ifdef USE_SERIAL_BRIDGE_TEE - if (SB_TEE == Settings->sserial_mode) { // CMND_SSERIALSEND9 - Enable logging tee to serialbridge + if (SB_TEE == Settings->sserial_mode) { // CMND_SSERIALSEND9 - Enable logging tee to serialbridge static bool serial_bridge_overrun = false; if (isprint(serial_in_byte)) { // Any char between 32 and 127 @@ -274,7 +295,7 @@ void SerialBridgeInit(void) { AddLog(LOG_LEVEL_DEBUG, PSTR("SBR: Serial UART%d"), SerialBridgeSerial->getUart()); #endif SerialBridgeSerial->flush(); - SerialBridgePrintf("\r\n"); +// SerialBridgeWrite((char*)"", 0); } } } @@ -456,7 +477,7 @@ bool Xdrv08(uint32_t function) { switch (function) { case FUNC_LOOP: case FUNC_SLEEP_LOOP: - SerialBridgeInput(); + SerialBridgeLoop(); break; case FUNC_JSON_APPEND: SerialBridgeShow(1); diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino index 08d160b99..0cd9c964c 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino @@ -1089,8 +1089,11 @@ extern "C" { if (len+3 > LOGSZ) { strcat(log_data, "..."); } // Actual data is more TasConsole.printf(log_data); #ifdef USE_SERIAL_BRIDGE - SerialBridgePrintf(log_data); + SerialBridgeWrite(log_data, strlen(log_data)); #endif // USE_SERIAL_BRIDGE +#ifdef USE_TELNET + TelnetWrite(log_data, strlen(log_data)); +#endif // USE_TELNET } void berry_log_C(const char * berry_buf, ...) { diff --git a/tasmota/tasmota_xdrv_driver/xdrv_78_telnet.ino b/tasmota/tasmota_xdrv_driver/xdrv_78_telnet.ino index 8d710d710..269b656f4 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_78_telnet.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_78_telnet.ino @@ -71,6 +71,33 @@ struct { /********************************************************************************************/ +void TelnetWrite(char *line, uint32_t len) { + if (Telnet.client) { + if (3 == Telnet.prompt) { // Print linefeed for non-requested data + Telnet.prompt = 2; // Do not print linefeed for any data and use log color + Telnet.client.write("\r\n"); + } + // line = 14:49:36.123-017 MQTT: stat/wemos5/RESULT = {"POWER":"OFF"} + uint32_t textcolor = Telnet.color[Telnet.prompt]; + uint32_t diffcolor = textcolor; + if ((textcolor >= 30) && (textcolor <= 37)) { + diffcolor += 60; // Highlight color + } + else if ((textcolor >= 90) && (textcolor <= 97)) { + diffcolor -= 60; // Lowlight color + } + char* time_end = (char*)memchr(line, ' ', len); // Find first word (usually 14:49:36.123-017) + uint32_t time_len = time_end - line; + Telnet.client.printf("\x1b[%dm", diffcolor); + Telnet.client.write(line, time_len); + Telnet.client.printf("\x1b[%dm", textcolor); + Telnet.client.write(time_end, len - time_len -1); + Telnet.client.write("\x1b[0m\r\n"); // Restore colors + } +} + +/********************************************************************************************/ + void TelnetLoop(void) { // check for a new client connection if ((Telnet.server) && (Telnet.server->hasClient())) { @@ -91,44 +118,40 @@ void TelnetLoop(void) { Telnet.client = new_client; if (Telnet.client) { Telnet.client.printf("Tasmota %s %s (%s) %s\r\n", TasmotaGlobal.hostname, TasmotaGlobal.version, GetBuildDateAndTime().c_str(), GetDeviceHardware().c_str()); - Telnet.log_index = 0; // Dump start of log buffer for restart messages Telnet.prompt = 3; +#ifdef ESP32 + uint32_t index = 1; + char* line; + size_t len; + while (GetLog(TasmotaGlobal.seriallog_level, &index, &line, &len)) { + TelnetWrite(line, len -1); + } + Telnet.prompt = 0; +#else // ESP8266 + Telnet.log_index = 0; // Dump start of log buffer for restart messages +#endif // ESP32 - ESP8266 } } if (Telnet.client) { // Output latest log buffer data +#ifdef ESP32 + if (0 == Telnet.prompt) { + Telnet.client.printf("\x1b[%dm%s:#\x1b[0m ", Telnet.color[0], TasmotaGlobal.hostname); // \x1b[33m = Yellow, \x1b[0m = end color + Telnet.prompt = 3; // Print linefeed for non-requested data + while (Telnet.client.available()) { Telnet.client.read(); } // Flush input + return; + } +#else // ESP8266 uint32_t index = Telnet.log_index; // Dump log buffer char* line; size_t len; bool any_line = false; while (GetLog(TasmotaGlobal.seriallog_level, &index, &line, &len)) { - if (!any_line) { - any_line = true; - if (3 == Telnet.prompt) { // Print linefeed for non-requested data - Telnet.prompt = 2; // Do not print linefeed for any data and use log color - Telnet.client.write("\r\n"); - } - } - // line = 14:49:36.123-017 MQTT: stat/wemos5/RESULT = {"POWER":"OFF"} - uint32_t textcolor = Telnet.color[Telnet.prompt]; - uint32_t diffcolor = textcolor; - if ((textcolor >= 30) && (textcolor <= 37)) { - diffcolor += 60; // Highlight color - } - else if ((textcolor >= 90) && (textcolor <= 97)) { - diffcolor -= 60; // Lowlight color - } - char* time_end = (char*)memchr(line, ' ', len); // Find first word (usually 14:49:36.123-017) - uint32_t time_len = time_end - line; - Telnet.client.printf("\x1b[%dm", diffcolor); - Telnet.client.write(line, time_len); - Telnet.client.printf("\x1b[%dm", textcolor); - Telnet.client.write(time_end, len - time_len -1); - Telnet.client.write("\r\n"); + any_line = true; + TelnetWrite(line, len -1); } if (any_line) { - Telnet.client.write("\x1b[0m"); // Restore colors if ((0 == Telnet.log_index) || (Telnet.prompt != 2)) { Telnet.client.printf("\x1b[%dm%s:#\x1b[0m ", Telnet.color[0], TasmotaGlobal.hostname); // \x1b[33m = Yellow, \x1b[0m = end color Telnet.prompt = 3; // Print linefeed for non-requested data @@ -137,6 +160,8 @@ void TelnetLoop(void) { Telnet.log_index = index; return; } +#endif // ESP32 - ESP8266 + // Input keyboard data while (Telnet.client.available()) { yield(); @@ -158,6 +183,9 @@ void TelnetLoop(void) { ExecuteCommand(Telnet.buffer, SRC_TELNET); } Telnet.in_byte_counter = 0; +#ifdef ESP32 + Telnet.prompt = 0; // Print prompt +#endif // ESP32 return; } }