From e5c2fea7318ac35360ebaf69662338718682211f Mon Sep 17 00:00:00 2001
From: david gauchard <gauchard@laas.fr>
Date: Thu, 5 Apr 2018 01:55:33 +0200
Subject: [PATCH 01/21] uart fixes and BW improvements

---
 cores/esp8266/HardwareSerial.h | 12 +++++
 cores/esp8266/uart.c           | 97 ++++++++++++++++++++++++----------
 cores/esp8266/uart.h           |  2 +
 3 files changed, 84 insertions(+), 27 deletions(-)

diff --git a/cores/esp8266/HardwareSerial.h b/cores/esp8266/HardwareSerial.h
index 0333d4ca87..532ed64241 100644
--- a/cores/esp8266/HardwareSerial.h
+++ b/cores/esp8266/HardwareSerial.h
@@ -88,6 +88,10 @@ class HardwareSerial: public Stream
     void end();
 
     size_t setRxBufferSize(size_t size);
+    size_t getRxBufferSize()
+    {
+        return uart_get_rx_buffer_size(_uart);
+    }
 
     void swap()
     {
@@ -128,6 +132,14 @@ class HardwareSerial: public Stream
         // this may return -1, but that's okay
         return uart_read_char(_uart);
     }
+    size_t readBytes (char* buffer, size_t size) override
+    {
+        return uart_read(_uart, buffer, size);
+    }
+    size_t readBytes (uint8_t* buffer, size_t size) override
+    {
+        return uart_read(_uart, (char*)buffer, size);
+    }
     int availableForWrite(void)
     {
         return static_cast<int>(uart_tx_free(_uart));
diff --git a/cores/esp8266/uart.c b/cores/esp8266/uart.c
index 47814f7a9d..9ac932e8ed 100644
--- a/cores/esp8266/uart.c
+++ b/cores/esp8266/uart.c
@@ -108,46 +108,26 @@ uart_rx_available_unsafe(uart_t* uart)
     return uart_rx_buffer_available_unsafe(uart->rx_buffer) + uart_rx_fifo_available(uart->uart_nr);
 }
 
-
 //#define UART_DISCARD_NEWEST
 
 // Copy all the rx fifo bytes that fit into the rx buffer
 inline void 
+ICACHE_RAM_ATTR
 uart_rx_copy_fifo_to_buffer_unsafe(uart_t* uart) 
 {
     struct uart_rx_buffer_ *rx_buffer = uart->rx_buffer;
-
     while(uart_rx_fifo_available(uart->uart_nr))
     {
         size_t nextPos = (rx_buffer->wpos + 1) % rx_buffer->size;
         if(nextPos == rx_buffer->rpos) 
-        {
-
-            if (!uart->overrun) 
-            {
-                uart->overrun = true;
-                os_printf_plus(overrun_str);
-            }
-
-            // a choice has to be made here,
-            // do we discard newest or oldest data?
-#ifdef UART_DISCARD_NEWEST
-            // discard newest data
-            // Stop copying if rx buffer is full
-            USF(uart->uart_nr);
             break;
-#else
-            // discard oldest data
-            if (++rx_buffer->rpos == rx_buffer->size)
-                rx_buffer->rpos = 0;
-#endif
-        }
         uint8_t data = USF(uart->uart_nr);
         rx_buffer->buffer[rx_buffer->wpos] = data;
         rx_buffer->wpos = nextPos;
     }
 }
 
+
 inline int 
 uart_peek_char_unsafe(uart_t* uart)
 {
@@ -212,6 +192,50 @@ uart_read_char(uart_t* uart)
     return data;
 }
 
+extern void iprint (int x);
+extern void sprint (const char* s);
+
+size_t
+uart_read(uart_t* uart, char* userbuffer, size_t usersize)
+{
+    if(uart == NULL || !uart->rx_enabled)
+        return -1;
+
+    size_t ret = 0;
+    
+    ETS_UART_INTR_DISABLE();
+
+sprint("a");iprint(usersize);iprint(uart->rx_buffer->rpos);
+    while (ret < usersize && uart_rx_available_unsafe(uart))
+    {
+#if 1
+        if (!uart_rx_buffer_available_unsafe(uart->rx_buffer))
+        {
+            // no more data in sw buffer, take them from hw fifo
+            while (ret < usersize && uart_rx_fifo_available(uart->uart_nr))
+	    	userbuffer[ret++] = USF(uart->uart_nr);
+	    	
+	    // no more sw/hw data available
+    	    break;
+        }
+#endif
+        // pour sw buffer to user's buffer
+        // get largest linear length from sw buffer
+        size_t chunk = uart->rx_buffer->rpos < uart->rx_buffer->wpos?
+                           uart->rx_buffer->wpos - uart->rx_buffer->rpos:
+                           uart->rx_buffer->size - uart->rx_buffer->rpos;
+        if (ret + chunk > usersize)
+            chunk = usersize - ret;
+        memcpy(userbuffer + ret, uart->rx_buffer->buffer + uart->rx_buffer->rpos, chunk);
+        uart->rx_buffer->rpos = (uart->rx_buffer->rpos + chunk) % uart->rx_buffer->size;
+        ret += chunk;
+    }
+iprint(ret);iprint(uart->rx_buffer->rpos);
+    
+    ETS_UART_INTR_ENABLE();
+    return ret;
+}
+
 size_t 
 uart_resize_rx_buffer(uart_t* uart, size_t new_size)
 {
@@ -240,22 +264,36 @@ uart_resize_rx_buffer(uart_t* uart, size_t new_size)
     return uart->rx_buffer->size;
 }
 
+size_t
+uart_get_rx_buffer_size(uart_t* uart)
+{
+    return uart && uart->rx_enabled? uart->rx_buffer->size: 0;
+}
 
 
 void ICACHE_RAM_ATTR 
 uart_isr(void * arg)
 {
     uart_t* uart = (uart_t*)arg;
+    uint32_t usis = USIS(uart->uart_nr);
+
     if(uart == NULL || !uart->rx_enabled) 
     {
-        USIC(uart->uart_nr) = USIS(uart->uart_nr);
+        USIC(uart->uart_nr) = usis;
         ETS_UART_INTR_DISABLE();
         return;
     }
-    if(USIS(uart->uart_nr) & ((1 << UIFF) | (1 << UITO)))
+
+    if(usis & (1 << UIFF))
         uart_rx_copy_fifo_to_buffer_unsafe(uart);
+
+    if((usis & (1 << UIOF)) && !uart->overrun)
+    {
+        uart->overrun = true;
+//        os_printf_plus(overrun_str);
+    }
     
-    USIC(uart->uart_nr) = USIS(uart->uart_nr);
+    USIC(uart->uart_nr) = usis;
 }
 
 static void 
@@ -268,9 +306,12 @@ uart_start_isr(uart_t* uart)
     // triggers the IRS very often.  A value of 127 would not leave much time
     // for ISR to clear fifo before the next byte is dropped.  So pick a value
     // in the middle.
-    USC1(uart->uart_nr) = (100   << UCFFT) | (0x02 << UCTOT) | (1 <<UCTOE );
+    #define INTRIGG 100 // was:100
+    //was:USC1(uart->uart_nr) = (INTRIGG << UCFFT) | (0x02 << UCTOT) | (1 <<UCTOE);
+    USC1(uart->uart_nr) = (INTRIGG << UCFFT);
     USIC(uart->uart_nr) = 0xffff;
-    USIE(uart->uart_nr) = (1 << UIFF) | (1 << UIFR) | (1 << UITO);
+    //was: USIE(uart->uart_nr) = (1 << UIFF) | (1 << UIFR) | (1 << UITO);
+    USIE(uart->uart_nr) = (1 << UIFF) | (1 << UIOF);
     ETS_UART_INTR_ATTACH(uart_isr,  (void *)uart);
     ETS_UART_INTR_ENABLE();
 }
@@ -312,9 +353,11 @@ uart_tx_fifo_full(const int uart_nr)
 static void 
 uart_do_write_char(const int uart_nr, char c)
 {
+    ETS_UART_INTR_DISABLE();
     while(uart_tx_fifo_full(uart_nr));
 
     USF(uart_nr) = c;
+    ETS_UART_INTR_ENABLE();
 }
 
 size_t 
diff --git a/cores/esp8266/uart.h b/cores/esp8266/uart.h
index 127c5d0ebb..73c4449274 100644
--- a/cores/esp8266/uart.h
+++ b/cores/esp8266/uart.h
@@ -126,11 +126,13 @@ void uart_set_baudrate(uart_t* uart, int baud_rate);
 int uart_get_baudrate(uart_t* uart);
 
 size_t uart_resize_rx_buffer(uart_t* uart, size_t new_size);
+size_t uart_get_rx_buffer_size(uart_t* uart);
 
 size_t uart_write_char(uart_t* uart, char c);
 size_t uart_write(uart_t* uart, const char* buf, size_t size);
 int uart_read_char(uart_t* uart);
 int uart_peek_char(uart_t* uart);
+size_t uart_read(uart_t* uart, char* buffer, size_t size);
 size_t uart_rx_available(uart_t* uart);
 size_t uart_tx_free(uart_t* uart);
 void uart_wait_tx_empty(uart_t* uart);

From f79bc9090ddb2b0d97deb6e6fe62c81524d43637 Mon Sep 17 00:00:00 2001
From: David Gauchard <gauchard@laas.fr>
Date: Thu, 5 Apr 2018 15:10:05 +0200
Subject: [PATCH 02/21] uart: read_char straightly use hw buffer

---
 cores/esp8266/HardwareSerial.h |  4 +--
 cores/esp8266/uart.c           | 55 ++++++++++++++++++++++++----------
 2 files changed, 42 insertions(+), 17 deletions(-)

diff --git a/cores/esp8266/HardwareSerial.h b/cores/esp8266/HardwareSerial.h
index 532ed64241..26b190bcf9 100644
--- a/cores/esp8266/HardwareSerial.h
+++ b/cores/esp8266/HardwareSerial.h
@@ -132,11 +132,11 @@ class HardwareSerial: public Stream
         // this may return -1, but that's okay
         return uart_read_char(_uart);
     }
-    size_t readBytes (char* buffer, size_t size) override
+    size_t readBytes(char* buffer, size_t size) override
     {
         return uart_read(_uart, buffer, size);
     }
-    size_t readBytes (uint8_t* buffer, size_t size) override
+    size_t readBytes(uint8_t* buffer, size_t size) override
     {
         return uart_read(_uart, (char*)buffer, size);
     }
diff --git a/cores/esp8266/uart.c b/cores/esp8266/uart.c
index 9ac932e8ed..4b3b4021a0 100644
--- a/cores/esp8266/uart.c
+++ b/cores/esp8266/uart.c
@@ -108,14 +108,12 @@ uart_rx_available_unsafe(uart_t* uart)
     return uart_rx_buffer_available_unsafe(uart->rx_buffer) + uart_rx_fifo_available(uart->uart_nr);
 }
 
