diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index e60588f931e..7d06f65dc93 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -233,7 +233,7 @@ void HardwareSerial::onReceive(OnReceiveCb function, bool onlyOnTimeout) // A low value of FIFO Full bytes will consume more CPU time within the ISR // A high value of FIFO Full bytes will make the application wait longer to have byte available for the Stkech in a streaming scenario // Both RX FIFO Full and RX Timeout may affect when onReceive() will be called -void HardwareSerial::setRxFIFOFull(uint8_t fifoBytes) +bool HardwareSerial::setRxFIFOFull(uint8_t fifoBytes) { HSERIAL_MUTEX_LOCK(); // in case that onReceive() shall work only with RX Timeout, FIFO shall be high @@ -242,14 +242,15 @@ void HardwareSerial::setRxFIFOFull(uint8_t fifoBytes) fifoBytes = 120; log_w("OnReceive is set to Timeout only, thus FIFO Full is now 120 bytes."); } - uartSetRxFIFOFull(_uart, fifoBytes); // Set new timeout + bool retCode = uartSetRxFIFOFull(_uart, fifoBytes); // Set new timeout if (fifoBytes > 0 && fifoBytes < SOC_UART_FIFO_LEN - 1) _rxFIFOFull = fifoBytes; HSERIAL_MUTEX_UNLOCK(); + return retCode; } // timout is calculates in time to receive UART symbols at the UART baudrate. // the estimation is about 11 bits per symbol (SERIAL_8N1) -void HardwareSerial::setRxTimeout(uint8_t symbols_timeout) +bool HardwareSerial::setRxTimeout(uint8_t symbols_timeout) { HSERIAL_MUTEX_LOCK(); @@ -258,9 +259,10 @@ void HardwareSerial::setRxTimeout(uint8_t symbols_timeout) _rxTimeout = symbols_timeout; if (!symbols_timeout) _onReceiveTimeout = false; // only when RX timeout is disabled, we also must disable this flag - uartSetRxTimeout(_uart, _rxTimeout); // Set new timeout + bool retCode = uartSetRxTimeout(_uart, _rxTimeout); // Set new timeout HSERIAL_MUTEX_UNLOCK(); + return retCode; } void HardwareSerial::eventQueueReset() @@ -548,15 +550,16 @@ void HardwareSerial::setRxInvert(bool invert) } // negative Pin value will keep it unmodified -void HardwareSerial::setPins(int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) +bool HardwareSerial::setPins(int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) { if(_uart == NULL) { log_e("setPins() shall be called after begin() - nothing done\n"); - return; + return false; } - // uartSetPins() checks if pins are valid for each function and for the SoC - if (uartSetPins(_uart, rxPin, txPin, ctsPin, rtsPin)) { + // uartSetPins() checks if pins are valid for each function and for the SoC + bool retCode = uartSetPins(_uart, rxPin, txPin, ctsPin, rtsPin); + if (retCode) { _txPin = _txPin >= 0 ? txPin : _txPin; _rxPin = _rxPin >= 0 ? rxPin : _rxPin; _rtsPin = _rtsPin >= 0 ? rtsPin : _rtsPin; @@ -564,12 +567,19 @@ void HardwareSerial::setPins(int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t r } else { log_e("Error when setting Serial port Pins. Invalid Pin.\n"); } + return retCode; } // Enables or disables Hardware Flow Control using RTS and/or CTS pins (must use setAllPins() before) -void HardwareSerial::setHwFlowCtrlMode(uint8_t mode, uint8_t threshold) +bool HardwareSerial::setHwFlowCtrlMode(uint8_t mode, uint8_t threshold) +{ + return uartSetHwFlowCtrlMode(_uart, mode, threshold); +} + +// Sets the uart mode in the esp32 uart for use with RS485 modes (HwFlowCtrl must be disabled and RTS pin set) +bool HardwareSerial::setMode(uint8_t mode) { - uartSetHwFlowCtrlMode(_uart, mode, threshold); + return uartSetMode(_uart, mode); } size_t HardwareSerial::setRxBufferSize(size_t new_size) { diff --git a/cores/esp32/HardwareSerial.h b/cores/esp32/HardwareSerial.h index 6291d241778..d6516f06f3e 100644 --- a/cores/esp32/HardwareSerial.h +++ b/cores/esp32/HardwareSerial.h @@ -80,13 +80,13 @@ class HardwareSerial: public Stream // Examples: Maximum for 11 bits symbol is 92 (SERIAL_8N2, SERIAL_8E1, SERIAL_8O1, etc), Maximum for 10 bits symbol is 101 (SERIAL_8N1). // For example symbols_timeout=1 defines a timeout equal to transmission time of one symbol (~11 bit) on current baudrate. // For a baudrate of 9600, SERIAL_8N1 (10 bit symbol) and symbols_timeout = 3, the timeout would be 3 / (9600 / 10) = 3.125 ms - void setRxTimeout(uint8_t symbols_timeout); + bool setRxTimeout(uint8_t symbols_timeout); // setRxFIFOFull(uint8_t fifoBytes) will set the number of bytes that will trigger UART_INTR_RXFIFO_FULL interrupt and fill up RxRingBuffer // This affects some functions such as Serial::available() and Serial.read() because, in a UART flow of receiving data, Serial internal // RxRingBuffer will be filled only after these number of bytes arrive or a RX Timeout happens. // This parameter can be set to 1 in order to receive byte by byte, but it will also consume more CPU time as the ISR will be activates often. - void setRxFIFOFull(uint8_t fifoBytes); + bool setRxFIFOFull(uint8_t fifoBytes); // onReceive will setup a callback that will be called whenever an UART interruption occurs (UART_INTR_RXFIFO_FULL or UART_INTR_RXFIFO_TOUT) // UART_INTR_RXFIFO_FULL interrupt triggers at UART_FULL_THRESH_DEFAULT bytes received (defined as 120 bytes by default in IDF) @@ -161,10 +161,11 @@ class HardwareSerial: public Stream // Negative Pin Number will keep it unmodified, thus this function can set individual pins // SetPins shall be called after Serial begin() - void setPins(int8_t rxPin, int8_t txPin, int8_t ctsPin = -1, int8_t rtsPin = -1); + bool setPins(int8_t rxPin, int8_t txPin, int8_t ctsPin = -1, int8_t rtsPin = -1); // Enables or disables Hardware Flow Control using RTS and/or CTS pins (must use setAllPins() before) - void setHwFlowCtrlMode(uint8_t mode = HW_FLOWCTRL_CTS_RTS, uint8_t threshold = 64); // 64 is half FIFO Length - + bool setHwFlowCtrlMode(uint8_t mode = HW_FLOWCTRL_CTS_RTS, uint8_t threshold = 64); // 64 is half FIFO Length + // Used to set RS485 modes such as UART_MODE_RS485_HALF_DUPLEX for Auto RTS function on ESP32 + bool setMode(uint8_t mode); size_t setRxBufferSize(size_t new_size); size_t setTxBufferSize(size_t new_size); diff --git a/cores/esp32/esp32-hal-uart.c b/cores/esp32/esp32-hal-uart.c index 7706f132d5e..ca212577891 100644 --- a/cores/esp32/esp32-hal-uart.c +++ b/cores/esp32/esp32-hal-uart.c @@ -160,13 +160,16 @@ bool uartSetPins(uart_t* uart, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t } // -void uartSetHwFlowCtrlMode(uart_t *uart, uint8_t mode, uint8_t threshold) { +bool uartSetHwFlowCtrlMode(uart_t *uart, uint8_t mode, uint8_t threshold) { if(uart == NULL) { - return; + return false; } // IDF will issue corresponding error message when mode or threshold are wrong and prevent crashing // IDF will check (mode > HW_FLOWCTRL_CTS_RTS || threshold >= SOC_UART_FIFO_LEN) - uart_set_hw_flow_ctrl(uart->num, (uart_hw_flowcontrol_t) mode, threshold); + UART_MUTEX_LOCK(); + bool retCode = (ESP_OK == uart_set_hw_flow_ctrl(uart->num, (uart_hw_flowcontrol_t) mode, threshold)); + UART_MUTEX_UNLOCK(); + return retCode; } @@ -244,26 +247,28 @@ void uartSetFastReading(uart_t* uart) } -void uartSetRxTimeout(uart_t* uart, uint8_t numSymbTimeout) +bool uartSetRxTimeout(uart_t* uart, uint8_t numSymbTimeout) { if(uart == NULL) { - return; + return false; } UART_MUTEX_LOCK(); - uart_set_rx_timeout(uart->num, numSymbTimeout); + bool retCode = (ESP_OK == uart_set_rx_timeout(uart->num, numSymbTimeout)); UART_MUTEX_UNLOCK(); + return retCode; } -void uartSetRxFIFOFull(uart_t* uart, uint8_t numBytesFIFOFull) +bool uartSetRxFIFOFull(uart_t* uart, uint8_t numBytesFIFOFull) { if(uart == NULL) { - return; + return false; } UART_MUTEX_LOCK(); - uart_set_rx_full_threshold(uart->num, numBytesFIFOFull); + bool retCode = (ESP_OK == uart_set_rx_full_threshold(uart->num, numBytesFIFOFull)); UART_MUTEX_UNLOCK(); + return retCode; } void uartEnd(uart_t* uart) @@ -518,6 +523,21 @@ void uart_install_putc() } } +// Routines that take care of UART mode in the HardwareSerial Class code +// used to set UART_MODE_RS485_HALF_DUPLEX auto RTS for TXD for ESP32 chips +bool uartSetMode(uart_t *uart, uint8_t mode) +{ + if (uart == NULL || uart->num >= SOC_UART_NUM) + { + return false; + } + + UART_MUTEX_LOCK(); + bool retCode = (ESP_OK == uart_set_mode(uart->num, mode)); + UART_MUTEX_UNLOCK(); + return retCode; +} + void uartSetDebug(uart_t* uart) { if(uart == NULL || uart->num >= SOC_UART_NUM) { diff --git a/cores/esp32/esp32-hal-uart.h b/cores/esp32/esp32-hal-uart.h index 2b3268af966..2870c31ae61 100644 --- a/cores/esp32/esp32-hal-uart.h +++ b/cores/esp32/esp32-hal-uart.h @@ -58,6 +58,15 @@ extern "C" { #define HW_FLOWCTRL_CTS 0x2 // use only CTS PIN for HW Flow Control #define HW_FLOWCTRL_CTS_RTS 0x3 // use both CTS and RTS PIN for HW Flow Control +// These are Hardware Uart Modes possible usage +// equivalent to UDF enum uart_mode_t from +// https://github.com/espressif/esp-idf/blob/master/components/hal/include/hal/uart_types.h#L34-L40 +#define MODE_UART 0x00 // mode: regular UART mode +#define MODE_RS485_HALF_DUPLEX 0x01 // mode: half duplex RS485 UART mode control by RTS pin +#define MODE_IRDA 0x02 // mode: IRDA UART mode +#define MODE_RS485_COLLISION_DETECT 0x03 // mode: RS485 collision detection UART mode (used for test purposes) +#define MODE_RS485_APP_CTRL 0x04 + struct uart_struct_t; typedef struct uart_struct_t uart_t; @@ -83,8 +92,8 @@ void uartSetBaudRate(uart_t* uart, uint32_t baud_rate); uint32_t uartGetBaudRate(uart_t* uart); void uartSetRxInvert(uart_t* uart, bool invert); -void uartSetRxTimeout(uart_t* uart, uint8_t numSymbTimeout); -void uartSetRxFIFOFull(uart_t* uart, uint8_t numBytesFIFOFull); +bool uartSetRxTimeout(uart_t* uart, uint8_t numSymbTimeout); +bool uartSetRxFIFOFull(uart_t* uart, uint8_t numBytesFIFOFull); void uartSetFastReading(uart_t* uart); void uartSetDebug(uart_t* uart); @@ -97,7 +106,11 @@ bool uartSetPins(uart_t* uart, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t void uartDetachPins(uart_t* uart, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin); // Enables or disables HW Flow Control function -- needs also to set CTS and/or RTS pins -void uartSetHwFlowCtrlMode(uart_t *uart, uint8_t mode, uint8_t threshold); +bool uartSetHwFlowCtrlMode(uart_t *uart, uint8_t mode, uint8_t threshold); + +// Used to set RS485 function -- needs to disable HW Flow Control and set RTS pin to use +// RTS pin becomes RS485 half duplex RE/DE +bool uartSetMode(uart_t *uart, uint8_t mode); void uartStartDetectBaudrate(uart_t *uart); unsigned long uartDetectBaudrate(uart_t *uart);