From 84119d5d52641ea9a0da2d4c65b99e11533262cc Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Fri, 28 Aug 2020 14:27:43 +0000 Subject: [PATCH] git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@13812 27425a3e-05d8-49a3-a47f-9c15f0e5edd8 --- os/hal/include/hal_sio.h | 28 +-- os/hal/ports/STM32/LLD/USARTv2/hal_sio_lld.c | 86 ++++++++- os/hal/ports/STM32/LLD/USARTv2/hal_sio_lld.h | 6 +- os/hal/src/hal_sio.c | 182 +++++++++++++++++++ 4 files changed, 283 insertions(+), 19 deletions(-) diff --git a/os/hal/include/hal_sio.h b/os/hal/include/hal_sio.h index f1fd1c73e..a34b6a3b6 100644 --- a/os/hal/include/hal_sio.h +++ b/os/hal/include/hal_sio.h @@ -160,12 +160,12 @@ struct hal_sio_operation { * @brief Receive buffer filled callback. * @note Can be @p NULL. */ - siocb_t rxne_cb; + siocb_t rx_cb; /** * @brief End of transmission buffer callback. * @note Can be @p NULL. */ - siocb_t txnf_cb; + siocb_t tx_cb; /** * @brief Physical end of transmission callback. * @note Can be @p NULL. @@ -197,7 +197,7 @@ struct hal_sio_operation { * * @xclass */ -#define sioRXIsEmptyX(siop) sio_lld_rx_is_empty(siop) +#define sioIsRXEmptyX(siop) sio_lld_is_rx_empty(siop) /** * @brief Determines the state of the TX FIFO. @@ -209,7 +209,7 @@ struct hal_sio_operation { * * @xclass */ -#define sioTXIsFullX(siop) sio_lld_tx_is_full(siop) +#define sioIsTXFullX(siop) sio_lld_is_tx_full(siop) /** * @brief Returns one frame from the RX FIFO. @@ -218,9 +218,9 @@ struct hal_sio_operation { * @param[in] siop pointer to the @p SIODriver object * @return The frame from RX FIFO. * - * @xclass + * @iclass */ -#define sioRXGetX(siop) sio_lld_rx_get(siop) +#define sioGetI(siop) sio_lld_get(siop) /** * @brief Pushes one frame into the TX FIFO. @@ -229,9 +229,9 @@ struct hal_sio_operation { * @param[in] siop pointer to the @p SIODriver object * @param[in] data frame to be written * - * @xclass + * @iclass */ -#define sioTXPutX(siop, data) sio_lld_tx_put(siop, data) +#define sioPutI(siop, data) sio_lld_put(siop, data) /** * @brief Reads data from the RX FIFO. @@ -245,9 +245,9 @@ struct hal_sio_operation { * @param[in] size maximum number of frames to read * @return The number of received frames. * - * @xclass + * @iclass */ -#define sioReadX(siop, buffer, size) sio_lld_read(siop, buffer, size) +#define sioAsyncReadI(siop, buffer, size) sio_lld_read(siop, buffer, size) /** * @brief Writes data into the TX FIFO. @@ -261,9 +261,9 @@ struct hal_sio_operation { * @param[in] size maximum number of frames to read * @return The number of transmitted frames. * - * @xclass + * @iclass */ -#define sioWriteX(siop, buffer, size) sio_lld_write(siop, buffer, size) +#define sioAsyncWriteI(siop, buffer, size) sio_lld_write(siop, buffer, size) /** * @brief Control operation on a serial port. @@ -294,9 +294,13 @@ extern "C" { void sioStop(SIODriver *siop); void sioStartOperation(SIODriver *siop, const SIOOperation *operation); void sioStopOperation(SIODriver *siop); + size_t sioAsyncRead(SIODriver *siop, size_t n, uint8_t *buffer); + size_t sioAsyncWrite(SIODriver *siop, size_t n, const uint8_t *buffer); +#if (HAL_SIO_USE_SYNCHRONIZATION == TRUE) || defined(__DOXYGEN__) msg_t sioSynchronizeRX(SIODriver *siop); msg_t sioSynchronizeTX(SIODriver *siop); msg_t sioSynchronizeTXEnd(SIODriver *siop); +#endif #ifdef __cplusplus } #endif diff --git a/os/hal/ports/STM32/LLD/USARTv2/hal_sio_lld.c b/os/hal/ports/STM32/LLD/USARTv2/hal_sio_lld.c index 6d818b065..94211688a 100644 --- a/os/hal/ports/STM32/LLD/USARTv2/hal_sio_lld.c +++ b/os/hal/ports/STM32/LLD/USARTv2/hal_sio_lld.c @@ -37,7 +37,7 @@ /** * @brief SIO1 driver identifier. */ -#if (PLATFORM_SIO_USE_SIO1 == TRUE) || defined(__DOXYGEN__) +#if (STM32_SIO_USE_USART1 == TRUE) || defined(__DOXYGEN__) SIODriver SIOD1; #endif @@ -64,7 +64,7 @@ SIODriver SIOD1; */ void sio_lld_init(void) { -#if PLATFORM_SIO_USE_SIO1 == TRUE +#if STM32_SIO_USE_USART1 == TRUE /* Driver initialization.*/ sioObjectInit(&SIOD1); #endif @@ -84,7 +84,7 @@ bool sio_lld_start(SIODriver *siop) { if (siop->state == SIO_STOP) { /* Enables the peripheral.*/ -#if PLATFORM_SIO_USE_SIO1 == TRUE +#if STM32_SIO_USE_USART1 == TRUE if (&SIOD1 == siop) { } @@ -108,13 +108,91 @@ void sio_lld_stop(SIODriver *siop) { /* Resets the peripheral.*/ /* Disables the peripheral.*/ -#if PLATFORM_SIO_USE_SIO1 == TRUE +#if STM32_SIO_USE_USART1 == TRUE if (&SIOD1 == siop) { } #endif } } +/** + * @brief Reads data from the RX FIFO. + * @details The function is not blocking, it writes frames until there + * is space available without waiting. + * + * @param[in] siop pointer to an @p SIODriver structure + * @param[in] n maximum number of frames to be read + * @param[in] buf pointer to the buffer for read frames + * @return The number of frames copied from the buffer. + * @retval 0 if the TX FIFO is full. + */ +size_t sio_lld_read(SIODriver *siop, size_t n, uint8_t *buf) { + size_t rd; + + rd = 0U; + while (true) { + +#if USART_ENABLE_INTERRUPTS == TRUE + /* If the RX FIFO has been emptied then the interrupt is enabled again.*/ + if (sio_lld_is_rx_empty(siop)) { + siop->usart->CR3 |= USART_CR3_RXFTIE; + break; + } +#endif + + /* Buffer filled condition.*/ + if (rd > n) { + break; + } + + *buf++ = (uint8_t)siop->usart->RDR; + rd++; + } + + return n - rd; +} + +/** + * @brief Writes data into the TX FIFO. + * @details The function is not blocking, it writes frames until there + * is space available without waiting. + * + * @param[in] siop pointer to an @p SIODriver structure + * @param[in] n maximum number of frames to be written + * @param[in] buf pointer to the buffer for read frames + * @return The number of frames copied from the buffer. + * @retval 0 if the TX FIFO is full. + */ +size_t sio_lld_write(SIODriver *siop, size_t n, const uint8_t *buf) { + size_t wr; + + wr = 0U; + while (true) { + +#if USART_ENABLE_INTERRUPTS == TRUE + /* If the TX FIFO has been filled then the interrupt is enabled again.*/ + if (sio_lld_is_tx_full(siop)) { + siop->usart->CR3 |= USART_CR3_TXFTIE; + break; + } +#endif + + /* Buffer emptied condition.*/ + if (wr >= n) { + break; + } + + siop->usart->TDR = (uint32_t)*buf++; + wr++; + } + +#if USART_ENABLE_INTERRUPTS == TRUE + /* The transmit complete interrupt is always re-enabled on write.*/ + siop->usart->CR1 |= USART_CR1_TCIE; +#endif + + return n - wr; +} /** * @brief Control operation on a serial port. diff --git a/os/hal/ports/STM32/LLD/USARTv2/hal_sio_lld.h b/os/hal/ports/STM32/LLD/USARTv2/hal_sio_lld.h index d495d7107..05761b962 100644 --- a/os/hal/ports/STM32/LLD/USARTv2/hal_sio_lld.h +++ b/os/hal/ports/STM32/LLD/USARTv2/hal_sio_lld.h @@ -44,8 +44,8 @@ * @details If set to @p TRUE the support for SIO1 is included. * @note The default is @p FALSE. */ -#if !defined(PLATFORM_SIO_USE_SIO1) || defined(__DOXYGEN__) -#define PLATFORM_SIO_USE_SIO1 FALSE +#if !defined(STM32_SIO_USE_USART1) || defined(__DOXYGEN__) +#define STM32_SIO_USE_USART1 FALSE #endif /** @} */ @@ -133,7 +133,7 @@ /* External declarations. */ /*===========================================================================*/ -#if (PLATFORM_SIO_USE_SIO1 == TRUE) && !defined(__DOXYGEN__) +#if (STM32_SIO_USE_USART1 == TRUE) && !defined(__DOXYGEN__) extern SIODriver SIOD1; #endif diff --git a/os/hal/src/hal_sio.c b/os/hal/src/hal_sio.c index cae346af4..6faf08033 100644 --- a/os/hal/src/hal_sio.c +++ b/os/hal/src/hal_sio.c @@ -129,6 +129,188 @@ void sioStop(SIODriver *siop) { osalSysUnlock(); } +/** + * @brief Starts n SIO operation. + * + * @param[in] siop pointer to an @p SIODriver structure + * @param[in] operation pointer to an @p SIOOperation structure + * encoding the operation to be performed + */ +void sioStartOperation(SIODriver *siop, const SIOOperation *operation) { + + osalDbgCheck((siop != NULL) && (operation != NULL)); + + osalSysLock(); + + osalDbgAssert(siop->state == SIO_READY, "invalid state"); + + siop->operation = operation; + siop->state = SIO_ACTIVE; + + sio_lld_start_operation(siop); + + osalSysUnlock(); +} + +/** + * @brief Stops an ongoing SIO operation, if any. + * + * @param[in] siop pointer to an @p SIODriver structure + */ +void sioStopOperation(SIODriver *siop) { + + osalDbgCheck(siop != NULL); + + osalSysLock(); + + osalDbgAssert(siop->state == SIO_ACTIVE, "invalid state"); + + sio_lld_stop_operation(siop); + + siop->operation = NULL; + siop->state = SIO_READY; + + osalSysUnlock(); +} + +/** + * @brief Reads data from the RX FIFO. + * @details This function is non-blocking, data is read if present and the + * effective amount is returned. + * @note This function can be called from any context but it is meant to + * be called from the @p rxne_cb callback handler. + * + * @param[in] siop pointer to the @p SIODriver object + * @param[in] buffer buffer for the received data + * @param[in] size maximum number of frames to read + * @return The number of received frames. + * + * @api + */ +size_t sioAsyncReadI(SIODriver *siop, size_t n, uint8_t *buffer) { + + osalDbgCheck((siop != NULL) && (buf != NULL)); + + osalSysLock(); + + n = sioAsyncReadI(siop, n, buffer); + + osalSysUnlock(); + + return n; +} + +/** + * @brief Writes data into the TX FIFO. + * @details This function is non-blocking, data is written if there is space + * in the FIFO and the effective amount is returned. + * @note This function can be called from any context but it is meant to + * be called from the @p txnf_cb callback handler. + * + * @param[in] siop pointer to the @p SIODriver object + * @param[out] buffer buffer containing the data to be transmitted + * @param[in] size maximum number of frames to read + * @return The number of transmitted frames. + * + * @api + */ +size_t sioAsyncWrite(SIODriver *siop, size_t n, const uint8_t *buffer) { + + osalDbgCheck((siop != NULL) && (buf != NULL)); + + osalSysLock(); + + n = sioAsyncWriteI(siop, n, buffer); + + osalSysUnlock(); + + return n; +} + +#if (HAL_SIO_USE_SYNCHRONIZATION == TRUE) || defined(__DOXYGEN__) +/** + * @brief Synchronizes with RX FIFO data availability. + * @note The exact behavior depends on low level FIFO settings such + * as thresholds, etc. + * @note This function can only be called by a single thread at time. + * + * @param[in] siop pointer to an @p SIODriver structure + * @param[in] timeout synchronization timeout + * @return The synchronization result. + * @retval MSG_OK if there is space in the TX FIFO. + * @retval MSG_TIMEOUT if synchronization timed out. + */ +msg_t sioSynchronizeRX(SIODriver *siop) { + + osalDbgCheck(siop != NULL); + + osalSysLock(); + + osalDbgAssert(siop->state == SIO_ACTIVE, "invalid state"); + + if (sio_lld_is_rx_empty(siop)) { + msg = osalThdSuspendTimeoutS(&siop->sync_rx, timeout); + } + else { + msg = MSG_OK; + } + + osalSysUnlock(); +} + +/** + * @brief Synchronizes with TX FIFO space availability. + * @note The exact behavior depends on low level FIFO settings such + * as thresholds, etc. + * @note This function can only be called by a single thread at time. + * + * @param[in] siop pointer to an @p SIODriver structure + * @param[in] timeout synchronization timeout + * @return The synchronization result. + * @retval MSG_OK if there is space in the TX FIFO. + * @retval MSG_TIMEOUT if synchronization timed out. + */ +msg_t sioSynchronizeTX(SIODriver *siop) { + + osalDbgCheck(siop != NULL); + + osalSysLock(); + + osalDbgAssert(siop->state == SIO_ACTIVE, "invalid state"); + + + osalSysUnlock(); +} + +/** + * @brief Synchronizes with TX completion. + * @note This function can only be called by a single thread at time. + * + * @param[in] siop pointer to an @p SIODriver structure + * @param[in] timeout synchronization timeout + * @return The synchronization result. + * @retval MSG_OK if TX operation finished. + * @retval MSG_TIMEOUT if synchronization timed out. + */ +msg_t sioSynchronizeTXEnd(SIODriver *siop) { + + osalDbgCheck(siop != NULL); + + osalSysLock(); + + osalDbgAssert(siop->state == SIO_ACTIVE, "invalid state"); + + if (sio_lld_is_tx_ongoing(siop)) { + msg = osalThdSuspendTimeoutS(&siop->sync_txend, timeout); + } + else { + msg = MSG_OK; + } + + osalSysUnlock(); +} +#endif /* HAL_SIO_USE_SYNCHRONIZATION == TRUE */ + #endif /* HAL_USE_SIO == TRUE */ /** @} */