-//#define UART_DISCARD_NEWEST
-
 // Copy all the rx fifo bytes that fit into the rx buffer
 inline void 
-ICACHE_RAM_ATTR
 uart_rx_copy_fifo_to_buffer_unsafe(uart_t* uart) 
 {
     struct uart_rx_buffer_ *rx_buffer = uart->rx_buffer;
+
     while(uart_rx_fifo_available(uart->uart_nr))
     {
         size_t nextPos = (rx_buffer->wpos + 1) % rx_buffer->size;
@@ -136,11 +134,14 @@ uart_peek_char_unsafe(uart_t* uart)
    
     //without the following if statement and body, there is a good chance of a fifo overrun
     if (uart_rx_buffer_available_unsafe(uart->rx_buffer) == 0)
+        // hw fifo can't be peeked, data need to be copied to sw
         uart_rx_copy_fifo_to_buffer_unsafe(uart);
     
     return uart->rx_buffer->buffer[uart->rx_buffer->rpos];
 }
 
+#if 0
+
 inline int 
 uart_read_char_unsafe(uart_t* uart)
 {
@@ -150,7 +151,31 @@ uart_read_char_unsafe(uart_t* uart)
     return data;
 }
 
+#else
 
+// taking data straight from hw fifo: loopback-test BW jumps by 19%
+inline int
+uart_read_char_unsafe(uart_t* uart)
+{
+    if (uart_rx_buffer_available_unsafe(uart->rx_buffer))
+    {
+        // take oldest sw data
+        int ret = uart->rx_buffer->buffer[uart->rx_buffer->rpos];
+        uart->rx_buffer->rpos = (uart->rx_buffer->rpos + 1) % uart->rx_buffer->size;
+        return ret;
+    }
+
+    if (uart_rx_fifo_available(uart->uart_nr))
+    {
+        // no sw data, take from hw fifo
+        return USF(uart->uart_nr);
+    }
+
+    // unavailable
+    return -1;
+}
+
+#endif
 /**********************************************************/
 
 
@@ -195,6 +220,7 @@ uart_read_char(uart_t* uart)
 extern void iprint (int x);
 extern void sprint (const char* s);
 
+// loopback-test BW jumps by 190%
 size_t
 uart_read(uart_t* uart, char* userbuffer, size_t usersize)
 {
@@ -202,23 +228,20 @@ uart_read(uart_t* uart, char* userbuffer, size_t usersize)
         return -1;
 
     size_t ret = 0;
-    
     ETS_UART_INTR_DISABLE();
 
-sprint("a");iprint(usersize);iprint(uart->rx_buffer->rpos);
     while (ret < usersize && uart_rx_available_unsafe(uart))
     {
-#if 1
         if (!uart_rx_buffer_available_unsafe(uart->rx_buffer))
         {
             // no more data in sw buffer, take them from hw fifo
             while (ret < usersize && uart_rx_fifo_available(uart->uart_nr))
-	    	userbuffer[ret++] = USF(uart->uart_nr);
-	    	
+                userbuffer[ret++] = USF(uart->uart_nr);
+
 	    // no more sw/hw data available
-    	    break;
+            break;
         }
-#endif
+
         // pour sw buffer to user's buffer
         // get largest linear length from sw buffer
         size_t chunk = uart->rx_buffer->rpos < uart->rx_buffer->wpos?
@@ -230,8 +253,7 @@ sprint("a");iprint(usersize);iprint(uart->rx_buffer->rpos);
         uart->rx_buffer->rpos = (uart->rx_buffer->rpos + chunk) % uart->rx_buffer->size;
         ret += chunk;
     }
-iprint(ret);iprint(uart->rx_buffer->rpos);
-    
+
     ETS_UART_INTR_ENABLE();
     return ret;
 }
@@ -306,7 +328,12 @@ uart_start_isr(uart_t* uart)
     // triggers the IRS very often.  A value of 127 would not leave much time
     // for ISR to clear fifo before the next byte is dropped.  So pick a value
     // in the middle.
-    #define INTRIGG 100 // was:100
+    // update: loopback test @ 3Mbauds/8n1 (=2343Kibits/s):
+    // - 4..120 give 2300Kibits/s
+    // - 1, 2, 3 are below
+    // was 100, use 8 to stay away from overrun
+    #define INTRIGG 8
+
     //was:USC1(uart->uart_nr) = (INTRIGG << UCFFT) | (0x02 << UCTOT) | (1 <<UCTOE);
     USC1(uart->uart_nr) = (INTRIGG << UCFFT);
     USIC(uart->uart_nr) = 0xffff;
@@ -353,11 +380,9 @@ uart_tx_fifo_full(const int uart_nr)
 static void 
 uart_do_write_char(const int uart_nr, char c)
 {
-    ETS_UART_INTR_DISABLE();
     while(uart_tx_fifo_full(uart_nr));
 
     USF(uart_nr) = c;
-    ETS_UART_INTR_ENABLE();
 }
 
 size_t 

From 45e2bd5fdcb5b5241f428472ef777b48d2cc3351 Mon Sep 17 00:00:00 2001
From: David Gauchard <gauchard@laas.fr>
Date: Thu, 5 Apr 2018 15:21:17 +0200
Subject: [PATCH 03/21] +attributes for functions called by ISR

---
 cores/esp8266/uart.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/cores/esp8266/uart.c b/cores/esp8266/uart.c
index 4b3b4021a0..e0f597435d 100644
--- a/cores/esp8266/uart.c
+++ b/cores/esp8266/uart.c
@@ -83,7 +83,8 @@ struct uart_
 
 
 
-inline size_t 
+// called by ISR
+inline size_t ICACHE_RAM_ATTR
 uart_rx_fifo_available(const int uart_nr) 
 {
     return (USS(uart_nr) >> USRXC) & 0xFF;
@@ -109,7 +110,8 @@ uart_rx_available_unsafe(uart_t* uart)
 }
 
 // Copy all the rx fifo bytes that fit into the rx buffer
-inline void 
+// called by ISR
+inline void ICACHE_RAM_ATTR
 uart_rx_copy_fifo_to_buffer_unsafe(uart_t* uart) 
 {
     struct uart_rx_buffer_ *rx_buffer = uart->rx_buffer;

From 974b758412171daf2b9e4f773608618677932a30 Mon Sep 17 00:00:00 2001
From: david gauchard <gauchard@laas.fr>
Date: Thu, 5 Apr 2018 01:55:33 +0200
Subject: [PATCH 04/21] uart: BW improvements read_char straightly use hw
 buffer (+ ~10%bw) read by block (+ ~190%bw) (instead of generic
 Stream::readBytes) attributes for functions called by ISR remove overrun
 message remove some ISR flags which were not honoured

---
 cores/esp8266/HardwareSerial.h |  8 +++
 cores/esp8266/uart.c           | 89 +++++++++++++++++++++++++++-------
 cores/esp8266/uart.h           |  1 +
 3 files changed, 80 insertions(+), 18 deletions(-)

diff --git a/cores/esp8266/HardwareSerial.h b/cores/esp8266/HardwareSerial.h
index 0333d4ca87..a8ab643049 100644
--- a/cores/esp8266/HardwareSerial.h
+++ b/cores/esp8266/HardwareSerial.h
@@ -128,6 +128,14 @@ class HardwareSerial: public Stream
         // this may return -1, but that's okay
         return uart_read_char(_uart);
     }
+    size_t readBytes(char* buffer, size_t size) override
+    {
+        return uart_read(_uart, buffer, size);
+    }
+    size_t readBytes(uint8_t* buffer, size_t size) override
+    {
+        return uart_read(_uart, (char*)buffer, size);
+    }
     int availableForWrite(void)
     {
         return static_cast<int>(uart_tx_free(_uart));
diff --git a/cores/esp8266/uart.c b/cores/esp8266/uart.c
index 47814f7a9d..b033dc65ec 100644
--- a/cores/esp8266/uart.c
+++ b/cores/esp8266/uart.c
@@ -45,7 +45,6 @@
 #include "esp8266_peri.h"
 #include "user_interface.h"
 
-const char overrun_str [] ICACHE_RODATA_ATTR STORE_ATTR = "uart input full!\r\n";
 static int s_uart_debug_nr = UART0;
 
 
@@ -83,7 +82,8 @@ struct uart_
 
 
 
-inline size_t 
+// called by ISR
+inline size_t ICACHE_RAM_ATTR
 uart_rx_fifo_available(const int uart_nr) 
 {
     return (USS(uart_nr) >> USRXC) & 0xFF;
@@ -108,11 +108,11 @@ uart_rx_available_unsafe(uart_t* uart)
     return uart_rx_buffer_available_unsafe(uart->rx_buffer) + uart_rx_fifo_available(uart->uart_nr);
 }
 
-
 //#define UART_DISCARD_NEWEST
 
 // Copy all the rx fifo bytes that fit into the rx buffer
-inline void 
+// called by ISR
+inline void ICACHE_RAM_ATTR
 uart_rx_copy_fifo_to_buffer_unsafe(uart_t* uart) 
 {
     struct uart_rx_buffer_ *rx_buffer = uart->rx_buffer;
@@ -122,12 +122,7 @@ uart_rx_copy_fifo_to_buffer_unsafe(uart_t* uart)
         size_t nextPos = (rx_buffer->wpos + 1) % rx_buffer->size;
         if(nextPos == rx_buffer->rpos) 
         {
-
-            if (!uart->overrun) 
-            {
-                uart->overrun = true;
-                os_printf_plus(overrun_str);
-            }
+            uart->overrun = true;
 
             // a choice has to be made here,
             // do we discard newest or oldest data?
@@ -156,20 +151,33 @@ uart_peek_char_unsafe(uart_t* uart)
    
     //without the following if statement and body, there is a good chance of a fifo overrun
     if (uart_rx_buffer_available_unsafe(uart->rx_buffer) == 0)
+        // hw fifo can't be peeked, data need to be copied to sw
         uart_rx_copy_fifo_to_buffer_unsafe(uart);
     
     return uart->rx_buffer->buffer[uart->rx_buffer->rpos];
 }
 
-inline int 
+// taking data straight from hw fifo: loopback-test BW jumps by 19%
+inline int
 uart_read_char_unsafe(uart_t* uart)
 {
-    int data = uart_peek_char_unsafe(uart);
-    if(data != -1)
+    if (uart_rx_buffer_available_unsafe(uart->rx_buffer))
+    {
+        // take oldest sw data
+        int ret = uart->rx_buffer->buffer[uart->rx_buffer->rpos];
         uart->rx_buffer->rpos = (uart->rx_buffer->rpos + 1) % uart->rx_buffer->size;
-    return data;
-}
+        return ret;
+    }
+
+    if (uart_rx_fifo_available(uart->uart_nr))
+    {
+        // no sw data, take from hw fifo
+        return USF(uart->uart_nr);
+    }
 
+    // unavailable
+    return -1;
+}
 
 /**********************************************************/
 
@@ -212,6 +220,44 @@ uart_read_char(uart_t* uart)
     return data;
 }
 
+// loopback-test BW jumps by 190%
+size_t
+uart_read(uart_t* uart, char* userbuffer, size_t usersize)
+{
+    if(uart == NULL || !uart->rx_enabled)
+        return -1;
+
+    size_t ret = 0;
+    ETS_UART_INTR_DISABLE();
+
+    while (ret < usersize && uart_rx_available_unsafe(uart))
+    {
+        if (!uart_rx_buffer_available_unsafe(uart->rx_buffer))
+        {
+            // no more data in sw buffer, take them from hw fifo
+            while (ret < usersize && uart_rx_fifo_available(uart->uart_nr))
+                userbuffer[ret++] = USF(uart->uart_nr);
+
+            // no more sw/hw data available
+            break;
+        }
+
+        // pour sw buffer to user's buffer
+        // get largest linear length from sw buffer
+        size_t chunk = uart->rx_buffer->rpos < uart->rx_buffer->wpos?
+                           uart->rx_buffer->wpos - uart->rx_buffer->rpos:
+                           uart->rx_buffer->size - uart->rx_buffer->rpos;
+        if (ret + chunk > usersize)
+            chunk = usersize - ret;
+        memcpy(userbuffer + ret, uart->rx_buffer->buffer + uart->rx_buffer->rpos, chunk);
+        uart->rx_buffer->rpos = (uart->rx_buffer->rpos + chunk) % uart->rx_buffer->size;
+        ret += chunk;
+    }
+
+    ETS_UART_INTR_ENABLE();
+    return ret;
+}
+
 size_t 
 uart_resize_rx_buffer(uart_t* uart, size_t new_size)
 {
@@ -252,7 +298,7 @@ uart_isr(void * arg)
         ETS_UART_INTR_DISABLE();
         return;
     }
-    if(USIS(uart->uart_nr) & ((1 << UIFF) | (1 << UITO)))
+    if(USIS(uart->uart_nr) & (1 << UIFF))
         uart_rx_copy_fifo_to_buffer_unsafe(uart);
     
     USIC(uart->uart_nr) = USIS(uart->uart_nr);
@@ -268,9 +314,16 @@ uart_start_isr(uart_t* uart)
     // triggers the IRS very often.  A value of 127 would not leave much time
     // for ISR to clear fifo before the next byte is dropped.  So pick a value
     // in the middle.
-    USC1(uart->uart_nr) = (100   << UCFFT) | (0x02 << UCTOT) | (1 <<UCTOE );
+    // update: with direct peeking and loopback test @ 3Mbauds/8n1 (=2343Kibits/s):
+    // when high, allows to directly peek into hw buffer, avoiding two copies
+    // - 4..120 give 2300Kibits/s
+    // - 1, 2, 3 are below
+    // - far below 2000 without direct peeking
+    #define INTRIGGER 100
+
+    USC1(uart->uart_nr) = (INTRIGGER << UCFFT);
     USIC(uart->uart_nr) = 0xffff;
-    USIE(uart->uart_nr) = (1 << UIFF) | (1 << UIFR) | (1 << UITO);
+    USIE(uart->uart_nr) = (1 << UIFF);
     ETS_UART_INTR_ATTACH(uart_isr,  (void *)uart);
     ETS_UART_INTR_ENABLE();
 }
