From 8701c881cf81ba730584e54d870c22568edea8e0 Mon Sep 17 00:00:00 2001
From: Rodrigo Garcia <rodrigo.garcia@espressif.com>
Date: Sun, 27 Nov 2022 17:09:41 -0300
Subject: [PATCH 1/4] Improves UART reading performance

---
 cores/esp32/HardwareSerial.cpp | 19 ++++++-------------
 cores/esp32/esp32-hal-uart.c   | 28 ++++++++++++++++++++++++++++
 cores/esp32/esp32-hal-uart.h   |  1 +
 3 files changed, 35 insertions(+), 13 deletions(-)

diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp
index 049c24a74d5..96fbb82cdc5 100644
--- a/cores/esp32/HardwareSerial.cpp
+++ b/cores/esp32/HardwareSerial.cpp
@@ -450,10 +450,12 @@ int HardwareSerial::peek(void)
 
 int HardwareSerial::read(void)
 {
-    if(available()) {
-        return uartRead(_uart);
+    uint8_t c = 0;
+    if (uartReadBytes(_uart, &c, 1, 0) == 1) {
+        return c;
+    } else {
+        return -1;
     }
-    return -1;
 }
 
 // read characters into buffer
@@ -462,16 +464,7 @@ int HardwareSerial::read(void)
 // the buffer is NOT null terminated.
 size_t HardwareSerial::read(uint8_t *buffer, size_t size)
 {
-    size_t avail = available();
-    if (size < avail) {
-        avail = size;
-    }
-    size_t count = 0;
-    while(count < avail) {
-        *buffer++ = uartRead(_uart);
-        count++;
-    }
-    return count;
+    return uartReadBytes(_uart, buffer, size, 0);
 }
 
 void HardwareSerial::flush(void)
diff --git a/cores/esp32/esp32-hal-uart.c b/cores/esp32/esp32-hal-uart.c
index e4b24a112f5..5ad7ba13a9c 100644
--- a/cores/esp32/esp32-hal-uart.c
+++ b/cores/esp32/esp32-hal-uart.c
@@ -326,6 +326,34 @@ uint32_t uartAvailableForWrite(uart_t* uart)
     return available;
 }
 
+size_t uartReadBytes(uart_t* uart, uint8_t *buffer, size_t size, uint32_t timeout_ms)
+{
+    if(uart == NULL || size == 0 || buffer == NULL) {
+        return 0;
+    }
+
+    size_t bytes_read = 0;
+
+    UART_MUTEX_LOCK();
+
+    if (uart->has_peek) {
+        uart->has_peek = false;
+        *buffer++ = uart->peek_byte;
+        size--;
+        bytes_read = 1;
+    }
+
+    if (size > 0) {
+       int len = uart_read_bytes(uart->num, buffer, size, pdMS_TO_TICKS(timeout_ms));
+       if (len < 0) len = 0;  // error reading UART
+       bytes_read += len;
+    }
+
+        
+    UART_MUTEX_UNLOCK();
+    return bytes_read;
+}
+
 
 uint8_t uartRead(uart_t* uart)
 {
diff --git a/cores/esp32/esp32-hal-uart.h b/cores/esp32/esp32-hal-uart.h
index ffb0a3f027a..8e6e7ec4a1b 100644
--- a/cores/esp32/esp32-hal-uart.h
+++ b/cores/esp32/esp32-hal-uart.h
@@ -69,6 +69,7 @@ void uartGetEventQueue(uart_t* uart, QueueHandle_t *q);
 
 uint32_t uartAvailable(uart_t* uart);
 uint32_t uartAvailableForWrite(uart_t* uart);
+size_t uartReadBytes(uart_t* uart, uint8_t *buffer, size_t size, uint32_t timeout_ms);
 uint8_t uartRead(uart_t* uart);
 uint8_t uartPeek(uart_t* uart);
 

From e0723028494de5ad6349a039bdd5a190fc5c61ab Mon Sep 17 00:00:00 2001
From: Rodrigo Garcia <rodrigo.garcia@espressif.com>
Date: Sun, 4 Dec 2022 10:44:58 -0300
Subject: [PATCH 2/4] overrides Stream::readBytes()

---
 cores/esp32/HardwareSerial.cpp | 6 ++++++
 cores/esp32/HardwareSerial.h   | 6 ++++++
 2 files changed, 12 insertions(+)

diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp
index 96fbb82cdc5..7b8ee993581 100644
--- a/cores/esp32/HardwareSerial.cpp
+++ b/cores/esp32/HardwareSerial.cpp
@@ -467,6 +467,12 @@ size_t HardwareSerial::read(uint8_t *buffer, size_t size)
     return uartReadBytes(_uart, buffer, size, 0);
 }
 
