fix(mux): 修复MUX半帧丢失与发送路径静默失败

This commit is contained in:
2026-04-18 18:48:38 +08:00
parent a0b27d34a0
commit 495fbe4298
4 changed files with 225 additions and 78 deletions
+9
View File
@@ -239,14 +239,23 @@ int tcp_client_send(uint8_t instance, const uint8_t *data, uint16_t len)
return -1; return -1;
} }
if (tcp_sndbuf(ctx->pcb) < len) { if (tcp_sndbuf(ctx->pcb) < len) {
ctx->status.errors++;
return 0; return 0;
} }
err = tcp_write(ctx->pcb, data, len, TCP_WRITE_FLAG_COPY); err = tcp_write(ctx->pcb, data, len, TCP_WRITE_FLAG_COPY);
if (err == ERR_MEM) {
ctx->status.errors++;
return 0;
}
if (err != ERR_OK) { if (err != ERR_OK) {
ctx->status.errors++; ctx->status.errors++;
return -1; return -1;
} }
err = tcp_output(ctx->pcb); err = tcp_output(ctx->pcb);
if (err == ERR_MEM) {
ctx->status.errors++;
return 0;
}
if (err != ERR_OK) { if (err != ERR_OK) {
ctx->status.errors++; ctx->status.errors++;
return -1; return -1;
+9
View File
@@ -228,15 +228,24 @@ int tcp_server_send(uint8_t instance, const uint8_t *data, uint16_t len)
return -1; return -1;
} }
if (tcp_sndbuf(ctx->client_pcb) < len) { if (tcp_sndbuf(ctx->client_pcb) < len) {
ctx->status.errors++;
return 0; return 0;
} }
err = tcp_write(ctx->client_pcb, data, len, TCP_WRITE_FLAG_COPY); err = tcp_write(ctx->client_pcb, data, len, TCP_WRITE_FLAG_COPY);
if (err == ERR_MEM) {
ctx->status.errors++;
return 0;
}
if (err != ERR_OK) { if (err != ERR_OK) {
ctx->status.errors++; ctx->status.errors++;
return -1; return -1;
} }
err = tcp_output(ctx->client_pcb); err = tcp_output(ctx->client_pcb);
if (err == ERR_MEM) {
ctx->status.errors++;
return 0;
}
if (err != ERR_OK) { if (err != ERR_OK) {
ctx->status.errors++; ctx->status.errors++;
return -1; return -1;
+87 -17
View File
@@ -43,6 +43,52 @@ static uint16_t ring_free(uint16_t head, uint16_t tail, uint16_t size)
return (uint16_t)(size - ring_used(head, tail, size) - 1u); return (uint16_t)(size - ring_used(head, tail, size) - 1u);
} }
static bool ring_peek_byte(const uart_channel_ctx_t *ctx, uint16_t offset, uint8_t *out)
{
uint16_t head;
uint16_t tail;
if (ctx == NULL || out == NULL) {
return false;
}
head = ctx->rx_head;
tail = ctx->rx_tail;
if (offset >= ring_used(head, tail, UART_RX_RING_BUFFER_SIZE)) {
return false;
}
*out = ctx->rx_ring[(tail + offset) % UART_RX_RING_BUFFER_SIZE];
return true;
}
static bool ring_peek_span(const uart_channel_ctx_t *ctx, uint16_t offset, uint8_t *data, uint16_t len)
{
if (ctx == NULL || data == NULL) {
return false;
}
for (uint16_t i = 0u; i < len; ++i) {
if (!ring_peek_byte(ctx, (uint16_t)(offset + i), &data[i])) {
return false;
}
}
return true;
}
static void ring_drop_bytes(uart_channel_ctx_t *ctx, uint16_t len)
{
if (ctx == NULL) {
return;
}
while (len > 0u && ctx->rx_tail != ctx->rx_head) {
ctx->rx_tail = (uint16_t)((ctx->rx_tail + 1u) % UART_RX_RING_BUFFER_SIZE);
--len;
}
}
static int apply_uart_config(uart_channel_t channel) static int apply_uart_config(uart_channel_t channel)
{ {
uart_channel_ctx_t *ctx = &g_channels[channel]; uart_channel_ctx_t *ctx = &g_channels[channel];
@@ -297,63 +343,87 @@ void uart_trans_tx_cplt_handler(uart_channel_t channel)
bool uart_mux_try_extract_frame(uart_channel_t channel, uart_mux_frame_t *frame) bool uart_mux_try_extract_frame(uart_channel_t channel, uart_mux_frame_t *frame)
{ {
uint8_t sync_byte; uart_channel_ctx_t *ctx;
uint8_t header[4]; uint8_t header[4];
uint8_t tail_byte;
uint16_t available; uint16_t available;
uint16_t payload_len; uint16_t payload_len;
uint16_t sync_offset;
uint16_t total_len;
if (channel >= UART_CHANNEL_MAX || frame == NULL) { if (channel >= UART_CHANNEL_MAX || frame == NULL) {
return false; return false;
} }
ctx = &g_channels[channel];
for (;;) {
available = uart_trans_rx_available(channel); available = uart_trans_rx_available(channel);
if (available < 6u) { if (available < 6u) {
return false; return false;
} }
/* Scan for SYNC byte (0x7E) — discard non-matching bytes one at a time */ sync_offset = available;
if (uart_trans_read(channel, &sync_byte, 1u) != 1u) { for (uint16_t i = 0u; i < available; ++i) {
uint8_t byte = 0u;
if (!ring_peek_byte(ctx, i, &byte)) {
return false; return false;
} }
if (sync_byte != UART_MUX_SYNC) { if (byte == UART_MUX_SYNC) {
sync_offset = i;
break;
}
}
if (sync_offset == available) {
ring_drop_bytes(ctx, available);
return false; return false;
} }
/* Need at least: 2(len) + 1(src) + 1(dst) + payload + 1(tail) = 5 + payload */ if (sync_offset > 0u) {
available = uart_trans_rx_available(channel); ring_drop_bytes(ctx, sync_offset);
if (available < 4u) { available = (uint16_t)(available - sync_offset);
}
if (available < 6u) {
return false; return false;
} }
if (uart_trans_read(channel, header, sizeof(header)) != sizeof(header)) { if (!ring_peek_span(ctx, 1u, header, sizeof(header))) {
return false; return false;
} }
payload_len = (uint16_t)(((uint16_t)header[0] << 8) | header[1]); payload_len = (uint16_t)(((uint16_t)header[0] << 8) | header[1]);
if (payload_len > sizeof(frame->payload)) { if (payload_len > sizeof(frame->payload)) {
ring_drop_bytes(ctx, 1u);
continue;
}
total_len = (uint16_t)(payload_len + 6u);
if (available < total_len) {
return false; return false;
} }
if (uart_trans_rx_available(channel) < (uint16_t)(payload_len + 1u)) {
if (!ring_peek_byte(ctx, (uint16_t)(total_len - 1u), &tail_byte)) {
return false; return false;
} }
if (tail_byte != UART_MUX_TAIL) {
ring_drop_bytes(ctx, 1u);
continue;
}
frame->src_id = header[2]; frame->src_id = header[2];
frame->dst_mask = header[3]; frame->dst_mask = header[3];
frame->payload_len = payload_len; frame->payload_len = payload_len;
if (payload_len > 0u) { if (payload_len > 0u) {
if (uart_trans_read(channel, frame->payload, payload_len) != payload_len) { if (!ring_peek_span(ctx, 5u, frame->payload, payload_len)) {
return false;
}
}
{
uint8_t tail = 0u;
if (uart_trans_read(channel, &tail, 1u) != 1u || tail != UART_MUX_TAIL) {
return false; return false;
} }
} }
ring_drop_bytes(ctx, total_len);
return true; return true;
}
} }
bool uart_mux_encode_frame(uint8_t src_id, bool uart_mux_encode_frame(uint8_t src_id,
+89 -30
View File
@@ -66,7 +66,9 @@ static void App_RouteMuxUartTraffic(void);
static void App_RouteTcpTraffic(void); static void App_RouteTcpTraffic(void);
static void StackGuard_Init(void); static void StackGuard_Init(void);
static void StackGuard_Check(void); static void StackGuard_Check(void);
static void App_SendToUart(uint8_t uart_index, uint8_t src_id, uint8_t dst_mask, const uint8_t *data, uint16_t len); static bool App_SendToUart(uint8_t uart_index, uint8_t src_id, uint8_t dst_mask, const uint8_t *data, uint16_t len);
static bool App_SendTcpServerPayload(uint8_t instance, const uint8_t *data, uint16_t len);
static bool App_SendTcpClientPayload(uint8_t instance, const uint8_t *data, uint16_t len);
/* USER CODE END PFP */ /* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/ /* Private user code ---------------------------------------------------------*/
@@ -261,19 +263,33 @@ static void App_Init(void)
} }
} }
static void App_SendToUart(uint8_t uart_index, uint8_t src_id, uint8_t dst_mask, const uint8_t *data, uint16_t len) static bool App_SendTcpServerPayload(uint8_t instance, const uint8_t *data, uint16_t len)
{
return tcp_server_send(instance, data, len) == (int)len;
}
static bool App_SendTcpClientPayload(uint8_t instance, const uint8_t *data, uint16_t len)
{
return tcp_client_send(instance, data, len) == (int)len;
}
static bool App_SendToUart(uint8_t uart_index, uint8_t src_id, uint8_t dst_mask, const uint8_t *data, uint16_t len)
{ {
const device_config_t *cfg = config_get(); const device_config_t *cfg = config_get();
uart_channel_t channel = (uart_index == LINK_UART_U1) ? UART_CHANNEL_U1 : UART_CHANNEL_U0; uart_channel_t channel = (uart_index == LINK_UART_U1) ? UART_CHANNEL_U1 : UART_CHANNEL_U0;
uint16_t written;
if (cfg->mux_mode == MUX_MODE_FRAME) { if (cfg->mux_mode == MUX_MODE_FRAME) {
uint8_t frame[APP_ROUTE_BUFFER_SIZE + 6u]; uint8_t frame[APP_ROUTE_BUFFER_SIZE + 6u];
uint16_t frame_len = 0u; uint16_t frame_len = 0u;
if (uart_mux_encode_frame(src_id, dst_mask, data, len, frame, &frame_len, sizeof(frame))) { if (uart_mux_encode_frame(src_id, dst_mask, data, len, frame, &frame_len, sizeof(frame))) {
(void)uart_trans_write(channel, frame, frame_len); written = uart_trans_write(channel, frame, frame_len);
return written == frame_len;
} }
return false;
} else { } else {
(void)uart_trans_write(channel, data, len); written = uart_trans_write(channel, data, len);
return written == len;
} }
} }
@@ -286,11 +302,13 @@ static void App_RouteTcpTraffic(void)
int rc = tcp_server_recv(i, buffer, sizeof(buffer)); int rc = tcp_server_recv(i, buffer, sizeof(buffer));
if (rc > 0) { if (rc > 0) {
uint8_t link_index = (i == 0u) ? CONFIG_LINK_S1 : CONFIG_LINK_S2; uint8_t link_index = (i == 0u) ? CONFIG_LINK_S1 : CONFIG_LINK_S2;
App_SendToUart(cfg->links[link_index].uart, if (!App_SendToUart(cfg->links[link_index].uart,
config_link_index_to_endpoint(link_index), config_link_index_to_endpoint(link_index),
config_uart_index_to_endpoint(cfg->links[link_index].uart), config_uart_index_to_endpoint(cfg->links[link_index].uart),
buffer, buffer,
(uint16_t)rc); (uint16_t)rc)) {
return;
}
} }
} }
@@ -298,11 +316,13 @@ static void App_RouteTcpTraffic(void)
int rc = tcp_client_recv(i, buffer, sizeof(buffer)); int rc = tcp_client_recv(i, buffer, sizeof(buffer));
if (rc > 0) { if (rc > 0) {
uint8_t link_index = (i == 0u) ? CONFIG_LINK_C1 : CONFIG_LINK_C2; uint8_t link_index = (i == 0u) ? CONFIG_LINK_C1 : CONFIG_LINK_C2;
App_SendToUart(cfg->links[link_index].uart, if (!App_SendToUart(cfg->links[link_index].uart,
config_link_index_to_endpoint(link_index), config_link_index_to_endpoint(link_index),
config_uart_index_to_endpoint(cfg->links[link_index].uart), config_uart_index_to_endpoint(cfg->links[link_index].uart),
buffer, buffer,
(uint16_t)rc); (uint16_t)rc)) {
return;
}
} }
} }
} }
@@ -315,37 +335,57 @@ static void App_RouteRawUartTraffic(void)
len = uart_trans_read(UART_CHANNEL_U0, buffer, sizeof(buffer)); len = uart_trans_read(UART_CHANNEL_U0, buffer, sizeof(buffer));
if (len > 0u) { if (len > 0u) {
bool routed_ok = true;
for (uint8_t i = 0; i < CONFIG_LINK_COUNT; ++i) { for (uint8_t i = 0; i < CONFIG_LINK_COUNT; ++i) {
bool sent = true;
if (cfg->links[i].enabled == 0u || cfg->links[i].uart != LINK_UART_U0) { if (cfg->links[i].enabled == 0u || cfg->links[i].uart != LINK_UART_U0) {
continue; continue;
} }
if (i == CONFIG_LINK_S1) { if (i == CONFIG_LINK_S1) {
(void)tcp_server_send(0u, buffer, len); sent = App_SendTcpServerPayload(0u, buffer, len);
} else if (i == CONFIG_LINK_S2) { } else if (i == CONFIG_LINK_S2) {
(void)tcp_server_send(1u, buffer, len); sent = App_SendTcpServerPayload(1u, buffer, len);
} else if (i == CONFIG_LINK_C1) { } else if (i == CONFIG_LINK_C1) {
(void)tcp_client_send(0u, buffer, len); sent = App_SendTcpClientPayload(0u, buffer, len);
} else if (i == CONFIG_LINK_C2) { } else if (i == CONFIG_LINK_C2) {
(void)tcp_client_send(1u, buffer, len); sent = App_SendTcpClientPayload(1u, buffer, len);
} }
if (!sent) {
routed_ok = false;
}
}
if (!routed_ok) {
return;
} }
} }
len = uart_trans_read(UART_CHANNEL_U1, buffer, sizeof(buffer)); len = uart_trans_read(UART_CHANNEL_U1, buffer, sizeof(buffer));
if (len > 0u) { if (len > 0u) {
bool routed_ok = true;
for (uint8_t i = 0; i < CONFIG_LINK_COUNT; ++i) { for (uint8_t i = 0; i < CONFIG_LINK_COUNT; ++i) {
bool sent = true;
if (cfg->links[i].enabled == 0u || cfg->links[i].uart != LINK_UART_U1) { if (cfg->links[i].enabled == 0u || cfg->links[i].uart != LINK_UART_U1) {
continue; continue;
} }
if (i == CONFIG_LINK_S1) { if (i == CONFIG_LINK_S1) {
(void)tcp_server_send(0u, buffer, len); sent = App_SendTcpServerPayload(0u, buffer, len);
} else if (i == CONFIG_LINK_S2) { } else if (i == CONFIG_LINK_S2) {
(void)tcp_server_send(1u, buffer, len); sent = App_SendTcpServerPayload(1u, buffer, len);
} else if (i == CONFIG_LINK_C1) { } else if (i == CONFIG_LINK_C1) {
(void)tcp_client_send(0u, buffer, len); sent = App_SendTcpClientPayload(0u, buffer, len);
} else if (i == CONFIG_LINK_C2) { } else if (i == CONFIG_LINK_C2) {
(void)tcp_client_send(1u, buffer, len); sent = App_SendTcpClientPayload(1u, buffer, len);
} }
if (!sent) {
routed_ok = false;
}
}
if (!routed_ok) {
return;
} }
} }
} }
@@ -354,6 +394,7 @@ static void App_RouteMuxUartTraffic(void)
{ {
uart_mux_frame_t frame; uart_mux_frame_t frame;
const device_config_t *cfg = config_get(); const device_config_t *cfg = config_get();
bool routed_ok;
while (uart_mux_try_extract_frame(UART_CHANNEL_U0, &frame)) { while (uart_mux_try_extract_frame(UART_CHANNEL_U0, &frame)) {
#if defined(DEBUG) && (DEBUG != 0) #if defined(DEBUG) && (DEBUG != 0)
@@ -366,33 +407,42 @@ static void App_RouteMuxUartTraffic(void)
uint16_t response_len = (uint16_t)strlen(response_text); uint16_t response_len = (uint16_t)strlen(response_text);
uint16_t frame_len = 0u; uint16_t frame_len = 0u;
if (uart_mux_encode_frame(config_uart_index_to_endpoint(LINK_UART_U0), 0u, (const uint8_t *)response_text, response_len, g_mux_response_frame, &frame_len, sizeof(g_mux_response_frame))) { if (uart_mux_encode_frame(config_uart_index_to_endpoint(LINK_UART_U0), 0u, (const uint8_t *)response_text, response_len, g_mux_response_frame, &frame_len, sizeof(g_mux_response_frame))) {
(void)uart_trans_write(UART_CHANNEL_U0, g_mux_response_frame, frame_len); if (uart_trans_write(UART_CHANNEL_U0, g_mux_response_frame, frame_len) != frame_len) {
return;
}
} }
if (result == AT_NEED_REBOOT) { if (result == AT_NEED_REBOOT) {
static const char hint[] = "Note: Use AT+SAVE then AT+RESET to apply changes\r\n"; static const char hint[] = "Note: Use AT+SAVE then AT+RESET to apply changes\r\n";
response_len = (uint16_t)strlen(hint); response_len = (uint16_t)strlen(hint);
if (uart_mux_encode_frame(config_uart_index_to_endpoint(LINK_UART_U0), 0u, (const uint8_t *)hint, response_len, g_mux_response_frame, &frame_len, sizeof(g_mux_response_frame))) { if (uart_mux_encode_frame(config_uart_index_to_endpoint(LINK_UART_U0), 0u, (const uint8_t *)hint, response_len, g_mux_response_frame, &frame_len, sizeof(g_mux_response_frame))) {
(void)uart_trans_write(UART_CHANNEL_U0, g_mux_response_frame, frame_len); if (uart_trans_write(UART_CHANNEL_U0, g_mux_response_frame, frame_len) != frame_len) {
return;
}
} }
} }
} }
continue; continue;
} }
routed_ok = true;
if ((frame.dst_mask & ENDPOINT_S1) != 0u) { if ((frame.dst_mask & ENDPOINT_S1) != 0u) {
(void)tcp_server_send(0u, frame.payload, frame.payload_len); routed_ok = App_SendTcpServerPayload(0u, frame.payload, frame.payload_len) && routed_ok;
} }
if ((frame.dst_mask & ENDPOINT_S2) != 0u) { if ((frame.dst_mask & ENDPOINT_S2) != 0u) {
(void)tcp_server_send(1u, frame.payload, frame.payload_len); routed_ok = App_SendTcpServerPayload(1u, frame.payload, frame.payload_len) && routed_ok;
} }
if ((frame.dst_mask & ENDPOINT_C1) != 0u) { if ((frame.dst_mask & ENDPOINT_C1) != 0u) {
(void)tcp_client_send(0u, frame.payload, frame.payload_len); routed_ok = App_SendTcpClientPayload(0u, frame.payload, frame.payload_len) && routed_ok;
} }
if ((frame.dst_mask & ENDPOINT_C2) != 0u) { if ((frame.dst_mask & ENDPOINT_C2) != 0u) {
(void)tcp_client_send(1u, frame.payload, frame.payload_len); routed_ok = App_SendTcpClientPayload(1u, frame.payload, frame.payload_len) && routed_ok;
} }
if ((frame.dst_mask & ENDPOINT_UART3) != 0u && cfg->links[CONFIG_LINK_S2].uart == LINK_UART_U1) { if ((frame.dst_mask & ENDPOINT_UART3) != 0u && cfg->links[CONFIG_LINK_S2].uart == LINK_UART_U1) {
App_SendToUart(LINK_UART_U1, frame.src_id, ENDPOINT_UART3, frame.payload, frame.payload_len); routed_ok = App_SendToUart(LINK_UART_U1, frame.src_id, ENDPOINT_UART3, frame.payload, frame.payload_len) && routed_ok;
}
if (!routed_ok) {
return;
} }
} }
@@ -407,33 +457,42 @@ static void App_RouteMuxUartTraffic(void)
uint16_t response_len = (uint16_t)strlen(response_text); uint16_t response_len = (uint16_t)strlen(response_text);
uint16_t frame_len = 0u; uint16_t frame_len = 0u;
if (uart_mux_encode_frame(config_uart_index_to_endpoint(LINK_UART_U1), 0u, (const uint8_t *)response_text, response_len, g_mux_response_frame, &frame_len, sizeof(g_mux_response_frame))) { if (uart_mux_encode_frame(config_uart_index_to_endpoint(LINK_UART_U1), 0u, (const uint8_t *)response_text, response_len, g_mux_response_frame, &frame_len, sizeof(g_mux_response_frame))) {
(void)uart_trans_write(UART_CHANNEL_U1, g_mux_response_frame, frame_len); if (uart_trans_write(UART_CHANNEL_U1, g_mux_response_frame, frame_len) != frame_len) {
return;
}
} }
if (result == AT_NEED_REBOOT) { if (result == AT_NEED_REBOOT) {
static const char hint[] = "Note: Use AT+SAVE then AT+RESET to apply changes\r\n"; static const char hint[] = "Note: Use AT+SAVE then AT+RESET to apply changes\r\n";
response_len = (uint16_t)strlen(hint); response_len = (uint16_t)strlen(hint);
if (uart_mux_encode_frame(config_uart_index_to_endpoint(LINK_UART_U1), 0u, (const uint8_t *)hint, response_len, g_mux_response_frame, &frame_len, sizeof(g_mux_response_frame))) { if (uart_mux_encode_frame(config_uart_index_to_endpoint(LINK_UART_U1), 0u, (const uint8_t *)hint, response_len, g_mux_response_frame, &frame_len, sizeof(g_mux_response_frame))) {
(void)uart_trans_write(UART_CHANNEL_U1, g_mux_response_frame, frame_len); if (uart_trans_write(UART_CHANNEL_U1, g_mux_response_frame, frame_len) != frame_len) {
return;
}
} }
} }
} }
continue; continue;
} }
routed_ok = true;
if ((frame.dst_mask & ENDPOINT_S1) != 0u) { if ((frame.dst_mask & ENDPOINT_S1) != 0u) {
(void)tcp_server_send(0u, frame.payload, frame.payload_len); routed_ok = App_SendTcpServerPayload(0u, frame.payload, frame.payload_len) && routed_ok;
} }
if ((frame.dst_mask & ENDPOINT_S2) != 0u) { if ((frame.dst_mask & ENDPOINT_S2) != 0u) {
(void)tcp_server_send(1u, frame.payload, frame.payload_len); routed_ok = App_SendTcpServerPayload(1u, frame.payload, frame.payload_len) && routed_ok;
} }
if ((frame.dst_mask & ENDPOINT_C1) != 0u) { if ((frame.dst_mask & ENDPOINT_C1) != 0u) {
(void)tcp_client_send(0u, frame.payload, frame.payload_len); routed_ok = App_SendTcpClientPayload(0u, frame.payload, frame.payload_len) && routed_ok;
} }
if ((frame.dst_mask & ENDPOINT_C2) != 0u) { if ((frame.dst_mask & ENDPOINT_C2) != 0u) {
(void)tcp_client_send(1u, frame.payload, frame.payload_len); routed_ok = App_SendTcpClientPayload(1u, frame.payload, frame.payload_len) && routed_ok;
} }
if ((frame.dst_mask & ENDPOINT_UART2) != 0u) { if ((frame.dst_mask & ENDPOINT_UART2) != 0u) {
App_SendToUart(LINK_UART_U0, frame.src_id, ENDPOINT_UART2, frame.payload, frame.payload_len); routed_ok = App_SendToUart(LINK_UART_U0, frame.src_id, ENDPOINT_UART2, frame.payload, frame.payload_len) && routed_ok;
}
if (!routed_ok) {
return;
} }
} }
} }