Add command `SSerialBuffer 64..256`

Add command ``SSerialBuffer 64..256`` to change software serial bridge receive buffer size from default (64) to max local buffer size (256) (#17120)
This commit is contained in:
Theo Arends 2022-11-18 13:00:59 +01:00
parent 3a20159dd5
commit 0674f9b0b6
6 changed files with 108 additions and 33 deletions

View File

@ -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

View File

@ -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``

View File

@ -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 {

View File

@ -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

View File

@ -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"

View File

@ -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 <TasmotaSerial.h>
#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