diff options
Diffstat (limited to 'os')
-rw-r--r-- | os/hal/include/spi.h | 4 | ||||
-rw-r--r-- | os/hal/include/uart.h | 223 | ||||
-rw-r--r-- | os/hal/ports/STM32/LLD/USARTv1/uart_lld.c | 35 | ||||
-rw-r--r-- | os/hal/ports/STM32/LLD/USARTv1/uart_lld.h | 20 | ||||
-rw-r--r-- | os/hal/ports/STM32/LLD/USARTv2/uart_lld.c | 35 | ||||
-rw-r--r-- | os/hal/ports/STM32/LLD/USARTv2/uart_lld.h | 20 | ||||
-rw-r--r-- | os/hal/src/uart.c | 187 | ||||
-rw-r--r-- | os/hal/templates/uart_lld.h | 20 |
8 files changed, 482 insertions, 62 deletions
diff --git a/os/hal/include/spi.h b/os/hal/include/spi.h index 40592776d..2db152ada 100644 --- a/os/hal/include/spi.h +++ b/os/hal/include/spi.h @@ -270,13 +270,13 @@ extern "C" { const void *txbuf, void *rxbuf);
void spiStartSend(SPIDriver *spip, size_t n, const void *txbuf);
void spiStartReceive(SPIDriver *spip, size_t n, void *rxbuf);
-#if SPI_USE_WAIT
+#if SPI_USE_WAIT == TRUE
void spiIgnore(SPIDriver *spip, size_t n);
void spiExchange(SPIDriver *spip, size_t n, const void *txbuf, void *rxbuf);
void spiSend(SPIDriver *spip, size_t n, const void *txbuf);
void spiReceive(SPIDriver *spip, size_t n, void *rxbuf);
#endif
-#if SPI_USE_MUTUAL_EXCLUSION
+#if SPI_USE_MUTUAL_EXCLUSION == TRUE
void spiAcquireBus(SPIDriver *spip);
void spiReleaseBus(SPIDriver *spip);
#endif
diff --git a/os/hal/include/uart.h b/os/hal/include/uart.h index 75a9e2b58..f619599d9 100644 --- a/os/hal/include/uart.h +++ b/os/hal/include/uart.h @@ -47,6 +47,27 @@ /* Driver pre-compile time settings. */
/*===========================================================================*/
+/**
+ * @name UART configuration options
+ * @{
+ */
+/**
+ * @brief Enables synchronous APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(UART_USE_WAIT) || defined(__DOXYGEN__)
+#define UART_USE_WAIT TRUE
+#endif
+
+/**
+ * @brief Enables the @p uartAcquireBus() and @p uartReleaseBus() APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(UART_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define UART_USE_MUTUAL_EXCLUSION TRUE
+#endif
+/** @} */
+
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
@@ -88,6 +109,196 @@ typedef enum { /* Driver macros. */
/*===========================================================================*/
+/**
+ * @name Low level driver helper macros
+ * @{
+ */
+#if (UART_USE_WAIT == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Wakes up the waiting thread in case of early TX complete.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @notapi
+ */
+#define _uart_wakeup_tx1_isr(uartp) { \
+ if ((uartp)->early == true) { \
+ osalSysLockFromISR(); \
+ osalThreadResumeI(&(uartp)->threadtx, MSG_OK); \
+ osalSysUnlockFromISR(); \
+ } \
+}
+#else /* !UART_USE_WAIT */
+#define _uart_wakeup_tx1_isr(uartp)
+#endif /* !UART_USE_WAIT */
+
+#if (UART_USE_WAIT == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Wakes up the waiting thread in case of late TX complete.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @notapi
+ */
+#define _uart_wakeup_tx2_isr(uartp) { \
+ if ((uartp)->early == false) { \
+ osalSysLockFromISR(); \
+ osalThreadResumeI(&(uartp)->threadtx, MSG_OK); \
+ osalSysUnlockFromISR(); \
+ } \
+}
+#else /* !UART_USE_WAIT */
+#define _uart_wakeup_tx2_isr(uartp)
+#endif /* !UART_USE_WAIT */
+
+#if (UART_USE_WAIT == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Wakes up the waiting thread in case of RX complete.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @notapi
+ */
+#define _uart_wakeup_rx_complete_isr(uartp) { \
+ osalSysLockFromISR(); \
+ osalThreadResumeI(&(uartp)->threadrx, MSG_OK); \
+ osalSysUnlockFromISR(); \
+}
+#else /* !UART_USE_WAIT */
+#define _uart_wakeup_rx_complete_isr(uartp)
+#endif /* !UART_USE_WAIT */
+
+#if (UART_USE_WAIT == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Wakes up the waiting thread in case of RX error.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @notapi
+ */
+#define _uart_wakeup_rx_error_isr(uartp) { \
+ osalSysLockFromISR(); \
+ osalThreadResumeI(&(uartp)->threadrx, MSG_RESET); \
+ osalSysUnlockFromISR(); \
+}
+#else /* !UART_USE_WAIT */
+#define _uart_wakeup_rx_error_isr(uartp)
+#endif /* !UART_USE_WAIT */
+
+/**
+ * @brief Common ISR code for early TX.
+ * @details This code handles the portable part of the ISR code:
+ * - Callback invocation.
+ * - Waiting thread wakeup, if any.
+ * - Driver state transitions.
+ * .
+ * @note This macro is meant to be used in the low level drivers
+ * implementation only.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @notapi
+ */
+#define _uart_tx1_isr_code(uartp) { \
+ (uartp)->txstate = UART_TX_COMPLETE; \
+ if ((uartp)->config->txend1_cb != NULL) { \
+ (uartp)->config->txend1_cb(uartp); \
+ } \
+ if ((uartp)->txstate == UART_TX_COMPLETE) { \
+ (uartp)->txstate = UART_TX_IDLE; \
+ } \
+ _uart_wakeup_tx1_isr(uartp); \
+}
+
+/**
+ * @brief Common ISR code for late TX.
+ * @details This code handles the portable part of the ISR code:
+ * - Callback invocation.
+ * - Waiting thread wakeup, if any.
+ * - Driver state transitions.
+ * .
+ * @note This macro is meant to be used in the low level drivers
+ * implementation only.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @notapi
+ */
+#define _uart_tx2_isr_code(uartp) { \
+ if ((uartp)->config->txend2_cb != NULL) { \
+ (uartp)->config->txend2_cb(uartp); \
+ } \
+ _uart_wakeup_tx2_isr(uartp); \
+}
+
+/**
+ * @brief Common ISR code for RX complete.
+ * @details This code handles the portable part of the ISR code:
+ * - Callback invocation.
+ * - Waiting thread wakeup, if any.
+ * - Driver state transitions.
+ * .
+ * @note This macro is meant to be used in the low level drivers
+ * implementation only.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @notapi
+ */
+#define _uart_rx_complete_isr_code(uartp) { \
+ (uartp)->rxstate = UART_RX_COMPLETE; \
+ if ((uartp)->config->rxend_cb != NULL) { \
+ (uartp)->config->rxend_cb(uartp); \
+ } \
+ if ((uartp)->rxstate == UART_RX_COMPLETE) { \
+ (uartp)->rxstate = UART_RX_IDLE; \
+ uart_enter_rx_idle_loop(uartp); \
+ } \
+ _uart_wakeup_rx_complete_isr(uartp); \
+}
+
+/**
+ * @brief Common ISR code for RX error.
+ * @details This code handles the portable part of the ISR code:
+ * - Callback invocation.
+ * - Waiting thread wakeup, if any.
+ * - Driver state transitions.
+ * .
+ * @note This macro is meant to be used in the low level drivers
+ * implementation only.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @notapi
+ */
+#define _uart_rx_error_isr_code(uartp, errors) { \
+ if ((uartp)->config->rxerr_cb != NULL) { \
+ (uartp)->config->rxerr_cb(uartp, errors); \
+ } \
+ _uart_wakeup_rx_error_isr(uartp); \
+}
+
+
+/**
+ * @brief Common ISR code for RX on idle.
+ * @details This code handles the portable part of the ISR code:
+ * - Callback invocation.
+ * - Waiting thread wakeup, if any.
+ * - Driver state transitions.
+ * .
+ * @note This macro is meant to be used in the low level drivers
+ * implementation only.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @notapi
+ */
+#define _uart_rx_idle_code(uartp) { \
+ if ((uartp)->config->rxchar_cb != NULL) \
+ (uartp)->config->rxchar_cb(uartp, (uartp)->rxbuf); \
+}
+/** @} */
+
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
@@ -107,6 +318,18 @@ extern "C" { void uartStartReceiveI(UARTDriver *uartp, size_t n, void *rxbuf);
size_t uartStopReceive(UARTDriver *uartp);
size_t uartStopReceiveI(UARTDriver *uartp);
+#if UART_USE_WAIT == TRUE
+ msg_t uartSendTimeout(UARTDriver *uartp, size_t *np,
+ const void *txbuf, systime_t time);
+ msg_t uartSendFullTimeout(UARTDriver *uartp, size_t *np,
+ const void *txbuf, systime_t time);
+ msg_t uartReceiveTimeout(UARTDriver *uartp, size_t *np,
+ void *rxbuf, systime_t time);
+#endif
+#if UART_USE_MUTUAL_EXCLUSION == TRUE
+ void uartAcquireBus(UARTDriver *uartp);
+ void uartReleaseBus(UARTDriver *uartp);
+#endif
#ifdef __cplusplus
}
#endif
diff --git a/os/hal/ports/STM32/LLD/USARTv1/uart_lld.c b/os/hal/ports/STM32/LLD/USARTv1/uart_lld.c index b346dba82..ec422dc6c 100644 --- a/os/hal/ports/STM32/LLD/USARTv1/uart_lld.c +++ b/os/hal/ports/STM32/LLD/USARTv1/uart_lld.c @@ -156,7 +156,7 @@ static uartflags_t translate_errors(uint16_t sr) { *
* @param[in] uartp pointer to the @p UARTDriver object
*/
-static void set_rx_idle_loop(UARTDriver *uartp) {
+static void uart_enter_rx_idle_loop(UARTDriver *uartp) {
uint32_t mode;
/* RX DMA channel preparation, if the char callback is defined then the
@@ -229,7 +229,7 @@ static void usart_start(UARTDriver *uartp) { u->CR1 = uartp->config->cr1 | cr1;
/* Starting the receiver idle loop.*/
- set_rx_idle_loop(uartp);
+ uart_enter_rx_idle_loop(uartp);
}
/**
@@ -252,23 +252,13 @@ static void uart_lld_serve_rx_end_irq(UARTDriver *uartp, uint32_t flags) { if (uartp->rxstate == UART_RX_IDLE) {
/* Receiver in idle state, a callback is generated, if enabled, for each
received character and then the driver stays in the same state.*/
- if (uartp->config->rxchar_cb != NULL)
- uartp->config->rxchar_cb(uartp, uartp->rxbuf);
+ _uart_rx_idle_code(uartp);
}
else {
/* Receiver in active state, a callback is generated, if enabled, after
a completed transfer.*/
dmaStreamDisable(uartp->dmarx);
- uartp->rxstate = UART_RX_COMPLETE;
- if (uartp->config->rxend_cb != NULL)
- uartp->config->rxend_cb(uartp);
-
- /* If the callback didn't explicitly change state then the receiver
- automatically returns to the idle state.*/
- if (uartp->rxstate == UART_RX_COMPLETE) {
- uartp->rxstate = UART_RX_IDLE;
- set_rx_idle_loop(uartp);
- }
+ _uart_rx_complete_isr_code(uartp);
}
}
@@ -292,14 +282,7 @@ static void uart_lld_serve_tx_end_irq(UARTDriver *uartp, uint32_t flags) { dmaStreamDisable(uartp->dmatx);
/* A callback is generated, if enabled, after a completed transfer.*/
- uartp->txstate = UART_TX_COMPLETE;
- if (uartp->config->txend1_cb != NULL)
- uartp->config->txend1_cb(uartp);
-
- /* If the callback didn't explicitly change state then the transmitter
- automatically returns to the idle state.*/
- if (uartp->txstate == UART_TX_COMPLETE)
- uartp->txstate = UART_TX_IDLE;
+ _uart_wakeup_tx1_isr(uartp);
}
/**
@@ -318,8 +301,7 @@ static void serve_usart_irq(UARTDriver *uartp) { if (sr & (USART_SR_LBD | USART_SR_ORE | USART_SR_NE |
USART_SR_FE | USART_SR_PE)) {
u->SR = ~USART_SR_LBD;
- if (uartp->config->rxerr_cb != NULL)
- uartp->config->rxerr_cb(uartp, translate_errors(sr));
+ _uart_rx_error_isr_code(uartp, translate_errors(sr));
}
if ((sr & USART_SR_TC) && (cr1 & USART_CR1_TCIE)) {
@@ -328,8 +310,7 @@ static void serve_usart_irq(UARTDriver *uartp) { u->CR1 = cr1 & ~USART_CR1_TCIE;
/* End of transmission, a callback is generated.*/
- if (uartp->config->txend2_cb != NULL)
- uartp->config->txend2_cb(uartp);
+ _uart_wakeup_tx2_isr(uartp);
}
}
@@ -820,7 +801,7 @@ size_t uart_lld_stop_receive(UARTDriver *uartp) { dmaStreamDisable(uartp->dmarx);
n = dmaStreamGetTransactionSize(uartp->dmarx);
- set_rx_idle_loop(uartp);
+ uart_enter_rx_idle_loop(uartp);
return n;
}
diff --git a/os/hal/ports/STM32/LLD/USARTv1/uart_lld.h b/os/hal/ports/STM32/LLD/USARTv1/uart_lld.h index 3f3bef590..fee0d1413 100644 --- a/os/hal/ports/STM32/LLD/USARTv1/uart_lld.h +++ b/os/hal/ports/STM32/LLD/USARTv1/uart_lld.h @@ -524,6 +524,26 @@ struct UARTDriver { * @brief Current configuration data.
*/
const UARTConfig *config;
+#if UART_USE_WAIT || defined(__DOXYGEN__)
+ /**
+ * @brief Synchronization flag for transmit operations.
+ */
+ bool early;
+ /**
+ * @brief Waiting thread on RX.
+ */
+ thread_reference_t threadrx;
+ /**
+ * @brief Waiting thread on TX.
+ */
+ thread_reference_t threadtx;
+#endif /* UART_USE_WAIT */
+#if UART_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
+ /**
+ * @brief Mutex protecting the peripheral.
+ */
+ mutex_t mutex;
+#endif /* UART_USE_MUTUAL_EXCLUSION */
#if defined(UART_DRIVER_EXT_FIELDS)
UART_DRIVER_EXT_FIELDS
#endif
diff --git a/os/hal/ports/STM32/LLD/USARTv2/uart_lld.c b/os/hal/ports/STM32/LLD/USARTv2/uart_lld.c index 59bb6c229..7594669f0 100644 --- a/os/hal/ports/STM32/LLD/USARTv2/uart_lld.c +++ b/os/hal/ports/STM32/LLD/USARTv2/uart_lld.c @@ -179,7 +179,7 @@ static uartflags_t translate_errors(uint32_t isr) { *
* @param[in] uartp pointer to the @p UARTDriver object
*/
-static void set_rx_idle_loop(UARTDriver *uartp) {
+static void uart_enter_rx_idle_loop(UARTDriver *uartp) {
uint32_t mode;
/* RX DMA channel preparation, if the char callback is defined then the
@@ -243,7 +243,7 @@ static void usart_start(UARTDriver *uartp) { u->CR1 = uartp->config->cr1 | cr1;
/* Starting the receiver idle loop.*/
- set_rx_idle_loop(uartp);
+ uart_enter_rx_idle_loop(uartp);
}
/**
@@ -266,23 +266,13 @@ static void uart_lld_serve_rx_end_irq(UARTDriver *uartp, uint32_t flags) { if (uartp->rxstate == UART_RX_IDLE) {
/* Receiver in idle state, a callback is generated, if enabled, for each
received character and then the driver stays in the same state.*/
- if (uartp->config->rxchar_cb != NULL)
- uartp->config->rxchar_cb(uartp, uartp->rxbuf);
+ _uart_rx_idle_code(uartp);
}
else {
/* Receiver in active state, a callback is generated, if enabled, after
a completed transfer.*/
dmaStreamDisable(uartp->dmarx);
- uartp->rxstate = UART_RX_COMPLETE;
- if (uartp->config->rxend_cb != NULL)
- uartp->config->rxend_cb(uartp);
-
- /* If the callback didn't explicitly change state then the receiver
- automatically returns to the idle state.*/
- if (uartp->rxstate == UART_RX_COMPLETE) {
- uartp->rxstate = UART_RX_IDLE;
- set_rx_idle_loop(uartp);
- }
+ _uart_rx_complete_isr_code(uartp);
}
}
@@ -306,14 +296,7 @@ static void uart_lld_serve_tx_end_irq(UARTDriver *uartp, uint32_t flags) { dmaStreamDisable(uartp->dmatx);
/* A callback is generated, if enabled, after a completed transfer.*/
- uartp->txstate = UART_TX_COMPLETE;
- if (uartp->config->txend1_cb != NULL)
- uartp->config->txend1_cb(uartp);
-
- /* If the callback didn't explicitly change state then the transmitter
- automatically returns to the idle state.*/
- if (uartp->txstate == UART_TX_COMPLETE)
- uartp->txstate = UART_TX_IDLE;
+ _uart_wakeup_tx1_isr(uartp);
}
/**
@@ -332,8 +315,7 @@ static void serve_usart_irq(UARTDriver *uartp) { if (isr & (USART_ISR_LBDF | USART_ISR_ORE | USART_ISR_NE |
USART_ISR_FE | USART_ISR_PE)) {
- if (uartp->config->rxerr_cb != NULL)
- uartp->config->rxerr_cb(uartp, translate_errors(isr));
+ _uart_rx_error_isr_code(uartp, translate_errors(isr));
}
if ((isr & USART_ISR_TC) && (cr1 & USART_CR1_TCIE)) {
@@ -341,8 +323,7 @@ static void serve_usart_irq(UARTDriver *uartp) { u->CR1 = cr1 & ~USART_CR1_TCIE;
/* End of transmission, a callback is generated.*/
- if (uartp->config->txend2_cb != NULL)
- uartp->config->txend2_cb(uartp);
+ _uart_wakeup_tx2_isr(uartp);
}
}
@@ -940,7 +921,7 @@ size_t uart_lld_stop_receive(UARTDriver *uartp) { dmaStreamDisable(uartp->dmarx);
n = dmaStreamGetTransactionSize(uartp->dmarx);
- set_rx_idle_loop(uartp);
+ uart_enter_rx_idle_loop(uartp);
return n;
}
diff --git a/os/hal/ports/STM32/LLD/USARTv2/uart_lld.h b/os/hal/ports/STM32/LLD/USARTv2/uart_lld.h index b8c227842..395cb3054 100644 --- a/os/hal/ports/STM32/LLD/USARTv2/uart_lld.h +++ b/os/hal/ports/STM32/LLD/USARTv2/uart_lld.h @@ -623,6 +623,26 @@ struct UARTDriver { * @brief Current configuration data.
*/
const UARTConfig *config;
+#if UART_USE_WAIT || defined(__DOXYGEN__)
+ /**
+ * @brief Synchronization flag for transmit operations.
+ */
+ bool early;
+ /**
+ * @brief Waiting thread on RX.
+ */
+ thread_reference_t threadrx;
+ /**
+ * @brief Waiting thread on TX.
+ */
+ thread_reference_t threadtx;
+#endif /* UART_USE_WAIT */
+#if UART_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
+ /**
+ * @brief Mutex protecting the peripheral.
+ */
+ mutex_t mutex;
+#endif /* UART_USE_MUTUAL_EXCLUSION */
#if defined(UART_DRIVER_EXT_FIELDS)
UART_DRIVER_EXT_FIELDS
#endif
diff --git a/os/hal/src/uart.c b/os/hal/src/uart.c index f5e28fd48..f521412ec 100644 --- a/os/hal/src/uart.c +++ b/os/hal/src/uart.c @@ -67,10 +67,19 @@ void uartInit(void) { */
void uartObjectInit(UARTDriver *uartp) {
- uartp->state = UART_STOP;
- uartp->txstate = UART_TX_IDLE;
- uartp->rxstate = UART_RX_IDLE;
- uartp->config = NULL;
+ uartp->state = UART_STOP;
+ uartp->txstate = UART_TX_IDLE;
+ uartp->rxstate = UART_RX_IDLE;
+ uartp->config = NULL;
+#if UART_USE_WAIT || defined(__DOXYGEN__)
+ uartp->early = false;
+ uartp->threadrx = NULL;
+ uartp->threadtx = NULL;
+#endif /* UART_USE_WAIT */
+#if UART_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
+ osalMutexObjectInit(&uartp->mutex);
+#endif /* UART_USE_MUTUAL_EXCLUSION */
+
/* Optional, user-defined initializer.*/
#if defined(UART_DRIVER_EXT_INIT_HOOK)
UART_DRIVER_EXT_INIT_HOOK(uartp);
@@ -233,7 +242,7 @@ size_t uartStopSendI(UARTDriver *uartp) { * or equal to 8 bits else it is organized as uint16_t arrays.
*
* @param[in] uartp pointer to the @p UARTDriver object
- * @param[in] n number of data frames to send
+ * @param[in] n number of data frames to receive
* @param[in] rxbuf the pointer to the receive buffer
*
* @api
@@ -258,7 +267,7 @@ void uartStartReceive(UARTDriver *uartp, size_t n, void *rxbuf) { * @note This function has to be invoked from a lock zone.
*
* @param[in] uartp pointer to the @p UARTDriver object
- * @param[in] n number of data frames to send
+ * @param[in] n number of data frames to receive
* @param[out] rxbuf the pointer to the receive buffer
*
* @iclass
@@ -333,6 +342,172 @@ size_t uartStopReceiveI(UARTDriver *uartp) { return 0;
}
+#if (UART_USE_WAIT == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Performs a transmission on the UART peripheral.
+ * @note The function returns when the specified number of frames have been
+ * sent to the UART or on timeout.
+ * @note The buffers are organized as uint8_t arrays for data sizes below
+ * or equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ * @param[in,out] np number of data frames to transmit, on exit the number
+ * of frames actually transmitted
+ * @param[in] txbuf the pointer to the transmit buffer
+ * @return The operation status.
+ * @retval MSG_OK if the operation completed successfully.
+ * @retval MSG_TIMEOUT if the operation timed out.
+ *
+ * @api
+ */
+msg_t uartSendTimeout(UARTDriver *uartp, size_t *np,
+ const void *txbuf, systime_t time) {
+ msg_t msg;
+
+ osalDbgCheck((uartp != NULL) && (*np > 0U) && (txbuf != NULL));
+
+ osalSysLock();
+ osalDbgAssert(uartp->state == UART_READY, "is active");
+ osalDbgAssert(uartp->txstate != UART_TX_ACTIVE, "tx active");
+
+ /* Transmission start.*/
+ uartp->early = true;
+ uart_lld_start_send(uartp, *np, txbuf);
+ uartp->txstate = UART_TX_ACTIVE;
+
+ /* Waiting for result.*/
+ msg = osalThreadSuspendTimeoutS(&uartp->threadtx, time);
+ if (msg != MSG_OK) {
+ *np = uartStopSendI(uartp);
+ }
+ osalSysUnlock();
+
+ return msg;
+}
+
+/**
+ * @brief Performs a transmission on the UART peripheral.
+ * @note The function returns when the specified number of frames have been
+ * physically transmitted or on timeout.
+ * @note The buffers are organized as uint8_t arrays for data sizes below
+ * or equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ * @param[in,out] np number of data frames to transmit, on exit the number
+ * of frames actually transmitted
+ * @param[in] txbuf the pointer to the transmit buffer
+ * @return The operation status.
+ * @retval MSG_OK if the operation completed successfully.
+ * @retval MSG_TIMEOUT if the operation timed out.
+ *
+ * @api
+ */
+msg_t uartSendFullTimeout(UARTDriver *uartp, size_t *np,
+ const void *txbuf, systime_t time) {
+ msg_t msg;
+
+ osalDbgCheck((uartp != NULL) && (*np > 0U) && (txbuf != NULL));
+
+ osalSysLock();
+ osalDbgAssert(uartp->state == UART_READY, "is active");
+ osalDbgAssert(uartp->txstate != UART_TX_ACTIVE, "tx active");
+
+ /* Transmission start.*/
+ uartp->early = false;
+ uart_lld_start_send(uartp, *np, txbuf);
+ uartp->txstate = UART_TX_ACTIVE;
+
+ /* Waiting for result.*/
+ msg = osalThreadSuspendTimeoutS(&uartp->threadtx, time);
+ if (msg != MSG_OK) {
+ *np = uartStopSendI(uartp);
+ }
+ osalSysUnlock();
+
+ return msg;
+}
+
+/**
+ * @brief Performs a receive operation on the UART peripheral.
+ * @note The function returns when the specified number of frames have been
+ * received or on error/timeout.
+ * @note The buffers are organized as uint8_t arrays for data sizes below
+ * or equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ * @param[in,out] np number of data frames to receive, on exit the number
+ * of frames actually received
+ * @param[in] rxbuf the pointer to the receive buffer
+ * @param[in] time operation timeout
+ *
+ * @return The operation status.
+ * @retval MSG_OK if the operation completed successfully.
+ * @retval MSG_TIMEOUT if the operation timed out.
+ * @retval MSG_RESET in case of a receive error.
+ *
+ * @api
+ */
+msg_t uartReceiveTimeout(UARTDriver *uartp, size_t *np,
+ void *rxbuf, systime_t time) {
+ msg_t msg;
+
+ osalDbgCheck((uartp != NULL) && (*np > 0U) && (rxbuf != NULL));
+
+ osalSysLock();
+ osalDbgAssert(uartp->state == UART_READY, "is active");
+ osalDbgAssert(uartp->rxstate != UART_RX_ACTIVE, "rx active");
+
+ /* Receive start.*/
+ uart_lld_start_receive(uartp, *np, rxbuf);
+ uartp->rxstate = UART_RX_ACTIVE;
+
+ /* Waiting for result.*/
+ msg = osalThreadSuspendTimeoutS(&uartp->threadrx, time);
+ if (msg != MSG_OK) {
+ *np = uartStopReceiveI(uartp);
+ }
+ osalSysUnlock();
+
+ return msg;
+}
+#endif
+
+#if (UART_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief Gains exclusive access to the UART bus.
+ * @details This function tries to gain ownership to the UART bus, if the bus
+ * is already being used then the invoking thread is queued.
+ * @pre In order to use this function the option @p UART_USE_MUTUAL_EXCLUSION
+ * must be enabled.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @api
+ */
+void uartAcquireBus(UARTDriver *uartp) {
+
+ osalDbgCheck(uartp != NULL);
+
+ osalMutexLock(&uartp->mutex);
+}
+
+/**
+ * @brief Releases exclusive access to the UART bus.
+ * @pre In order to use this function the option @p UART_USE_MUTUAL_EXCLUSION
+ * must be enabled.
+ *
+ * @param[in] uartp pointer to the @p UARTDriver object
+ *
+ * @api
+ */
+void uartReleaseBus(UARTDriver *uartp) {
+
+ osalDbgCheck(uartp != NULL);
+
+ osalMutexUnlock(&uartp->mutex);
+}
+#endif
+
#endif /* HAL_USE_UART == TRUE */
/** @} */
diff --git a/os/hal/templates/uart_lld.h b/os/hal/templates/uart_lld.h index 13d105b16..0451dcb21 100644 --- a/os/hal/templates/uart_lld.h +++ b/os/hal/templates/uart_lld.h @@ -143,6 +143,26 @@ struct UARTDriver { * @brief Current configuration data.
*/
const UARTConfig *config;
+#if UART_USE_WAIT || defined(__DOXYGEN__)
+ /**
+ * @brief Synchronization flag for transmit operations.
+ */
+ bool early;
+ /**
+ * @brief Waiting thread on RX.
+ */
+ thread_reference_t threadrx;
+ /**
+ * @brief Waiting thread on TX.
+ */
+ thread_reference_t threadtx;
+#endif /* UART_USE_WAIT */
+#if UART_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
+ /**
+ * @brief Mutex protecting the peripheral.
+ */
+ mutex_t mutex;
+#endif /* UART_USE_MUTUAL_EXCLUSION */
#if defined(UART_DRIVER_EXT_FIELDS)
UART_DRIVER_EXT_FIELDS
#endif
|