From cc4355a2c8ba5c61485827825852f338cede7996 Mon Sep 17 00:00:00 2001
From: patricklaf <patrick.lafarguette@gmail.com>
Date: Tue, 15 Apr 2025 16:09:56 +0200
Subject: [PATCH] chore(uart): harden init

Signed-off-by: patricklaf <patrick.lafarguette@gmail.com>
---
 cores/arduino/HardwareSerial.cpp      | 10 +++--
 cores/arduino/HardwareSerial.h        |  3 +-
 libraries/SrcWrapper/inc/uart.h       |  2 +-
 libraries/SrcWrapper/src/stm32/uart.c | 54 +++++++++++++++------------
 4 files changed, 41 insertions(+), 28 deletions(-)

diff --git a/cores/arduino/HardwareSerial.cpp b/cores/arduino/HardwareSerial.cpp
index 4dd8fd02a4..cde5cab7e0 100644
--- a/cores/arduino/HardwareSerial.cpp
+++ b/cores/arduino/HardwareSerial.cpp
@@ -446,13 +446,17 @@ void HardwareSerial::begin(unsigned long baud, byte config)
       break;
   }
 
-  uart_init(&_serial, (uint32_t)baud, databits, parity, stopbits, _rx_invert, _tx_invert, _data_invert);
-  enableHalfDuplexRx();
-  uart_attach_rx_callback(&_serial, _rx_complete_irq);
+  _ready = uart_init(&_serial, (uint32_t)baud, databits, parity, stopbits, _rx_invert, _tx_invert, _data_invert);
+  if (_ready) {
+    enableHalfDuplexRx();
+    uart_attach_rx_callback(&_serial, _rx_complete_irq);
+  }
 }
 
 void HardwareSerial::end()
 {
+  _ready = false;
+
   // wait for transmission of outgoing data
   flush(TX_TIMEOUT);
 
diff --git a/cores/arduino/HardwareSerial.h b/cores/arduino/HardwareSerial.h
index 3ed29a873d..be670e9540 100644
--- a/cores/arduino/HardwareSerial.h
+++ b/cores/arduino/HardwareSerial.h
@@ -146,7 +146,7 @@ class HardwareSerial : public Stream {
     using Print::write; // pull in write(str) from Print
     operator bool()
     {
-      return true;
+      return _ready;
     }
 
     void setRx(uint32_t _rx);
@@ -189,6 +189,7 @@ class HardwareSerial : public Stream {
 #endif // HAL_UART_MODULE_ENABLED && !HAL_UART_MODULE_ONLY
 
   private:
+    bool _ready;
     bool _rx_enabled;
     uint8_t _config;
     unsigned long _baud;
diff --git a/libraries/SrcWrapper/inc/uart.h b/libraries/SrcWrapper/inc/uart.h
index 7f99d498e7..5d681407f8 100644
--- a/libraries/SrcWrapper/inc/uart.h
+++ b/libraries/SrcWrapper/inc/uart.h
@@ -255,7 +255,7 @@ struct serial_s {
 
 /* Exported macro ------------------------------------------------------------*/
 /* Exported functions ------------------------------------------------------- */
-void uart_init(serial_t *obj, uint32_t baudrate, uint32_t databits, uint32_t parity, uint32_t stopbits, bool rx_invert, bool tx_invert, bool data_invert);
+bool uart_init(serial_t *obj, uint32_t baudrate, uint32_t databits, uint32_t parity, uint32_t stopbits, bool rx_invert, bool tx_invert, bool data_invert);
 void uart_deinit(serial_t *obj);
 #if defined(HAL_PWR_MODULE_ENABLED) && (defined(UART_IT_WUF) || defined(LPUART1_BASE))
 void uart_config_lowpower(serial_t *obj);
diff --git a/libraries/SrcWrapper/src/stm32/uart.c b/libraries/SrcWrapper/src/stm32/uart.c
index 4aaa3f0e2e..14e431dc09 100644
--- a/libraries/SrcWrapper/src/stm32/uart.c
+++ b/libraries/SrcWrapper/src/stm32/uart.c
@@ -113,12 +113,12 @@ serial_t *get_serial_obj(UART_HandleTypeDef *huart)
 /**
   * @brief  Function called to initialize the uart interface
   * @param  obj : pointer to serial_t structure
-  * @retval None
+  * @retval boolean status
   */
-void uart_init(serial_t *obj, uint32_t baudrate, uint32_t databits, uint32_t parity, uint32_t stopbits, bool rx_invert, bool tx_invert, bool data_invert)
+bool uart_init(serial_t *obj, uint32_t baudrate, uint32_t databits, uint32_t parity, uint32_t stopbits, bool rx_invert, bool tx_invert, bool data_invert)
 {
   if (obj == NULL) {
-    return;
+    return false;
   }
 
   UART_HandleTypeDef *huart = &(obj->handle);
@@ -143,28 +143,28 @@ void uart_init(serial_t *obj, uint32_t baudrate, uint32_t databits, uint32_t par
     if (obj != &serial_debug) {
       core_debug("ERROR: [U(S)ART] Tx pin has no peripheral!\n");
     }
-    return;
+    return false;
   }
   /* Pin Rx must not be NP if not half-duplex */
   if ((obj->pin_rx != NC) && (uart_rx == NP) && (uart_rx_swap == NP)) {
     if (obj != &serial_debug) {
       core_debug("ERROR: [U(S)ART] Rx pin has no peripheral!\n");
     }
-    return;
+    return false;
   }
   /* Pin RTS must not be NP if flow control is enabled */
   if ((obj->pin_rts != NC) && (uart_rts == NP)) {
     if (obj != &serial_debug) {
       core_debug("ERROR: [U(S)ART] RTS pin has no peripheral!\n");
     }
-    return;
+    return false;
   }
   /* Pin CTS must not be NP if flow control is enabled */
   if ((obj->pin_cts != NC) && (uart_cts == NP)) {
     if (obj != &serial_debug) {
       core_debug("ERROR: [U(S)ART] CTS pin has no peripheral!\n");
     }
-    return;
+    return false;
   }
 
   /*
@@ -184,7 +184,7 @@ void uart_init(serial_t *obj, uint32_t baudrate, uint32_t databits, uint32_t par
     if (obj != &serial_debug) {
       core_debug("ERROR: [U(S)ART] Rx/Tx/RTS/CTS pins peripherals mismatch!\n");
     }
-    return;
+    return false;
   }
 
   /* Enable USART clock */
@@ -364,6 +364,12 @@ void uart_init(serial_t *obj, uint32_t baudrate, uint32_t databits, uint32_t par
     obj->irq = UART12_IRQn;
   }
 #endif
+  else {
+    if (obj != &serial_debug) {
+      core_debug("ERROR: [U(S)ART] Peripheral not supported!\n");
+    }
+    return false;
+  }
   /* Configure UART GPIO pins */
 #if defined(UART_ADVFEATURE_SWAP_INIT)
   uint32_t pin_swap = UART_ADVFEATURE_SWAP_DISABLE;
@@ -468,10 +474,10 @@ void uart_init(serial_t *obj, uint32_t baudrate, uint32_t databits, uint32_t par
     /* Trying default LPUART clock source */
     if ((uart_rx == NP) && (uart_rx_swap == NP)) {
       if (HAL_HalfDuplex_Init(huart) == HAL_OK) {
-        return;
+        return true;
       }
     } else if (HAL_UART_Init(huart) == HAL_OK) {
-      return;
+      return true;
     }
     /* Trying to change LPUART clock source */
     /* If baudrate is lower than or equal to 9600 try to change to LSE */
@@ -494,10 +500,10 @@ void uart_init(serial_t *obj, uint32_t baudrate, uint32_t databits, uint32_t par
 #endif
         if ((uart_rx == NP) && (uart_rx_swap == NP)) {
           if (HAL_HalfDuplex_Init(huart) == HAL_OK) {
-            return;
+            return true;
           }
         } else if (HAL_UART_Init(huart) == HAL_OK) {
-          return;
+          return true;
         }
       }
     }
@@ -517,10 +523,10 @@ void uart_init(serial_t *obj, uint32_t baudrate, uint32_t databits, uint32_t par
 #endif
       if ((uart_rx == NP) && (uart_rx_swap == NP)) {
         if (HAL_HalfDuplex_Init(huart) == HAL_OK) {
-          return;
+          return true;
         }
       } else if (HAL_UART_Init(huart) == HAL_OK) {
-        return;
+        return true;
       }
     }
     if (obj->uart == LPUART1) {
@@ -544,10 +550,10 @@ void uart_init(serial_t *obj, uint32_t baudrate, uint32_t databits, uint32_t par
 #endif
     if ((uart_rx == NP) && (uart_rx_swap == NP)) {
       if (HAL_HalfDuplex_Init(huart) == HAL_OK) {
-        return;
+        return true;
       }
     } else if (HAL_UART_Init(huart) == HAL_OK) {
-      return;
+      return true;
     }
 #if defined(RCC_LPUART1CLKSOURCE_SYSCLK)
     if (obj->uart == LPUART1) {
@@ -569,11 +575,12 @@ void uart_init(serial_t *obj, uint32_t baudrate, uint32_t databits, uint32_t par
 
   if ((uart_rx == NP) && (uart_rx_swap == NP)) {
     if (HAL_HalfDuplex_Init(huart) != HAL_OK) {
-      return;
+      return false;
     }
   } else if (HAL_UART_Init(huart) != HAL_OK) {
-    return;
+    return false;
   }
+  return true;
 }
 
 /**
@@ -821,10 +828,11 @@ void uart_config_lowpower(serial_t *obj)
   * @note   Call only if debug U(S)ART peripheral is not already initialized
   *         by a Serial instance
   *         Default config: 8N1
-  * @retval None
+  * @retval boolean status
   */
-void uart_debug_init(void)
+bool uart_debug_init(void)
 {
+  bool status = false;
   if (DEBUG_UART != NP) {
 #if defined(DEBUG_PINNAME_TX)
     serial_debug.pin_tx = DEBUG_PINNAME_TX;
@@ -832,8 +840,9 @@ void uart_debug_init(void)
     serial_debug.pin_tx = pinmap_pin(DEBUG_UART, PinMap_UART_TX);
 #endif
     /* serial_debug.pin_rx set by default to NC to configure in half duplex mode */
-    uart_init(&serial_debug, DEBUG_UART_BAUDRATE, UART_WORDLENGTH_8B, UART_PARITY_NONE, UART_STOPBITS_1, false, false, false);
+    status = uart_init(&serial_debug, DEBUG_UART_BAUDRATE, UART_WORDLENGTH_8B, UART_PARITY_NONE, UART_STOPBITS_1, false, false, false);
   }
+  return status;
 }
 
 /**
@@ -863,8 +872,7 @@ size_t uart_debug_write(uint8_t *data, uint32_t size)
 
     if (serial_debug.index >= UART_NUM) {
       /* DEBUG_UART not initialized */
-      uart_debug_init();
-      if (serial_debug.index >= UART_NUM) {
+      if (!uart_debug_init()) {
         return 0;
       }
     }