+// Overrides Stream::readBytes() to be faster using IDF
+size_t HardwareSerial::readBytes(uint8_t *buffer, size_t length)
+{
+    return uartReadBytes(_uart, buffer, length, (uint32_t)getTimeout());
+}
+
 void HardwareSerial::flush(void)
 {
     uartFlush(_uart);
diff --git a/cores/esp32/HardwareSerial.h b/cores/esp32/HardwareSerial.h
index 0c673c1483f..24b1421311b 100644
--- a/cores/esp32/HardwareSerial.h
+++ b/cores/esp32/HardwareSerial.h
@@ -118,6 +118,12 @@ class HardwareSerial: public Stream
     {
         return read((uint8_t*) buffer, size);
     }
+    // Overrides Stream::readBytes() to be faster using IDF
+    size_t readBytes(uint8_t *buffer, size_t length);
+    size_t readBytes(char *buffer, size_t length)
+    {
+        return readBytes((char *) buffer, length);
+    }    
     void flush(void);
     void flush( bool txOnly);
     size_t write(uint8_t);

From 6ef09b6a4e13f65b268117ce8356a660d9683ba1 Mon Sep 17 00:00:00 2001
From: Rodrigo Garcia <rodrigo.garcia@espressif.com>
Date: Tue, 6 Dec 2022 16:42:48 -0300
Subject: [PATCH 3/4] fixes override signature

---
 cores/esp32/HardwareSerial.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/cores/esp32/HardwareSerial.h b/cores/esp32/HardwareSerial.h
index 24b1421311b..d5f9c7c1a7b 100644
--- a/cores/esp32/HardwareSerial.h
+++ b/cores/esp32/HardwareSerial.h
@@ -122,7 +122,7 @@ class HardwareSerial: public Stream
     size_t readBytes(uint8_t *buffer, size_t length);
     size_t readBytes(char *buffer, size_t length)
     {
-        return readBytes((char *) buffer, length);
+        return readBytes((uint8_t *) buffer, length);
     }    
     void flush(void);
     void flush( bool txOnly);

From d37a199ebe23ff0f4eb7b923687490780c23ae42 Mon Sep 17 00:00:00 2001
From: Rodrigo Garcia <rodrigo.garcia@espressif.com>
Date: Tue, 6 Dec 2022 16:57:06 -0300
Subject: [PATCH 4/4] adds some IDF error return  conditions

---
 cores/esp32/esp32-hal-uart.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/cores/esp32/esp32-hal-uart.c b/cores/esp32/esp32-hal-uart.c
index 5ad7ba13a9c..cad9ce7d9c2 100644
--- a/cores/esp32/esp32-hal-uart.c
+++ b/cores/esp32/esp32-hal-uart.c
@@ -354,7 +354,8 @@ size_t uartReadBytes(uart_t* uart, uint8_t *buffer, size_t size, uint32_t timeou
     return bytes_read;
 }
 
-
+// DEPRICATED but the original code will be kepts here as future reference when a final solution
+// to the UART driver is defined in the use case of reading byte by byte from UART.
 uint8_t uartRead(uart_t* uart)
 {
     if(uart == NULL) {
@@ -370,7 +371,7 @@ uint8_t uartRead(uart_t* uart)
     } else {
 
         int len = uart_read_bytes(uart->num, &c, 1, 20 / portTICK_RATE_MS);
-        if (len == 0) {
+        if (len <= 0) { // includes negative return from IDF in case of error
             c  = 0;
         }
     }
@@ -378,6 +379,7 @@ uint8_t uartRead(uart_t* uart)
     return c;
 }
 
+
 uint8_t uartPeek(uart_t* uart)
 {
     if(uart == NULL) {
@@ -391,7 +393,7 @@ uint8_t uartPeek(uart_t* uart)
       c = uart->peek_byte;
     } else {
         int len = uart_read_bytes(uart->num, &c, 1, 20 / portTICK_RATE_MS);
-        if (len == 0) {
+        if (len <= 0) { // includes negative return from IDF in case of error
             c  = 0;
         } else {
             uart->has_peek = true;