fix: make uart tx enqueue all-or-nothing
This commit is contained in:
+243
-50
@@ -32,10 +32,27 @@ typedef struct {
|
||||
volatile uint16_t tx_tail;
|
||||
volatile uint16_t tx_dma_len;
|
||||
volatile uint8_t tx_busy;
|
||||
volatile uint8_t tx_kick_fail_logged;
|
||||
} uart_channel_ctx_t;
|
||||
|
||||
static uart_channel_ctx_t g_channels[UART_CHANNEL_MAX];
|
||||
|
||||
const char *uart_trans_send_result_to_str(uart_trans_send_result_t result)
|
||||
{
|
||||
switch (result) {
|
||||
case UART_TRANS_SEND_OK:
|
||||
return "ok";
|
||||
case UART_TRANS_SEND_INVALID_INPUT:
|
||||
return "invalid";
|
||||
case UART_TRANS_SEND_RING_FULL:
|
||||
return "full";
|
||||
case UART_TRANS_SEND_KICK_FAILED:
|
||||
return "kick";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static uint16_t ring_used(uint16_t head, uint16_t tail, uint16_t size)
|
||||
{
|
||||
return (head >= tail) ? (head - tail) : (size - tail + head);
|
||||
@@ -66,20 +83,21 @@ static void process_rx_snapshot(uart_channel_t channel)
|
||||
}
|
||||
}
|
||||
|
||||
static void kick_tx(uart_channel_t channel)
|
||||
static uart_trans_send_result_t kick_tx(uart_channel_t channel)
|
||||
{
|
||||
uart_channel_ctx_t *ctx = &g_channels[channel];
|
||||
uint16_t available;
|
||||
uint16_t chunk;
|
||||
uint16_t tail;
|
||||
uint16_t i;
|
||||
|
||||
if (ctx->tx_busy != 0u) {
|
||||
return;
|
||||
return UART_TRANS_SEND_OK;
|
||||
}
|
||||
|
||||
available = ring_used(ctx->tx_head, ctx->tx_tail, UART_TX_RING_BUFFER_SIZE);
|
||||
if (available == 0u) {
|
||||
return;
|
||||
return UART_TRANS_SEND_OK;
|
||||
}
|
||||
|
||||
chunk = available;
|
||||
@@ -87,16 +105,28 @@ static void kick_tx(uart_channel_t channel)
|
||||
chunk = UART_TX_DMA_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
tail = ctx->tx_tail;
|
||||
for (i = 0; i < chunk; ++i) {
|
||||
ctx->tx_dma_buffer[i] = ctx->tx_ring[ctx->tx_tail];
|
||||
ctx->tx_tail = (uint16_t)((ctx->tx_tail + 1u) % UART_TX_RING_BUFFER_SIZE);
|
||||
ctx->tx_dma_buffer[i] = ctx->tx_ring[tail];
|
||||
tail = (uint16_t)((tail + 1u) % UART_TX_RING_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
if (HAL_UART_Transmit_DMA(ctx->huart, ctx->tx_dma_buffer, chunk) != HAL_OK) {
|
||||
ctx->tx_dma_len = 0u;
|
||||
if (ctx->tx_kick_fail_logged == 0u) {
|
||||
debug_log_printf("[UART] kick-fail ch=%u len=%u\r\n",
|
||||
(unsigned int)channel,
|
||||
(unsigned int)chunk);
|
||||
ctx->tx_kick_fail_logged = 1u;
|
||||
}
|
||||
return UART_TRANS_SEND_KICK_FAILED;
|
||||
}
|
||||
|
||||
ctx->tx_tail = tail;
|
||||
ctx->tx_dma_len = chunk;
|
||||
ctx->tx_busy = 1u;
|
||||
if (HAL_UART_Transmit_DMA(ctx->huart, ctx->tx_dma_buffer, chunk) != HAL_OK) {
|
||||
ctx->tx_busy = 0u;
|
||||
}
|
||||
ctx->tx_kick_fail_logged = 0u;
|
||||
return UART_TRANS_SEND_OK;
|
||||
}
|
||||
|
||||
static uint16_t uart_ring_available(uart_channel_t channel)
|
||||
@@ -143,6 +173,7 @@ static void uart_route_raw_channel(uart_channel_t channel)
|
||||
uint16_t len;
|
||||
uint8_t uart_endpoint = (channel == UART_CHANNEL_U1) ? ENDPOINT_UART3 : ENDPOINT_UART2;
|
||||
uint32_t i;
|
||||
route_send_result_t route_result;
|
||||
|
||||
len = uart_ring_read(channel, buffer, sizeof(buffer));
|
||||
if (len == 0u) {
|
||||
@@ -154,38 +185,143 @@ static void uart_route_raw_channel(uart_channel_t channel)
|
||||
continue;
|
||||
}
|
||||
|
||||
(void)route_send(xLinkTxQueues[i],
|
||||
uart_endpoint,
|
||||
config_link_index_to_endpoint((uint8_t)i),
|
||||
(channel == UART_CHANNEL_U1) ? ROUTE_CONN_UART3 : ROUTE_CONN_UART2,
|
||||
buffer,
|
||||
len,
|
||||
pdMS_TO_TICKS(10));
|
||||
route_result = route_send(xLinkTxQueues[i],
|
||||
uart_endpoint,
|
||||
config_link_index_to_endpoint((uint8_t)i),
|
||||
(channel == UART_CHANNEL_U1) ? ROUTE_CONN_UART3 : ROUTE_CONN_UART2,
|
||||
buffer,
|
||||
len,
|
||||
pdMS_TO_TICKS(10));
|
||||
if (route_result != ROUTE_SEND_OK) {
|
||||
debug_log_printf("[UART] raw-route-fail idx=%u rc=%s len=%u\r\n",
|
||||
(unsigned int)i,
|
||||
route_send_result_to_str(route_result),
|
||||
(unsigned int)len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void uart_send_tcp_msg_to_uarts(route_msg_t *msg)
|
||||
static uart_trans_send_result_t uart_send_tcp_msg_chunk(route_msg_t *msg,
|
||||
uint16_t offset,
|
||||
uint16_t *accepted_len)
|
||||
{
|
||||
uint8_t frame[ROUTE_MSG_MAX_PAYLOAD + 6u];
|
||||
uint16_t frame_len = 0u;
|
||||
uint16_t remaining;
|
||||
uint16_t chunk_len;
|
||||
uint8_t uart_mask;
|
||||
uart_trans_send_result_t uart_result;
|
||||
|
||||
if ((msg->dst_mask & ENDPOINT_UART2) != 0u) {
|
||||
if (config_get()->mux_mode == MUX_MODE_FRAME) {
|
||||
if (uart_mux_encode_frame(msg->src_id, ENDPOINT_UART2, msg->data, msg->len, frame, &frame_len, sizeof(frame))) {
|
||||
(void)uart_trans_send_buffer(UART_CHANNEL_U0, frame, frame_len);
|
||||
}
|
||||
} else {
|
||||
(void)uart_trans_send_buffer(UART_CHANNEL_U0, msg->data, msg->len);
|
||||
}
|
||||
if (accepted_len == NULL || msg == NULL || offset >= msg->len) {
|
||||
return UART_TRANS_SEND_INVALID_INPUT;
|
||||
}
|
||||
|
||||
if ((msg->dst_mask & ENDPOINT_UART3) != 0u) {
|
||||
*accepted_len = 0u;
|
||||
|
||||
uart_mask = (uint8_t)(msg->dst_mask & (ENDPOINT_UART2 | ENDPOINT_UART3));
|
||||
if ((msg->dst_mask != uart_mask) ||
|
||||
(uart_mask != ENDPOINT_UART2 && uart_mask != ENDPOINT_UART3)) {
|
||||
return UART_TRANS_SEND_INVALID_INPUT;
|
||||
}
|
||||
|
||||
remaining = (uint16_t)(msg->len - offset);
|
||||
|
||||
if (uart_mask == ENDPOINT_UART2) {
|
||||
if (config_get()->mux_mode == MUX_MODE_FRAME) {
|
||||
if (uart_mux_encode_frame(msg->src_id, ENDPOINT_UART3, msg->data, msg->len, frame, &frame_len, sizeof(frame))) {
|
||||
(void)uart_trans_send_buffer(UART_CHANNEL_U1, frame, frame_len);
|
||||
chunk_len = remaining;
|
||||
if (chunk_len > (uint16_t)(UART_TX_RING_BUFFER_SIZE - 1u - 6u)) {
|
||||
chunk_len = (uint16_t)(UART_TX_RING_BUFFER_SIZE - 1u - 6u);
|
||||
}
|
||||
} else {
|
||||
(void)uart_trans_send_buffer(UART_CHANNEL_U1, msg->data, msg->len);
|
||||
if (!uart_mux_encode_frame(msg->src_id, ENDPOINT_UART2, &msg->data[offset], chunk_len, frame, &frame_len, sizeof(frame))) {
|
||||
return UART_TRANS_SEND_INVALID_INPUT;
|
||||
}
|
||||
uart_result = uart_trans_send_buffer(UART_CHANNEL_U0, frame, frame_len);
|
||||
if (uart_result != UART_TRANS_SEND_OK) {
|
||||
return uart_result;
|
||||
}
|
||||
*accepted_len = chunk_len;
|
||||
return UART_TRANS_SEND_OK;
|
||||
}
|
||||
|
||||
chunk_len = remaining;
|
||||
if (chunk_len > (uint16_t)(UART_TX_RING_BUFFER_SIZE - 1u)) {
|
||||
chunk_len = (uint16_t)(UART_TX_RING_BUFFER_SIZE - 1u);
|
||||
}
|
||||
uart_result = uart_trans_send_buffer(UART_CHANNEL_U0, &msg->data[offset], chunk_len);
|
||||
if (uart_result != UART_TRANS_SEND_OK) {
|
||||
return uart_result;
|
||||
}
|
||||
*accepted_len = chunk_len;
|
||||
return UART_TRANS_SEND_OK;
|
||||
}
|
||||
|
||||
if (config_get()->mux_mode == MUX_MODE_FRAME) {
|
||||
chunk_len = remaining;
|
||||
if (chunk_len > (uint16_t)(UART_TX_RING_BUFFER_SIZE - 1u - 6u)) {
|
||||
chunk_len = (uint16_t)(UART_TX_RING_BUFFER_SIZE - 1u - 6u);
|
||||
}
|
||||
if (!uart_mux_encode_frame(msg->src_id, ENDPOINT_UART3, &msg->data[offset], chunk_len, frame, &frame_len, sizeof(frame))) {
|
||||
return UART_TRANS_SEND_INVALID_INPUT;
|
||||
}
|
||||
uart_result = uart_trans_send_buffer(UART_CHANNEL_U1, frame, frame_len);
|
||||
if (uart_result != UART_TRANS_SEND_OK) {
|
||||
return uart_result;
|
||||
}
|
||||
*accepted_len = chunk_len;
|
||||
return UART_TRANS_SEND_OK;
|
||||
}
|
||||
|
||||
chunk_len = remaining;
|
||||
if (chunk_len > (uint16_t)(UART_TX_RING_BUFFER_SIZE - 1u)) {
|
||||
chunk_len = (uint16_t)(UART_TX_RING_BUFFER_SIZE - 1u);
|
||||
}
|
||||
uart_result = uart_trans_send_buffer(UART_CHANNEL_U1, &msg->data[offset], chunk_len);
|
||||
if (uart_result != UART_TRANS_SEND_OK) {
|
||||
return uart_result;
|
||||
}
|
||||
*accepted_len = chunk_len;
|
||||
return UART_TRANS_SEND_OK;
|
||||
}
|
||||
|
||||
static void uart_try_advance_pending_tcp_msg(route_msg_t **pending_tcp_msg,
|
||||
uint16_t *pending_tcp_offset,
|
||||
uart_trans_send_result_t *pending_tcp_result)
|
||||
{
|
||||
route_msg_t *msg;
|
||||
uart_trans_send_result_t uart_result;
|
||||
uint16_t accepted_len;
|
||||
|
||||
if (pending_tcp_msg == NULL || pending_tcp_offset == NULL || pending_tcp_result == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
msg = *pending_tcp_msg;
|
||||
if (msg == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
accepted_len = 0u;
|
||||
uart_result = uart_send_tcp_msg_chunk(msg, *pending_tcp_offset, &accepted_len);
|
||||
if (uart_result != UART_TRANS_SEND_OK) {
|
||||
if (uart_result != *pending_tcp_result) {
|
||||
debug_log_printf("[UART] tcp-pend src=0x%02X dst=0x%02X off=%u rc=%s\r\n",
|
||||
(unsigned int)msg->src_id,
|
||||
(unsigned int)msg->dst_mask,
|
||||
(unsigned int)(*pending_tcp_offset),
|
||||
uart_trans_send_result_to_str(uart_result));
|
||||
*pending_tcp_result = uart_result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
*pending_tcp_offset = (uint16_t)(*pending_tcp_offset + accepted_len);
|
||||
*pending_tcp_result = UART_TRANS_SEND_OK;
|
||||
if (*pending_tcp_offset >= msg->len) {
|
||||
route_msg_free(msg);
|
||||
*pending_tcp_msg = NULL;
|
||||
*pending_tcp_offset = 0u;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -194,18 +330,26 @@ static void uart_route_mux_frame(uart_channel_t source_channel, const uart_mux_f
|
||||
{
|
||||
const device_config_t *cfg = config_get();
|
||||
uint32_t i;
|
||||
uint8_t endpoint;
|
||||
uint8_t source_conn = (source_channel == UART_CHANNEL_U1) ? ROUTE_CONN_UART3 : ROUTE_CONN_UART2;
|
||||
uint8_t out_frame[ROUTE_MSG_MAX_PAYLOAD + 6u];
|
||||
uint16_t out_frame_len = 0u;
|
||||
route_send_result_t route_result;
|
||||
uart_trans_send_result_t uart_result;
|
||||
|
||||
if (frame->dst_mask == 0u) {
|
||||
(void)route_send(xConfigQueue,
|
||||
frame->src_id,
|
||||
0u,
|
||||
source_conn,
|
||||
frame->payload,
|
||||
frame->payload_len,
|
||||
pdMS_TO_TICKS(10));
|
||||
route_result = route_send(xConfigQueue,
|
||||
frame->src_id,
|
||||
0u,
|
||||
source_conn,
|
||||
frame->payload,
|
||||
frame->payload_len,
|
||||
pdMS_TO_TICKS(10));
|
||||
if (route_result != ROUTE_SEND_OK) {
|
||||
debug_log_printf("[UART] mux-cfg-fail rc=%s len=%u\r\n",
|
||||
route_send_result_to_str(route_result),
|
||||
(unsigned int)frame->payload_len);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -213,21 +357,41 @@ static void uart_route_mux_frame(uart_channel_t source_channel, const uart_mux_f
|
||||
if (cfg->links[i].enabled == 0u) {
|
||||
continue;
|
||||
}
|
||||
uint8_t endpoint = config_link_index_to_endpoint((uint8_t)i);
|
||||
endpoint = config_link_index_to_endpoint((uint8_t)i);
|
||||
if ((frame->dst_mask & endpoint) != 0u) {
|
||||
(void)route_send(xLinkTxQueues[i], frame->src_id, endpoint, source_conn, frame->payload, frame->payload_len, pdMS_TO_TICKS(10));
|
||||
route_result = route_send(xLinkTxQueues[i], frame->src_id, endpoint, source_conn, frame->payload, frame->payload_len, pdMS_TO_TICKS(10));
|
||||
if (route_result != ROUTE_SEND_OK) {
|
||||
debug_log_printf("[UART] mux-route-fail idx=%u rc=%s len=%u\r\n",
|
||||
(unsigned int)i,
|
||||
route_send_result_to_str(route_result),
|
||||
(unsigned int)frame->payload_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((frame->dst_mask & ENDPOINT_UART2) != 0u && source_channel != UART_CHANNEL_U0) {
|
||||
if (uart_mux_encode_frame(frame->src_id, ENDPOINT_UART2, frame->payload, frame->payload_len, out_frame, &out_frame_len, sizeof(out_frame))) {
|
||||
(void)uart_trans_send_buffer(UART_CHANNEL_U0, out_frame, out_frame_len);
|
||||
uart_result = uart_trans_send_buffer(UART_CHANNEL_U0, out_frame, out_frame_len);
|
||||
if (uart_result != UART_TRANS_SEND_OK) {
|
||||
debug_log_printf("[UART] mux-u0-tx-fail rc=%s len=%u\r\n",
|
||||
uart_trans_send_result_to_str(uart_result),
|
||||
(unsigned int)out_frame_len);
|
||||
}
|
||||
} else {
|
||||
debug_log_printf("[UART] mux-u0-enc-fail len=%u\r\n", (unsigned int)frame->payload_len);
|
||||
}
|
||||
}
|
||||
|
||||
if ((frame->dst_mask & ENDPOINT_UART3) != 0u && source_channel != UART_CHANNEL_U1) {
|
||||
if (uart_mux_encode_frame(frame->src_id, ENDPOINT_UART3, frame->payload, frame->payload_len, out_frame, &out_frame_len, sizeof(out_frame))) {
|
||||
(void)uart_trans_send_buffer(UART_CHANNEL_U1, out_frame, out_frame_len);
|
||||
uart_result = uart_trans_send_buffer(UART_CHANNEL_U1, out_frame, out_frame_len);
|
||||
if (uart_result != UART_TRANS_SEND_OK) {
|
||||
debug_log_printf("[UART] mux-u1-tx-fail rc=%s len=%u\r\n",
|
||||
uart_trans_send_result_to_str(uart_result),
|
||||
(unsigned int)out_frame_len);
|
||||
}
|
||||
} else {
|
||||
debug_log_printf("[UART] mux-u1-enc-fail len=%u\r\n", (unsigned int)frame->payload_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -273,22 +437,44 @@ int uart_trans_start_all(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool uart_trans_send_buffer(uart_channel_t channel, const uint8_t *data, uint16_t len)
|
||||
uart_trans_send_result_t uart_trans_send_buffer(uart_channel_t channel, const uint8_t *data, uint16_t len)
|
||||
{
|
||||
uart_channel_ctx_t *ctx = &g_channels[channel];
|
||||
uart_channel_ctx_t *ctx;
|
||||
uart_trans_send_result_t uart_result;
|
||||
uint16_t original_head;
|
||||
uint16_t written = 0u;
|
||||
|
||||
if (data == NULL || len == 0u) {
|
||||
return false;
|
||||
if (channel >= UART_CHANNEL_MAX || data == NULL || len == 0u || len >= UART_TX_RING_BUFFER_SIZE) {
|
||||
return UART_TRANS_SEND_INVALID_INPUT;
|
||||
}
|
||||
|
||||
while (written < len && ring_free(ctx->tx_head, ctx->tx_tail, UART_TX_RING_BUFFER_SIZE) > 0u) {
|
||||
ctx = &g_channels[channel];
|
||||
if (ctx->huart == NULL) {
|
||||
return UART_TRANS_SEND_INVALID_INPUT;
|
||||
}
|
||||
|
||||
taskENTER_CRITICAL();
|
||||
original_head = ctx->tx_head;
|
||||
if (ring_free(ctx->tx_head, ctx->tx_tail, UART_TX_RING_BUFFER_SIZE) < len) {
|
||||
taskEXIT_CRITICAL();
|
||||
return UART_TRANS_SEND_RING_FULL;
|
||||
}
|
||||
|
||||
while (written < len) {
|
||||
ctx->tx_ring[ctx->tx_head] = data[written++];
|
||||
ctx->tx_head = (uint16_t)((ctx->tx_head + 1u) % UART_TX_RING_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
kick_tx(channel);
|
||||
return (written == len);
|
||||
uart_result = kick_tx(channel);
|
||||
if (uart_result != UART_TRANS_SEND_OK) {
|
||||
ctx->tx_head = original_head;
|
||||
taskEXIT_CRITICAL();
|
||||
return uart_result;
|
||||
}
|
||||
|
||||
taskEXIT_CRITICAL();
|
||||
|
||||
return UART_TRANS_SEND_OK;
|
||||
}
|
||||
|
||||
void uart_trans_notify_rx_from_isr(uart_channel_t channel, BaseType_t *xHigherPriorityTaskWoken)
|
||||
@@ -412,8 +598,11 @@ void UartRxTask(void *argument)
|
||||
uint32_t notify_value;
|
||||
BaseType_t notified;
|
||||
route_msg_t *msg;
|
||||
route_msg_t *pending_tcp_msg = NULL;
|
||||
uint16_t pending_tcp_offset = 0u;
|
||||
uart_mux_frame_t frame;
|
||||
const device_config_t *cfg;
|
||||
uart_trans_send_result_t pending_tcp_result = UART_TRANS_SEND_OK;
|
||||
|
||||
(void)argument;
|
||||
if (uart_trans_start_all() != 0) {
|
||||
@@ -439,9 +628,13 @@ void UartRxTask(void *argument)
|
||||
g_channels[UART_CHANNEL_U1].tx_busy = 0u;
|
||||
}
|
||||
|
||||
while (xQueueReceive(xTcpRxQueue, &msg, 0) == pdPASS) {
|
||||
uart_send_tcp_msg_to_uarts(msg);
|
||||
route_msg_free(msg);
|
||||
uart_try_advance_pending_tcp_msg(&pending_tcp_msg, &pending_tcp_offset, &pending_tcp_result);
|
||||
|
||||
while (pending_tcp_msg == NULL && xQueueReceive(xTcpRxQueue, &msg, 0) == pdPASS) {
|
||||
pending_tcp_msg = msg;
|
||||
pending_tcp_offset = 0u;
|
||||
pending_tcp_result = UART_TRANS_SEND_OK;
|
||||
uart_try_advance_pending_tcp_msg(&pending_tcp_msg, &pending_tcp_offset, &pending_tcp_result);
|
||||
}
|
||||
|
||||
cfg = config_get();
|
||||
|
||||
Reference in New Issue
Block a user