diff --git a/cores/esp8266/uart.h b/cores/esp8266/uart.h
index 127c5d0ebb..e0a36eb5d2 100644
--- a/cores/esp8266/uart.h
+++ b/cores/esp8266/uart.h
@@ -131,6 +131,7 @@ size_t uart_write_char(uart_t* uart, char c);
 size_t uart_write(uart_t* uart, const char* buf, size_t size);
 int uart_read_char(uart_t* uart);
 int uart_peek_char(uart_t* uart);
+size_t uart_read(uart_t* uart, char* buffer, size_t size);
 size_t uart_rx_available(uart_t* uart);
 size_t uart_tx_free(uart_t* uart);
 void uart_wait_tx_empty(uart_t* uart);

From 6560ab87f509fbeb6e1827aaed90f866ccde37d3 Mon Sep 17 00:00:00 2001
From: David Gauchard <gauchard@laas.fr>
Date: Fri, 30 Nov 2018 15:19:17 +0100
Subject: [PATCH 05/21] fix merge

---
 cores/esp8266/HardwareSerial.h |  4 +-
 cores/esp8266/uart.c           | 89 +++++-----------------------------
 2 files changed, 15 insertions(+), 78 deletions(-)

diff --git a/cores/esp8266/HardwareSerial.h b/cores/esp8266/HardwareSerial.h
index cddd4fe311..54d600ccca 100644
--- a/cores/esp8266/HardwareSerial.h
+++ b/cores/esp8266/HardwareSerial.h
@@ -124,12 +124,12 @@ class HardwareSerial: public Stream
 
     int peek(void) override
     {
-        // this may return -1, but that's okay
+        // return -1 when data is unvailable (arduino api)
         return uart_peek_char(_uart);
     }
     int read(void) override
     {
-        // this may return -1, but that's okay
+        // return -1 when data is unvailable (arduino api)
         return uart_read_char(_uart);
     }
     size_t readBytes(char* buffer, size_t size) override
diff --git a/cores/esp8266/uart.c b/cores/esp8266/uart.c
index 69ab124a7a..f78b78cfef 100644
--- a/cores/esp8266/uart.c
+++ b/cores/esp8266/uart.c
@@ -47,7 +47,7 @@
 #include "user_interface.h"
 #include "uart_register.h"
 
-//const char overrun_str [] PROGMEM STORE_ATTR = "uart input full!\r\n";
+const char overrun_str [] PROGMEM STORE_ATTR = "uart input full!\r\n";
 static int s_uart_debug_nr = UART0;
 
 
@@ -111,11 +111,8 @@ uart_rx_available_unsafe(uart_t* uart)
     return uart_rx_buffer_available_unsafe(uart->rx_buffer) + uart_rx_fifo_available(uart->uart_nr);
 }
 
-<<<<<<< HEAD
-=======
 //#define UART_DISCARD_NEWEST
 
->>>>>>> 3c1e312faff1669b62cfd47bee6edaea49785aa5
 // Copy all the rx fifo bytes that fit into the rx buffer
 // called by ISR
 inline void ICACHE_RAM_ATTR
@@ -127,10 +124,12 @@ uart_rx_copy_fifo_to_buffer_unsafe(uart_t* uart)
     {
         size_t nextPos = (rx_buffer->wpos + 1) % rx_buffer->size;
         if(nextPos == rx_buffer->rpos) 
-<<<<<<< HEAD
-=======
         {
-            uart->overrun = true;
+            if (!uart->overrun) 
+            {
+                uart->overrun = true;
+                os_printf_plus(overrun_str);
+            }
 
             // a choice has to be made here,
             // do we discard newest or oldest data?
@@ -138,15 +137,19 @@ uart_rx_copy_fifo_to_buffer_unsafe(uart_t* uart)
             // discard newest data
             // Stop copying if rx buffer is full
             USF(uart->uart_nr);
->>>>>>> 3c1e312faff1669b62cfd47bee6edaea49785aa5
             break;
+#else
+            // discard oldest data
+            if (++rx_buffer->rpos == rx_buffer->size)
+                rx_buffer->rpos = 0;
+#endif
+        }
         uint8_t data = USF(uart->uart_nr);
         rx_buffer->buffer[rx_buffer->wpos] = data;
         rx_buffer->wpos = nextPos;
     }
 }
 
-
 inline int 
 uart_peek_char_unsafe(uart_t* uart)
 {
@@ -161,27 +164,6 @@ uart_peek_char_unsafe(uart_t* uart)
     return uart->rx_buffer->buffer[uart->rx_buffer->rpos];
 }
 
-<<<<<<< HEAD
-#if 0
-
-inline int 
-=======
-// taking data straight from hw fifo: loopback-test BW jumps by 19%
-inline int
->>>>>>> 3c1e312faff1669b62cfd47bee6edaea49785aa5
-uart_read_char_unsafe(uart_t* uart)
-{
-    if (uart_rx_buffer_available_unsafe(uart->rx_buffer))
-    {
-        // take oldest sw data
-        int ret = uart->rx_buffer->buffer[uart->rx_buffer->rpos];
-        uart->rx_buffer->rpos = (uart->rx_buffer->rpos + 1) % uart->rx_buffer->size;
-        return ret;
-    }
-
-<<<<<<< HEAD
-#else
-
 // taking data straight from hw fifo: loopback-test BW jumps by 19%
 inline int
 uart_read_char_unsafe(uart_t* uart)
@@ -193,33 +175,11 @@ uart_read_char_unsafe(uart_t* uart)
         uart->rx_buffer->rpos = (uart->rx_buffer->rpos + 1) % uart->rx_buffer->size;
         return ret;
     }
-=======
-    if (uart_rx_fifo_available(uart->uart_nr))
-    {
-        // no sw data, take from hw fifo
-        return USF(uart->uart_nr);
-    }
-
-    // unavailable
-    return -1;
-}
->>>>>>> 3c1e312faff1669b62cfd47bee6edaea49785aa5
-
-    if (uart_rx_fifo_available(uart->uart_nr))
-    {
-        // no sw data, take from hw fifo
-        return USF(uart->uart_nr);
-    }
 
     // unavailable
-    return -1;
+    return -3;
 }
 
-#endif
-/**********************************************************/
-
-
-
 size_t 
 uart_rx_available(uart_t* uart)
 {
@@ -257,12 +217,6 @@ uart_read_char(uart_t* uart)
     return data;
 }
 
-<<<<<<< HEAD
-extern void iprint (int x);
-extern void sprint (const char* s);
-
-=======
->>>>>>> 3c1e312faff1669b62cfd47bee6edaea49785aa5
 // loopback-test BW jumps by 190%
 size_t
 uart_read(uart_t* uart, char* userbuffer, size_t usersize)
@@ -281,11 +235,7 @@ uart_read(uart_t* uart, char* userbuffer, size_t usersize)
             while (ret < usersize && uart_rx_fifo_available(uart->uart_nr))
                 userbuffer[ret++] = USF(uart->uart_nr);
 
-<<<<<<< HEAD
 	    // no more sw/hw data available
-=======
-            // no more sw/hw data available
->>>>>>> 3c1e312faff1669b62cfd47bee6edaea49785aa5
             break;
         }
 
@@ -375,7 +325,6 @@ uart_start_isr(uart_t* uart)
     // triggers the IRS very often.  A value of 127 would not leave much time
     // for ISR to clear fifo before the next byte is dropped.  So pick a value
     // in the middle.
