diff --git a/CHANGELOG.md b/CHANGELOG.md index b0ef04cd5..cbc9cc693 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. ## [12.2.0.5] ### Added - ESP32 DS18x20 parasitic power usage when defining W1_PARASITE_POWER (#17112) +- Command ``SSerialBuffer 64..256`` to change software serial bridge receive buffer size from default (64) to max local buffer size (256) (#17120) ### Breaking Changed diff --git a/RELEASENOTES.md b/RELEASENOTES.md index dc470bdb0..7d52cd8f2 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -112,6 +112,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo - Command ``SetOption47 1..255`` to delay power on relay state in seconds reducing power surge. ``SO47 1`` delays until network connected. ``SO47 2`` delays until mqtt connected - Command ``RgxClients`` for range extender clients list [#17048](https://github.com/arendst/Tasmota/issues/17048) - Command ``RgxPort [tcp|udp], gateway_port, client_mac, client_port`` for range extender port forwardings [#17092](https://github.com/arendst/Tasmota/issues/17092) +- Command ``SSerialBuffer 64..256`` to change software serial bridge receive buffer size from default (64) to max local buffer size (256) [#17120](https://github.com/arendst/Tasmota/issues/17120) - Command ``SwitchMode 16`` sending only MQTT message on inverted switch change [#17028](https://github.com/arendst/Tasmota/issues/17028) - Command NeoPool ``NPFiltration 2`` toggle [#16859](https://github.com/arendst/Tasmota/issues/16859) - Support for two phase power calibration using commands ``PowerSet2``, ``VoltageSet2`` and ``CurrentSet2`` diff --git a/lib/default/TasmotaSerial-3.5.0/src/TasmotaSerial.cpp b/lib/default/TasmotaSerial-3.5.0/src/TasmotaSerial.cpp index f750b956f..59b6dfe10 100644 --- a/lib/default/TasmotaSerial-3.5.0/src/TasmotaSerial.cpp +++ b/lib/default/TasmotaSerial-3.5.0/src/TasmotaSerial.cpp @@ -134,12 +134,70 @@ bool TasmotaSerial::freeUart(void) { } return false; } + +void TasmotaSerial::Esp32Begin(void) { + TSerial->begin(m_speed, m_config, m_rx_pin, m_tx_pin); + // For low bit rate, below 9600, set the Full RX threshold at 10 bytes instead of the default 120 + if (m_speed <= 9600) { + // At 9600, 10 chars are ~10ms + uart_set_rx_full_threshold(m_uart, 10); + } else if (m_speed < 115200) { + // At 19200, 120 chars are ~60ms + // At 76800, 120 chars are ~15ms + uart_set_rx_full_threshold(m_uart, 120); + } else { + // At 115200, 256 chars are ~20ms + // Zigbee requires to keep frames together, i.e. 256 bytes max + uart_set_rx_full_threshold(m_uart, 256); + } + // For bitrate below 115200, set the Rx time out to 6 chars instead of the default 10 + if (m_speed < 115200) { + // At 76800 the timeout is ~1ms + uart_set_rx_timeout(m_uart, 6); + } +} #endif +size_t TasmotaSerial::setRxBufferSize(size_t size) { + if (size != serial_buffer_size) { + if (m_hardserial) { + if (size > 256) { // Default hardware serial Rx buffer size + #ifdef ESP8266 + serial_buffer_size = size; + Serial.setRxBufferSize(serial_buffer_size); + #endif // ESP8266 + #ifdef ESP32 + if (TSerial) { + // RX Buffer can't be resized when Serial is already running + serial_buffer_size = size; + TSerial->flush(); + TSerial->end(); + delay(10); // Allow time to cleanup queues - if not used hangs ESP32 + TSerial->setRxBufferSize(serial_buffer_size); + Esp32Begin(); + } + #endif // ESP32 + } + } + else if (m_buffer) { + uint8_t *m_buffer_temp = (uint8_t*)malloc(size); // Allocate new buffer + if (m_buffer_temp) { // If succesful de-allocate old buffer + free(m_buffer); + m_buffer = m_buffer_temp; + serial_buffer_size = size; + } + } + } + return serial_buffer_size; +} + bool TasmotaSerial::begin(uint32_t speed, uint32_t config) { if (!m_valid) { return false; } if (m_hardserial) { + if (serial_buffer_size < 256) { + serial_buffer_size = 256; + } #ifdef ESP8266 Serial.flush(); Serial.begin(speed, (SerialConfig)config); @@ -157,10 +215,10 @@ bool TasmotaSerial::begin(uint32_t speed, uint32_t config) { TSerial = new HardwareSerial(m_uart); #else if (0 == m_uart) { - Serial.flush(); - Serial.end(); - delay(10); // Allow time to cleanup queues - if not used hangs ESP32 - TSerial = &Serial; + Serial.flush(); + Serial.end(); + delay(10); // Allow time to cleanup queues - if not used hangs ESP32 + TSerial = &Serial; } else { TSerial = new HardwareSerial(m_uart); } @@ -173,25 +231,9 @@ bool TasmotaSerial::begin(uint32_t speed, uint32_t config) { return m_valid; // As we currently only support hardware serial on ESP32 it's safe to exit here } } - TSerial->begin(speed, config, m_rx_pin, m_tx_pin); - // For low bit rate, below 9600, set the Full RX threshold at 10 bytes instead of the default 120 - if (speed <= 9600) { - // At 9600, 10 chars are ~10ms - uart_set_rx_full_threshold(m_uart, 10); - } else if (speed < 115200) { - // At 19200, 120 chars are ~60ms - // At 76800, 120 chars are ~15ms - uart_set_rx_full_threshold(m_uart, 120); - } else { - // At 115200, 256 chars are ~20ms - // Zigbee requires to keep frames together, i.e. 256 bytes max - uart_set_rx_full_threshold(m_uart, 256); - } - // For bitrate below 115200, set the Rx time out to 6 chars instead of the default 10 - if (speed < 115200) { - // At 76800 the timeout is ~1ms - uart_set_rx_timeout(m_uart, 6); - } + m_speed = speed; + m_config = config; + Esp32Begin(); // Serial.printf("TSR: Using UART%d\n", m_uart); #endif // ESP32 } else { diff --git a/lib/default/TasmotaSerial-3.5.0/src/TasmotaSerial.h b/lib/default/TasmotaSerial-3.5.0/src/TasmotaSerial.h index f0ff57cd2..759433d66 100644 --- a/lib/default/TasmotaSerial-3.5.0/src/TasmotaSerial.h +++ b/lib/default/TasmotaSerial-3.5.0/src/TasmotaSerial.h @@ -40,6 +40,9 @@ class TasmotaSerial : public Stream { TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fallback = 0, int nwmode = 0, int buffer_size = TM_SERIAL_BUFFER_SIZE); virtual ~TasmotaSerial(); + size_t setRxBufferSize(size_t size); + size_t getRxBufferSize() { return serial_buffer_size; } + bool begin(uint32_t speed = TM_SERIAL_BAUDRATE, uint32_t config = SERIAL_8N1); void end(bool turnOffDebug = true); bool hardwareSerial(void); @@ -65,6 +68,7 @@ class TasmotaSerial : public Stream { bool isValidGPIOpin(int pin); #ifdef ESP32 bool freeUart(void); + void Esp32Begin(void); #endif size_t txWrite(uint8_t byte); @@ -80,18 +84,20 @@ class TasmotaSerial : public Stream { uint32_t m_bit_follow_metric = 0; uint32_t m_in_pos; uint32_t m_out_pos; - uint32_t serial_buffer_size; + uint32_t serial_buffer_size = TM_SERIAL_BUFFER_SIZE; bool m_valid; bool m_nwmode; bool m_hardserial; bool m_hardswap; bool m_high_speed = false; bool m_very_high_speed = false; // above 100000 bauds - uint8_t *m_buffer; + uint8_t *m_buffer = nullptr; void _fast_write(uint8_t b); // IRAM minimized version #ifdef ESP32 + uint32_t m_speed; + uint32_t m_config; HardwareSerial *TSerial; int m_uart = 0; #endif diff --git a/tasmota/include/i18n.h b/tasmota/include/i18n.h index a46c9d1a1..b40438194 100644 --- a/tasmota/include/i18n.h +++ b/tasmota/include/i18n.h @@ -575,6 +575,7 @@ // Commands xdrv_08_serial_bridge.ino #define D_CMND_SSERIALSEND "SSerialSend" #define D_CMND_SBAUDRATE "SBaudrate" +#define D_CMND_SSERIALBUFFER "SSerialBuffer" #define D_CMND_SSERIALCONFIG "SSerialConfig" #define D_JSON_SSERIALRECEIVED "SSerialReceived" diff --git a/tasmota/tasmota_xdrv_driver/xdrv_08_serial_bridge.ino b/tasmota/tasmota_xdrv_driver/xdrv_08_serial_bridge.ino index b4562561b..aae239e10 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_08_serial_bridge.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_08_serial_bridge.ino @@ -27,20 +27,22 @@ #define USE_SERIAL_BRIDGE_TEE -#ifdef ESP8266 -const uint16_t SERIAL_BRIDGE_BUFFER_SIZE = MIN_INPUT_BUFFER_SIZE; -#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; + D_CMND_SSERIALSEND "|" D_CMND_SBAUDRATE "|" D_CMND_SSERIALBUFFER "|" D_CMND_SSERIALCONFIG; void (* const SerialBridgeCommand[])(void) PROGMEM = { - &CmndSSerialSend, &CmndSBaudrate, &CmndSSerialConfig }; + &CmndSSerialSend, &CmndSBaudrate, &CmndSSerialBuffer, &CmndSSerialConfig }; #include +#ifdef ESP8266 +const uint16_t SERIAL_BRIDGE_BUFFER_MIN_SIZE = TM_SERIAL_BUFFER_SIZE; // 64 (TasmotaSerial.h) +const uint16_t SERIAL_BRIDGE_BUFFER_SIZE = MIN_INPUT_BUFFER_SIZE; // 256 +#else +const uint16_t SERIAL_BRIDGE_BUFFER_MIN_SIZE = MIN_INPUT_BUFFER_SIZE; // 256 +const uint16_t SERIAL_BRIDGE_BUFFER_SIZE = INPUT_BUFFER_SIZE; // 800 +#endif + TasmotaSerial *SerialBridgeSerial = nullptr; unsigned long serial_bridge_polling_window = 0; @@ -263,6 +265,28 @@ void CmndSBaudrate(void) { ResponseCmndNumber(Settings->sbaudrate * 300); } +void CmndSSerialBuffer(void) { + // Allow non-pesistent serial receive buffer size change + if (SerialBridgeSerial->hardwareSerial()) { + // between MIN_INPUT_BUFFER_SIZE and MAX_INPUT_BUFFER_SIZE characters + CmndSerialBuffer(); + } else { + // ESP8266 (software serial): between TM_SERIAL_BUFFER_SIZE and SERIAL_BRIDGE_BUFFER_SIZE characters + // ESP32 (hardware serial only): between MIN_INPUT_BUFFER_SIZE and MAX_INPUT_BUFFER_SIZE characters + if (XdrvMailbox.data_len > 0) { + size_t size = XdrvMailbox.payload; + if (XdrvMailbox.payload < SERIAL_BRIDGE_BUFFER_MIN_SIZE) { + size = SERIAL_BRIDGE_BUFFER_MIN_SIZE; // 64 / 256 + } + else if (XdrvMailbox.payload > SERIAL_BRIDGE_BUFFER_SIZE) { + size = SERIAL_BRIDGE_BUFFER_SIZE; // 256 / 800 + } + SerialBridgeSerial->setRxBufferSize(size); + } + ResponseCmndNumber(SerialBridgeSerial->getRxBufferSize()); + } +} + void CmndSSerialConfig(void) { // See TasmotaSerialConfig for possible options // SSerialConfig 0..23 where 3 equals 8N1