Add command ``SSerialSend9 0/1`` to enable Serial Bridge console Tee for debugging purposes

This commit is contained in:
Theo Arends 2022-06-06 17:48:40 +02:00
parent a7d7b571ee
commit 44ce19f26f
8 changed files with 169 additions and 73 deletions

View File

@ -7,9 +7,11 @@ All notable changes to this project will be documented in this file.
### Added
- Support for HYTxxx temperature and humidity sensor (#15715)
- Support for Sensirion SHT4X using define USE_SHT3X (#15349)
- Command ``SSerialSend9 0/1`` to enable Serial Bridge console Tee for debugging purposes
### Changed
- Restructured tasmota source directories taking benefit from PlatformIO Core v6.0.2
- ESP32 increase Serial Bridge input buffer from 130 to 520 characters
### Fixed

View File

@ -112,6 +112,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo
- Command ``EnergyExportActive<phase>`` to (p)reset energy export active for supported devices. Currently ADE7880 only [#13515](https://github.com/arendst/Tasmota/issues/13515)
- Command ``IfxRp ""|<policy>`` adds optional InfluxDb Retention Policy [#15513](https://github.com/arendst/Tasmota/issues/15513)
- Command ``SspmDisplay 2`` to display Sonoff SPM energy data in GUI for user tab-selected relay modules [#13447](https://github.com/arendst/Tasmota/issues/13447)
- Command ``SSerialSend9 0/1`` to enable Serial Bridge console Tee for debugging purposes
- Support for Sonoff MS01 soil moisture sensor [#15335](https://github.com/arendst/Tasmota/issues/15335)
- Support for daisy chaining MAX7219 displays [#15345](https://github.com/arendst/Tasmota/issues/15345)
- Support for Sensirion SHT4X using define USE_SHT3X [#15349](https://github.com/arendst/Tasmota/issues/15349)
@ -129,6 +130,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo
- Restructured tasmota source directories taking benefit from PlatformIO Core v6.0.2
- Prepare to remove dedicated Home Assistant discovery in favour of Tasmota Discovery and hatasmota
- ESP32 Tasmota SafeBoot with changed partition scheme allowing larger binaries
- ESP32 increase Serial Bridge input buffer from 130 to 520 characters
### Fixed
- Improv initial or erase device installation failing to provide Configure WiFi option

43
boards/esp32s2usb.json Normal file
View File

@ -0,0 +1,43 @@
{
"build": {
"arduino":{
"ldscript": "esp32s2_out.ld"
},
"core": "esp32",
"extra_flags": "-DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=0 -DARDUINO_USB_CDC_ON_BOOT=0 -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0 -DUSE_USB_SERIAL_CONSOLE -DESP32_4M -DESP32S2",
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "dout",
"mcu": "esp32s2",
"variant": "esp32s2",
"partitions": "partitions/esp32_partition_app2880k_fs320k.csv"
},
"connectivity": [
"wifi"
],
"debug": {
"openocd_target": "esp32s2.cfg"
},
"frameworks": [
"espidf",
"arduino"
],
"name": "Espressif Generic ESP32-S2 4M Flash, Tasmota 2880k Code/OTA, 320k FS",
"upload": {
"arduino": {
"flash_extra_images": [
[
"0x10000",
"variants/tasmota/tasmota32s2usb-safeboot.bin"
]
]
},
"flash_size": "4MB",
"maximum_ram_size": 327680,
"maximum_size": 4194304,
"require_upload_port": true,
"speed": 460800
},
"url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/hw-reference/esp32s2/user-guide-saola-1-v1.2.html",
"vendor": "Espressif"
}

View File

@ -45,6 +45,9 @@ extern "C" void custom_crash_callback(struct rst_info * rst_info, uint32_t stack
extern "C" void resetPins();
extern "C" int startWaveformClockCycles(uint8_t pin, uint32_t highCcys, uint32_t lowCcys,
uint32_t runTimeCcys, int8_t alignPhase, uint32_t phaseOffsetCcys, bool autoPwm);
#ifdef USE_SERIAL_BRIDGE
void SerialBridgeLog(const char *mxtime, const char *log_data = nullptr, const char *log_data_payload = nullptr, const char *log_data_retained = nullptr);
#endif
#ifdef USE_INFLUXDB
void InfluxDbProcess(bool use_copy = false);
#endif

View File

@ -289,7 +289,7 @@ typedef union {
uint32_t sspm_display : 1; // bit 8 (v10.0.0.4) - CMND_SSPMDISPLAY - Enable gui display of powered on relays only
uint32_t local_ntp_server : 1; // bit 9 (v11.0.0.4) - CMND_RTCNTPSERVER - Enable local NTP server
uint32_t influxdb_sensor : 1; // bit 10 (v11.0.0.5) - CMND_IFXSENSOR - Enable sensor support in addition to teleperiod support
uint32_t spare11 : 1; // bit 11
uint32_t serbridge_console : 1; // bit 11 (v11.1.0.4) - CMND_SSERIALSEND9 - Enable logging tee to serialbridge
uint32_t spare12 : 1; // bit 12
uint32_t spare13 : 1; // bit 13
uint32_t spare14 : 1; // bit 14

View File

@ -2594,6 +2594,9 @@ 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
SerialBridgeLog(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

View File

@ -1634,38 +1634,38 @@ void SerialInput(void)
/*-------------------------------------------------------------------------------------------*/
if (TasmotaGlobal.serial_in_byte > 127 && !Settings->flag.mqtt_serial_raw) { // Discard binary data above 127 if no raw reception allowed - CMND_SERIALSEND3
if (TasmotaGlobal.serial_in_byte > 127 && !Settings->flag.mqtt_serial_raw) { // Discard binary data above 127 if no raw reception allowed - CMND_SERIALSEND3
TasmotaGlobal.serial_in_byte_counter = 0;
Serial.flush();
return;
}
if (!Settings->flag.mqtt_serial) { // SerialSend active - CMND_SERIALSEND and CMND_SERIALLOG
if (isprint(TasmotaGlobal.serial_in_byte)) { // Any char between 32 and 127
if (TasmotaGlobal.serial_in_byte_counter < INPUT_BUFFER_SIZE -1) { // Add char to string if it still fits
if (!Settings->flag.mqtt_serial) { // SerialSend active - CMND_SERIALSEND and CMND_SERIALLOG
if (isprint(TasmotaGlobal.serial_in_byte)) { // Any char between 32 and 127
if (TasmotaGlobal.serial_in_byte_counter < INPUT_BUFFER_SIZE -1) { // Add char to string if it still fits
TasmotaGlobal.serial_in_buffer[TasmotaGlobal.serial_in_byte_counter++] = TasmotaGlobal.serial_in_byte;
} else {
serial_buffer_overrun = true; // Signal overrun but continue reading input to flush until '\n' (EOL)
serial_buffer_overrun = true; // Signal overrun but continue reading input to flush until '\n' (EOL)
}
}
} else {
if (TasmotaGlobal.serial_in_byte || Settings->flag.mqtt_serial_raw) { // Any char between 1 and 127 or any char (0 - 255) - CMND_SERIALSEND3
bool in_byte_is_delimiter = // Char is delimiter when...
if (TasmotaGlobal.serial_in_byte || Settings->flag.mqtt_serial_raw) { // Any char between 1 and 127 or any char (0 - 255) - CMND_SERIALSEND3
bool in_byte_is_delimiter = // Char is delimiter when...
(((Settings->serial_delimiter < 128) && (TasmotaGlobal.serial_in_byte == Settings->serial_delimiter)) || // Any char between 1 and 127 and being delimiter
((Settings->serial_delimiter == 128) && !isprint(TasmotaGlobal.serial_in_byte))) && // Any char not between 32 and 127
!Settings->flag.mqtt_serial_raw; // In raw mode (CMND_SERIALSEND3) there is never a delimiter
!Settings->flag.mqtt_serial_raw; // In raw mode (CMND_SERIALSEND3) there is never a delimiter
if ((TasmotaGlobal.serial_in_byte_counter < INPUT_BUFFER_SIZE -1) && // Add char to string if it still fits and ...
!in_byte_is_delimiter) { // Char is not a delimiter
if ((TasmotaGlobal.serial_in_byte_counter < INPUT_BUFFER_SIZE -1) && // Add char to string if it still fits and ...
!in_byte_is_delimiter) { // Char is not a delimiter
TasmotaGlobal.serial_in_buffer[TasmotaGlobal.serial_in_byte_counter++] = TasmotaGlobal.serial_in_byte;
}
if ((TasmotaGlobal.serial_in_byte_counter >= INPUT_BUFFER_SIZE -1) || // Send message when buffer is full or ...
in_byte_is_delimiter) { // Char is delimiter
serial_polling_window = 0; // Reception done - send mqtt
if ((TasmotaGlobal.serial_in_byte_counter >= INPUT_BUFFER_SIZE -1) || // Send message when buffer is full or ...
in_byte_is_delimiter) { // Char is delimiter
serial_polling_window = 0; // Reception done - send mqtt
break;
}
serial_polling_window = millis(); // Wait for next char
serial_polling_window = millis(); // Wait for next char
}
}
@ -1674,8 +1674,8 @@ void SerialInput(void)
* Sonoff SC 19200 baud serial interface
\*-------------------------------------------------------------------------------------------*/
if (SONOFF_SC == TasmotaGlobal.module_type) {
if (TasmotaGlobal.serial_in_byte == '\x1B') { // Sonoff SC status from ATMEGA328P
TasmotaGlobal.serial_in_buffer[TasmotaGlobal.serial_in_byte_counter] = 0; // Serial data completed
if (TasmotaGlobal.serial_in_byte == '\x1B') { // Sonoff SC status from ATMEGA328P
TasmotaGlobal.serial_in_buffer[TasmotaGlobal.serial_in_byte_counter] = 0; // Serial data completed
SonoffScSerialInput(TasmotaGlobal.serial_in_buffer);
TasmotaGlobal.serial_in_byte_counter = 0;
Serial.flush();
@ -1689,8 +1689,8 @@ void SerialInput(void)
if (tasconsole_serial) {
#endif // ESP32
if (!Settings->flag.mqtt_serial && (TasmotaGlobal.serial_in_byte == '\n')) { // CMND_SERIALSEND and CMND_SERIALLOG
TasmotaGlobal.serial_in_buffer[TasmotaGlobal.serial_in_byte_counter] = 0; // Serial data completed
if (!Settings->flag.mqtt_serial && (TasmotaGlobal.serial_in_byte == '\n')) { // CMND_SERIALSEND and CMND_SERIALLOG
TasmotaGlobal.serial_in_buffer[TasmotaGlobal.serial_in_byte_counter] = 0; // Serial data completed
TasmotaGlobal.seriallog_level = (Settings->seriallog_level < LOG_LEVEL_INFO) ? (uint8_t)LOG_LEVEL_INFO : Settings->seriallog_level;
if (serial_buffer_overrun) {
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_COMMAND "Serial buffer overrun"));
@ -1711,7 +1711,7 @@ void SerialInput(void)
} // endWhile
if (Settings->flag.mqtt_serial && TasmotaGlobal.serial_in_byte_counter && (millis() > (serial_polling_window + SERIAL_POLLING))) { // CMND_SERIALSEND and CMND_SERIALLOG
TasmotaGlobal.serial_in_buffer[TasmotaGlobal.serial_in_byte_counter] = 0; // Serial data completed
TasmotaGlobal.serial_in_buffer[TasmotaGlobal.serial_in_byte_counter] = 0; // Serial data completed
bool assume_json = (!Settings->flag.mqtt_serial_raw && (TasmotaGlobal.serial_in_buffer[0] == '{'));
if (serial_buffer_overrun) {
@ -1758,7 +1758,7 @@ void TasConsoleInput(void) {
console_buffer_overrun = true; // Signal overrun but continue reading input to flush until '\n' (EOL)
}
}
if (console_in_byte == '\n') {
else if (console_in_byte == '\n') {
TasmotaGlobal.seriallog_level = (Settings->seriallog_level < LOG_LEVEL_INFO) ? (uint8_t)LOG_LEVEL_INFO : Settings->seriallog_level;
if (console_buffer_overrun) {
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_COMMAND "Console buffer overrun"));

View File

@ -25,7 +25,11 @@
#define XDRV_08 8
#define HARDWARE_FALLBACK 2
const uint8_t SERIAL_BRIDGE_BUFFER_SIZE = 130;
#ifdef ESP8266
const uint16_t SERIAL_BRIDGE_BUFFER_SIZE = 130;
#else
const uint16_t SERIAL_BRIDGE_BUFFER_SIZE = INPUT_BUFFER_SIZE;
#endif
const char kSerialBridgeCommands[] PROGMEM = "|" // No prefix
D_CMND_SSERIALSEND "|" D_CMND_SBAUDRATE "|" D_CMND_SSERIALCONFIG;
@ -40,7 +44,6 @@ TasmotaSerial *SerialBridgeSerial = nullptr;
unsigned long serial_bridge_polling_window = 0;
char *serial_bridge_buffer = nullptr;
int serial_bridge_in_byte_counter = 0;
bool serial_bridge_active = true;
bool serial_bridge_raw = false;
/********************************************************************************************/
@ -59,68 +62,104 @@ void SetSSerialConfig(uint32_t serial_config) {
}
}
void SerialBridgeLog(const char *mxtime, const char *log_data, const char *log_data_payload, const char *log_data_retained) {
if (Settings->sbflag1.serbridge_console && serial_bridge_buffer) {
char empty[2] = { 0 };
if (!log_data) { log_data = empty; }
if (!log_data_payload) { log_data_payload = empty; }
if (!log_data_retained) { log_data_retained = empty; }
SerialBridgeSerial->printf("%s%s%s%s\r\n", mxtime, log_data, log_data_payload, log_data_retained);
}
}
/********************************************************************************************/
void SerialBridgeInput(void) {
while (SerialBridgeSerial->available()) {
yield();
uint8_t serial_in_byte = SerialBridgeSerial->read();
serial_bridge_raw = Settings->serial_delimiter == 254;
if ((serial_in_byte > 127) && !serial_bridge_raw) { // Discard binary data above 127 if no raw reception allowed
serial_bridge_in_byte_counter = 0;
SerialBridgeSerial->flush();
return;
}
if (serial_in_byte || serial_bridge_raw) { // Any char between 1 and 127 or any char (0 - 255)
bool in_byte_is_delimiter = // Char is delimiter when...
(((Settings->serial_delimiter < 128) && (serial_in_byte == Settings->serial_delimiter)) || // Any char between 1 and 127 and being delimiter
((Settings->serial_delimiter == 128) && !isprint(serial_in_byte))) && // Any char not between 32 and 127
!serial_bridge_raw; // In raw mode (CMND_SERIALSEND3) there is never a delimiter
if ((serial_bridge_in_byte_counter < SERIAL_BRIDGE_BUFFER_SIZE -1) && // Add char to string if it still fits and ...
!in_byte_is_delimiter) { // Char is not a delimiter
serial_bridge_buffer[serial_bridge_in_byte_counter++] = serial_in_byte;
if (Settings->sbflag1.serbridge_console) {
static bool serial_bridge_overrun = false;
if (isprint(serial_in_byte)) { // Any char between 32 and 127
if (serial_bridge_in_byte_counter < SERIAL_BRIDGE_BUFFER_SIZE -1) { // Add char to string if it still fits
serial_bridge_buffer[serial_bridge_in_byte_counter++] = serial_in_byte;
} else {
serial_bridge_overrun = true; // Signal overrun but continue reading input to flush until '\n' (EOL)
}
}
if ((serial_bridge_in_byte_counter >= SERIAL_BRIDGE_BUFFER_SIZE -1) || // Send message when buffer is full or ...
in_byte_is_delimiter) { // Char is delimiter
serial_bridge_polling_window = 0; // Publish now
break;
else if (serial_in_byte == '\n') {
serial_bridge_buffer[serial_bridge_in_byte_counter] = 0; // Serial data completed
TasmotaGlobal.seriallog_level = (Settings->seriallog_level < LOG_LEVEL_INFO) ? (uint8_t)LOG_LEVEL_INFO : Settings->seriallog_level;
if (serial_bridge_overrun) {
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_COMMAND "SSerial buffer overrun"));
} else {
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_COMMAND "%s"), serial_bridge_buffer);
ExecuteCommand(serial_bridge_buffer, SRC_SERIAL);
}
serial_bridge_in_byte_counter = 0;
serial_bridge_overrun = false;
SerialBridgeSerial->flush();
return;
}
} else {
serial_bridge_raw = (254 == Settings->serial_delimiter);
if ((serial_in_byte > 127) && !serial_bridge_raw) { // Discard binary data above 127 if no raw reception allowed
serial_bridge_in_byte_counter = 0;
SerialBridgeSerial->flush();
return;
}
if (serial_in_byte || serial_bridge_raw) { // Any char between 1 and 127 or any char (0 - 255)
bool in_byte_is_delimiter = // Char is delimiter when...
(((Settings->serial_delimiter < 128) && (serial_in_byte == Settings->serial_delimiter)) || // Any char between 1 and 127 and being delimiter
((Settings->serial_delimiter == 128) && !isprint(serial_in_byte))) && // Any char not between 32 and 127
!serial_bridge_raw; // In raw mode (CMND_SERIALSEND3) there is never a delimiter
serial_bridge_polling_window = millis(); // Wait for more data
if ((serial_bridge_in_byte_counter < SERIAL_BRIDGE_BUFFER_SIZE -1) && // Add char to string if it still fits and ...
!in_byte_is_delimiter) { // Char is not a delimiter
serial_bridge_buffer[serial_bridge_in_byte_counter++] = serial_in_byte;
}
if ((serial_bridge_in_byte_counter >= SERIAL_BRIDGE_BUFFER_SIZE -1) || // Send message when buffer is full or ...
in_byte_is_delimiter) { // Char is delimiter
serial_bridge_polling_window = 0; // Publish now
break;
}
}
serial_bridge_polling_window = millis(); // Wait for more data
}
}
if (serial_bridge_in_byte_counter && (millis() > (serial_bridge_polling_window + SERIAL_POLLING))) {
serial_bridge_buffer[serial_bridge_in_byte_counter] = 0; // Serial data completed
bool assume_json = (!serial_bridge_raw && (serial_bridge_buffer[0] == '{'));
if (!Settings->sbflag1.serbridge_console) {
if (serial_bridge_in_byte_counter && (millis() > (serial_bridge_polling_window + SERIAL_POLLING))) {
serial_bridge_buffer[serial_bridge_in_byte_counter] = 0; // Serial data completed
bool assume_json = (!serial_bridge_raw && (serial_bridge_buffer[0] == '{'));
Response_P(PSTR("{\"" D_JSON_SSERIALRECEIVED "\":"));
if (assume_json) {
ResponseAppend_P(serial_bridge_buffer);
} else {
ResponseAppend_P(PSTR("\""));
if (serial_bridge_raw) {
char hex_char[(serial_bridge_in_byte_counter * 2) + 2];
ResponseAppend_P(ToHex_P((unsigned char*)serial_bridge_buffer, serial_bridge_in_byte_counter, hex_char, sizeof(hex_char)));
Response_P(PSTR("{\"" D_JSON_SSERIALRECEIVED "\":"));
if (assume_json) {
ResponseAppend_P(serial_bridge_buffer);
} else {
ResponseAppend_P(EscapeJSONString(serial_bridge_buffer).c_str());
ResponseAppend_P(PSTR("\""));
if (serial_bridge_raw) {
char hex_char[(serial_bridge_in_byte_counter * 2) + 2];
ResponseAppend_P(ToHex_P((unsigned char*)serial_bridge_buffer, serial_bridge_in_byte_counter, hex_char, sizeof(hex_char)));
} else {
ResponseAppend_P(EscapeJSONString(serial_bridge_buffer).c_str());
}
ResponseAppend_P(PSTR("\""));
}
ResponseAppend_P(PSTR("\""));
}
ResponseJsonEnd();
ResponseJsonEnd();
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_SSERIALRECEIVED));
serial_bridge_in_byte_counter = 0;
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_SSERIALRECEIVED));
serial_bridge_in_byte_counter = 0;
}
}
}
/********************************************************************************************/
void SerialBridgeInit(void)
{
serial_bridge_active = false;
void SerialBridgeInit(void) {
if (PinUsed(GPIO_SBR_RX) && PinUsed(GPIO_SBR_TX)) {
SerialBridgeSerial = new TasmotaSerial(Pin(GPIO_SBR_RX), Pin(GPIO_SBR_TX), HARDWARE_FALLBACK);
if (SetSSerialBegin()) {
@ -130,7 +169,6 @@ void SerialBridgeInit(void)
} else {
serial_bridge_buffer = (char*)(malloc(SERIAL_BRIDGE_BUFFER_SIZE));
}
serial_bridge_active = true;
SerialBridgeSerial->flush();
}
}
@ -140,10 +178,10 @@ void SerialBridgeInit(void)
* Commands
\*********************************************************************************************/
void CmndSSerialSend(void)
{
void CmndSSerialSend(void) {
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 6)) {
serial_bridge_raw = (XdrvMailbox.index > 3);
Settings->sbflag1.serbridge_console = 0; // Disable console Tee
if (XdrvMailbox.data_len > 0) {
if (1 == XdrvMailbox.index) {
SerialBridgeSerial->write(XdrvMailbox.data, XdrvMailbox.data_len); // "Hello Tiger"
@ -183,6 +221,12 @@ void CmndSSerialSend(void)
ResponseCmndDone();
}
}
if (9 == XdrvMailbox.index) {
if (XdrvMailbox.payload >= 0) {
Settings->sbflag1.serbridge_console = XdrvMailbox.payload &1;
}
ResponseCmndStateText(Settings->sbflag1.serbridge_console);
}
}
void CmndSBaudrate(void) {
@ -219,17 +263,16 @@ void CmndSSerialConfig(void) {
* Interface
\*********************************************************************************************/
bool Xdrv08(uint8_t function)
{
bool Xdrv08(uint8_t function) {
bool result = false;
if (serial_bridge_active) {
if (FUNC_PRE_INIT == function) {
SerialBridgeInit();
}
else if (serial_bridge_buffer) {
switch (function) {
case FUNC_LOOP:
if (SerialBridgeSerial) { SerialBridgeInput(); }
break;
case FUNC_PRE_INIT:
SerialBridgeInit();
SerialBridgeInput();
break;
case FUNC_COMMAND:
result = DecodeCommand(kSerialBridgeCommands, SerialBridgeCommand);