-<<<<<<< HEAD
     // update: loopback test @ 3Mbauds/8n1 (=2343Kibits/s):
     // - 4..120 give 2300Kibits/s
     // - 1, 2, 3 are below
@@ -387,18 +336,6 @@ uart_start_isr(uart_t* uart)
     USIC(uart->uart_nr) = 0xffff;
     //was: USIE(uart->uart_nr) = (1 << UIFF) | (1 << UIFR) | (1 << UITO);
     USIE(uart->uart_nr) = (1 << UIFF) | (1 << UIOF);
-=======
-    // update: with direct peeking and loopback test @ 3Mbauds/8n1 (=2343Kibits/s):
-    // when high, allows to directly peek into hw buffer, avoiding two copies
-    // - 4..120 give 2300Kibits/s
-    // - 1, 2, 3 are below
-    // - far below 2000 without direct peeking
-    #define INTRIGGER 100
-
-    USC1(uart->uart_nr) = (INTRIGGER << UCFFT);
-    USIC(uart->uart_nr) = 0xffff;
-    USIE(uart->uart_nr) = (1 << UIFF);
->>>>>>> 3c1e312faff1669b62cfd47bee6edaea49785aa5
     ETS_UART_INTR_ATTACH(uart_isr,  (void *)uart);
     ETS_UART_INTR_ENABLE();
 }

From c68d474c4151f5b9a5964dbf96f3d9b092d9d71e Mon Sep 17 00:00:00 2001
From: David Gauchard <gauchard@laas.fr>
Date: Wed, 5 Dec 2018 13:02:47 +0100
Subject: [PATCH 06/21] fix buffer overflow

---
 cores/esp8266/uart.c | 16 ++++++----------
 1 file changed, 6 insertions(+), 10 deletions(-)

diff --git a/cores/esp8266/uart.c b/cores/esp8266/uart.c
index f78b78cfef..d4545ca2b8 100644
--- a/cores/esp8266/uart.c
+++ b/cores/esp8266/uart.c
@@ -175,9 +175,8 @@ uart_read_char_unsafe(uart_t* uart)
         uart->rx_buffer->rpos = (uart->rx_buffer->rpos + 1) % uart->rx_buffer->size;
         return ret;
     }
-
     // unavailable
-    return -3;
+    return -1;
 }
 
 size_t 
@@ -208,13 +207,8 @@ uart_peek_char(uart_t* uart)
 int 
 uart_read_char(uart_t* uart)
 {
-    if(uart == NULL || !uart->rx_enabled)
-        return -1;
-    
-    ETS_UART_INTR_DISABLE();
-    int data = uart_read_char_unsafe(uart);
-    ETS_UART_INTR_ENABLE();
-    return data;
+    uint8_t ret;
+    return uart_read(uart, (char*)&ret, 1)? ret: -1;
 }
 
 // loopback-test BW jumps by 190%
