From 4bfdfa01326732e90a395dcdad8cc7b521fcf9ba Mon Sep 17 00:00:00 2001 From: Stuart Longland Date: Wed, 24 Jul 2019 14:01:16 +1000 Subject: [PATCH] [platform] add a UART flush operation (#4003) This commit allows the CLI to flush its transmit buffer of pending data so that it can resume writing to the buffer. This allows for reducing the size of the transmit buffer used for the CLI whilst still retaining the ability to transmit long blocks of text (which is required by the Thread certification tests) without locking up the use of that memory on constrained devices like CC2538. --- examples/platforms/cc1352/uart.c | 19 +++++--- examples/platforms/cc2538/uart.c | 12 +++-- examples/platforms/cc2650/uart.c | 19 +++++--- examples/platforms/cc2652/uart.c | 19 +++++--- examples/platforms/efr32mg12/uart.c | 5 ++ examples/platforms/efr32mg21/uart.c | 5 ++ examples/platforms/gp712/uart-posix.c | 5 ++ examples/platforms/gp712/uart-socket.c | 5 ++ examples/platforms/kw41z/uart.c | 5 ++ examples/platforms/nrf52811/uart.c | 5 ++ examples/platforms/nrf52840/uart.c | 5 ++ examples/platforms/nrf52840/usb-cdc-uart.c | 5 ++ examples/platforms/posix/sim/platform-sim.c | 5 ++ examples/platforms/posix/uart-posix.c | 5 ++ examples/platforms/qpg6095/uart.c | 5 ++ examples/platforms/samr21/uart.c | 5 ++ include/openthread/platform/uart.h | 13 +++++ src/cli/cli_uart.cpp | 53 ++++++++++++++++----- src/posix/platform/uart.c | 5 ++ 19 files changed, 166 insertions(+), 34 deletions(-) diff --git a/examples/platforms/cc1352/uart.c b/examples/platforms/cc1352/uart.c index 99881eb9f..34cd86504 100644 --- a/examples/platforms/cc1352/uart.c +++ b/examples/platforms/cc1352/uart.c @@ -192,10 +192,7 @@ static void processReceive(void) } } -/** - * @brief process the transmit side of the buffers - */ -static void processTransmit(void) +otError otPlatUartFlush(void) { otEXPECT(sSendBuffer != NULL); @@ -207,10 +204,20 @@ static void processTransmit(void) sSendBuffer = NULL; sSendLen = 0; - otPlatUartSendDone(); + + return OT_ERROR_NONE; exit: - return; + return OT_ERROR_INVALID_STATE; +} + +/** + * @brief process the transmit side of the buffers + */ +static void processTransmit(void) +{ + otPlatUartFlush(); + otPlatUartSendDone(); } /** diff --git a/examples/platforms/cc2538/uart.c b/examples/platforms/cc2538/uart.c index d709b840f..992af65d5 100644 --- a/examples/platforms/cc2538/uart.c +++ b/examples/platforms/cc2538/uart.c @@ -179,7 +179,7 @@ void processReceive(void) } } -void processTransmit(void) +otError otPlatUartFlush(void) { otEXPECT(sTransmitBuffer != NULL); @@ -192,10 +192,16 @@ void processTransmit(void) } sTransmitBuffer = NULL; - otPlatUartSendDone(); + return OT_ERROR_NONE; exit: - return; + return OT_ERROR_INVALID_STATE; +} + +void processTransmit(void) +{ + otPlatUartFlush(); + otPlatUartSendDone(); } void cc2538UartProcess(void) diff --git a/examples/platforms/cc2650/uart.c b/examples/platforms/cc2650/uart.c index fe8b38840..d6f048325 100644 --- a/examples/platforms/cc2650/uart.c +++ b/examples/platforms/cc2650/uart.c @@ -147,10 +147,7 @@ static void processReceive(void) } } -/** - * @brief process the transmit side of the buffers - */ -static void processTransmit(void) +otError otPlatUartFlush(void) { otEXPECT(sSendBuffer != NULL); @@ -162,10 +159,20 @@ static void processTransmit(void) sSendBuffer = NULL; sSendLen = 0; - otPlatUartSendDone(); + + return OT_ERROR_NONE; exit: - return; + return OT_ERROR_INVALID_STATE; +} + +/** + * @brief process the transmit side of the buffers + */ +static void processTransmit(void) +{ + otPlatUartFlush(); + otPlatUartSendDone(); } /** diff --git a/examples/platforms/cc2652/uart.c b/examples/platforms/cc2652/uart.c index 493aa0870..b342a5275 100644 --- a/examples/platforms/cc2652/uart.c +++ b/examples/platforms/cc2652/uart.c @@ -192,10 +192,7 @@ static void processReceive(void) } } -/** - * @brief process the transmit side of the buffers - */ -static void processTransmit(void) +otError otPlatUartFlush(void) { otEXPECT(sSendBuffer != NULL); @@ -207,10 +204,20 @@ static void processTransmit(void) sSendBuffer = NULL; sSendLen = 0; - otPlatUartSendDone(); + + return OT_ERROR_NONE; exit: - return; + return OT_ERROR_INVALID_STATE; +} + +/** + * @brief process the transmit side of the buffers + */ +static void processTransmit(void) +{ + otPlatUartFlush(); + otPlatUartSendDone(); } /** diff --git a/examples/platforms/efr32mg12/uart.c b/examples/platforms/efr32mg12/uart.c index 36858acd8..5576d469b 100644 --- a/examples/platforms/efr32mg12/uart.c +++ b/examples/platforms/efr32mg12/uart.c @@ -253,6 +253,11 @@ static void processReceive(void) CORE_EXIT_NVIC(); } +otError otPlatUartFlush(void) +{ + return OT_ERROR_NOT_IMPLEMENTED; +} + static void processTransmit(void) { if (sTransmitBuffer != NULL && sTransmitLength == 0) diff --git a/examples/platforms/efr32mg21/uart.c b/examples/platforms/efr32mg21/uart.c index cffafc00c..98c67ee84 100644 --- a/examples/platforms/efr32mg21/uart.c +++ b/examples/platforms/efr32mg21/uart.c @@ -250,6 +250,11 @@ static void processReceive(void) CORE_EXIT_NVIC(); } +otError otPlatUartFlush(void) +{ + return OT_ERROR_NOT_IMPLEMENTED; +} + static void processTransmit(void) { if (sTransmitBuffer != NULL && sTransmitLength == 0) diff --git a/examples/platforms/gp712/uart-posix.c b/examples/platforms/gp712/uart-posix.c index 7f80c203c..fee2e217c 100644 --- a/examples/platforms/gp712/uart-posix.c +++ b/examples/platforms/gp712/uart-posix.c @@ -207,6 +207,11 @@ exit: return error; } +otError otPlatUartFlush(void) +{ + return OT_ERROR_NOT_IMPLEMENTED; +} + void platformUartProcess(void) { ssize_t rval; diff --git a/examples/platforms/gp712/uart-socket.c b/examples/platforms/gp712/uart-socket.c index 36b9f1c43..754d56eb3 100644 --- a/examples/platforms/gp712/uart-socket.c +++ b/examples/platforms/gp712/uart-socket.c @@ -149,6 +149,11 @@ otError otPlatUartSend(const uint8_t *aBuf, uint16_t aBufLength) return error; } +otError otPlatUartFlush(void) +{ + return OT_ERROR_NOT_IMPLEMENTED; +} + void platformUartInit(void) { } diff --git a/examples/platforms/kw41z/uart.c b/examples/platforms/kw41z/uart.c index 6f2b671b1..226e04e16 100644 --- a/examples/platforms/kw41z/uart.c +++ b/examples/platforms/kw41z/uart.c @@ -120,6 +120,11 @@ exit: return error; } +otError otPlatUartFlush(void) +{ + return OT_ERROR_NOT_IMPLEMENTED; +} + static void processTransmit(void) { if (sTransmitBuffer && sTransmitDone) diff --git a/examples/platforms/nrf52811/uart.c b/examples/platforms/nrf52811/uart.c index c56bae881..73383162d 100644 --- a/examples/platforms/nrf52811/uart.c +++ b/examples/platforms/nrf52811/uart.c @@ -119,6 +119,11 @@ exit: return; } +otError otPlatUartFlush(void) +{ + return OT_ERROR_NOT_IMPLEMENTED; +} + /** * Function for notifying application about transmission being done. */ diff --git a/examples/platforms/nrf52840/uart.c b/examples/platforms/nrf52840/uart.c index d871b402e..c9b1ff59a 100644 --- a/examples/platforms/nrf52840/uart.c +++ b/examples/platforms/nrf52840/uart.c @@ -119,6 +119,11 @@ exit: return; } +otError otPlatUartFlush(void) +{ + return OT_ERROR_NOT_IMPLEMENTED; +} + /** * Function for notifying application about transmission being done. */ diff --git a/examples/platforms/nrf52840/usb-cdc-uart.c b/examples/platforms/nrf52840/usb-cdc-uart.c index 8c325b1ed..48e0ce361 100644 --- a/examples/platforms/nrf52840/usb-cdc-uart.c +++ b/examples/platforms/nrf52840/usb-cdc-uart.c @@ -362,4 +362,9 @@ exit: return error; } +otError otPlatUartFlush(void) +{ + return OT_ERROR_NOT_IMPLEMENTED; +} + #endif // USB_CDC_AS_SERIAL_TRANSPORT == 1 diff --git a/examples/platforms/posix/sim/platform-sim.c b/examples/platforms/posix/sim/platform-sim.c index 6d38e0824..87936c651 100644 --- a/examples/platforms/posix/sim/platform-sim.c +++ b/examples/platforms/posix/sim/platform-sim.c @@ -165,6 +165,11 @@ otError otPlatUartSend(const uint8_t *aData, uint16_t aLength) return error; } + +otError otPlatUartFlush(void) +{ + return OT_ERROR_NOT_IMPLEMENTED; +} #endif // OPENTHREAD_POSIX_VIRTUAL_TIME_UART static void socket_init(void) diff --git a/examples/platforms/posix/uart-posix.c b/examples/platforms/posix/uart-posix.c index 391b4b118..af375dcae 100644 --- a/examples/platforms/posix/uart-posix.c +++ b/examples/platforms/posix/uart-posix.c @@ -222,6 +222,11 @@ void platformUartUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, fd_set *aE } } +otError otPlatUartFlush(void) +{ + return OT_ERROR_NOT_IMPLEMENTED; +} + void platformUartProcess(void) { ssize_t rval; diff --git a/examples/platforms/qpg6095/uart.c b/examples/platforms/qpg6095/uart.c index eaf027dc6..c5336a260 100644 --- a/examples/platforms/qpg6095/uart.c +++ b/examples/platforms/qpg6095/uart.c @@ -57,6 +57,11 @@ otError otPlatUartDisable(void) return error; } +otError otPlatUartFlush(void) +{ + return OT_ERROR_NOT_IMPLEMENTED; +} + otError otPlatUartSend(const uint8_t *aBuf, uint16_t aBufLength) { otError error = OT_ERROR_NONE; diff --git a/examples/platforms/samr21/uart.c b/examples/platforms/samr21/uart.c index 3c7da8547..8f8aa1eaa 100644 --- a/examples/platforms/samr21/uart.c +++ b/examples/platforms/samr21/uart.c @@ -97,6 +97,11 @@ static void processReceive(void) } } +otError otPlatUartFlush(void) +{ + return OT_ERROR_NOT_IMPLEMENTED; +} + static void processTransmit(void) { if (sTransmitDone) diff --git a/include/openthread/platform/uart.h b/include/openthread/platform/uart.h index c6a89b460..6366dfefc 100644 --- a/include/openthread/platform/uart.h +++ b/include/openthread/platform/uart.h @@ -83,6 +83,19 @@ otError otPlatUartDisable(void); */ otError otPlatUartSend(const uint8_t *aBuf, uint16_t aBufLength); +/** + * Flush the outgoing transmit buffer and wait for the data to be sent. + * This is called when the CLI UART interface has a full buffer but still + * wishes to send more data. + * + * @retval OT_ERROR_NONE Flush succeeded, we can proceed to write more + * data to the buffer. + * + * @retval OT_ERROR_NOT_IMPLEMENTED Driver does not support synchronous flush. + * @retval OT_ERROR_INVALID_STATE Driver has no data to flush. + */ +otError otPlatUartFlush(void); + /** * The UART driver calls this method to notify OpenThread that the requested bytes have been sent. * diff --git a/src/cli/cli_uart.cpp b/src/cli/cli_uart.cpp index 9818a9d5d..097561a6e 100644 --- a/src/cli/cli_uart.cpp +++ b/src/cli/cli_uart.cpp @@ -237,25 +237,52 @@ otError Uart::ProcessCommand(void) int Uart::Output(const char *aBuf, uint16_t aBufLength) { OT_CLI_UART_OUTPUT_LOCK(); - uint16_t remaining = kTxBufferSize - mTxLength; - uint16_t tail; + uint16_t sent = 0; - if (aBufLength > remaining) + while (aBufLength > 0) { - aBufLength = remaining; + uint16_t remaining = kTxBufferSize - mTxLength; + uint16_t tail; + uint16_t sendLength = aBufLength; + + if (sendLength > remaining) + { + sendLength = remaining; + } + + for (uint16_t i = 0; i < sendLength; i++) + { + tail = (mTxHead + mTxLength) % kTxBufferSize; + mTxBuffer[tail] = *aBuf++; + aBufLength--; + mTxLength++; + } + + Send(); + + sent += sendLength; + + if (aBufLength > 0) + { + // More to send, so flush what's waiting now + otError err = otPlatUartFlush(); + + if (err == OT_ERROR_NONE) + { + // Flush successful, reset the pointers + SendDoneTask(); + } + else + { + // Flush did not succeed, so abort here. + break; + } + } } - for (int i = 0; i < aBufLength; i++) - { - tail = (mTxHead + mTxLength) % kTxBufferSize; - mTxBuffer[tail] = *aBuf++; - mTxLength++; - } - - Send(); OT_CLI_UART_OUTPUT_UNLOCK(); - return aBufLength; + return sent; } void Uart::Send(void) diff --git a/src/posix/platform/uart.c b/src/posix/platform/uart.c index 93859ff82..4534ceee0 100644 --- a/src/posix/platform/uart.c +++ b/src/posix/platform/uart.c @@ -157,6 +157,11 @@ exit: return error; } +otError otPlatUartFlush(void) +{ + return OT_ERROR_NOT_IMPLEMENTED; +} + void platformUartUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, fd_set *aErrorFdSet, int *aMaxFd) { otEXPECT(sEnabled);