#include "uart_trans.h" #include #include "FreeRTOS.h" #include "task.h" #include "usart.h" #include "app_runtime.h" #include "config.h" #include "debug_log.h" #include "route_msg.h" #define UART_MUX_SYNC 0x7Eu #define UART_MUX_TAIL 0x7Fu #define UART_NOTIFY_RX_U0 (1UL << 0) #define UART_NOTIFY_RX_U1 (1UL << 1) #define UART_NOTIFY_TX_U0 (1UL << 8) #define UART_NOTIFY_TX_U1 (1UL << 9) typedef struct { UART_HandleTypeDef *huart; uint8_t rx_dma_buffer[UART_RX_DMA_BUFFER_SIZE]; uint8_t tx_dma_buffer[UART_TX_DMA_BUFFER_SIZE]; uint8_t rx_ring[UART_RX_RING_BUFFER_SIZE]; uint8_t tx_ring[UART_TX_RING_BUFFER_SIZE]; volatile uint16_t rx_dma_read_index; volatile uint16_t rx_head; volatile uint16_t rx_tail; volatile uint16_t tx_head; 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); } static uint16_t ring_free(uint16_t head, uint16_t tail, uint16_t size) { return (uint16_t)(size - ring_used(head, tail, size) - 1u); } static void process_rx_snapshot(uart_channel_t channel) { uart_channel_ctx_t *ctx = &g_channels[channel]; uint16_t dma_write_index = (uint16_t)(UART_RX_DMA_BUFFER_SIZE - __HAL_DMA_GET_COUNTER(ctx->huart->hdmarx)); if (dma_write_index >= UART_RX_DMA_BUFFER_SIZE) { dma_write_index = 0u; } while (ctx->rx_dma_read_index != dma_write_index) { uint16_t next_head = (uint16_t)((ctx->rx_head + 1u) % UART_RX_RING_BUFFER_SIZE); if (next_head == ctx->rx_tail) { break; } ctx->rx_ring[ctx->rx_head] = ctx->rx_dma_buffer[ctx->rx_dma_read_index]; ctx->rx_head = next_head; ctx->rx_dma_read_index = (uint16_t)((ctx->rx_dma_read_index + 1u) % UART_RX_DMA_BUFFER_SIZE); } } 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 UART_TRANS_SEND_OK; } available = ring_used(ctx->tx_head, ctx->tx_tail, UART_TX_RING_BUFFER_SIZE); if (available == 0u) { return UART_TRANS_SEND_OK; } chunk = available; if (chunk > UART_TX_DMA_BUFFER_SIZE) { chunk = UART_TX_DMA_BUFFER_SIZE; } tail = ctx->tx_tail; for (i = 0; i < chunk; ++i) { 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; ctx->tx_kick_fail_logged = 0u; return UART_TRANS_SEND_OK; } static uint16_t uart_ring_available(uart_channel_t channel) { return ring_used(g_channels[channel].rx_head, g_channels[channel].rx_tail, UART_RX_RING_BUFFER_SIZE); } static uint16_t uart_ring_read(uart_channel_t channel, uint8_t *data, uint16_t max_len) { uart_channel_ctx_t *ctx = &g_channels[channel]; uint16_t copied = 0u; while (copied < max_len && ctx->rx_tail != ctx->rx_head) { data[copied++] = ctx->rx_ring[ctx->rx_tail]; ctx->rx_tail = (uint16_t)((ctx->rx_tail + 1u) % UART_RX_RING_BUFFER_SIZE); } return copied; } static bool uart_ring_peek_byte(uart_channel_t channel, uint16_t offset, uint8_t *data) { uart_channel_ctx_t *ctx = &g_channels[channel]; uint16_t available = ring_used(ctx->rx_head, ctx->rx_tail, UART_RX_RING_BUFFER_SIZE); if (data == NULL || offset >= available) { return false; } *data = ctx->rx_ring[(ctx->rx_tail + offset) % UART_RX_RING_BUFFER_SIZE]; return true; } static void uart_ring_drop(uart_channel_t channel, uint16_t len) { uart_channel_ctx_t *ctx = &g_channels[channel]; ctx->rx_tail = (uint16_t)((ctx->rx_tail + len) % UART_RX_RING_BUFFER_SIZE); } static void uart_route_raw_channel(uart_channel_t channel) { const device_config_t *cfg = config_get(); uint8_t buffer[ROUTE_MSG_MAX_PAYLOAD]; 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) { return; } for (i = 0; i < CONFIG_LINK_COUNT; ++i) { if (cfg->links[i].enabled == 0u || cfg->links[i].uart != ((channel == UART_CHANNEL_U1) ? LINK_UART_U1 : LINK_UART_U0)) { continue; } 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 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 (accepted_len == NULL || msg == NULL || offset >= msg->len) { return UART_TRANS_SEND_INVALID_INPUT; } *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) { 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_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; } } } static void uart_route_mux_frame(uart_channel_t source_channel, const uart_mux_frame_t *frame) { 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) { 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; } for (i = 0; i < CONFIG_LINK_COUNT; ++i) { if (cfg->links[i].enabled == 0u) { continue; } endpoint = config_link_index_to_endpoint((uint8_t)i); if ((frame->dst_mask & endpoint) != 0u) { 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))) { 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))) { 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); } } } int uart_trans_init(void) { memset(g_channels, 0, sizeof(g_channels)); g_channels[UART_CHANNEL_U0].huart = &huart2; g_channels[UART_CHANNEL_U1].huart = &huart3; debug_log_printf("[UART] init u0=%p u1=%p\r\n", (void *)g_channels[UART_CHANNEL_U0].huart, (void *)g_channels[UART_CHANNEL_U1].huart); return 0; } int uart_trans_config(uint8_t uart_index, uint32_t baudrate) { UART_HandleTypeDef *huart = (uart_index == LINK_UART_U1) ? &huart3 : &huart2; huart->Init.BaudRate = baudrate; return (HAL_UART_Init(huart) == HAL_OK) ? 0 : -1; } int uart_trans_start_all(void) { uint32_t i; for (i = 0; i < UART_CHANNEL_MAX; ++i) { if (g_channels[i].huart == NULL) { debug_log_printf("[UART] start fail null handle ch=%lu\r\n", (unsigned long)i); return -1; } g_channels[i].rx_dma_read_index = 0u; g_channels[i].rx_head = 0u; g_channels[i].rx_tail = 0u; g_channels[i].tx_head = 0u; g_channels[i].tx_tail = 0u; g_channels[i].tx_dma_len = 0u; g_channels[i].tx_busy = 0u; __HAL_UART_ENABLE_IT(g_channels[i].huart, UART_IT_IDLE); if (HAL_UART_Receive_DMA(g_channels[i].huart, g_channels[i].rx_dma_buffer, UART_RX_DMA_BUFFER_SIZE) != HAL_OK) { debug_log_printf("[UART] dma start fail ch=%lu\r\n", (unsigned long)i); return -1; } } debug_log_write("[UART] rx dma started\r\n"); return 0; } 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; uart_trans_send_result_t uart_result; uint16_t original_head; uint16_t written = 0u; if (channel >= UART_CHANNEL_MAX || data == NULL || len == 0u || len >= UART_TX_RING_BUFFER_SIZE) { return UART_TRANS_SEND_INVALID_INPUT; } 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); } 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) { uint32_t notify = (channel == UART_CHANNEL_U1) ? UART_NOTIFY_RX_U1 : UART_NOTIFY_RX_U0; if (xUartRxTaskHandle != NULL) { xTaskNotifyFromISR(xUartRxTaskHandle, notify, eSetBits, xHigherPriorityTaskWoken); } } void uart_trans_tx_cplt_handler(uart_channel_t channel) { uint32_t notify = (channel == UART_CHANNEL_U1) ? UART_NOTIFY_TX_U1 : UART_NOTIFY_TX_U0; BaseType_t xHigherPriorityTaskWoken = pdFALSE; if (xUartRxTaskHandle != NULL) { xTaskNotifyFromISR(xUartRxTaskHandle, notify, eSetBits, &xHigherPriorityTaskWoken); portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } } bool uart_mux_try_extract_frame(uart_channel_t channel, uart_mux_frame_t *frame) { uint16_t available; uint16_t payload_len; uint8_t sync_byte; uint16_t i; if (frame == NULL) { return false; } available = uart_ring_available(channel); if (available == 0u) { return false; } if (!uart_ring_peek_byte(channel, 0u, &sync_byte)) { return false; } if (sync_byte != UART_MUX_SYNC) { uart_ring_drop(channel, 1u); return false; } if (available < 6u) { return false; } if (!uart_ring_peek_byte(channel, 1u, &sync_byte)) { return false; } payload_len = (uint16_t)((uint16_t)sync_byte << 8); if (!uart_ring_peek_byte(channel, 2u, &sync_byte)) { return false; } payload_len = (uint16_t)(payload_len | sync_byte); if (payload_len > sizeof(frame->payload)) { uart_ring_drop(channel, 1u); return false; } if (available < (uint16_t)(payload_len + 6u)) { return false; } if (!uart_ring_peek_byte(channel, 5u + payload_len, &sync_byte)) { return false; } if (sync_byte != UART_MUX_TAIL) { uart_ring_drop(channel, 1u); return false; } if (!uart_ring_peek_byte(channel, 3u, &frame->src_id) || !uart_ring_peek_byte(channel, 4u, &frame->dst_mask)) { return false; } frame->payload_len = payload_len; for (i = 0u; i < payload_len; ++i) { if (!uart_ring_peek_byte(channel, (uint16_t)(5u + i), &frame->payload[i])) { return false; } } uart_ring_drop(channel, (uint16_t)(payload_len + 6u)); return true; } bool uart_mux_encode_frame(uint8_t src_id, uint8_t dst_mask, const uint8_t *payload, uint16_t payload_len, uint8_t *out, uint16_t *out_len, uint16_t out_capacity) { uint16_t frame_len = (uint16_t)(payload_len + 6u); if (out == NULL || out_len == NULL || frame_len > out_capacity) { return false; } out[0] = UART_MUX_SYNC; out[1] = (uint8_t)(payload_len >> 8); out[2] = (uint8_t)(payload_len & 0xFFu); out[3] = src_id; out[4] = dst_mask; if (payload_len > 0u && payload != NULL) { memcpy(&out[5], payload, payload_len); } out[5 + payload_len] = UART_MUX_TAIL; *out_len = frame_len; return true; } 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) { Debug_TrapWithRttHint("uart-start-fail"); vTaskSuspend(NULL); } debug_log_boot("uart-task-started"); for (;;) { notify_value = 0u; notified = xTaskNotifyWait(0u, 0xFFFFFFFFu, ¬ify_value, pdMS_TO_TICKS(10)); if ((notified == pdTRUE) && ((notify_value & UART_NOTIFY_RX_U0) != 0u)) { process_rx_snapshot(UART_CHANNEL_U0); } if ((notified == pdTRUE) && ((notify_value & UART_NOTIFY_RX_U1) != 0u)) { process_rx_snapshot(UART_CHANNEL_U1); } if ((notified == pdTRUE) && ((notify_value & UART_NOTIFY_TX_U0) != 0u)) { g_channels[UART_CHANNEL_U0].tx_busy = 0u; } if ((notified == pdTRUE) && ((notify_value & UART_NOTIFY_TX_U1) != 0u)) { g_channels[UART_CHANNEL_U1].tx_busy = 0u; } 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(); if (cfg->mux_mode == MUX_MODE_FRAME) { while (uart_mux_try_extract_frame(UART_CHANNEL_U0, &frame)) { uart_route_mux_frame(UART_CHANNEL_U0, &frame); } while (uart_mux_try_extract_frame(UART_CHANNEL_U1, &frame)) { uart_route_mux_frame(UART_CHANNEL_U1, &frame); } } else { uart_route_raw_channel(UART_CHANNEL_U0); uart_route_raw_channel(UART_CHANNEL_U1); } kick_tx(UART_CHANNEL_U0); kick_tx(UART_CHANNEL_U1); } }