Skip to content

Commit 7af818b

Browse files
committed
feat(esp_driver_uart): Add uart_write_bytes_with_timeout()
Avoids locking if the uart is blocked due to flow control.
1 parent 474ecad commit 7af818b

File tree

2 files changed

+59
-11
lines changed

2 files changed

+59
-11
lines changed

components/esp_driver_uart/include/driver/uart.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,26 @@ int uart_tx_chars(uart_port_t uart_num, const char* buffer, uint32_t len);
553553
*/
554554
int uart_write_bytes(uart_port_t uart_num, const void* src, size_t size);
555555

556+
/**
557+
* @brief Send data to the UART port from a given buffer and length,
558+
*
559+
* If the UART driver's parameter 'tx_buffer_size' is set to zero:
560+
* This function will return before all the data have been sent out, if it times out.
561+
*
562+
* Otherwise, if the 'tx_buffer_size' > 0, this function will return after copying all the data to tx ring buffer,
563+
* UART ISR will then move data from the ring buffer to TX FIFO gradually.
564+
*
565+
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
566+
* @param src data buffer address
567+
* @param size data length to send
568+
* @param ticks_to_wait Timeout, count in RTOS ticks
569+
*
570+
* @return
571+
* - (-1) Parameter error
572+
* - OTHERS (>=0) The number of bytes pushed to the TX FIFO
573+
*/
574+
int uart_write_bytes_with_timeout(uart_port_t uart_num, const void* src, size_t size, TickType_t ticks_to_wait);
575+
556576
/**
557577
* @brief Send data to the UART port from a given buffer and length,
558578
*

components/esp_driver_uart/src/uart.c

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1611,15 +1611,17 @@ int uart_tx_chars(uart_port_t uart_num, const char *buffer, uint32_t len)
16111611

16121612
// Per transaction in the ring buffer:
16131613
// A data description item, followed by one or more data chunk items
1614-
static int uart_tx_all(uart_port_t uart_num, const char *src, size_t size, bool brk_en, int brk_len)
1614+
static int uart_tx_all(uart_port_t uart_num, const char *src, size_t size, bool brk_en, int brk_len, TickType_t ticks_to_wait)
16151615
{
16161616
if (size == 0) {
16171617
return 0;
16181618
}
1619-
size_t original_size = size;
1619+
size_t bytes_transmitted = 0;
16201620

16211621
//lock for uart_tx
1622-
xSemaphoreTake(p_uart_obj[uart_num]->tx_mux, (TickType_t)portMAX_DELAY);
1622+
if (xSemaphoreTake(p_uart_obj[uart_num]->tx_mux, (TickType_t)ticks_to_wait) != pdTRUE) {
1623+
return -1;
1624+
}
16231625
#if PROTECT_APB
16241626
esp_pm_lock_acquire(p_uart_obj[uart_num]->pm_lock);
16251627
#endif
@@ -1647,7 +1649,10 @@ static int uart_tx_all(uart_port_t uart_num, const char *src, size_t size, bool
16471649
// Accuire space for data description and data chunk, this gives a strong
16481650
// guarantee that data chunk can be copied in one go
16491651
uart_tx_data_t *tx_data = NULL;
1650-
xRingbufferSendAcquire(p_uart_obj[uart_num]->tx_ring_buf, (void **)&tx_data, acquire_size, portMAX_DELAY);
1652+
BaseType_t res = xRingbufferSendAcquire(p_uart_obj[uart_num]->tx_ring_buf, (void **)&tx_data, acquire_size, ticks_to_wait);
1653+
if (res != pdTRUE) {
1654+
break; // Timeout
1655+
}
16511656

16521657
size_t send_size = acquire_size - sizeof(uart_tx_data_t);
16531658

@@ -1667,20 +1672,26 @@ static int uart_tx_all(uart_port_t uart_num, const char *src, size_t size, bool
16671672

16681673
size -= send_size;
16691674
offset += send_size;
1675+
bytes_transmitted += send_size;
16701676
}
16711677

1672-
uart_enable_tx_intr(uart_num, 1, UART_THRESHOLD_NUM(uart_num, UART_EMPTY_THRESH_DEFAULT));
1678+
// If at least some data has been sent to the ring buffer, enable TX interrupt to start sending
1679+
if (bytes_transmitted > 0) {
1680+
uart_enable_tx_intr(uart_num, 1, UART_THRESHOLD_NUM(uart_num, UART_EMPTY_THRESH_DEFAULT));
1681+
}
16731682
} else {
16741683
while (size) {
16751684
//semaphore for tx_fifo available
1676-
if (pdTRUE == xSemaphoreTake(p_uart_obj[uart_num]->tx_fifo_sem, (TickType_t)portMAX_DELAY)) {
1685+
if (pdTRUE == xSemaphoreTake(p_uart_obj[uart_num]->tx_fifo_sem, ticks_to_wait)) {
16771686
uint32_t sent = uart_enable_tx_write_fifo(uart_num, (const uint8_t *) src, size);
16781687
if (sent < size) {
16791688
p_uart_obj[uart_num]->tx_waiting_fifo = true;
16801689
uart_enable_tx_intr(uart_num, 1, UART_THRESHOLD_NUM(uart_num, UART_EMPTY_THRESH_DEFAULT));
16811690
}
16821691
size -= sent;
16831692
src += sent;
1693+
bytes_transmitted += sent;
1694+
xSemaphoreGive(p_uart_obj[uart_num]->tx_fifo_sem);
16841695
} else {
16851696
break;
16861697
}
@@ -1691,23 +1702,40 @@ static int uart_tx_all(uart_port_t uart_num, const char *src, size_t size, bool
16911702
uart_hal_tx_break(&(uart_context[uart_num].hal), brk_len);
16921703
uart_hal_ena_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TX_BRK_DONE);
16931704
UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock));
1694-
xSemaphoreTake(p_uart_obj[uart_num]->tx_brk_sem, (TickType_t)portMAX_DELAY);
1705+
if (pdFALSE == xSemaphoreTake(p_uart_obj[uart_num]->tx_brk_sem, ticks_to_wait)) {
1706+
uart_hal_disable_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TX_BRK_DONE);
1707+
bytes_transmitted = -1; // Indicate failure due to timeout waiting for break to complete
1708+
}
16951709
}
1696-
xSemaphoreGive(p_uart_obj[uart_num]->tx_fifo_sem);
1710+
16971711
}
1712+
16981713
#if PROTECT_APB
16991714
esp_pm_lock_release(p_uart_obj[uart_num]->pm_lock);
17001715
#endif
17011716
xSemaphoreGive(p_uart_obj[uart_num]->tx_mux);
1702-
return original_size;
1717+
1718+
// If no bytes were transmitted due to timeout, return -1 to indicate failure
1719+
if (bytes_transmitted == 0) {
1720+
return -1;
1721+
}
1722+
return bytes_transmitted;
17031723
}
17041724

17051725
int uart_write_bytes(uart_port_t uart_num, const void *src, size_t size)
17061726
{
17071727
ESP_RETURN_ON_FALSE((uart_num < UART_NUM_MAX), (-1), UART_TAG, "uart_num error");
17081728
ESP_RETURN_ON_FALSE((p_uart_obj[uart_num] != NULL), (-1), UART_TAG, "uart driver error");
17091729
ESP_RETURN_ON_FALSE(src, (-1), UART_TAG, "buffer null");
1710-
return uart_tx_all(uart_num, src, size, 0, 0);
1730+
return uart_tx_all(uart_num, src, size, 0, 0, portMAX_DELAY);
1731+
}
1732+
1733+
int uart_write_bytes_with_timeout(uart_port_t uart_num, const void *src, size_t size, TickType_t ticks_to_wait)
1734+
{
1735+
ESP_RETURN_ON_FALSE((uart_num < UART_NUM_MAX), (-1), UART_TAG, "uart_num error");
1736+
ESP_RETURN_ON_FALSE((p_uart_obj[uart_num] != NULL), (-1), UART_TAG, "uart driver error");
1737+
ESP_RETURN_ON_FALSE(src, (-1), UART_TAG, "buffer null");
1738+
return uart_tx_all(uart_num, src, size, 0, 0, ticks_to_wait);
17111739
}
17121740

17131741
int uart_write_bytes_with_break(uart_port_t uart_num, const void *src, size_t size, int brk_len)
@@ -1717,7 +1745,7 @@ int uart_write_bytes_with_break(uart_port_t uart_num, const void *src, size_t si
17171745
ESP_RETURN_ON_FALSE((size > 0), (-1), UART_TAG, "uart size error");
17181746
ESP_RETURN_ON_FALSE((src), (-1), UART_TAG, "uart data null");
17191747
ESP_RETURN_ON_FALSE((brk_len > 0 && brk_len < 256), (-1), UART_TAG, "break_num error");
1720-
return uart_tx_all(uart_num, src, size, 1, brk_len);
1748+
return uart_tx_all(uart_num, src, size, 1, brk_len, portMAX_DELAY);
17211749
}
17221750

17231751
static bool uart_check_buf_full(uart_port_t uart_num)

0 commit comments

Comments
 (0)