@@ -222,7 +216,7 @@ size_t
 uart_read(uart_t* uart, char* userbuffer, size_t usersize)
 {
     if(uart == NULL || !uart->rx_enabled)
-        return -1;
+        return 0;
 
     size_t ret = 0;
     ETS_UART_INTR_DISABLE();
@@ -272,6 +266,8 @@ uart_resize_rx_buffer(uart_t* uart, size_t new_size)
     ETS_UART_INTR_DISABLE();
     while(uart_rx_available_unsafe(uart) && new_wpos < new_size)
         new_buf[new_wpos++] = uart_read_char_unsafe(uart); //if uart_rx_available_unsafe() returns non-0, uart_read_char_unsafe() can't return -1
+    if (new_wpos == new_size)
+        new_wpos = 0;
     
     uint8_t * old_buf = uart->rx_buffer->buffer;
     uart->rx_buffer->rpos = 0;

From ff63718320cd3b539e4f6011ad9c5388f6966e07 Mon Sep 17 00:00:00 2001
From: David Gauchard <gauchard@laas.fr>
Date: Wed, 5 Dec 2018 13:18:58 +0100
Subject: [PATCH 07/21] serial stress test sketch

---
 cores/esp8266/uart.c                          |   6 +-
 .../examples/serialStress/serialStress.ino    | 164 ++++++++++++++++++
 2 files changed, 167 insertions(+), 3 deletions(-)
 create mode 100644 libraries/esp8266/examples/serialStress/serialStress.ino

diff --git a/cores/esp8266/uart.c b/cores/esp8266/uart.c
index d4545ca2b8..d47bc77840 100644
--- a/cores/esp8266/uart.c
+++ b/cores/esp8266/uart.c
@@ -322,10 +322,10 @@ uart_start_isr(uart_t* uart)
     // for ISR to clear fifo before the next byte is dropped.  So pick a value
     // in the middle.
     // update: loopback test @ 3Mbauds/8n1 (=2343Kibits/s):
-    // - 4..120 give 2300Kibits/s
+    // - 4..120 give > 2300Kibits/s
     // - 1, 2, 3 are below
-    // was 100, use 8 to stay away from overrun
-    #define INTRIGG 8
+    // was 100, use 16 to stay away from overrun
+    #define INTRIGG 16
 
     //was:USC1(uart->uart_nr) = (INTRIGG << UCFFT) | (0x02 << UCTOT) | (1 <<UCTOE);
     USC1(uart->uart_nr) = (INTRIGG << UCFFT);
diff --git a/libraries/esp8266/examples/serialStress/serialStress.ino b/libraries/esp8266/examples/serialStress/serialStress.ino
new file mode 100644
index 0000000000..b2c7df1bc6
--- /dev/null
+++ b/libraries/esp8266/examples/serialStress/serialStress.ino
@@ -0,0 +1,164 @@
+
+/*
+  Serial read/write/verify/benchmark
+  Using internal loopback
+  Using SoftwareSerial library for logging
+  
+  Sketch meant for debugging only
+  Released to public domain
+*/
+
+#include <ESP8266WiFi.h>
+#include <SoftwareSerial.h>
+
+#define SSBAUD          115200  // logger on console for humans
+#define BAUD            3000000 // hardware serial stress test
+#define BUFFER_SIZE     4096    // may be useless to use more than 2*SERIAL_SIZE_RX
+#define SERIAL_SIZE_RX  1024    // Serial.setRxBufferSize()
+
+#define TIMEOUT 5000
+#define DEBUG(x...) //x
+
+uint8_t buf [BUFFER_SIZE];
+uint8_t temp [BUFFER_SIZE];
+
+static size_t out_idx = 0, in_idx = 0;
+static size_t local_receive_size = 0;
+static size_t size_for_1sec, size_for_led = 0;
+static size_t maxavail = 0;
+static uint64_t in_total = 0, in_prev = 0;
+static uint64_t start_ms, last_ms;
+static uint64_t timeout;
+
+Stream* logger;
+
+void error (const char* what)
+{
+  logger->printf("\r\nerror: %s after %ld minutes\r\nread idx:  %d\r\nwrite idx: %d\r\ntotal:     %ld\r\nlast read: %d\r\nmaxavail:  %d\r\n",
+                 what, (long)((millis() - start_ms) / 60000), in_idx, out_idx, (long)in_total, (int)local_receive_size, maxavail);
+  if (Serial.hasOverrun())
+    logger->printf("overrun!\r\n");
+  logger->printf("should be (size=%d idx=%d..%d):\r\n    ", BUFFER_SIZE, in_idx, in_idx + local_receive_size - 1);
+  for (size_t i = in_idx; i < in_idx + local_receive_size; i++)
+    logger->printf("%02x(%c) ", buf[i], (unsigned char)((buf[i] > 31 && buf[i] < 128) ? buf[i] : '.'));
+  logger->print("\r\n\r\nis: ");
+  for (size_t i = 0; i < local_receive_size; i++)
+    logger->printf("%02x(%c) ", temp[i], (unsigned char)((temp[i] > 31 && temp[i] < 128) ? temp[i] : '.'));
+  logger->println("\r\n\r\n");
+
+  while (true)
+    delay(1000);
+}
+
+void preinit()
+{
+  // (no C++ in function)
+  // disable wifi
+  ESP8266WiFiClass::preinitWiFiOff();
+}
+
+void setup()
+{
+  pinMode(LED_BUILTIN, OUTPUT);
+
+  Serial.begin(BAUD);
+  Serial.swap(); // RX=GPIO13 TX=GPIO15
+  Serial.setRxBufferSize(SERIAL_SIZE_RX);
+
+  // using HardwareSerial0 pins,
+  // so we can still log to the regular usbserial chips
+  SoftwareSerial* ss = new SoftwareSerial(3, 1);
+  ss->begin(SSBAUD);
+  logger = ss;
+  logger->println();
+  logger->printf("\r\n\r\nOn Software Serial for logging\r\n");
+
+  int baud = Serial.baudRate();
+  logger->printf(ESP.getFullVersion().c_str());
+  logger->printf("\r\n\r\nBAUD: %d - CoreRxBuffer: %d bytes - TestBuffer: %d bytes\r\n",
+                 baud, SERIAL_SIZE_RX, BUFFER_SIZE);
+
+  size_for_1sec = baud / 10; // 8n1=10baudFor8bits
+  logger->printf("led changes state every %zd bytes (= 1 second)\r\n", size_for_1sec);
+
+  // prepare send/compare buffer
+  for (size_t i = 0; i < sizeof buf; i++)
+    buf[i] = (uint8_t)i;
+
+  // bind RX and TX
+  USC0(0) |= (1 << UCLBE);
+
+  while (Serial.read() == -1);
+  if (Serial.hasOverrun())
+    logger->print("overrun?\r\n");
+
+  timeout = (start_ms = last_ms = millis()) + TIMEOUT;
+  logger->println("setup done");
+}
+
+void loop()
+{
+  size_t maxlen = Serial.availableForWrite();
+  // check remaining space in buffer
+  if (maxlen > BUFFER_SIZE - out_idx)
+    maxlen = BUFFER_SIZE - out_idx;
+  // check if not cycling more than buffer size relatively to input
+  size_t in_out = out_idx == in_idx ?
+                  BUFFER_SIZE :
+                  (in_idx + BUFFER_SIZE - out_idx - 1) % BUFFER_SIZE;
+  if (maxlen > in_out)
+    maxlen = in_out;
+  DEBUG(logger->printf("(aw%i/w%i", Serial.availableForWrite(), maxlen));
+  size_t local_written_size = Serial.write(buf + out_idx, maxlen);
+  DEBUG(logger->printf(":w%i/aw%i/ar%i)\r\n", local_written_size, Serial.availableForWrite(), Serial.available()));
+  if (local_written_size > maxlen)
+    error("bad write");
+  if ((out_idx += local_written_size) == BUFFER_SIZE)
+    out_idx = 0;
+  delay(0);
+
+  DEBUG(logger->printf("----------\r\n"));
+
+  if (Serial.hasOverrun())
+    logger->printf("overrun!\r\n");
+
+  // receive data
+  maxlen = Serial.available();
+  if (maxlen > maxavail)
+    maxavail = maxlen;
+  // check space in temp receive buffer
+  if (maxlen > BUFFER_SIZE - in_idx)
+    maxlen = BUFFER_SIZE - in_idx;
+  DEBUG(logger->printf("(ar%i/r%i", Serial.available(), maxlen));
+  local_receive_size = Serial.readBytes(temp, maxlen);
+  DEBUG(logger->printf(":r%i/ar%i)\r\n", local_receive_size, Serial.available()));
+  if (local_receive_size > maxlen)
+    error("bad read");
+  if (local_receive_size)
+  {
+    if (memcmp(buf + in_idx, temp, local_receive_size) != 0)
+      error("fail");
+    if ((in_idx += local_receive_size) == BUFFER_SIZE)
+      in_idx = 0;
+    in_total += local_receive_size;
+  }
+  DEBUG(logger->printf("r(%d) ok\r\n", local_receive_size));
+
+  // say something on data every second
+  if ((size_for_led += local_written_size) >= size_for_1sec || millis() > timeout)
+  {
+    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
+    size_for_led = 0;
+
+    if (in_prev == in_total)
+      error("receiving nothing?\r\n");
+
+    unsigned long now_ms = millis();
+    int bwkbps_avg = ((((uint64_t)in_total) * 8000) / (now_ms - start_ms)) >> 10;
+    int bwkbps_now = (((in_total - in_prev) * 8000) / (now_ms - last_ms)) >> 10 ;
+    logger->printf("bwavg=%d bwnow=%d kbps maxavail=%i\r\n", bwkbps_avg, bwkbps_now, maxavail);
+
+    in_prev = in_total;
+    timeout = (last_ms = now_ms) + TIMEOUT;
+  }
+}

From 40f237f10fc52ae6837446197ff88ee7d0fc62f3 Mon Sep 17 00:00:00 2001
From: David Gauchard <gauchard@laas.fr>
Date: Wed, 5 Dec 2018 13:19:49 +0100
Subject: [PATCH 08/21] astyle

---
 .../examples/serialStress/serialStress.ino    | 71 +++++++++++--------
 1 file changed, 41 insertions(+), 30 deletions(-)

diff --git a/libraries/esp8266/examples/serialStress/serialStress.ino b/libraries/esp8266/examples/serialStress/serialStress.ino
index b2c7df1bc6..53d4ce034b 100644
--- a/libraries/esp8266/examples/serialStress/serialStress.ino
+++ b/libraries/esp8266/examples/serialStress/serialStress.ino
@@ -3,7 +3,7 @@
   Serial read/write/verify/benchmark
   Using internal loopback
   Using SoftwareSerial library for logging
-  
+
   Sketch meant for debugging only
   Released to public domain
 */
@@ -32,33 +32,34 @@ static uint64_t timeout;
 
 Stream* logger;
 
-void error (const char* what)
-{
+void error(const char* what) {
   logger->printf("\r\nerror: %s after %ld minutes\r\nread idx:  %d\r\nwrite idx: %d\r\ntotal:     %ld\r\nlast read: %d\r\nmaxavail:  %d\r\n",
                  what, (long)((millis() - start_ms) / 60000), in_idx, out_idx, (long)in_total, (int)local_receive_size, maxavail);
-  if (Serial.hasOverrun())
+  if (Serial.hasOverrun()) {
     logger->printf("overrun!\r\n");
+  }
   logger->printf("should be (size=%d idx=%d..%d):\r\n    ", BUFFER_SIZE, in_idx, in_idx + local_receive_size - 1);
-  for (size_t i = in_idx; i < in_idx + local_receive_size; i++)
+  for (size_t i = in_idx; i < in_idx + local_receive_size; i++) {
     logger->printf("%02x(%c) ", buf[i], (unsigned char)((buf[i] > 31 && buf[i] < 128) ? buf[i] : '.'));
+  }
   logger->print("\r\n\r\nis: ");
-  for (size_t i = 0; i < local_receive_size; i++)
+  for (size_t i = 0; i < local_receive_size; i++) {
     logger->printf("%02x(%c) ", temp[i], (unsigned char)((temp[i] > 31 && temp[i] < 128) ? temp[i] : '.'));
+  }
   logger->println("\r\n\r\n");
 
-  while (true)
+  while (true) {
     delay(1000);
+  }
 }
 
-void preinit()
-{
+void preinit() {
   // (no C++ in function)
   // disable wifi
   ESP8266WiFiClass::preinitWiFiOff();
 }
 
-void setup()
-{
+void setup() {
   pinMode(LED_BUILTIN, OUTPUT);
 
   Serial.begin(BAUD);
@@ -82,76 +83,86 @@ void setup()
   logger->printf("led changes state every %zd bytes (= 1 second)\r\n", size_for_1sec);
 
   // prepare send/compare buffer
-  for (size_t i = 0; i < sizeof buf; i++)
+  for (size_t i = 0; i < sizeof buf; i++) {
     buf[i] = (uint8_t)i;
+  }
 
   // bind RX and TX
   USC0(0) |= (1 << UCLBE);
 
   while (Serial.read() == -1);
-  if (Serial.hasOverrun())
+  if (Serial.hasOverrun()) {
     logger->print("overrun?\r\n");
+  }
 
   timeout = (start_ms = last_ms = millis()) + TIMEOUT;
   logger->println("setup done");
 }
 
-void loop()
-{
+void loop() {
   size_t maxlen = Serial.availableForWrite();
   // check remaining space in buffer
-  if (maxlen > BUFFER_SIZE - out_idx)
+  if (maxlen > BUFFER_SIZE - out_idx) {
     maxlen = BUFFER_SIZE - out_idx;
+  }
   // check if not cycling more than buffer size relatively to input
   size_t in_out = out_idx == in_idx ?
                   BUFFER_SIZE :
                   (in_idx + BUFFER_SIZE - out_idx - 1) % BUFFER_SIZE;
-  if (maxlen > in_out)
+  if (maxlen > in_out) {
     maxlen = in_out;
+  }
   DEBUG(logger->printf("(aw%i/w%i", Serial.availableForWrite(), maxlen));
   size_t local_written_size = Serial.write(buf + out_idx, maxlen);
   DEBUG(logger->printf(":w%i/aw%i/ar%i)\r\n", local_written_size, Serial.availableForWrite(), Serial.available()));
-  if (local_written_size > maxlen)
+  if (local_written_size > maxlen) {
     error("bad write");
-  if ((out_idx += local_written_size) == BUFFER_SIZE)
+  }
+  if ((out_idx += local_written_size) == BUFFER_SIZE) {
     out_idx = 0;
+  }
   delay(0);
 
   DEBUG(logger->printf("----------\r\n"));
 
-  if (Serial.hasOverrun())
+  if (Serial.hasOverrun()) {
     logger->printf("overrun!\r\n");
+  }
 
   // receive data
   maxlen = Serial.available();
-  if (maxlen > maxavail)
+  if (maxlen > maxavail) {
     maxavail = maxlen;
+  }
   // check space in temp receive buffer
-  if (maxlen > BUFFER_SIZE - in_idx)
+  if (maxlen > BUFFER_SIZE - in_idx) {
     maxlen = BUFFER_SIZE - in_idx;
+  }
   DEBUG(logger->printf("(ar%i/r%i", Serial.available(), maxlen));
   local_receive_size = Serial.readBytes(temp, maxlen);
   DEBUG(logger->printf(":r%i/ar%i)\r\n", local_receive_size, Serial.available()));
-  if (local_receive_size > maxlen)
+  if (local_receive_size > maxlen) {
     error("bad read");
-  if (local_receive_size)
-  {
-    if (memcmp(buf + in_idx, temp, local_receive_size) != 0)
+  }
+  if (local_receive_size) {
+    if (memcmp(buf + in_idx, temp, local_receive_size) != 0) {
       error("fail");
-    if ((in_idx += local_receive_size) == BUFFER_SIZE)
+    }
+    if ((in_idx += local_receive_size) == BUFFER_SIZE) {
       in_idx = 0;
+    }
     in_total += local_receive_size;
   }
   DEBUG(logger->printf("r(%d) ok\r\n", local_receive_size));
 
   // say something on data every second
-  if ((size_for_led += local_written_size) >= size_for_1sec || millis() > timeout)
-  {
+  if ((size_for_led += local_written_size) >= size_for_1sec || millis() > timeout) {
     digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
     size_for_led = 0;
 
-    if (in_prev == in_total)
+    if (in_prev == in_total) {
       error("receiving nothing?\r\n");
+    }
 
     unsigned long now_ms = millis();
     int bwkbps_avg = ((((uint64_t)in_total) * 8000) / (now_ms - start_ms)) >> 10;

From 3428144634a0d797709c8fa9c25db049b880a2c7 Mon Sep 17 00:00:00 2001
From: david gauchard <gauchard@laas.fr>
Date: Wed, 5 Dec 2018 23:07:05 +0100
Subject: [PATCH 09/21] serial stress example: interactive keyboard, stop
 reading, overrun

---
 .../examples/serialStress/serialStress.ino    | 82 +++++++++++--------
 1 file changed, 46 insertions(+), 36 deletions(-)

diff --git a/libraries/esp8266/examples/serialStress/serialStress.ino b/libraries/esp8266/examples/serialStress/serialStress.ino
index 53d4ce034b..7b25ff9f2f 100644
--- a/libraries/esp8266/examples/serialStress/serialStress.ino
+++ b/libraries/esp8266/examples/serialStress/serialStress.ino
@@ -21,6 +21,7 @@
 
 uint8_t buf [BUFFER_SIZE];
 uint8_t temp [BUFFER_SIZE];
+bool reading = true;
 
 static size_t out_idx = 0, in_idx = 0;
 static size_t local_receive_size = 0;
@@ -33,20 +34,20 @@ static uint64_t timeout;
 Stream* logger;
 
 void error(const char* what) {
-  logger->printf("\r\nerror: %s after %ld minutes\r\nread idx:  %d\r\nwrite idx: %d\r\ntotal:     %ld\r\nlast read: %d\r\nmaxavail:  %d\r\n",
+  logger->printf("\nerror: %s after %ld minutes\nread idx:  %d\nwrite idx: %d\ntotal:     %ld\nlast read: %d\nmaxavail:  %d\n",
                  what, (long)((millis() - start_ms) / 60000), in_idx, out_idx, (long)in_total, (int)local_receive_size, maxavail);
   if (Serial.hasOverrun()) {
-    logger->printf("overrun!\r\n");
+    logger->printf("overrun!\n");
   }
-  logger->printf("should be (size=%d idx=%d..%d):\r\n    ", BUFFER_SIZE, in_idx, in_idx + local_receive_size - 1);
+  logger->printf("should be (size=%d idx=%d..%d):\n    ", BUFFER_SIZE, in_idx, in_idx + local_receive_size - 1);
   for (size_t i = in_idx; i < in_idx + local_receive_size; i++) {
     logger->printf("%02x(%c) ", buf[i], (unsigned char)((buf[i] > 31 && buf[i] < 128) ? buf[i] : '.'));
   }
-  logger->print("\r\n\r\nis: ");
+  logger->print("\n\nis: ");
   for (size_t i = 0; i < local_receive_size; i++) {
     logger->printf("%02x(%c) ", temp[i], (unsigned char)((temp[i] > 31 && temp[i] < 128) ? temp[i] : '.'));
   }
-  logger->println("\r\n\r\n");
+  logger->println("\n\n");
 
   while (true) {
     delay(1000);
@@ -72,15 +73,15 @@ void setup() {
   ss->begin(SSBAUD);
   logger = ss;
   logger->println();
-  logger->printf("\r\n\r\nOn Software Serial for logging\r\n");
+  logger->printf("\n\nOn Software Serial for logging\n");
 
   int baud = Serial.baudRate();
   logger->printf(ESP.getFullVersion().c_str());
-  logger->printf("\r\n\r\nBAUD: %d - CoreRxBuffer: %d bytes - TestBuffer: %d bytes\r\n",
+  logger->printf("\n\nBAUD: %d - CoreRxBuffer: %d bytes - TestBuffer: %d bytes\n",
                  baud, SERIAL_SIZE_RX, BUFFER_SIZE);
 
   size_for_1sec = baud / 10; // 8n1=10baudFor8bits
-  logger->printf("led changes state every %zd bytes (= 1 second)\r\n", size_for_1sec);
+  logger->printf("led changes state every %zd bytes (= 1 second)\n", size_for_1sec);
 
   // prepare send/compare buffer
   for (size_t i = 0; i < sizeof buf; i++) {
@@ -92,7 +93,7 @@ void setup() {
 
   while (Serial.read() == -1);
   if (Serial.hasOverrun()) {
-    logger->print("overrun?\r\n");
+    logger->print("overrun?\n");
   }
 
   timeout = (start_ms = last_ms = millis()) + TIMEOUT;
@@ -114,7 +115,7 @@ void loop() {
   }
   DEBUG(logger->printf("(aw%i/w%i", Serial.availableForWrite(), maxlen));
   size_t local_written_size = Serial.write(buf + out_idx, maxlen);
-  DEBUG(logger->printf(":w%i/aw%i/ar%i)\r\n", local_written_size, Serial.availableForWrite(), Serial.available()));
+  DEBUG(logger->printf(":w%i/aw%i/ar%i)\n", local_written_size, Serial.availableForWrite(), Serial.available()));
   if (local_written_size > maxlen) {
     error("bad write");
   }
@@ -123,37 +124,40 @@ void loop() {
   }
   delay(0);
 
-  DEBUG(logger->printf("----------\r\n"));
+  DEBUG(logger->printf("----------\n"));
 
   if (Serial.hasOverrun()) {
-    logger->printf("overrun!\r\n");
+    logger->printf("overrun!\n");
   }
 
-  // receive data
-  maxlen = Serial.available();
-  if (maxlen > maxavail) {
-    maxavail = maxlen;
-  }
-  // check space in temp receive buffer
-  if (maxlen > BUFFER_SIZE - in_idx) {
-    maxlen = BUFFER_SIZE - in_idx;
-  }
-  DEBUG(logger->printf("(ar%i/r%i", Serial.available(), maxlen));
-  local_receive_size = Serial.readBytes(temp, maxlen);
-  DEBUG(logger->printf(":r%i/ar%i)\r\n", local_receive_size, Serial.available()));
-  if (local_receive_size > maxlen) {
-    error("bad read");
-  }
-  if (local_receive_size) {
-    if (memcmp(buf + in_idx, temp, local_receive_size) != 0) {
-      error("fail");
+  if (reading)
+  {
+    // receive data
+    maxlen = Serial.available();
+    if (maxlen > maxavail) {
+      maxavail = maxlen;
+    }
+    // check space in temp receive buffer
+    if (maxlen > BUFFER_SIZE - in_idx) {
+      maxlen = BUFFER_SIZE - in_idx;
     }
-    if ((in_idx += local_receive_size) == BUFFER_SIZE) {
-      in_idx = 0;
+    DEBUG(logger->printf("(ar%i/r%i", Serial.available(), maxlen));
+    local_receive_size = Serial.readBytes(temp, maxlen);
+    DEBUG(logger->printf(":r%i/ar%i)\n", local_receive_size, Serial.available()));
+    if (local_receive_size > maxlen) {
+      error("bad read");
     }
-    in_total += local_receive_size;
+    if (local_receive_size) {
+      if (memcmp(buf + in_idx, temp, local_receive_size) != 0) {
+        error("fail");
+      }
+      if ((in_idx += local_receive_size) == BUFFER_SIZE) {
+        in_idx = 0;
+      }
+      in_total += local_receive_size;
+    }
+    DEBUG(logger->printf("r(%d) ok\n", local_receive_size));
   }
-  DEBUG(logger->printf("r(%d) ok\r\n", local_receive_size));
 
   // say something on data every second
   if ((size_for_led += local_written_size) >= size_for_1sec || millis() > timeout) {
@@ -161,15 +165,21 @@ void loop() {
     size_for_led = 0;
 
     if (in_prev == in_total) {
-      error("receiving nothing?\r\n");
+      error("receiving nothing?\n");
     }
 
     unsigned long now_ms = millis();
     int bwkbps_avg = ((((uint64_t)in_total) * 8000) / (now_ms - start_ms)) >> 10;
     int bwkbps_now = (((in_total - in_prev) * 8000) / (now_ms - last_ms)) >> 10 ;
-    logger->printf("bwavg=%d bwnow=%d kbps maxavail=%i\r\n", bwkbps_avg, bwkbps_now, maxavail);
+    logger->printf("bwavg=%d bwnow=%d kbps maxavail=%i\n", bwkbps_avg, bwkbps_now, maxavail);
 
     in_prev = in_total;
     timeout = (last_ms = now_ms) + TIMEOUT;
   }
+
+  if (logger->read() == 's')
+  {
+    logger->println("now stopping reading, keeping writing");
+    reading = false;
+  }
 }

From 882989ec2e36613be300980bfc9f1d8e47b56aeb Mon Sep 17 00:00:00 2001
From: David Gauchard <gauchard@laas.fr>
Date: Thu, 6 Dec 2018 16:06:27 +0100
Subject: [PATCH 10/21] serial device test: bandwidth & overrun

---
 tests/device/test_serial/test_serial.ino | 191 +++++++++++++++++++++++
 1 file changed, 191 insertions(+)
 create mode 100644 tests/device/test_serial/test_serial.ino

diff --git a/tests/device/test_serial/test_serial.ino b/tests/device/test_serial/test_serial.ino
new file mode 100644
index 0000000000..19481f91ff
--- /dev/null
+++ b/tests/device/test_serial/test_serial.ino
@@ -0,0 +1,191 @@
+#include <BSTest.h>
+BS_ENV_DECLARE();
+
+// this is the serialStress.ino example, stripped down
+
+/*
+  Serial read/write/verify/benchmark
+  Using internal loopback
+
+  Released to public domain
+*/
+
+#include <ESP8266WiFi.h>
+
+#define SSBAUD          115200  // console for humans
+#define BAUD            3000000 // hardware serial stress test
+#define BUFFER_SIZE     4096    // may be useless to use more than 2*SERIAL_SIZE_RX
+#define SERIAL_SIZE_RX  1024    // Serial.setRxBufferSize()
+
+#define TIMEOUT 5000
+#define DEBUG(x...) //x
+
+uint8_t buf [BUFFER_SIZE];
+uint8_t temp [BUFFER_SIZE];
+bool reading = true;
+bool overrun = false;
+
+static size_t out_idx = 0, in_idx = 0;
+static size_t local_receive_size = 0;
+static size_t size_for_1sec, size_for_led = 0;
+static size_t maxavail = 0;
+static uint64_t in_total = 0, in_prev = 0;
+static uint64_t start_ms, last_ms;
+static uint64_t timeout;
+
+void preinit() {
+  // (no C++ in function)
+  // disable wifi
+  ESP8266WiFiClass::preinitWiFiOff();
+}
+
+void setup()
+{
+  Serial.begin(SSBAUD);
+
+  int baud = BAUD;
+  size_for_1sec = baud / 10; // 8n1=10baudFor8bits
+  //Serial.printf(ESP.getFullVersion().c_str());
+  //Serial.printf("\n\nBAUD: %d - CoreRxBuffer: %d bytes - TestBuffer: %d bytes\n",
+  //               baud, SERIAL_SIZE_RX, BUFFER_SIZE);
+
+  //Serial.printf("led changes state every %zd bytes (= 1 second)\n", size_for_1sec);
+  //Serial.printf("press 's' to stop reading, not writing (induces overrun)\n");
+
+  BS_RUN(Serial);
+}
+
+void test_setup()
+{
+  Serial.begin(BAUD);
+
+  // bind RX and TX
+  USC0(0) |= (1 << UCLBE);
+
+  Serial.flush();
+  while (Serial.read() != -1);
+  timeout = (start_ms = last_ms = millis()) + TIMEOUT;
+}
+
+void test_setdown ()
+{
+  // unbind RX and TX
+  Serial.flush();
+  USC0(0) &= ~(1 << UCLBE);
+  while (Serial.read() != -1);
+  Serial.begin(SSBAUD);
+}
+
+int bwkbps_avg = 0;
+
+bool test_loop ()
+{
+  size_t maxlen = Serial.availableForWrite();
+  // check remaining space in buffer
+  if (maxlen > BUFFER_SIZE - out_idx) {
+    maxlen = BUFFER_SIZE - out_idx;
+  }
+  // check if not cycling more than buffer size relatively to input
+  size_t in_out = out_idx == in_idx ?
+                  BUFFER_SIZE :
+                  (in_idx + BUFFER_SIZE - out_idx - 1) % BUFFER_SIZE;
+  if (maxlen > in_out) {
+    maxlen = in_out;
+  }
+  size_t local_written_size = Serial.write(buf + out_idx, maxlen);
+  if (local_written_size > maxlen) {
+    return false;
+  }
+  if ((out_idx += local_written_size) == BUFFER_SIZE) {
+    out_idx = 0;
+  }
+  delay(0);
+
+  if (Serial.hasOverrun()) {
+    overrun = true;
+  }
+  if (Serial.hasRxError()) {
+  }
+
+  if (reading)
+  {
+    // receive data
+    maxlen = Serial.available();
+    if (maxlen > maxavail) {
+      maxavail = maxlen;
+    }
+    // check space in temp receive buffer
+    if (maxlen > BUFFER_SIZE - in_idx) {
+      maxlen = BUFFER_SIZE - in_idx;
+    }
+    local_receive_size = Serial.readBytes(temp, maxlen);
+    if (local_receive_size > maxlen) {
+      return false;
+    }
+    if (local_receive_size) {
+      if (memcmp(buf + in_idx, temp, local_receive_size) != 0) {
+        return false;
+      }
+      if ((in_idx += local_receive_size) == BUFFER_SIZE) {
+        in_idx = 0;
+      }
+      in_total += local_receive_size;
+    }
+  }
+
+  // say something on data every second
+  if ((size_for_led += local_written_size) >= size_for_1sec || millis() > timeout) {
+    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
+    size_for_led = 0;
+
+    if (in_prev == in_total) {
+      return false;
+    }
+
+    unsigned long now_ms = millis();
+    bwkbps_avg = ((((uint64_t)in_total) * 8000) / (now_ms - start_ms)) >> 10;
+    //bwkbps_now = (((in_total - in_prev) * 8000) / (now_ms - last_ms)) >> 10 ;
+
+    in_prev = in_total;
+    timeout = (last_ms = now_ms) + TIMEOUT;
+  }
+
+  if (millis() > 5000)
+  {
+    reading = false;
+  }
+  if (millis() > 6000)
+  {
+    return false;
+  }
+  
+  return true;
+}
+
+TEST_CASE("bandwidth and overrun", "[serial]")
+{
+  overrun = false;
+  bwkbps_avg = 0;
+  CHECK(overrun == false);
+  CHECK(bwkbps_avg == 0);
+
+  // let serial flush its BS output before flushing and switching to 3MBPS
+  delay(100);
+  
+  test_setup();
+  while (test_loop());
+  test_setdown();
+
+  Serial.printf("bandwidth = %d kbps  -  overrun=%d\n", bwkbps_avg, overrun);
+
+  // BAUD*10/8/1000 =>kbps *9/10 => 90% at least
+  CHECK(bwkbps_avg > ((((BAUD*8/10)/1000)*9)/10));
+  CHECK(overrun == true);
+
+  while (Serial.read() != -1);
+  Serial.flush();
+}
+
+void loop ()
+{
+}

From 3ec2a6057037112d68424962cb985295541c0aef Mon Sep 17 00:00:00 2001
From: David Gauchard <gauchard@laas.fr>
Date: Thu, 6 Dec 2018 16:07:08 +0100
Subject: [PATCH 11/21] update + HardwareSerial::hasError()

---
 cores/esp8266/HardwareSerial.h                |  5 +++
 cores/esp8266/uart.c                          | 45 ++++++++++++++-----
 cores/esp8266/uart.h                          |  1 +
 .../examples/serialStress/serialStress.ino    |  5 ++-
 4 files changed, 43 insertions(+), 13 deletions(-)

diff --git a/cores/esp8266/HardwareSerial.h b/cores/esp8266/HardwareSerial.h
index 54d600ccca..f76e804319 100644
--- a/cores/esp8266/HardwareSerial.h
+++ b/cores/esp8266/HardwareSerial.h
@@ -196,6 +196,11 @@ class HardwareSerial: public Stream
         return uart_has_overrun(_uart);
     }
 
+    bool hasRxError(void)
+    {
+        return uart_has_rx_error(_uart);
+    }
+
     void startDetectBaudrate();
 
     unsigned long testBaudrate();
diff --git a/cores/esp8266/uart.c b/cores/esp8266/uart.c
index d47bc77840..9e640a3dfd 100644
--- a/cores/esp8266/uart.c
+++ b/cores/esp8266/uart.c
@@ -47,7 +47,7 @@
 #include "user_interface.h"
 #include "uart_register.h"
 
-const char overrun_str [] PROGMEM STORE_ATTR = "uart input full!\r\n";
+//const char overrun_str [] PROGMEM STORE_ATTR = "uart input full!\r\n";
 static int s_uart_debug_nr = UART0;
 
 
@@ -65,7 +65,8 @@ struct uart_
     int baud_rate;
     bool rx_enabled;
     bool tx_enabled;
-    bool overrun;
+    bool rx_overrun;
+    bool rx_error;
     uint8_t rx_pin;
     uint8_t tx_pin;
     struct uart_rx_buffer_ * rx_buffer;
@@ -125,10 +126,10 @@ uart_rx_copy_fifo_to_buffer_unsafe(uart_t* uart)
         size_t nextPos = (rx_buffer->wpos + 1) % rx_buffer->size;
         if(nextPos == rx_buffer->rpos) 
         {
-            if (!uart->overrun) 
+            if (!uart->rx_overrun)
             {
-                uart->overrun = true;
-                os_printf_plus(overrun_str);
+                uart->rx_overrun = true;
+                //os_printf_plus(overrun_str);
             }
 
             // a choice has to be made here,
@@ -302,12 +303,15 @@ uart_isr(void * arg)
     if(usis & (1 << UIFF))
         uart_rx_copy_fifo_to_buffer_unsafe(uart);
 
-    if((usis & (1 << UIOF)) && !uart->overrun)
+    if((usis & (1 << UIOF)) && !uart->rx_overrun)
     {
-        uart->overrun = true;
-//        os_printf_plus(overrun_str);
+        uart->rx_overrun = true;
+        //os_printf_plus(overrun_str);
     }
     
+    if (usis & ((1 << UIFR) | (1 << UIPE) | (1 << UITO)))
+        uart->rx_error = true;
+
     USIC(uart->uart_nr) = usis;
 }
 
@@ -331,7 +335,12 @@ uart_start_isr(uart_t* uart)
     USC1(uart->uart_nr) = (INTRIGG << UCFFT);
     USIC(uart->uart_nr) = 0xffff;
     //was: USIE(uart->uart_nr) = (1 << UIFF) | (1 << UIFR) | (1 << UITO);
-    USIE(uart->uart_nr) = (1 << UIFF) | (1 << UIOF);
+    // UIFF: rx fifo full
+    // UIOF: rx fifo overflow (=overrun)
+    // UIFR: frame error
+    // UIPE: parity error
+    // UITO: rx fifo timeout
+    USIE(uart->uart_nr) = (1 << UIFF) | (1 << UIOF) | (1 << UIFR) | (1 << UIPE) | (1 << UITO);
     ETS_UART_INTR_ATTACH(uart_isr,  (void *)uart);
     ETS_UART_INTR_ENABLE();
 }
@@ -474,7 +483,8 @@ uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin, size_t rx
         return NULL;
 
     uart->uart_nr = uart_nr;
-    uart->overrun = false;
+    uart->rx_overrun = false;
+    uart->rx_error = false;
 
     switch(uart->uart_nr) 
     {
@@ -737,11 +747,22 @@ uart_rx_enabled(uart_t* uart)
 bool 
 uart_has_overrun (uart_t* uart)
 {
-    if (uart == NULL || !uart->overrun)
+    if (uart == NULL || !uart->rx_overrun)
+        return false;
+
+    // clear flag
+    uart->rx_overrun = false;
+    return true;
+}
+
+bool
+uart_has_rx_error (uart_t* uart)
+{
+    if (uart == NULL || !uart->rx_error)
         return false;
 
     // clear flag
-    uart->overrun = false;
+    uart->rx_error = false;
     return true;
 }
 
diff --git a/cores/esp8266/uart.h b/cores/esp8266/uart.h
index 8e9e35b71f..7f9dce0f0a 100644
--- a/cores/esp8266/uart.h
+++ b/cores/esp8266/uart.h
@@ -139,6 +139,7 @@ void uart_wait_tx_empty(uart_t* uart);
 void uart_flush(uart_t* uart);
 
 bool uart_has_overrun (uart_t* uart); // returns then clear overrun flag
+bool uart_has_rx_error (uart_t* uart); // returns then clear rxerror flag
 
 void uart_set_debug(int uart_nr);
 int uart_get_debug();
diff --git a/libraries/esp8266/examples/serialStress/serialStress.ino b/libraries/esp8266/examples/serialStress/serialStress.ino
index 7b25ff9f2f..6d1bcbdc65 100644
--- a/libraries/esp8266/examples/serialStress/serialStress.ino
+++ b/libraries/esp8266/examples/serialStress/serialStress.ino
@@ -127,7 +127,10 @@ void loop() {
   DEBUG(logger->printf("----------\n"));
 
   if (Serial.hasOverrun()) {
-    logger->printf("overrun!\n");
+    logger->printf("rx overrun!\n");
+  }
+  if (Serial.hasRxError()) {
+    logger->printf("rx error!\n");
   }
 
   if (reading)

From a38f9d86693d79e676ffe79a3afb91657d243e9b Mon Sep 17 00:00:00 2001
From: David Gauchard <gauchard@laas.fr>
Date: Thu, 6 Dec 2018 16:11:50 +0100
Subject: [PATCH 12/21] interactive overrun in example

---
 .../serialStress.ino => SerialStress/SerialStress.ino}           | 1 +
 1 file changed, 1 insertion(+)
 rename libraries/esp8266/examples/{serialStress/serialStress.ino => SerialStress/SerialStress.ino} (98%)

diff --git a/libraries/esp8266/examples/serialStress/serialStress.ino b/libraries/esp8266/examples/SerialStress/SerialStress.ino
similarity index 98%
rename from libraries/esp8266/examples/serialStress/serialStress.ino
rename to libraries/esp8266/examples/SerialStress/SerialStress.ino
index 6d1bcbdc65..eafa425876 100644
--- a/libraries/esp8266/examples/serialStress/serialStress.ino
+++ b/libraries/esp8266/examples/SerialStress/SerialStress.ino
@@ -82,6 +82,7 @@ void setup() {
 
   size_for_1sec = baud / 10; // 8n1=10baudFor8bits
   logger->printf("led changes state every %zd bytes (= 1 second)\n", size_for_1sec);
+  logger->printf("press 's' to stop reading, not writing (induces overrun)\n");
 
   // prepare send/compare buffer
   for (size_t i = 0; i < sizeof buf; i++) {

From 6b7771548584890349b1de9970a866c970329527 Mon Sep 17 00:00:00 2001
From: David Gauchard <gauchard@laas.fr>
Date: Thu, 6 Dec 2018 16:12:35 +0100
Subject: [PATCH 13/21] astyle

---
 libraries/esp8266/examples/SerialStress/SerialStress.ino | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/libraries/esp8266/examples/SerialStress/SerialStress.ino b/libraries/esp8266/examples/SerialStress/SerialStress.ino
index eafa425876..7b13d6eb74 100644
--- a/libraries/esp8266/examples/SerialStress/SerialStress.ino
+++ b/libraries/esp8266/examples/SerialStress/SerialStress.ino
@@ -134,8 +134,7 @@ void loop() {
     logger->printf("rx error!\n");
   }
 
-  if (reading)
-  {
+  if (reading) {
     // receive data
     maxlen = Serial.available();
     if (maxlen > maxavail) {
@@ -181,8 +180,7 @@ void loop() {
     timeout = (last_ms = now_ms) + TIMEOUT;
   }
 
-  if (logger->read() == 's')
-  {
+  if (logger->read() == 's') {
     logger->println("now stopping reading, keeping writing");
     reading = false;
   }

From b63926142f074a21f0ebc761117a08f353e6da0e Mon Sep 17 00:00:00 2001
From: David Gauchard <gauchard@laas.fr>
Date: Thu, 6 Dec 2018 17:06:12 +0100
Subject: [PATCH 14/21] Test using @plerup's SoftwareSerial as submodule (tag
 3.4.1)

---
 .gitmodules              | 3 +++
 libraries/SoftwareSerial | 1 +
 2 files changed, 4 insertions(+)
 create mode 160000 libraries/SoftwareSerial

diff --git a/.gitmodules b/.gitmodules
index 2703cecb68..6ccf7f096b 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,3 +4,6 @@
 [submodule "tools/sdk/ssl/bearssl"]
 	path = tools/sdk/ssl/bearssl
 	url = https://github.com/earlephilhower/bearssl-esp8266
+[submodule "libraries/SoftwareSerial"]
+	path = libraries/SoftwareSerial
+	url = https://github.com/plerup/espsoftwareserial.git
diff --git a/libraries/SoftwareSerial b/libraries/SoftwareSerial
new file mode 160000
index 0000000000..5378868de7
--- /dev/null
+++ b/libraries/SoftwareSerial
@@ -0,0 +1 @@
+Subproject commit 5378868de76e1a38d34e0fc888d26e3612a5497d

From 40d123714afa57fb6eb8821e270a298f0a744b52 Mon Sep 17 00:00:00 2001
From: David Gauchard <gauchard@laas.fr>
Date: Thu, 6 Dec 2018 23:37:50 +0100
Subject: [PATCH 15/21] update upstream ref (fix warning)

---
 libraries/SoftwareSerial | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libraries/SoftwareSerial b/libraries/SoftwareSerial
index 5378868de7..23ae000cb2 160000
--- a/libraries/SoftwareSerial
+++ b/libraries/SoftwareSerial
@@ -1 +1 @@
-Subproject commit 5378868de76e1a38d34e0fc888d26e3612a5497d
+Subproject commit 23ae000cb2cf4d5823a2744f6b8ae831575ff135

From c48b54f0b7bbe77b323c18a39715b28bece76a81 Mon Sep 17 00:00:00 2001
From: David Gauchard <gauchard@laas.fr>
Date: Fri, 7 Dec 2018 00:53:58 +0100
Subject: [PATCH 16/21] host mock uart/read(buf,size)

---
 tests/host/common/MockSerial.cpp | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/tests/host/common/MockSerial.cpp b/tests/host/common/MockSerial.cpp
index 4aa097a0cd..8c2798dba0 100644
--- a/tests/host/common/MockSerial.cpp
+++ b/tests/host/common/MockSerial.cpp
@@ -109,4 +109,11 @@ size_t uart_write (uart_t* uart, const char* buf, size_t size)
 	return write(1, buf, size);
 }
 
+size_t uart_read(uart_t* uart, char* userbuffer, size_t usersize)
+{
+	///XXXTODO
+	(void)uart;
+	return read(0, userbuffer, usersize);
+}
+
 } // extern "C"

From 18a189f6708c6fb87f17ae2277e32a006035351d Mon Sep 17 00:00:00 2001
From: David Gauchard <gauchard@laas.fr>
Date: Fri, 7 Dec 2018 01:05:39 +0100
Subject: [PATCH 17/21] reset style changes in submodules before style diff

---
 tests/common.sh | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/tests/common.sh b/tests/common.sh
index 5fbe245060..e9fa151458 100755
--- a/tests/common.sh
+++ b/tests/common.sh
@@ -248,6 +248,9 @@ function check_examples_style()
             --suffix=none \
             --options=$TRAVIS_BUILD_DIR/tests/examples_style.conf {} \;
 
+    # we have no control over submodules
+    git submodule foreach --recursive git reset --hard
+
     git diff --exit-code -- $TRAVIS_BUILD_DIR/libraries
 
     echo -e "travis_fold:end:check_examples_style"

From fb25c8d7c9f3cecc6510e2c7fdd73c90cfb453a6 Mon Sep 17 00:00:00 2001
From: david gauchard <gauchard@laas.fr>
Date: Sat, 8 Dec 2018 22:52:51 +0100
Subject: [PATCH 18/21] update build_boards_manager_package.sh for submodules

---
 package/build_boards_manager_package.sh | 23 ++++++++++++++---------
 1 file changed, 14 insertions(+), 9 deletions(-)

diff --git a/package/build_boards_manager_package.sh b/package/build_boards_manager_package.sh
index 3da5ef8ffe..42c088e8fa 100755
--- a/package/build_boards_manager_package.sh
+++ b/package/build_boards_manager_package.sh
@@ -16,6 +16,8 @@ else
     plain_ver=$ver
 fi
 
+set -e
+
 package_name=esp8266-$ver
 echo "Version: $ver"
 echo "Package name: $package_name"
@@ -44,10 +46,20 @@ srcdir=$PWD
 rm -rf package/versions/$ver
 mkdir -p $outdir
 
+# Get submodules
+modules=libraries/SoftwareSerial
+for mod in $modules; do
+    echo "refreshing submodule: $mod"
+    git submodule update --init -- $mod
+    (cd $mod && git reset --hard)
+done
+echo "done with submodules"
+
 # Some files should be excluded from the package
 cat << EOF > exclude.txt
 .git
 .gitignore
+.gitmodules
 .travis.yml
 package
 doc
@@ -58,15 +70,6 @@ git ls-files --other --directory >> exclude.txt
 rsync -a --exclude-from 'exclude.txt' $srcdir/ $outdir/
 rm exclude.txt
 
-# Get additional libraries (TODO: add them as git submodule or subtree?)
-
-# SoftwareSerial library
-curl -L -o SoftwareSerial.zip https://github.com/plerup/espsoftwareserial/archive/3.4.1.zip
-unzip -q SoftwareSerial.zip
-rm -rf SoftwareSerial.zip
-mv espsoftwareserial-* SoftwareSerial
-mv SoftwareSerial $outdir/libraries
-
 # For compatibility, on OS X we need GNU sed which is usually called 'gsed'
 if [ "$(uname)" == "Darwin" ]; then
     SED=gsed
@@ -154,3 +157,5 @@ python ../../merge_packages.py $new_json $old_json >tmp && mv tmp $new_json && r
 
 popd
 popd
+
+echo "All done"

From cbd8b449ee261fec11f765a79bd826fb9a8e851b Mon Sep 17 00:00:00 2001
From: David Gauchard <gauchard@laas.fr>
Date: Mon, 10 Dec 2018 10:15:01 +0100
Subject: [PATCH 19/21] trigger CI (removing space)

---
 cores/esp8266/uart.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/cores/esp8266/uart.c b/cores/esp8266/uart.c
index 9e640a3dfd..e16b309df0 100644
--- a/cores/esp8266/uart.c
+++ b/cores/esp8266/uart.c
@@ -51,7 +51,7 @@
 static int s_uart_debug_nr = UART0;
 
 
-struct uart_rx_buffer_ 
+struct uart_rx_buffer_
 {
     size_t size;
     size_t rpos;

From 99fcfdacea379c52106fb8b78356c68924d931a6 Mon Sep 17 00:00:00 2001
From: David Gauchard <gauchard@laas.fr>
Date: Mon, 10 Dec 2018 11:46:13 +0100
Subject: [PATCH 20/21] cannot reproduce locally the CI issue, setting bash -x
 option to get live trace

---
 package/build_boards_manager_package.sh | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/package/build_boards_manager_package.sh b/package/build_boards_manager_package.sh
index 42c088e8fa..b1fe72357e 100755
--- a/package/build_boards_manager_package.sh
+++ b/package/build_boards_manager_package.sh
@@ -1,6 +1,8 @@
 #!/bin/bash
 #
 
+set -x
+
 # Extract next version from platform.txt
 next=`sed -n -E 's/version=([0-9.]+)/\1/p' ../platform.txt`
 

From 6234fe02dccf5adcedf693fc677ac4d68904bb0c Mon Sep 17 00:00:00 2001
From: David Gauchard <gauchard@laas.fr>
Date: Mon, 10 Dec 2018 12:28:38 +0100
Subject: [PATCH 21/21] remove previously added (in this PR) 'set -e' in
 package builder (passes local tests, not real CI) script-comment new
 recipe.hooks.core.prebuild.3 (along with already commented .1 and .2) moved
 CI package test to be first on the test list remove 'set -x', wish me luck

---
 .travis.yml                             | 4 ++--
 package/build_boards_manager_package.sh | 6 ++++--
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index a992a5094e..732b21b126 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,6 +8,8 @@ cache:
 
 matrix:
   include:
+    - env:
+      - BUILD_TYPE=package
     - env:
       - BUILD_TYPE=build_even
     - env:
@@ -22,8 +24,6 @@ matrix:
       - BUILD_TYPE=platformio_odd
     - env:
       - BUILD_TYPE=docs
-    - env:
-      - BUILD_TYPE=package
     - env:
       - BUILD_TYPE=host_tests
     - env:
diff --git a/package/build_boards_manager_package.sh b/package/build_boards_manager_package.sh
index b1fe72357e..9e4468c58b 100755
--- a/package/build_boards_manager_package.sh
+++ b/package/build_boards_manager_package.sh
@@ -1,7 +1,7 @@
 #!/bin/bash
 #
 
-set -x
+#set -x
 
 # Extract next version from platform.txt
 next=`sed -n -E 's/version=([0-9.]+)/\1/p' ../platform.txt`
@@ -18,7 +18,8 @@ else
     plain_ver=$ver
 fi
 
-set -e
+# 'set -e' breaks CI but not local tests
+#set -e
 
 package_name=esp8266-$ver
 echo "Version: $ver"
@@ -88,6 +89,7 @@ $SED 's/tools.esptool.path={runtime.platform.path}\/tools\/esptool/tools.esptool
 $SED 's/tools.mkspiffs.path={runtime.platform.path}\/tools\/mkspiffs/tools.mkspiffs.path=\{runtime.tools.mkspiffs.path\}/g' |\
 $SED 's/recipe.hooks.core.prebuild.1.pattern.*//g' |\
 $SED 's/recipe.hooks.core.prebuild.2.pattern.*//g' |\
+$SED 's/recipe.hooks.core.prebuild.3.pattern.*//g' |\
 $SED "s/version=.*/version=$ver/g" |\
 $SED -E "s/name=([a-zA-Z0-9\ -]+).*/name=\1($ver)/g"\
  > $outdir/platform.txt