fix: potential blocking code when call uart_wait_tx_done()

1. there is a risk of ticks_end overflow, if xTaskGetTickCount() plus ticks_to_wait is bigger than portMAX_DELAY
2. potential blocking code on waiting for tx fifo done. It usually occurs at esp uart uses flow control, and the other side of uart not.
This commit is contained in:
Chen Wu
2021-04-28 11:56:21 +08:00
parent 870aa0a1e4
commit 38011372cd

View File

@ -257,7 +257,18 @@ esp_err_t uart_wait_tx_done(uart_port_t uart_num, TickType_t ticks_to_wait)
uint32_t baudrate;
uint32_t byte_delay_us = 0;
BaseType_t res;
portTickType ticks_cur;
portTickType ticks_start = xTaskGetTickCount();
portTickType ticks_end = xTaskGetTickCount() + ticks_to_wait;
/**
* Considering the overflow of the ticks_end and the ticks_cur (xTaskGetTickCount()),
* the possible tick timestamp is as follows:
* (one start tick timestamp, two end tick timestamps, four current tick timestamps)
*
* ticks: 0 0xFFFFFFFF
* |_______._______._______._______._______._______._______._______|
* cur1 end1 cur2 start cur3 end2 cur4
*/
// Take tx_mux
res = xSemaphoreTake(p_uart_obj[uart_num]->tx_mux, (portTickType)ticks_to_wait);
@ -273,10 +284,22 @@ esp_err_t uart_wait_tx_done(uart_port_t uart_num, TickType_t ticks_to_wait)
uart_get_baudrate(uart_num, &baudrate);
byte_delay_us = (uint32_t)(10000000 / baudrate); // (1/baudrate)*10*1000_000 us
ticks_to_wait = ticks_end - xTaskGetTickCount();
ticks_cur = xTaskGetTickCount();
if (ticks_start <= ticks_cur) {
ticks_to_wait = ticks_to_wait - (ticks_cur - ticks_start);
} else {
ticks_to_wait = ticks_to_wait - (portMAX_DELAY - ticks_start + ticks_cur);
}
// wait for tx done sem.
if (pdTRUE == xSemaphoreTake(p_uart_obj[uart_num]->tx_done_sem, ticks_to_wait)) {
while (1) {
ticks_cur = xTaskGetTickCount();
bool end1_timeout = (ticks_end < ticks_start && ticks_cur < ticks_start && ticks_cur > ticks_end);
bool end2_timeout = (ticks_start < ticks_end && (ticks_cur < ticks_start || ticks_end < ticks_cur));
if (end1_timeout || end2_timeout) {
xSemaphoreGive(p_uart_obj[uart_num]->tx_mux);
return ESP_ERR_TIMEOUT;
}
if (UART[uart_num]->status.txfifo_cnt == 0) {
ets_delay_us(byte_delay_us); // Delay one byte time to guarantee transmission completion
break;