feat: save stable CH390 bridge baseline

This commit is contained in:
2026-04-04 02:48:21 +08:00
parent 6f4ba247a4
commit d5b2506269
18 changed files with 2146 additions and 1621 deletions
+3
View File
@@ -28,6 +28,9 @@ Release/
MDK-ARM/DebugConfig/ MDK-ARM/DebugConfig/
MDK-ARM/TCP2UART/ MDK-ARM/TCP2UART/
# CMake build
build/
# OS # OS
Thumbs.db Thumbs.db
Desktop.ini Desktop.ini
+524 -199
View File
@@ -1,32 +1,61 @@
/** /**
* @file config.c * @file config.c
* @brief Bare-metal AT command configuration module implementation. * @brief Bare-metal final AT configuration module implementation.
*/ */
#include "config.h" #include "config.h"
#include "flash_param.h" #include "flash_param.h"
#include "usart.h" #include "../Core/Inc/usart.h"
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "SEGGER_RTT.h" #define CONFIG_TX_BUFFER_SIZE 512u
#define CONFIG_CMD_MAX_LEN 160u
#define CONFIG_TX_BUFFER_SIZE 256u
#define CONFIG_CMD_MAX_LEN 128u
#define CONFIG_UART_HANDLE huart1 #define CONFIG_UART_HANDLE huart1
typedef struct {
uint32_t magic;
uint16_t version;
uint16_t reserved;
uint8_t mac[6];
uint8_t dhcp_enable;
uint8_t reserved2;
uint8_t ip[4];
uint8_t mask[4];
uint8_t gw[4];
uint16_t server_port;
uint16_t reserved3;
uint8_t remote_ip[4];
uint16_t remote_port;
uint16_t reconnect_interval;
uint32_t uart2_baudrate;
uint32_t uart3_baudrate;
uint8_t uart2_databits;
uint8_t uart2_stopbits;
uint8_t uart2_parity;
uint8_t uart3_databits;
uint8_t uart3_stopbits;
uint8_t uart3_parity;
uint16_t reserved4;
uint32_t crc;
} legacy_device_config_v2_t;
static device_config_t g_config; static device_config_t g_config;
static volatile bool g_reset_requested; static volatile bool g_reset_requested;
static char g_uart_cmd_buffer[CONFIG_CMD_MAX_LEN]; static uint8_t g_uart_cmd_buffer[CONFIG_CMD_MAX_LEN];
static uint16_t g_uart_cmd_len; static uint16_t g_uart_cmd_len;
static bool g_uart_rx_seen_cr;
static char g_pending_cmd_buffer[CONFIG_CMD_MAX_LEN]; static char g_pending_cmd_buffer[CONFIG_CMD_MAX_LEN];
static volatile uint16_t g_pending_cmd_len; static volatile uint16_t g_pending_cmd_len;
static volatile bool g_pending_cmd_ready; static volatile bool g_pending_cmd_ready;
static char g_at_response_buffer[CONFIG_TX_BUFFER_SIZE];
static char g_cmd_parse_buffer[CONFIG_CMD_MAX_LEN];
static char g_cmd_work_buffer[CONFIG_CMD_MAX_LEN];
static uint32_t config_calc_crc(const device_config_t *cfg) static uint32_t config_calc_crc(const device_config_t *cfg)
{ {
@@ -56,8 +85,12 @@ static bool equals_ignore_case(const char *a, const char *b)
char c1 = *a++; char c1 = *a++;
char c2 = *b++; char c2 = *b++;
if (c1 >= 'a' && c1 <= 'z') c1 -= 32; if (c1 >= 'a' && c1 <= 'z') {
if (c2 >= 'a' && c2 <= 'z') c2 -= 32; c1 -= 32;
}
if (c2 >= 'a' && c2 <= 'z') {
c2 -= 32;
}
if (c1 != c2) { if (c1 != c2) {
return false; return false;
@@ -67,12 +100,31 @@ static bool equals_ignore_case(const char *a, const char *b)
return (*a == '\0' && *b == '\0'); return (*a == '\0' && *b == '\0');
} }
static int parse_baudrate_value(const char *value, uint32_t *baudrate) static int prefix_equals_ignore_case(const char *str, const char *prefix)
{
while (*prefix != '\0') {
char c1 = *str++;
char c2 = *prefix++;
if (c1 >= 'a' && c1 <= 'z') {
c1 -= 32;
}
if (c2 >= 'a' && c2 <= 'z') {
c2 -= 32;
}
if (c1 != c2) {
return 0;
}
}
return 1;
}
static int parse_u32_value(const char *value, uint32_t min_value, uint32_t max_value, uint32_t *parsed_value)
{ {
char *endptr; char *endptr;
unsigned long parsed; unsigned long parsed;
if (value == NULL || baudrate == NULL) { if (value == NULL || parsed_value == NULL) {
return -1; return -1;
} }
@@ -80,54 +132,262 @@ static int parse_baudrate_value(const char *value, uint32_t *baudrate)
if (endptr == value || *skip_whitespace(endptr) != '\0') { if (endptr == value || *skip_whitespace(endptr) != '\0') {
return -1; return -1;
} }
if (parsed < min_value || parsed > max_value) {
if (parsed < 1200ul || parsed > 921600ul) {
return -1; return -1;
} }
*baudrate = (uint32_t)parsed; *parsed_value = (uint32_t)parsed;
return 0; return 0;
} }
static at_result_t handle_query(char *response, uint16_t max_len) static int parse_link_uart(const char *value, uint8_t *uart)
{
if (equals_ignore_case(value, "U0")) {
*uart = LINK_UART_U0;
return 0;
}
if (equals_ignore_case(value, "U1")) {
*uart = LINK_UART_U1;
return 0;
}
return -1;
}
static const char *link_uart_to_str(uint8_t uart)
{
return (uart == LINK_UART_U1) ? "U1" : "U0";
}
static bool parse_command_with_value(const char *cmd, const char *name, const char **value)
{
size_t name_len;
if (cmd == NULL || name == NULL || value == NULL) {
return false;
}
name_len = strlen(name);
if (!prefix_equals_ignore_case(cmd, name)) {
return false;
}
if (cmd[name_len] != '=') {
return false;
}
*value = skip_whitespace(cmd + name_len + 1u);
return true;
}
static char *config_next_token(char **cursor)
{
char *start;
char *end;
if (cursor == NULL || *cursor == NULL) {
return NULL;
}
start = *cursor;
while (*start == ' ' || *start == '\t') {
++start;
}
if (*start == '\0') {
*cursor = NULL;
return NULL;
}
end = start;
while (*end != '\0' && *end != ',') {
++end;
}
if (*end == ',') {
*end = '\0';
*cursor = end + 1;
} else {
*cursor = NULL;
}
trim_trailing(start);
return start;
}
static void set_link_defaults(void)
{
static const uint8_t zero_ip[4] = {0u, 0u, 0u, 0u};
static const uint8_t c1_ip[4] = {192u, 168u, 1u, 200u};
static const uint8_t c2_ip[4] = {192u, 168u, 1u, 201u};
memset(g_config.links, 0, sizeof(g_config.links));
g_config.links[CONFIG_LINK_S1].enabled = 1u;
g_config.links[CONFIG_LINK_S1].uart = LINK_UART_U0;
g_config.links[CONFIG_LINK_S1].local_port = 8080u;
memcpy(g_config.links[CONFIG_LINK_S1].remote_ip, zero_ip, sizeof(zero_ip));
g_config.links[CONFIG_LINK_S2].enabled = 0u;
g_config.links[CONFIG_LINK_S2].uart = LINK_UART_U1;
g_config.links[CONFIG_LINK_S2].local_port = 8081u;
memcpy(g_config.links[CONFIG_LINK_S2].remote_ip, zero_ip, sizeof(zero_ip));
g_config.links[CONFIG_LINK_C1].enabled = 1u;
g_config.links[CONFIG_LINK_C1].uart = LINK_UART_U1;
g_config.links[CONFIG_LINK_C1].local_port = 9001u;
memcpy(g_config.links[CONFIG_LINK_C1].remote_ip, c1_ip, sizeof(c1_ip));
g_config.links[CONFIG_LINK_C1].remote_port = 9000u;
g_config.links[CONFIG_LINK_C2].enabled = 0u;
g_config.links[CONFIG_LINK_C2].uart = LINK_UART_U0;
g_config.links[CONFIG_LINK_C2].local_port = 9002u;
memcpy(g_config.links[CONFIG_LINK_C2].remote_ip, c2_ip, sizeof(c2_ip));
g_config.links[CONFIG_LINK_C2].remote_port = 9001u;
}
static void migrate_legacy_config(const legacy_device_config_v2_t *legacy)
{
config_set_defaults();
memcpy(g_config.net.mac, legacy->mac, sizeof(g_config.net.mac));
memcpy(g_config.net.ip, legacy->ip, sizeof(g_config.net.ip));
memcpy(g_config.net.mask, legacy->mask, sizeof(g_config.net.mask));
memcpy(g_config.net.gw, legacy->gw, sizeof(g_config.net.gw));
g_config.uart_baudrate[0] = legacy->uart2_baudrate;
g_config.uart_baudrate[1] = legacy->uart3_baudrate;
g_config.mux_mode = MUX_MODE_RAW;
g_config.links[CONFIG_LINK_S1].enabled = (legacy->server_port != 0u) ? 1u : 0u;
g_config.links[CONFIG_LINK_S1].uart = LINK_UART_U0;
g_config.links[CONFIG_LINK_S1].local_port = legacy->server_port;
memset(g_config.links[CONFIG_LINK_S1].remote_ip, 0, sizeof(g_config.links[CONFIG_LINK_S1].remote_ip));
g_config.links[CONFIG_LINK_S1].remote_port = 0u;
g_config.links[CONFIG_LINK_S2].enabled = 0u;
g_config.links[CONFIG_LINK_C1].enabled = (legacy->remote_port != 0u) ? 1u : 0u;
g_config.links[CONFIG_LINK_C1].uart = LINK_UART_U1;
g_config.links[CONFIG_LINK_C1].local_port = 8081u;
memcpy(g_config.links[CONFIG_LINK_C1].remote_ip, legacy->remote_ip, sizeof(g_config.links[CONFIG_LINK_C1].remote_ip));
g_config.links[CONFIG_LINK_C1].remote_port = legacy->remote_port;
g_config.links[CONFIG_LINK_C2].enabled = 0u;
g_config.crc = config_calc_crc(&g_config);
}
static bool try_load_legacy_config(void)
{
legacy_device_config_v2_t legacy;
uint32_t expected_crc;
if (flash_param_read(&legacy, sizeof(legacy)) != 0) {
return false;
}
expected_crc = flash_param_crc32(&legacy, offsetof(legacy_device_config_v2_t, crc));
if (legacy.magic != CONFIG_MAGIC || legacy.version != 0x0002u || legacy.crc != expected_crc) {
return false;
}
migrate_legacy_config(&legacy);
return true;
}
static at_result_t handle_summary_query(char *response, uint16_t max_len)
{ {
char ip_str[16]; char ip_str[16];
char mask_str[16]; char mask_str[16];
char gw_str[16]; char gw_str[16];
char rip_str[16];
char mac_str[18]; char mac_str[18];
char rip_str[CONFIG_LINK_COUNT][16];
config_ip_to_str(g_config.ip, ip_str); config_ip_to_str(g_config.net.ip, ip_str);
config_ip_to_str(g_config.mask, mask_str); config_ip_to_str(g_config.net.mask, mask_str);
config_ip_to_str(g_config.gw, gw_str); config_ip_to_str(g_config.net.gw, gw_str);
config_ip_to_str(g_config.remote_ip, rip_str); config_mac_to_str(g_config.net.mac, mac_str);
config_mac_to_str(g_config.mac, mac_str); for (uint32_t i = 0; i < CONFIG_LINK_COUNT; ++i) {
config_ip_to_str(g_config.links[i].remote_ip, rip_str[i]);
}
snprintf(response, max_len, snprintf(response, max_len,
"MAC: %s\r\n" "+NET:IP=%s,MASK=%s,GW=%s,MAC=%s\r\n"
"DHCP: %u\r\n" "+LINK:0,EN=%u,LPORT=%u,RIP=%s,RPORT=%u,UART=%s\r\n"
"IP: %s\r\n" "+LINK:1,EN=%u,LPORT=%u,RIP=%s,RPORT=%u,UART=%s\r\n"
"MASK: %s\r\n" "+LINK:2,EN=%u,LPORT=%u,RIP=%s,RPORT=%u,UART=%s\r\n"
"GW: %s\r\n" "+LINK:3,EN=%u,LPORT=%u,RIP=%s,RPORT=%u,UART=%s\r\n"
"PORT: %u\r\n" "+MUX:%u\r\n"
"RIP: %s\r\n" "+MAP:UART2=0x04,UART3=0x08,C1=0x01,C2=0x02,S1=0x10,S2=0x20\r\n"
"RPORT: %u\r\n" "+BAUD:U0=%lu,U1=%lu\r\n"
"BAUD1: %lu\r\n" "OK\r\n",
"BAUD2: %lu\r\n", ip_str, mask_str, gw_str, mac_str,
mac_str, g_config.links[0].enabled, g_config.links[0].local_port, rip_str[0], g_config.links[0].remote_port, link_uart_to_str(g_config.links[0].uart),
g_config.dhcp_enable, g_config.links[1].enabled, g_config.links[1].local_port, rip_str[1], g_config.links[1].remote_port, link_uart_to_str(g_config.links[1].uart),
ip_str, g_config.links[2].enabled, g_config.links[2].local_port, rip_str[2], g_config.links[2].remote_port, link_uart_to_str(g_config.links[2].uart),
mask_str, g_config.links[3].enabled, g_config.links[3].local_port, rip_str[3], g_config.links[3].remote_port, link_uart_to_str(g_config.links[3].uart),
gw_str, g_config.mux_mode,
g_config.server_port, g_config.uart_baudrate[0],
rip_str, g_config.uart_baudrate[1]);
g_config.remote_port,
g_config.uart2_baudrate,
g_config.uart3_baudrate);
return AT_OK; return AT_OK;
} }
static at_result_t handle_net_query(char *response, uint16_t max_len)
{
char ip_str[16];
char mask_str[16];
char gw_str[16];
char mac_str[18];
config_ip_to_str(g_config.net.ip, ip_str);
config_ip_to_str(g_config.net.mask, mask_str);
config_ip_to_str(g_config.net.gw, gw_str);
config_mac_to_str(g_config.net.mac, mac_str);
snprintf(response, max_len, "+NET:IP=%s,MASK=%s,GW=%s,MAC=%s\r\nOK\r\n", ip_str, mask_str, gw_str, mac_str);
return AT_OK;
}
static at_result_t handle_link_query(uint32_t index, char *response, uint16_t max_len)
{
char rip_str[16];
if (index >= CONFIG_LINK_COUNT) {
snprintf(response, max_len, "ERROR: Invalid route field\r\n");
return AT_INVALID_PARAM;
}
config_ip_to_str(g_config.links[index].remote_ip, rip_str);
snprintf(response,
max_len,
"+LINK:%lu,EN=%u,LPORT=%u,RIP=%s,RPORT=%u,UART=%s\r\nOK\r\n",
index,
g_config.links[index].enabled,
g_config.links[index].local_port,
rip_str,
g_config.links[index].remote_port,
link_uart_to_str(g_config.links[index].uart));
return AT_OK;
}
static at_result_t handle_all_link_query(char *response, uint16_t max_len)
{
char rip_str[CONFIG_LINK_COUNT][16];
for (uint32_t i = 0; i < CONFIG_LINK_COUNT; ++i) {
config_ip_to_str(g_config.links[i].remote_ip, rip_str[i]);
}
snprintf(response,
max_len,
"+LINK:0,EN=%u,LPORT=%u,RIP=%s,RPORT=%u,UART=%s\r\n"
"+LINK:1,EN=%u,LPORT=%u,RIP=%s,RPORT=%u,UART=%s\r\n"
"+LINK:2,EN=%u,LPORT=%u,RIP=%s,RPORT=%u,UART=%s\r\n"
"+LINK:3,EN=%u,LPORT=%u,RIP=%s,RPORT=%u,UART=%s\r\n"
"OK\r\n",
g_config.links[0].enabled, g_config.links[0].local_port, rip_str[0], g_config.links[0].remote_port, link_uart_to_str(g_config.links[0].uart),
g_config.links[1].enabled, g_config.links[1].local_port, rip_str[1], g_config.links[1].remote_port, link_uart_to_str(g_config.links[1].uart),
g_config.links[2].enabled, g_config.links[2].local_port, rip_str[2], g_config.links[2].remote_port, link_uart_to_str(g_config.links[2].uart),
g_config.links[3].enabled, g_config.links[3].local_port, rip_str[3], g_config.links[3].remote_port, link_uart_to_str(g_config.links[3].uart));
return AT_OK;
}
int config_init(void) int config_init(void)
{ {
flash_param_init(); flash_param_init();
@@ -136,17 +396,21 @@ int config_init(void)
int config_load(void) int config_load(void)
{ {
if (flash_param_read(&g_config, sizeof(g_config)) != 0 || if (flash_param_read(&g_config, sizeof(g_config)) == 0 &&
g_config.magic != CONFIG_MAGIC || g_config.magic == CONFIG_MAGIC &&
g_config.version != CONFIG_VERSION || g_config.version == CONFIG_VERSION &&
g_config.crc != config_calc_crc(&g_config)) { g_config.crc == config_calc_crc(&g_config)) {
config_set_defaults(); return 0;
return -1;
} }
if (try_load_legacy_config()) {
return 0; return 0;
} }
config_set_defaults();
return -1;
}
int config_save(void) int config_save(void)
{ {
g_config.magic = CONFIG_MAGIC; g_config.magic = CONFIG_MAGIC;
@@ -157,33 +421,22 @@ int config_save(void)
void config_set_defaults(void) void config_set_defaults(void)
{ {
const uint8_t default_ip[] = DEFAULT_IP; const uint8_t default_ip[] = DEFAULT_NET_IP;
const uint8_t default_mask[] = DEFAULT_MASK; const uint8_t default_mask[] = DEFAULT_NET_MASK;
const uint8_t default_gw[] = DEFAULT_GW; const uint8_t default_gw[] = DEFAULT_NET_GW;
const uint8_t default_mac[] = DEFAULT_MAC; const uint8_t default_mac[] = DEFAULT_NET_MAC;
const uint8_t default_rip[] = DEFAULT_REMOTE_IP;
memset(&g_config, 0, sizeof(g_config)); memset(&g_config, 0, sizeof(g_config));
g_config.magic = CONFIG_MAGIC; g_config.magic = CONFIG_MAGIC;
g_config.version = CONFIG_VERSION; g_config.version = CONFIG_VERSION;
memcpy(g_config.mac, default_mac, sizeof(g_config.mac)); g_config.mux_mode = MUX_MODE_RAW;
memcpy(g_config.ip, default_ip, sizeof(g_config.ip)); memcpy(g_config.net.ip, default_ip, sizeof(g_config.net.ip));
memcpy(g_config.mask, default_mask, sizeof(g_config.mask)); memcpy(g_config.net.mask, default_mask, sizeof(g_config.net.mask));
memcpy(g_config.gw, default_gw, sizeof(g_config.gw)); memcpy(g_config.net.gw, default_gw, sizeof(g_config.net.gw));
memcpy(g_config.remote_ip, default_rip, sizeof(g_config.remote_ip)); memcpy(g_config.net.mac, default_mac, sizeof(g_config.net.mac));
set_link_defaults();
g_config.dhcp_enable = DEFAULT_DHCP_ENABLE; g_config.uart_baudrate[0] = DEFAULT_UART_BAUDRATE;
g_config.server_port = DEFAULT_SERVER_PORT; g_config.uart_baudrate[1] = DEFAULT_UART_BAUDRATE;
g_config.remote_port = DEFAULT_REMOTE_PORT;
g_config.reconnect_interval = DEFAULT_RECONNECT_MS;
g_config.uart2_baudrate = DEFAULT_UART_BAUDRATE;
g_config.uart3_baudrate = DEFAULT_UART_BAUDRATE;
g_config.uart2_databits = DEFAULT_UART_DATABITS;
g_config.uart2_stopbits = DEFAULT_UART_STOPBITS;
g_config.uart2_parity = DEFAULT_UART_PARITY;
g_config.uart3_databits = DEFAULT_UART_DATABITS;
g_config.uart3_stopbits = DEFAULT_UART_STOPBITS;
g_config.uart3_parity = DEFAULT_UART_PARITY;
g_config.crc = config_calc_crc(&g_config); g_config.crc = config_calc_crc(&g_config);
} }
@@ -199,50 +452,37 @@ device_config_t *config_get_mutable(void)
at_result_t config_process_at_cmd(const char *cmd, char *response, uint16_t max_len) at_result_t config_process_at_cmd(const char *cmd, char *response, uint16_t max_len)
{ {
char cmd_copy[CONFIG_CMD_MAX_LEN]; const char *value;
char *cmd_name;
char *value;
const char *p; const char *p;
if (cmd == NULL || response == NULL || max_len == 0u) { if (cmd == NULL || response == NULL || max_len == 0u) {
return AT_ERROR; return AT_ERROR;
} }
strncpy(cmd_copy, cmd, CONFIG_CMD_MAX_LEN - 1u); strncpy(g_cmd_work_buffer, cmd, sizeof(g_cmd_work_buffer) - 1u);
cmd_copy[CONFIG_CMD_MAX_LEN - 1u] = '\0'; g_cmd_work_buffer[sizeof(g_cmd_work_buffer) - 1u] = '\0';
trim_trailing(cmd_copy); trim_trailing(g_cmd_work_buffer);
p = skip_whitespace(cmd_copy); p = skip_whitespace(g_cmd_work_buffer);
if ((p[0] != 'A' && p[0] != 'a') || (p[1] != 'T' && p[1] != 't')) { if ((p[0] != 'A' && p[0] != 'a') || (p[1] != 'T' && p[1] != 't')) {
snprintf(response, max_len, "ERROR: Unknown command\r\n"); snprintf(response, max_len, "ERROR: Unknown command\r\n");
return AT_UNKNOWN_CMD; return AT_UNKNOWN_CMD;
} }
if (p[2] == '\0') { if (p[2] == '\0') {
snprintf(response, max_len, "OK\r\n"); snprintf(response, max_len, "OK\r\n");
return AT_OK; return AT_OK;
} }
if (p[2] != '+') { if (p[2] != '+') {
snprintf(response, max_len, "ERROR: Unknown command\r\n"); snprintf(response, max_len, "ERROR: Unknown command\r\n");
return AT_UNKNOWN_CMD; return AT_UNKNOWN_CMD;
} }
p += 3; p += 3;
value = strchr((char *)p, '=');
if (value != NULL) {
*value = '\0';
++value;
value = (char *)skip_whitespace(value);
}
cmd_name = (char *)p; if ((equals_ignore_case(p, "?") || equals_ignore_case(p, "QUERY"))) {
trim_trailing(cmd_name); return handle_summary_query(response, max_len);
if ((equals_ignore_case(cmd_name, "?") || equals_ignore_case(cmd_name, "QUERY")) && value == NULL) {
return handle_query(response, max_len);
} }
if (equals_ignore_case(cmd_name, "SAVE") && value == NULL) { if (equals_ignore_case(p, "SAVE")) {
if (config_save() != 0) { if (config_save() != 0) {
snprintf(response, max_len, "ERROR: Save failed\r\n"); snprintf(response, max_len, "ERROR: Save failed\r\n");
return AT_SAVE_FAILED; return AT_SAVE_FAILED;
@@ -250,103 +490,139 @@ at_result_t config_process_at_cmd(const char *cmd, char *response, uint16_t max_
snprintf(response, max_len, "OK: Configuration saved\r\n"); snprintf(response, max_len, "OK: Configuration saved\r\n");
return AT_OK; return AT_OK;
} }
if (equals_ignore_case(cmd_name, "RESET") && value == NULL) { if (equals_ignore_case(p, "RESET")) {
g_reset_requested = true; g_reset_requested = true;
snprintf(response, max_len, "OK: Resetting...\r\n"); snprintf(response, max_len, "OK: Resetting...\r\n");
return AT_OK; return AT_OK;
} }
if (equals_ignore_case(cmd_name, "DEFAULT") && value == NULL) { if (equals_ignore_case(p, "DEFAULT")) {
config_set_defaults(); config_set_defaults();
snprintf(response, max_len, "OK: Defaults restored\r\n"); snprintf(response, max_len, "OK: Defaults restored\r\n");
return AT_OK; return AT_OK;
} }
if (equals_ignore_case(cmd_name, "IP") && value != NULL) { if (equals_ignore_case(p, "MUX?")) {
if (config_str_to_ip(value, g_config.ip) != 0) { snprintf(response, max_len, "+MUX:%u\r\nOK\r\n", g_config.mux_mode);
snprintf(response, max_len, "ERROR: Invalid IP format\r\n"); return AT_OK;
return AT_INVALID_PARAM;
} }
snprintf(response, max_len, "OK\r\n"); if (parse_command_with_value(p, "MUX", &value)) {
return AT_NEED_REBOOT; uint32_t mux_value;
} if (parse_u32_value(value, 0u, 1u, &mux_value) != 0) {
if (equals_ignore_case(cmd_name, "MASK") && value != NULL) {
if (config_str_to_ip(value, g_config.mask) != 0) {
snprintf(response, max_len, "ERROR: Invalid mask format\r\n");
return AT_INVALID_PARAM;
}
snprintf(response, max_len, "OK\r\n");
return AT_NEED_REBOOT;
}
if (equals_ignore_case(cmd_name, "GW") && value != NULL) {
if (config_str_to_ip(value, g_config.gw) != 0) {
snprintf(response, max_len, "ERROR: Invalid gateway format\r\n");
return AT_INVALID_PARAM;
}
snprintf(response, max_len, "OK\r\n");
return AT_NEED_REBOOT;
}
if (equals_ignore_case(cmd_name, "RIP") && value != NULL) {
if (config_str_to_ip(value, g_config.remote_ip) != 0) {
snprintf(response, max_len, "ERROR: Invalid remote IP format\r\n");
return AT_INVALID_PARAM;
}
snprintf(response, max_len, "OK\r\n");
return AT_NEED_REBOOT;
}
if (equals_ignore_case(cmd_name, "MAC") && value != NULL) {
if (config_str_to_mac(value, g_config.mac) != 0) {
snprintf(response, max_len, "ERROR: Invalid MAC format\r\n");
return AT_INVALID_PARAM;
}
snprintf(response, max_len, "OK\r\n");
return AT_NEED_REBOOT;
}
if (equals_ignore_case(cmd_name, "PORT") && value != NULL) {
int port = atoi(value);
if (port < 1 || port > 65535) {
snprintf(response, max_len, "ERROR: Invalid port\r\n");
return AT_INVALID_PARAM;
}
g_config.server_port = (uint16_t)port;
snprintf(response, max_len, "OK\r\n");
return AT_NEED_REBOOT;
}
if (equals_ignore_case(cmd_name, "RPORT") && value != NULL) {
int port = atoi(value);
if (port < 1 || port > 65535) {
snprintf(response, max_len, "ERROR: Invalid port\r\n");
return AT_INVALID_PARAM;
}
g_config.remote_port = (uint16_t)port;
snprintf(response, max_len, "OK\r\n");
return AT_NEED_REBOOT;
}
if (equals_ignore_case(cmd_name, "BAUD1") && value != NULL) {
if (parse_baudrate_value(value, &g_config.uart2_baudrate) != 0) {
snprintf(response, max_len, "ERROR: Invalid baudrate\r\n");
return AT_INVALID_PARAM;
}
snprintf(response, max_len, "OK\r\n");
return AT_NEED_REBOOT;
}
if (equals_ignore_case(cmd_name, "BAUD2") && value != NULL) {
if (parse_baudrate_value(value, &g_config.uart3_baudrate) != 0) {
snprintf(response, max_len, "ERROR: Invalid baudrate\r\n");
return AT_INVALID_PARAM;
}
snprintf(response, max_len, "OK\r\n");
return AT_NEED_REBOOT;
}
if (equals_ignore_case(cmd_name, "DHCP") && value != NULL) {
int dhcp = atoi(value);
if (dhcp != 0 && dhcp != 1) {
snprintf(response, max_len, "ERROR: Invalid value\r\n"); snprintf(response, max_len, "ERROR: Invalid value\r\n");
return AT_INVALID_PARAM; return AT_INVALID_PARAM;
} }
if (dhcp != 0) { g_config.mux_mode = (uint8_t)mux_value;
snprintf(response, max_len, "ERROR: DHCP disabled in this build\r\n"); snprintf(response, max_len, "OK\r\n");
return AT_NEED_REBOOT;
}
if (equals_ignore_case(p, "NET?")) {
return handle_net_query(response, max_len);
}
if (parse_command_with_value(p, "NET", &value)) {
char value_copy[96];
char *token;
char *cursor;
uint8_t ip[4];
uint8_t mask[4];
uint8_t gw[4];
uint8_t mac[6];
strncpy(value_copy, value, sizeof(value_copy) - 1u);
value_copy[sizeof(value_copy) - 1u] = '\0';
cursor = value_copy;
token = config_next_token(&cursor);
if (token == NULL || config_str_to_ip(token, ip) != 0) {
snprintf(response, max_len, "ERROR: Invalid IP format\r\n");
return AT_INVALID_PARAM; return AT_INVALID_PARAM;
} }
g_config.dhcp_enable = (uint8_t)dhcp; token = config_next_token(&cursor);
if (token == NULL || config_str_to_ip(token, mask) != 0) {
snprintf(response, max_len, "ERROR: Invalid mask format\r\n");
return AT_INVALID_PARAM;
}
token = config_next_token(&cursor);
if (token == NULL || config_str_to_ip(token, gw) != 0) {
snprintf(response, max_len, "ERROR: Invalid gateway format\r\n");
return AT_INVALID_PARAM;
}
token = config_next_token(&cursor);
if (token == NULL || config_str_to_mac(token, mac) != 0) {
snprintf(response, max_len, "ERROR: Invalid MAC format\r\n");
return AT_INVALID_PARAM;
}
if (config_next_token(&cursor) != NULL) {
snprintf(response, max_len, "ERROR: Invalid value\r\n");
return AT_INVALID_PARAM;
}
memcpy(g_config.net.ip, ip, sizeof(ip));
memcpy(g_config.net.mask, mask, sizeof(mask));
memcpy(g_config.net.gw, gw, sizeof(gw));
memcpy(g_config.net.mac, mac, sizeof(mac));
snprintf(response, max_len, "OK\r\n");
return AT_NEED_REBOOT;
}
if (equals_ignore_case(p, "LINK?")) {
return handle_all_link_query(response, max_len);
}
if (parse_command_with_value(p, "LINK", &value)) {
char value_copy[96];
char *cursor;
char *token;
uint32_t index;
uint32_t enabled;
uint32_t local_port;
uint32_t remote_port;
uint8_t rip[4];
uint8_t uart;
strncpy(value_copy, value, sizeof(value_copy) - 1u);
value_copy[sizeof(value_copy) - 1u] = '\0';
cursor = value_copy;
token = config_next_token(&cursor);
if (token == NULL || parse_u32_value(token, 0u, CONFIG_LINK_COUNT - 1u, &index) != 0) {
snprintf(response, max_len, "ERROR: Invalid route field\r\n");
return AT_INVALID_PARAM;
}
token = config_next_token(&cursor);
if (token == NULL) {
return handle_link_query(index, response, max_len);
}
if (parse_u32_value(token, 0u, 1u, &enabled) != 0) {
snprintf(response, max_len, "ERROR: Invalid value\r\n");
return AT_INVALID_PARAM;
}
token = config_next_token(&cursor);
if (token == NULL || parse_u32_value(token, 1u, 65535u, &local_port) != 0) {
snprintf(response, max_len, "ERROR: Invalid port\r\n");
return AT_INVALID_PARAM;
}
token = config_next_token(&cursor);
if (token == NULL || config_str_to_ip(token, rip) != 0) {
snprintf(response, max_len, "ERROR: Invalid remote IP format\r\n");
return AT_INVALID_PARAM;
}
token = config_next_token(&cursor);
if (token == NULL || parse_u32_value(token, 0u, 65535u, &remote_port) != 0) {
snprintf(response, max_len, "ERROR: Invalid port\r\n");
return AT_INVALID_PARAM;
}
token = config_next_token(&cursor);
if (token == NULL || parse_link_uart(token, &uart) != 0) {
snprintf(response, max_len, "ERROR: Invalid route field\r\n");
return AT_INVALID_PARAM;
}
if (config_next_token(&cursor) != NULL) {
snprintf(response, max_len, "ERROR: Invalid value\r\n");
return AT_INVALID_PARAM;
}
g_config.links[index].enabled = (uint8_t)enabled;
g_config.links[index].local_port = (uint16_t)local_port;
memcpy(g_config.links[index].remote_ip, rip, sizeof(rip));
g_config.links[index].remote_port = (uint16_t)remote_port;
g_config.links[index].uart = uart;
snprintf(response, max_len, "OK\r\n"); snprintf(response, max_len, "OK\r\n");
return AT_NEED_REBOOT; return AT_NEED_REBOOT;
} }
@@ -362,7 +638,10 @@ void config_ip_to_str(const uint8_t *ip, char *str)
int config_str_to_ip(const char *str, uint8_t *ip) int config_str_to_ip(const char *str, uint8_t *ip)
{ {
int a, b, c, d; int a;
int b;
int c;
int d;
if (sscanf(str, "%d.%d.%d.%d", &a, &b, &c, &d) != 4) { if (sscanf(str, "%d.%d.%d.%d", &a, &b, &c, &d) != 4) {
return -1; return -1;
@@ -398,7 +677,6 @@ int config_str_to_mac(const char *str, uint8_t *mac)
} }
mac[i] = (uint8_t)a[i]; mac[i] = (uint8_t)a[i];
} }
return 0; return 0;
} }
@@ -406,7 +684,6 @@ void config_poll(void)
{ {
if (g_pending_cmd_ready) { if (g_pending_cmd_ready) {
uint16_t len = g_pending_cmd_len; uint16_t len = g_pending_cmd_len;
g_pending_cmd_ready = false; g_pending_cmd_ready = false;
g_pending_cmd_len = 0u; g_pending_cmd_len = 0u;
(void)config_try_process_frame((const uint8_t *)g_pending_cmd_buffer, len); (void)config_try_process_frame((const uint8_t *)g_pending_cmd_buffer, len);
@@ -415,8 +692,13 @@ void config_poll(void)
void config_uart_rx_byte(uint8_t byte) void config_uart_rx_byte(uint8_t byte)
{ {
if (byte == '\r' || byte == '\n') { if (byte == '\r') {
if (g_uart_cmd_len > 0u) { g_uart_rx_seen_cr = true;
return;
}
if (byte == '\n') {
if (g_uart_rx_seen_cr && g_uart_cmd_len > 0u) {
if (!g_pending_cmd_ready) { if (!g_pending_cmd_ready) {
memcpy(g_pending_cmd_buffer, g_uart_cmd_buffer, g_uart_cmd_len); memcpy(g_pending_cmd_buffer, g_uart_cmd_buffer, g_uart_cmd_len);
g_pending_cmd_buffer[g_uart_cmd_len] = '\0'; g_pending_cmd_buffer[g_uart_cmd_len] = '\0';
@@ -425,43 +707,58 @@ void config_uart_rx_byte(uint8_t byte)
} }
g_uart_cmd_len = 0u; g_uart_cmd_len = 0u;
} }
g_uart_rx_seen_cr = false;
return; return;
} }
if (g_uart_rx_seen_cr) {
g_uart_cmd_len = 0u;
g_uart_rx_seen_cr = false;
}
if (g_uart_cmd_len < (CONFIG_CMD_MAX_LEN - 1u)) { if (g_uart_cmd_len < (CONFIG_CMD_MAX_LEN - 1u)) {
g_uart_cmd_buffer[g_uart_cmd_len++] = (char)byte; g_uart_cmd_buffer[g_uart_cmd_len++] = byte;
g_uart_cmd_buffer[g_uart_cmd_len] = '\0'; g_uart_cmd_buffer[g_uart_cmd_len] = '\0';
} else { } else {
g_uart_cmd_len = 0u; g_uart_cmd_len = 0u;
} }
} }
bool config_build_response_frame(const uint8_t *data,
uint16_t len,
char *response,
uint16_t max_len,
at_result_t *result)
{
if (data == NULL || response == NULL || len < 2u || max_len == 0u) {
return false;
}
if (len >= CONFIG_CMD_MAX_LEN) {
return false;
}
memcpy(g_cmd_parse_buffer, data, len);
g_cmd_parse_buffer[len] = '\0';
if (((g_cmd_parse_buffer[0] != 'A') && (g_cmd_parse_buffer[0] != 'a')) ||
((g_cmd_parse_buffer[1] != 'T') && (g_cmd_parse_buffer[1] != 't'))) {
return false;
}
*result = config_process_at_cmd(g_cmd_parse_buffer, response, max_len);
return true;
}
bool config_try_process_frame(const uint8_t *data, uint16_t len) bool config_try_process_frame(const uint8_t *data, uint16_t len)
{ {
char response[CONFIG_TX_BUFFER_SIZE]; at_result_t result = AT_ERROR;
char cmd_buffer[CONFIG_CMD_MAX_LEN];
at_result_t result;
if (data == NULL || len < 2u) { if (!config_build_response_frame(data, len, g_at_response_buffer, sizeof(g_at_response_buffer), &result)) {
return false; return false;
} }
if (len >= CONFIG_CMD_MAX_LEN) {
len = CONFIG_CMD_MAX_LEN - 1u;
}
memcpy(cmd_buffer, data, len);
cmd_buffer[len] = '\0';
if (((cmd_buffer[0] != 'A') && (cmd_buffer[0] != 'a')) ||
((cmd_buffer[1] != 'T') && (cmd_buffer[1] != 't'))) {
return false;
}
result = config_process_at_cmd(cmd_buffer, response, sizeof(response));
if (HAL_UART_Transmit(&CONFIG_UART_HANDLE, if (HAL_UART_Transmit(&CONFIG_UART_HANDLE,
(uint8_t *)response, (uint8_t *)g_at_response_buffer,
(uint16_t)strlen(response), (uint16_t)strlen(g_at_response_buffer),
1000u) != HAL_OK) { 1000u) != HAL_OK) {
return false; return false;
} }
@@ -488,3 +785,31 @@ void config_clear_reset_requested(void)
{ {
g_reset_requested = false; g_reset_requested = false;
} }
uint8_t config_link_index_to_endpoint(uint8_t index)
{
switch (index) {
case CONFIG_LINK_S1:
return ENDPOINT_S1;
case CONFIG_LINK_S2:
return ENDPOINT_S2;
case CONFIG_LINK_C1:
return ENDPOINT_C1;
case CONFIG_LINK_C2:
return ENDPOINT_C2;
default:
return 0u;
}
}
uint8_t config_uart_index_to_endpoint(uint8_t uart_index)
{
return (uart_index == LINK_UART_U1) ? ENDPOINT_UART3 : ENDPOINT_UART2;
}
bool config_endpoint_is_single(uint8_t endpoint)
{
return endpoint == ENDPOINT_C1 || endpoint == ENDPOINT_C2 ||
endpoint == ENDPOINT_UART2 || endpoint == ENDPOINT_UART3 ||
endpoint == ENDPOINT_S1 || endpoint == ENDPOINT_S2;
}
+61 -157
View File
@@ -1,96 +1,78 @@
/** /**
* @file config.h * @file config.h
* @brief AT command configuration module for TCP2UART * @brief Final AT configuration model for TCP2UART.
*
* Handles UART1 AT commands for network and serial port configuration.
*
* Supported AT commands:
* - AT+IP=192.168.1.100 Set device IP
* - AT+MASK=255.255.255.0 Set subnet mask
* - AT+GW=192.168.1.1 Set gateway
* - AT+PORT=8080 Set TCP Server listen port
* - AT+RIP=192.168.1.200 Set TCP Client remote IP
* - AT+RPORT=9000 Set TCP Client remote port
* - AT+BAUD1=115200 Set UART2 baudrate
* - AT+BAUD2=115200 Set UART3 baudrate
* - AT+MAC=00:11:22:33:44:55 Set MAC address
* - AT+DHCP=0/1 Enable/disable DHCP
* - AT+SAVE Save parameters to Flash
* - AT+RESET Reset device
* - AT+DEFAULT Restore factory defaults
* - AT+? Query current configuration
*/ */
#ifndef __CONFIG_H__ #ifndef __CONFIG_H__
#define __CONFIG_H__ #define __CONFIG_H__
#include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/* Configuration magic number "TCPU" */ #define CONFIG_MAGIC 0x54435055u
#define CONFIG_MAGIC 0x54435055 #define CONFIG_VERSION 0x0003u
/* Configuration version for compatibility */ #define CONFIG_UART_COUNT 2u
#define CONFIG_VERSION 0x0002 #define CONFIG_LINK_COUNT 4u
#define CONFIG_LINK_S1 0u
#define CONFIG_LINK_S2 1u
#define CONFIG_LINK_C1 2u
#define CONFIG_LINK_C2 3u
#define ENDPOINT_C1 0x01u
#define ENDPOINT_C2 0x02u
#define ENDPOINT_UART2 0x04u
#define ENDPOINT_UART3 0x08u
#define ENDPOINT_S1 0x10u
#define ENDPOINT_S2 0x20u
#define LINK_UART_U0 0u
#define LINK_UART_U1 1u
typedef enum {
MUX_MODE_RAW = 0,
MUX_MODE_FRAME = 1
} mux_mode_t;
/* Device configuration structure */
typedef struct { typedef struct {
uint32_t magic; /* Magic number for validation */ uint8_t ip[4];
uint16_t version; /* Configuration version */ uint8_t mask[4];
uint16_t reserved; /* Reserved for alignment */ uint8_t gw[4];
uint8_t mac[6];
uint8_t reserved[2];
} net_config_t;
/* Network settings */ typedef struct {
uint8_t mac[6]; /* MAC address */ uint8_t enabled;
uint8_t dhcp_enable; /* DHCP enable flag */ uint8_t uart;
uint8_t reserved2; /* Reserved for alignment */ uint16_t local_port;
uint8_t ip[4]; /* Device IP address */ uint8_t remote_ip[4];
uint8_t mask[4]; /* Subnet mask */ uint16_t remote_port;
uint8_t gw[4]; /* Gateway */ uint16_t reserved;
} link_config_t;
/* TCP Server settings */ typedef struct {
uint16_t server_port; /* Server listen port */ uint32_t magic;
uint16_t reserved3; /* Reserved for alignment */ uint16_t version;
uint8_t mux_mode;
/* TCP Client settings */ uint8_t reserved0;
uint8_t remote_ip[4]; /* Remote server IP */ net_config_t net;
uint16_t remote_port; /* Remote server port */ link_config_t links[CONFIG_LINK_COUNT];
uint16_t reconnect_interval;/* Reconnect interval (ms) */ uint32_t uart_baudrate[CONFIG_UART_COUNT];
/* UART settings */
uint32_t uart2_baudrate; /* UART2 (Server) baudrate */
uint32_t uart3_baudrate; /* UART3 (Client) baudrate */
uint8_t uart2_databits; /* UART2 data bits */
uint8_t uart2_stopbits; /* UART2 stop bits */
uint8_t uart2_parity; /* UART2 parity */
uint8_t uart3_databits; /* UART3 data bits */
uint8_t uart3_stopbits; /* UART3 stop bits */
uint8_t uart3_parity; /* UART3 parity */
uint16_t reserved4; /* Reserved for alignment */
/* CRC32 checksum (must be last) */
uint32_t crc; uint32_t crc;
} device_config_t; } device_config_t;
/* Default configuration values */ #define DEFAULT_NET_IP {192, 168, 1, 100}
#define DEFAULT_IP {192, 168, 31, 100} #define DEFAULT_NET_MASK {255, 255, 255, 0}
#define DEFAULT_MASK {255, 255, 255, 0} #define DEFAULT_NET_GW {192, 168, 1, 1}
#define DEFAULT_GW {192, 168, 31, 1} #define DEFAULT_NET_MAC {0x02, 0x00, 0x00, 0x00, 0x00, 0x01}
#define DEFAULT_MAC {0x02, 0x00, 0x00, 0x00, 0x00, 0x01} #define DEFAULT_UART_BAUDRATE 115200u
#define DEFAULT_SERVER_PORT 8080
#define DEFAULT_REMOTE_IP {192, 168, 31, 1}
#define DEFAULT_REMOTE_PORT 8081
#define DEFAULT_UART_BAUDRATE 115200
#define DEFAULT_UART_DATABITS 8
#define DEFAULT_UART_STOPBITS 1
#define DEFAULT_UART_PARITY 0
#define DEFAULT_DHCP_ENABLE 0
#define DEFAULT_RECONNECT_MS 3000
/* AT command result codes */
typedef enum { typedef enum {
AT_OK = 0, AT_OK = 0,
AT_ERROR, AT_ERROR,
@@ -100,108 +82,30 @@ typedef enum {
AT_NEED_REBOOT AT_NEED_REBOOT
} at_result_t; } at_result_t;
/**
* @brief Initialize configuration module
* @return 0 on success, negative on error
*/
int config_init(void); int config_init(void);
/**
* @brief Load configuration from Flash
* @return 0 on success, negative on error (defaults loaded)
*/
int config_load(void); int config_load(void);
/**
* @brief Save configuration to Flash
* @return 0 on success, negative on error
*/
int config_save(void); int config_save(void);
/**
* @brief Reset configuration to factory defaults
*/
void config_set_defaults(void); void config_set_defaults(void);
/**
* @brief Get current configuration
* @return Pointer to current configuration (read-only)
*/
const device_config_t *config_get(void); const device_config_t *config_get(void);
/**
* @brief Get mutable configuration for modification
* @return Pointer to configuration structure
*/
device_config_t *config_get_mutable(void); device_config_t *config_get_mutable(void);
/**
* @brief Process AT command received from UART1
* @param cmd Command string (null-terminated)
* @param response Response buffer
* @param max_len Maximum response length
* @return AT command result code
*/
at_result_t config_process_at_cmd(const char *cmd, char *response, uint16_t max_len); at_result_t config_process_at_cmd(const char *cmd, char *response, uint16_t max_len);
/**
* @brief Poll configuration UART and process pending AT commands
*/
void config_poll(void); void config_poll(void);
/**
* @brief Feed one byte received from the config UART.
* @param byte Received byte.
*/
void config_uart_rx_byte(uint8_t byte); void config_uart_rx_byte(uint8_t byte);
/**
* @brief Try to process one AT command frame from an external UART source.
* @param data Input bytes.
* @param len Input length.
* @return true if the frame was recognized as an AT/config command.
*/
bool config_try_process_frame(const uint8_t *data, uint16_t len); bool config_try_process_frame(const uint8_t *data, uint16_t len);
bool config_build_response_frame(const uint8_t *data,
/** uint16_t len,
* @brief Check whether AT+RESET requested a system reset char *response,
*/ uint16_t max_len,
at_result_t *result);
bool config_is_reset_requested(void); bool config_is_reset_requested(void);
/**
* @brief Clear the pending reset request flag
*/
void config_clear_reset_requested(void); void config_clear_reset_requested(void);
/**
* @brief Format IP address to string
* @param ip IP address bytes
* @param str Output string buffer (min 16 bytes)
*/
void config_ip_to_str(const uint8_t *ip, char *str); void config_ip_to_str(const uint8_t *ip, char *str);
/**
* @brief Parse IP address from string
* @param str IP address string (e.g. "192.168.1.100")
* @param ip Output IP address bytes
* @return 0 on success, negative on error
*/
int config_str_to_ip(const char *str, uint8_t *ip); int config_str_to_ip(const char *str, uint8_t *ip);
/**
* @brief Format MAC address to string
* @param mac MAC address bytes
* @param str Output string buffer (min 18 bytes)
*/
void config_mac_to_str(const uint8_t *mac, char *str); void config_mac_to_str(const uint8_t *mac, char *str);
/**
* @brief Parse MAC address from string
* @param str MAC address string (e.g. "00:11:22:33:44:55")
* @param mac Output MAC address bytes
* @return 0 on success, negative on error
*/
int config_str_to_mac(const char *str, uint8_t *mac); int config_str_to_mac(const char *str, uint8_t *mac);
uint8_t config_link_index_to_endpoint(uint8_t index);
uint8_t config_uart_index_to_endpoint(uint8_t uart_index);
bool config_endpoint_is_single(uint8_t endpoint);
#ifdef __cplusplus #ifdef __cplusplus
} }
+13 -44
View File
@@ -19,41 +19,10 @@
* Private Variables * Private Variables
*---------------------------------------------------------------------------*/ *---------------------------------------------------------------------------*/
/* CRC32 lookup table */
static uint32_t g_crc_table[256];
static bool g_crc_table_initialized = false;
/*--------------------------------------------------------------------------- /*---------------------------------------------------------------------------
* Private Functions * Private Functions
*---------------------------------------------------------------------------*/ *---------------------------------------------------------------------------*/
/**
* @brief Initialize CRC32 lookup table
*/
static void crc32_init_table(void)
{
uint32_t i, j, crc;
for (i = 0; i < 256; i++)
{
crc = i;
for (j = 0; j < 8; j++)
{
if (crc & 1)
{
crc = (crc >> 1) ^ CRC32_POLYNOMIAL;
}
else
{
crc >>= 1;
}
}
g_crc_table[i] = crc;
}
g_crc_table_initialized = true;
}
/** /**
* @brief Unlock Flash for writing * @brief Unlock Flash for writing
*/ */
@@ -105,12 +74,6 @@ static HAL_StatusTypeDef flash_program_halfword(uint32_t addr, uint16_t data)
*/ */
int flash_param_init(void) int flash_param_init(void)
{ {
/* Initialize CRC table */
if (!g_crc_table_initialized)
{
crc32_init_table();
}
return 0; return 0;
} }
@@ -243,16 +206,22 @@ uint32_t flash_param_crc32(const void *data, uint32_t len)
const uint8_t *p = (const uint8_t *)data; const uint8_t *p = (const uint8_t *)data;
uint32_t crc = 0xFFFFFFFF; uint32_t crc = 0xFFFFFFFF;
uint32_t i; uint32_t i;
uint32_t j;
/* Initialize table if needed */
if (!g_crc_table_initialized)
{
crc32_init_table();
}
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
{ {
crc = g_crc_table[(crc ^ p[i]) & 0xFF] ^ (crc >> 8); crc ^= p[i];
for (j = 0; j < 8u; ++j)
{
if ((crc & 1u) != 0u)
{
crc = (crc >> 1) ^ CRC32_POLYNOMIAL;
}
else
{
crc >>= 1;
}
}
} }
return crc ^ 0xFFFFFFFF; return crc ^ 0xFFFFFFFF;
+117 -142
View File
@@ -1,17 +1,14 @@
/** /**
* @file tcp_client.c * @file tcp_client.c
* @brief lwIP RAW TCP client for the UART3 bridge. * @brief Indexed lwIP RAW TCP client manager.
*/ */
#include "tcp_client.h" #include "tcp_client.h"
#include "main.h" #include "../Core/Inc/main.h"
#include "../Drivers/LwIP/src/include/lwip/ip_addr.h"
#include "SEGGER_RTT.h" #include "../Drivers/LwIP/src/include/lwip/pbuf.h"
#include "../Drivers/LwIP/src/include/lwip/tcp.h"
#include "lwip/ip_addr.h"
#include "lwip/pbuf.h"
#include "lwip/tcp.h"
#include <string.h> #include <string.h>
@@ -21,11 +18,12 @@ typedef struct {
uint16_t rx_head; uint16_t rx_head;
uint16_t rx_tail; uint16_t rx_tail;
uint32_t next_retry_ms; uint32_t next_retry_ms;
tcp_client_config_t config; uint8_t index;
tcp_client_instance_config_t config;
tcp_client_status_t status; tcp_client_status_t status;
} tcp_client_ctx_t; } tcp_client_ctx_t;
static tcp_client_ctx_t g_client; static tcp_client_ctx_t g_clients[TCP_CLIENT_INSTANCE_COUNT];
static uint16_t ring_free(uint16_t head, uint16_t tail, uint16_t size) static uint16_t ring_free(uint16_t head, uint16_t tail, uint16_t size)
{ {
@@ -37,13 +35,18 @@ static err_t tcp_client_on_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p,
tcp_client_ctx_t *ctx = (tcp_client_ctx_t *)arg; tcp_client_ctx_t *ctx = (tcp_client_ctx_t *)arg;
struct pbuf *q; struct pbuf *q;
if (ctx == NULL) {
if (p != NULL) {
pbuf_free(p);
}
return ERR_ARG;
}
if (err != ERR_OK) { if (err != ERR_OK) {
if (p != NULL) { if (p != NULL) {
pbuf_free(p); pbuf_free(p);
} }
return err; return err;
} }
if (p == NULL) { if (p == NULL) {
tcp_arg(pcb, NULL); tcp_arg(pcb, NULL);
tcp_recv(pcb, NULL); tcp_recv(pcb, NULL);
@@ -80,7 +83,9 @@ static err_t tcp_client_on_sent(void *arg, struct tcp_pcb *pcb, u16_t len)
{ {
tcp_client_ctx_t *ctx = (tcp_client_ctx_t *)arg; tcp_client_ctx_t *ctx = (tcp_client_ctx_t *)arg;
(void)pcb; (void)pcb;
if (ctx != NULL) {
ctx->status.tx_bytes += len; ctx->status.tx_bytes += len;
}
return ERR_OK; return ERR_OK;
} }
@@ -90,34 +95,30 @@ static void tcp_client_on_err(void *arg, err_t err)
if (ctx == NULL) { if (ctx == NULL) {
return; return;
} }
ctx->pcb = NULL; ctx->pcb = NULL;
ctx->status.state = TCP_CLIENT_STATE_DISCONNECTED; ctx->status.state = TCP_CLIENT_STATE_DISCONNECTED;
ctx->status.errors++; ctx->status.errors++;
ctx->next_retry_ms = HAL_GetTick() + ctx->config.reconnect_interval_ms; ctx->next_retry_ms = HAL_GetTick() + ctx->config.reconnect_interval_ms;
SEGGER_RTT_printf(0, "TCP client error=%d, reconnect scheduled\r\n", (int)err); (void)err;
} }
static err_t tcp_client_on_connected(void *arg, struct tcp_pcb *pcb, err_t err) static err_t tcp_client_on_connected(void *arg, struct tcp_pcb *pcb, err_t err)
{ {
tcp_client_ctx_t *ctx = (tcp_client_ctx_t *)arg; tcp_client_ctx_t *ctx = (tcp_client_ctx_t *)arg;
if (ctx == NULL) {
return ERR_ARG;
}
if (err != ERR_OK) { if (err != ERR_OK) {
ctx->pcb = NULL; ctx->pcb = NULL;
ctx->status.state = TCP_CLIENT_STATE_DISCONNECTED; ctx->status.state = TCP_CLIENT_STATE_DISCONNECTED;
ctx->status.errors++; ctx->status.errors++;
ctx->next_retry_ms = HAL_GetTick() + ctx->config.reconnect_interval_ms; ctx->next_retry_ms = HAL_GetTick() + ctx->config.reconnect_interval_ms;
SEGGER_RTT_printf(0, "TCP client connect callback failed err=%d\r\n", (int)err);
return err; return err;
} }
ctx->pcb = pcb; ctx->pcb = pcb;
ctx->status.state = TCP_CLIENT_STATE_CONNECTED; ctx->status.state = TCP_CLIENT_STATE_CONNECTED;
SEGGER_RTT_printf(0,
"TCP client connected to %u.%u.%u.%u:%u\r\n",
ctx->config.server_ip[0], ctx->config.server_ip[1],
ctx->config.server_ip[2], ctx->config.server_ip[3],
ctx->config.server_port);
tcp_nagle_disable(pcb); tcp_nagle_disable(pcb);
tcp_arg(pcb, ctx); tcp_arg(pcb, ctx);
tcp_recv(pcb, tcp_client_on_recv); tcp_recv(pcb, tcp_client_on_recv);
@@ -126,207 +127,181 @@ static err_t tcp_client_on_connected(void *arg, struct tcp_pcb *pcb, err_t err)
return ERR_OK; return ERR_OK;
} }
int tcp_client_init(const tcp_client_config_t *config) int tcp_client_init_all(void)
{ {
memset(&g_client, 0, sizeof(g_client)); memset(g_clients, 0, sizeof(g_clients));
g_client.config.server_ip[0] = 192u; for (uint8_t i = 0; i < TCP_CLIENT_INSTANCE_COUNT; ++i) {
g_client.config.server_ip[1] = 168u; g_clients[i].index = i;
g_client.config.server_ip[2] = 31u; g_clients[i].status.state = TCP_CLIENT_STATE_IDLE;
g_client.config.server_ip[3] = 1u; g_clients[i].config.reconnect_interval_ms = TCP_CLIENT_RECONNECT_DELAY_MS;
g_client.config.local_port = TCP_CLIENT_DEFAULT_PORT; g_clients[i].config.auto_reconnect = true;
g_client.config.server_port = TCP_CLIENT_DEFAULT_PORT;
g_client.config.auto_reconnect = true;
g_client.config.reconnect_interval_ms = TCP_CLIENT_RECONNECT_DELAY_MS;
g_client.status.state = TCP_CLIENT_STATE_IDLE;
if (config != NULL) {
g_client.config = *config;
} }
return 0; return 0;
} }
int tcp_client_connect(void) int tcp_client_config(uint8_t instance, const tcp_client_instance_config_t *config)
{
if (instance >= TCP_CLIENT_INSTANCE_COUNT || config == NULL) {
return -1;
}
g_clients[instance].config = *config;
return 0;
}
int tcp_client_connect(uint8_t instance)
{ {
struct tcp_pcb *pcb; struct tcp_pcb *pcb;
ip_addr_t remote_addr; ip_addr_t remote_addr;
err_t err; err_t err;
tcp_client_ctx_t *ctx;
if (g_client.pcb != NULL) { if (instance >= TCP_CLIENT_INSTANCE_COUNT) {
return -1;
}
ctx = &g_clients[instance];
if (!ctx->config.enabled) {
return 0;
}
if (ctx->pcb != NULL) {
return 0; return 0;
} }
pcb = tcp_new_ip_type(IPADDR_TYPE_V4); pcb = tcp_new_ip_type(IPADDR_TYPE_V4);
if (pcb == NULL) { if (pcb == NULL) {
g_client.status.errors++; ctx->status.errors++;
g_client.status.state = TCP_CLIENT_STATE_ERROR; ctx->status.state = TCP_CLIENT_STATE_ERROR;
SEGGER_RTT_WriteString(0, "TCP client connect failed: no PCB\r\n");
return -1; return -1;
} }
if (ctx->config.local_port != 0u) {
if (g_client.config.local_port != 0u) { err = tcp_bind(pcb, IP_ANY_TYPE, ctx->config.local_port);
err = tcp_bind(pcb, IP_ANY_TYPE, g_client.config.local_port);
if (err != ERR_OK) { if (err != ERR_OK) {
tcp_abort(pcb); tcp_abort(pcb);
g_client.status.state = TCP_CLIENT_STATE_DISCONNECTED; ctx->status.state = TCP_CLIENT_STATE_DISCONNECTED;
g_client.status.errors++; ctx->status.errors++;
g_client.next_retry_ms = HAL_GetTick() + g_client.config.reconnect_interval_ms; ctx->next_retry_ms = HAL_GetTick() + ctx->config.reconnect_interval_ms;
SEGGER_RTT_printf(0, "TCP client bind failed err=%d\r\n", (int)err);
return -1; return -1;
} }
} }
IP_ADDR4(&remote_addr, IP_ADDR4(&remote_addr,
g_client.config.server_ip[0], ctx->config.remote_ip[0],
g_client.config.server_ip[1], ctx->config.remote_ip[1],
g_client.config.server_ip[2], ctx->config.remote_ip[2],
g_client.config.server_ip[3]); ctx->config.remote_ip[3]);
g_client.status.state = TCP_CLIENT_STATE_CONNECTING; ctx->status.state = TCP_CLIENT_STATE_CONNECTING;
tcp_arg(pcb, &g_client); tcp_arg(pcb, ctx);
tcp_err(pcb, tcp_client_on_err); tcp_err(pcb, tcp_client_on_err);
err = tcp_connect(pcb, &remote_addr, g_client.config.server_port, tcp_client_on_connected); err = tcp_connect(pcb, &remote_addr, ctx->config.remote_port, tcp_client_on_connected);
if (err != ERR_OK) { if (err != ERR_OK) {
tcp_err(pcb, NULL); tcp_err(pcb, NULL);
tcp_abort(pcb); tcp_abort(pcb);
g_client.status.state = TCP_CLIENT_STATE_DISCONNECTED; ctx->status.state = TCP_CLIENT_STATE_DISCONNECTED;
g_client.status.errors++; ctx->status.errors++;
g_client.next_retry_ms = HAL_GetTick() + g_client.config.reconnect_interval_ms; ctx->next_retry_ms = HAL_GetTick() + ctx->config.reconnect_interval_ms;
SEGGER_RTT_printf(0, "TCP client connect start failed err=%d\r\n", (int)err);
return -1; return -1;
} }
g_client.pcb = pcb; ctx->pcb = pcb;
SEGGER_RTT_printf(0,
"TCP client connecting to %u.%u.%u.%u:%u\r\n",
g_client.config.server_ip[0], g_client.config.server_ip[1],
g_client.config.server_ip[2], g_client.config.server_ip[3],
g_client.config.server_port);
return 0; return 0;
} }
int tcp_client_disconnect(void) int tcp_client_disconnect(uint8_t instance)
{ {
if (g_client.pcb != NULL) { tcp_client_ctx_t *ctx;
tcp_arg(g_client.pcb, NULL);
tcp_recv(g_client.pcb, NULL);
tcp_sent(g_client.pcb, NULL);
tcp_err(g_client.pcb, NULL);
tcp_abort(g_client.pcb);
g_client.pcb = NULL;
}
g_client.status.state = TCP_CLIENT_STATE_DISCONNECTED; if (instance >= TCP_CLIENT_INSTANCE_COUNT) {
SEGGER_RTT_WriteString(0, "TCP client disconnected\r\n"); return -1;
}
ctx = &g_clients[instance];
if (ctx->pcb != NULL) {
tcp_arg(ctx->pcb, NULL);
tcp_recv(ctx->pcb, NULL);
tcp_sent(ctx->pcb, NULL);
tcp_err(ctx->pcb, NULL);
tcp_abort(ctx->pcb);
ctx->pcb = NULL;
}
ctx->status.state = TCP_CLIENT_STATE_DISCONNECTED;
ctx->rx_head = 0u;
ctx->rx_tail = 0u;
return 0; return 0;
} }
int tcp_client_send(const uint8_t *data, uint16_t len) int tcp_client_send(uint8_t instance, const uint8_t *data, uint16_t len)
{ {
err_t err; err_t err;
tcp_client_ctx_t *ctx;
if (g_client.pcb == NULL || data == NULL || len == 0u) { if (instance >= TCP_CLIENT_INSTANCE_COUNT || data == NULL || len == 0u) {
return -1; return -1;
} }
ctx = &g_clients[instance];
if ((g_client.pcb->flags & TF_RXCLOSED) != 0u) { if (ctx->pcb == NULL) {
g_client.status.errors++;
return -1; return -1;
} }
if (tcp_sndbuf(ctx->pcb) < len) {
if (tcp_sndbuf(g_client.pcb) < len) {
return 0; return 0;
} }
err = tcp_write(ctx->pcb, data, len, TCP_WRITE_FLAG_COPY);
err = tcp_write(g_client.pcb, data, len, TCP_WRITE_FLAG_COPY);
if (err != ERR_OK) { if (err != ERR_OK) {
g_client.status.errors++; ctx->status.errors++;
return -1; return -1;
} }
err = tcp_output(ctx->pcb);
err = tcp_output(g_client.pcb);
if (err != ERR_OK) { if (err != ERR_OK) {
g_client.status.errors++; ctx->status.errors++;
return -1; return -1;
} }
return (int)len; return (int)len;
} }
int tcp_client_recv(uint8_t *data, uint16_t max_len, uint32_t timeout_ms) int tcp_client_recv(uint8_t instance, uint8_t *data, uint16_t max_len)
{ {
uint16_t copied = 0u; uint16_t copied = 0u;
(void)timeout_ms; tcp_client_ctx_t *ctx;
if (data == NULL || max_len == 0u) { if (instance >= TCP_CLIENT_INSTANCE_COUNT || data == NULL || max_len == 0u) {
return -1; return -1;
} }
ctx = &g_clients[instance];
while (copied < max_len && g_client.rx_tail != g_client.rx_head) { while (copied < max_len && ctx->rx_tail != ctx->rx_head) {
data[copied++] = g_client.rx_ring[g_client.rx_tail]; data[copied++] = ctx->rx_ring[ctx->rx_tail];
g_client.rx_tail = (uint16_t)((g_client.rx_tail + 1u) % TCP_CLIENT_RX_BUFFER_SIZE); ctx->rx_tail = (uint16_t)((ctx->rx_tail + 1u) % TCP_CLIENT_RX_BUFFER_SIZE);
} }
return (int)copied; return (int)copied;
} }
bool tcp_client_is_connected(void) bool tcp_client_is_connected(uint8_t instance)
{ {
return (g_client.pcb != NULL) && (g_client.status.state == TCP_CLIENT_STATE_CONNECTED); return (instance < TCP_CLIENT_INSTANCE_COUNT) &&
(g_clients[instance].pcb != NULL) &&
(g_clients[instance].status.state == TCP_CLIENT_STATE_CONNECTED);
} }
int tcp_client_set_server(const uint8_t *ip, uint16_t port) void tcp_client_get_status(uint8_t instance, tcp_client_status_t *status)
{ {
if (ip == NULL || port == 0u) { if (instance < TCP_CLIENT_INSTANCE_COUNT && status != NULL) {
return -1; *status = g_clients[instance].status;
} }
memcpy(g_client.config.server_ip, ip, 4u);
g_client.config.server_port = port;
return 0;
}
void tcp_client_get_status(tcp_client_status_t *status)
{
if (status != NULL) {
*status = g_client.status;
}
}
void *tcp_client_get_rx_stream(void)
{
return NULL;
}
void *tcp_client_get_tx_stream(void)
{
return NULL;
}
void tcp_client_task(void *argument)
{
(void)argument;
} }
void tcp_client_poll(void) void tcp_client_poll(void)
{ {
uint32_t now; uint32_t now = HAL_GetTick();
if (!g_client.config.auto_reconnect || tcp_client_is_connected()) { for (uint8_t i = 0; i < TCP_CLIENT_INSTANCE_COUNT; ++i) {
return; tcp_client_ctx_t *ctx = &g_clients[i];
if (!ctx->config.enabled || !ctx->config.auto_reconnect || tcp_client_is_connected(i)) {
continue;
} }
if ((ctx->pcb != NULL) && (ctx->status.state == TCP_CLIENT_STATE_CONNECTING)) {
if ((g_client.pcb != NULL) && (g_client.status.state == TCP_CLIENT_STATE_CONNECTING)) { continue;
return; }
if (now >= ctx->next_retry_ms) {
ctx->status.reconnect_count++;
ctx->next_retry_ms = now + ctx->config.reconnect_interval_ms;
(void)tcp_client_connect(i);
} }
now = HAL_GetTick();
if (now >= g_client.next_retry_ms) {
g_client.status.reconnect_count++;
g_client.next_retry_ms = now + g_client.config.reconnect_interval_ms;
SEGGER_RTT_printf(0,
"TCP client reconnect attempt %lu\r\n",
g_client.status.reconnect_count);
(void)tcp_client_connect();
} }
} }
+21 -97
View File
@@ -1,49 +1,39 @@
/** /**
* @file tcp_client.h * @file tcp_client.h
* @brief TCP Client module for transparent transmission with UART3 * @brief Indexed lwIP RAW TCP client manager.
*/ */
#ifndef __TCP_CLIENT_H__ #ifndef __TCP_CLIENT_H__
#define __TCP_CLIENT_H__ #define __TCP_CLIENT_H__
#include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/* Default TCP Client settings */ #define TCP_CLIENT_INSTANCE_COUNT 2u
#define TCP_CLIENT_DEFAULT_PORT 8081 #define TCP_CLIENT_RX_BUFFER_SIZE 512u
#define TCP_CLIENT_DEFAULT_SERVER "192.168.1.100" #define TCP_CLIENT_RECONNECT_DELAY_MS 3000u
/* Reconnect settings */
#define TCP_CLIENT_RECONNECT_DELAY_MS 3000
#define TCP_CLIENT_MAX_RECONNECT_TRIES 0 /* 0 = infinite */
/* Buffer sizes */
#define TCP_CLIENT_RX_BUFFER_SIZE 512
#define TCP_CLIENT_TX_BUFFER_SIZE 512
/* TCP Client state */
typedef enum { typedef enum {
TCP_CLIENT_STATE_IDLE, TCP_CLIENT_STATE_IDLE = 0,
TCP_CLIENT_STATE_CONNECTING, TCP_CLIENT_STATE_CONNECTING,
TCP_CLIENT_STATE_CONNECTED, TCP_CLIENT_STATE_CONNECTED,
TCP_CLIENT_STATE_DISCONNECTED, TCP_CLIENT_STATE_DISCONNECTED,
TCP_CLIENT_STATE_ERROR TCP_CLIENT_STATE_ERROR
} tcp_client_state_t; } tcp_client_state_t;
/* TCP Client configuration */
typedef struct { typedef struct {
uint8_t server_ip[4]; /* Server IP address */ uint8_t remote_ip[4];
uint16_t local_port; /* Local source port */ uint16_t local_port;
uint16_t server_port; /* Server port */ uint16_t remote_port;
bool auto_reconnect; /* Auto reconnect on disconnect */ uint16_t reconnect_interval_ms;
uint16_t reconnect_interval_ms; /* Reconnect interval */ bool enabled;
} tcp_client_config_t; bool auto_reconnect;
} tcp_client_instance_config_t;
/* TCP Client status */
typedef struct { typedef struct {
tcp_client_state_t state; tcp_client_state_t state;
uint32_t rx_bytes; uint32_t rx_bytes;
@@ -52,80 +42,14 @@ typedef struct {
uint32_t errors; uint32_t errors;
} tcp_client_status_t; } tcp_client_status_t;
/** int tcp_client_init_all(void);
* @brief Initialize TCP Client module int tcp_client_config(uint8_t instance, const tcp_client_instance_config_t *config);
* @param config Client configuration int tcp_client_connect(uint8_t instance);
* @return 0 on success, negative on error int tcp_client_disconnect(uint8_t instance);
*/ int tcp_client_send(uint8_t instance, const uint8_t *data, uint16_t len);
int tcp_client_init(const tcp_client_config_t *config); int tcp_client_recv(uint8_t instance, uint8_t *data, uint16_t max_len);
bool tcp_client_is_connected(uint8_t instance);
/** void tcp_client_get_status(uint8_t instance, tcp_client_status_t *status);
* @brief Connect to remote server
* @return 0 on success, negative on error
*/
int tcp_client_connect(void);
/**
* @brief Disconnect from server
* @return 0 on success, negative on error
*/
int tcp_client_disconnect(void);
/**
* @brief Send data to server
* @param data Data buffer
* @param len Data length
* @return Number of bytes sent, negative on error
*/
int tcp_client_send(const uint8_t *data, uint16_t len);
/**
* @brief Receive data from server
* @param data Data buffer
* @param max_len Maximum length to receive
* @param timeout_ms Timeout in milliseconds (0 = non-blocking)
* @return Number of bytes received, 0 if no data, negative on error
*/
int tcp_client_recv(uint8_t *data, uint16_t max_len, uint32_t timeout_ms);
/**
* @brief Check if connected to server
* @return true if connected
*/
bool tcp_client_is_connected(void);
/**
* @brief Update server configuration (for AT command)
* @param ip Server IP address (4 bytes)
* @param port Server port
* @return 0 on success, negative on error
*/
int tcp_client_set_server(const uint8_t *ip, uint16_t port);
/**
* @brief Get TCP Client status
* @param status Pointer to status structure
*/
void tcp_client_get_status(tcp_client_status_t *status);
/**
* @brief Get TCP Client RX StreamBuffer handle for UART integration
* @return StreamBuffer handle for receiving data from TCP
*/
void *tcp_client_get_rx_stream(void);
/**
* @brief Get TCP Client TX StreamBuffer handle for UART integration
* @return StreamBuffer handle for sending data to TCP
*/
void *tcp_client_get_tx_stream(void);
/**
* @brief TCP Client task function (for FreeRTOS)
* @param argument Task argument (unused)
*/
void tcp_client_task(void *argument);
void tcp_client_poll(void); void tcp_client_poll(void);
#ifdef __cplusplus #ifdef __cplusplus
+102 -95
View File
@@ -1,12 +1,12 @@
/** /**
* @file tcp_server.c * @file tcp_server.c
* @brief lwIP RAW TCP server for the UART2 bridge. * @brief Indexed lwIP RAW TCP server manager.
*/ */
#include "tcp_server.h" #include "tcp_server.h"
#include "lwip/pbuf.h" #include "../Drivers/LwIP/src/include/lwip/pbuf.h"
#include "lwip/tcp.h" #include "../Drivers/LwIP/src/include/lwip/tcp.h"
#include "SEGGER_RTT.h" #include "SEGGER_RTT.h"
@@ -18,11 +18,12 @@ typedef struct {
uint8_t rx_ring[TCP_SERVER_RX_BUFFER_SIZE]; uint8_t rx_ring[TCP_SERVER_RX_BUFFER_SIZE];
uint16_t rx_head; uint16_t rx_head;
uint16_t rx_tail; uint16_t rx_tail;
tcp_server_config_t config; uint8_t index;
tcp_server_instance_config_t config;
tcp_server_status_t status; tcp_server_status_t status;
} tcp_server_ctx_t; } tcp_server_ctx_t;
static tcp_server_ctx_t g_server; static tcp_server_ctx_t g_servers[TCP_SERVER_INSTANCE_COUNT];
static uint16_t ring_free(uint16_t head, uint16_t tail, uint16_t size) static uint16_t ring_free(uint16_t head, uint16_t tail, uint16_t size)
{ {
@@ -34,13 +35,18 @@ static err_t tcp_server_on_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p,
tcp_server_ctx_t *ctx = (tcp_server_ctx_t *)arg; tcp_server_ctx_t *ctx = (tcp_server_ctx_t *)arg;
struct pbuf *q; struct pbuf *q;
if (ctx == NULL) {
if (p != NULL) {
pbuf_free(p);
}
return ERR_ARG;
}
if (err != ERR_OK) { if (err != ERR_OK) {
if (p != NULL) { if (p != NULL) {
pbuf_free(p); pbuf_free(p);
} }
return err; return err;
} }
if (p == NULL) { if (p == NULL) {
tcp_arg(pcb, NULL); tcp_arg(pcb, NULL);
tcp_recv(pcb, NULL); tcp_recv(pcb, NULL);
@@ -50,8 +56,7 @@ static err_t tcp_server_on_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p,
tcp_abort(pcb); tcp_abort(pcb);
} }
ctx->client_pcb = NULL; ctx->client_pcb = NULL;
ctx->status.state = TCP_SERVER_STATE_LISTENING; ctx->status.state = ctx->config.enabled ? TCP_SERVER_STATE_LISTENING : TCP_SERVER_STATE_IDLE;
SEGGER_RTT_WriteString(0, "TCP server peer disconnected\r\n");
return ERR_OK; return ERR_OK;
} }
@@ -77,28 +82,31 @@ static err_t tcp_server_on_sent(void *arg, struct tcp_pcb *pcb, u16_t len)
{ {
tcp_server_ctx_t *ctx = (tcp_server_ctx_t *)arg; tcp_server_ctx_t *ctx = (tcp_server_ctx_t *)arg;
(void)pcb; (void)pcb;
if (ctx != NULL) {
ctx->status.tx_bytes += len; ctx->status.tx_bytes += len;
}
return ERR_OK; return ERR_OK;
} }
static void tcp_server_on_err(void *arg, err_t err) static void tcp_server_on_err(void *arg, err_t err)
{ {
tcp_server_ctx_t *ctx = (tcp_server_ctx_t *)arg; tcp_server_ctx_t *ctx = (tcp_server_ctx_t *)arg;
(void)err; if (ctx == NULL) {
return;
}
ctx->client_pcb = NULL; ctx->client_pcb = NULL;
ctx->status.state = TCP_SERVER_STATE_LISTENING; ctx->status.state = ctx->config.enabled ? TCP_SERVER_STATE_LISTENING : TCP_SERVER_STATE_IDLE;
ctx->status.errors++; ctx->status.errors++;
SEGGER_RTT_printf(0, "TCP server connection error=%d\r\n", (int)err); SEGGER_RTT_printf(0, "TCP server[%u] connection error=%d\r\n", ctx->index, (int)err);
} }
static err_t tcp_server_on_accept(void *arg, struct tcp_pcb *newpcb, err_t err) static err_t tcp_server_on_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
{ {
tcp_server_ctx_t *ctx = (tcp_server_ctx_t *)arg; tcp_server_ctx_t *ctx = (tcp_server_ctx_t *)arg;
if (err != ERR_OK) { if (ctx == NULL || err != ERR_OK) {
return err; return (ctx == NULL) ? ERR_ARG : err;
} }
if (ctx->client_pcb != NULL) { if (ctx->client_pcb != NULL) {
tcp_abort(newpcb); tcp_abort(newpcb);
return ERR_ABRT; return ERR_ABRT;
@@ -107,10 +115,7 @@ static err_t tcp_server_on_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
ctx->client_pcb = newpcb; ctx->client_pcb = newpcb;
ctx->status.state = TCP_SERVER_STATE_CONNECTED; ctx->status.state = TCP_SERVER_STATE_CONNECTED;
ctx->status.connections++; ctx->status.connections++;
SEGGER_RTT_WriteString(0, "TCP server client connected\r\n");
tcp_nagle_disable(newpcb); tcp_nagle_disable(newpcb);
tcp_arg(newpcb, ctx); tcp_arg(newpcb, ctx);
tcp_recv(newpcb, tcp_server_on_recv); tcp_recv(newpcb, tcp_server_on_recv);
tcp_sent(newpcb, tcp_server_on_sent); tcp_sent(newpcb, tcp_server_on_sent);
@@ -118,149 +123,151 @@ static err_t tcp_server_on_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
return ERR_OK; return ERR_OK;
} }
int tcp_server_init(const tcp_server_config_t *config) int tcp_server_init_all(void)
{ {
memset(&g_server, 0, sizeof(g_server)); memset(g_servers, 0, sizeof(g_servers));
g_server.config.port = TCP_SERVER_DEFAULT_PORT; for (uint8_t i = 0; i < TCP_SERVER_INSTANCE_COUNT; ++i) {
g_server.config.auto_reconnect = true; g_servers[i].index = i;
g_server.status.state = TCP_SERVER_STATE_IDLE; g_servers[i].status.state = TCP_SERVER_STATE_IDLE;
if (config != NULL) {
g_server.config = *config;
} }
return 0; return 0;
} }
int tcp_server_start(void) int tcp_server_config(uint8_t instance, const tcp_server_instance_config_t *config)
{
if (instance >= TCP_SERVER_INSTANCE_COUNT || config == NULL) {
return -1;
}
g_servers[instance].config = *config;
return 0;
}
int tcp_server_start(uint8_t instance)
{ {
struct tcp_pcb *pcb; struct tcp_pcb *pcb;
err_t err; err_t err;
tcp_server_ctx_t *ctx;
if (g_server.listen_pcb != NULL) { if (instance >= TCP_SERVER_INSTANCE_COUNT) {
return -1;
}
ctx = &g_servers[instance];
if (!ctx->config.enabled) {
ctx->status.state = TCP_SERVER_STATE_IDLE;
return 0;
}
if (ctx->listen_pcb != NULL) {
return 0; return 0;
} }
pcb = tcp_new_ip_type(IPADDR_TYPE_V4); pcb = tcp_new_ip_type(IPADDR_TYPE_V4);
if (pcb == NULL) { if (pcb == NULL) {
g_server.status.errors++; ctx->status.errors++;
return -1; return -1;
} }
err = tcp_bind(pcb, IP_ANY_TYPE, g_server.config.port); err = tcp_bind(pcb, IP_ANY_TYPE, ctx->config.port);
if (err != ERR_OK) { if (err != ERR_OK) {
tcp_abort(pcb); tcp_abort(pcb);
g_server.status.errors++; ctx->status.errors++;
return -1; return -1;
} }
g_server.listen_pcb = tcp_listen_with_backlog(pcb, 1); ctx->listen_pcb = tcp_listen_with_backlog(pcb, 1);
if (g_server.listen_pcb == NULL) { if (ctx->listen_pcb == NULL) {
g_server.status.errors++; ctx->status.errors++;
return -1; return -1;
} }
tcp_arg(g_server.listen_pcb, &g_server); tcp_arg(ctx->listen_pcb, ctx);
tcp_accept(g_server.listen_pcb, tcp_server_on_accept); tcp_accept(ctx->listen_pcb, tcp_server_on_accept);
g_server.status.state = TCP_SERVER_STATE_LISTENING; ctx->status.state = TCP_SERVER_STATE_LISTENING;
SEGGER_RTT_printf(0, "TCP server listening on %u\r\n", g_server.config.port);
return 0; return 0;
} }
int tcp_server_stop(void) int tcp_server_stop(uint8_t instance)
{ {
if (g_server.client_pcb != NULL) { tcp_server_ctx_t *ctx;
tcp_arg(g_server.client_pcb, NULL);
tcp_recv(g_server.client_pcb, NULL); if (instance >= TCP_SERVER_INSTANCE_COUNT) {
tcp_sent(g_server.client_pcb, NULL); return -1;
tcp_err(g_server.client_pcb, NULL); }
tcp_abort(g_server.client_pcb); ctx = &g_servers[instance];
g_server.client_pcb = NULL;
if (ctx->client_pcb != NULL) {
tcp_arg(ctx->client_pcb, NULL);
tcp_recv(ctx->client_pcb, NULL);
tcp_sent(ctx->client_pcb, NULL);
tcp_err(ctx->client_pcb, NULL);
tcp_abort(ctx->client_pcb);
ctx->client_pcb = NULL;
}
if (ctx->listen_pcb != NULL) {
tcp_arg(ctx->listen_pcb, NULL);
tcp_accept(ctx->listen_pcb, NULL);
tcp_close(ctx->listen_pcb);
ctx->listen_pcb = NULL;
} }
if (g_server.listen_pcb != NULL) { ctx->status.state = TCP_SERVER_STATE_IDLE;
tcp_arg(g_server.listen_pcb, NULL); ctx->rx_head = 0u;
tcp_accept(g_server.listen_pcb, NULL); ctx->rx_tail = 0u;
tcp_close(g_server.listen_pcb);
g_server.listen_pcb = NULL;
}
g_server.status.state = TCP_SERVER_STATE_IDLE;
return 0; return 0;
} }
int tcp_server_send(const uint8_t *data, uint16_t len) int tcp_server_send(uint8_t instance, const uint8_t *data, uint16_t len)
{ {
err_t err; err_t err;
tcp_server_ctx_t *ctx;
if (g_server.client_pcb == NULL || data == NULL || len == 0u) { if (instance >= TCP_SERVER_INSTANCE_COUNT || data == NULL || len == 0u) {
return -1; return -1;
} }
ctx = &g_servers[instance];
if ((g_server.client_pcb->flags & TF_RXCLOSED) != 0u) { if (ctx->client_pcb == NULL) {
g_server.status.errors++;
return -1; return -1;
} }
if (tcp_sndbuf(ctx->client_pcb) < len) {
if (tcp_sndbuf(g_server.client_pcb) < len) {
return 0; return 0;
} }
err = tcp_write(g_server.client_pcb, data, len, TCP_WRITE_FLAG_COPY); err = tcp_write(ctx->client_pcb, data, len, TCP_WRITE_FLAG_COPY);
if (err != ERR_OK) { if (err != ERR_OK) {
g_server.status.errors++; ctx->status.errors++;
return -1; return -1;
} }
err = tcp_output(ctx->client_pcb);
err = tcp_output(g_server.client_pcb);
if (err != ERR_OK) { if (err != ERR_OK) {
g_server.status.errors++; ctx->status.errors++;
return -1; return -1;
} }
return (int)len; return (int)len;
} }
int tcp_server_recv(uint8_t *data, uint16_t max_len, uint32_t timeout_ms) int tcp_server_recv(uint8_t instance, uint8_t *data, uint16_t max_len)
{ {
uint16_t copied = 0u; uint16_t copied = 0u;
(void)timeout_ms; tcp_server_ctx_t *ctx;
if (data == NULL || max_len == 0u) { if (instance >= TCP_SERVER_INSTANCE_COUNT || data == NULL || max_len == 0u) {
return -1; return -1;
} }
ctx = &g_servers[instance];
while (copied < max_len && g_server.rx_tail != g_server.rx_head) { while (copied < max_len && ctx->rx_tail != ctx->rx_head) {
data[copied++] = g_server.rx_ring[g_server.rx_tail]; data[copied++] = ctx->rx_ring[ctx->rx_tail];
g_server.rx_tail = (uint16_t)((g_server.rx_tail + 1u) % TCP_SERVER_RX_BUFFER_SIZE); ctx->rx_tail = (uint16_t)((ctx->rx_tail + 1u) % TCP_SERVER_RX_BUFFER_SIZE);
} }
return (int)copied; return (int)copied;
} }
bool tcp_server_is_connected(void) bool tcp_server_is_connected(uint8_t instance)
{ {
return g_server.client_pcb != NULL; return (instance < TCP_SERVER_INSTANCE_COUNT) && (g_servers[instance].client_pcb != NULL);
} }
void tcp_server_get_status(tcp_server_status_t *status) void tcp_server_get_status(uint8_t instance, tcp_server_status_t *status)
{ {
if (status != NULL) { if (instance < TCP_SERVER_INSTANCE_COUNT && status != NULL) {
*status = g_server.status; *status = g_servers[instance].status;
} }
} }
void *tcp_server_get_rx_stream(void)
{
return NULL;
}
void *tcp_server_get_tx_stream(void)
{
return NULL;
}
void tcp_server_task(void *argument)
{
(void)argument;
}
+15 -82
View File
@@ -1,43 +1,33 @@
/** /**
* @file tcp_server.h * @file tcp_server.h
* @brief TCP Server module for transparent transmission with UART2 * @brief Indexed lwIP RAW TCP server manager.
*/ */
#ifndef __TCP_SERVER_H__ #ifndef __TCP_SERVER_H__
#define __TCP_SERVER_H__ #define __TCP_SERVER_H__
#include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/* Default TCP Server port */ #define TCP_SERVER_INSTANCE_COUNT 2u
#define TCP_SERVER_DEFAULT_PORT 8080 #define TCP_SERVER_RX_BUFFER_SIZE 512u
/* Maximum number of simultaneous connections */
#define TCP_SERVER_MAX_CONNECTIONS 1
/* Buffer sizes */
#define TCP_SERVER_RX_BUFFER_SIZE 512
#define TCP_SERVER_TX_BUFFER_SIZE 512
/* TCP Server state */
typedef enum { typedef enum {
TCP_SERVER_STATE_IDLE, TCP_SERVER_STATE_IDLE = 0,
TCP_SERVER_STATE_LISTENING, TCP_SERVER_STATE_LISTENING,
TCP_SERVER_STATE_CONNECTED, TCP_SERVER_STATE_CONNECTED,
TCP_SERVER_STATE_ERROR TCP_SERVER_STATE_ERROR
} tcp_server_state_t; } tcp_server_state_t;
/* TCP Server configuration */
typedef struct { typedef struct {
uint16_t port; uint16_t port;
bool auto_reconnect; bool enabled;
} tcp_server_config_t; } tcp_server_instance_config_t;
/* TCP Server status */
typedef struct { typedef struct {
tcp_server_state_t state; tcp_server_state_t state;
uint32_t rx_bytes; uint32_t rx_bytes;
@@ -46,71 +36,14 @@ typedef struct {
uint32_t errors; uint32_t errors;
} tcp_server_status_t; } tcp_server_status_t;
/** int tcp_server_init_all(void);
* @brief Initialize TCP Server module int tcp_server_config(uint8_t instance, const tcp_server_instance_config_t *config);
* @param config Server configuration int tcp_server_start(uint8_t instance);
* @return 0 on success, negative on error int tcp_server_stop(uint8_t instance);
*/ int tcp_server_send(uint8_t instance, const uint8_t *data, uint16_t len);
int tcp_server_init(const tcp_server_config_t *config); int tcp_server_recv(uint8_t instance, uint8_t *data, uint16_t max_len);
bool tcp_server_is_connected(uint8_t instance);
/** void tcp_server_get_status(uint8_t instance, tcp_server_status_t *status);
* @brief Start TCP Server (begin listening)
* @return 0 on success, negative on error
*/
int tcp_server_start(void);
/**
* @brief Stop TCP Server
* @return 0 on success, negative on error
*/
int tcp_server_stop(void);
/**
* @brief Send data to connected client
* @param data Data buffer
* @param len Data length
* @return Number of bytes sent, negative on error
*/
int tcp_server_send(const uint8_t *data, uint16_t len);
/**
* @brief Receive data from connected client
* @param data Data buffer
* @param max_len Maximum length to receive
* @param timeout_ms Timeout in milliseconds (0 = non-blocking)
* @return Number of bytes received, 0 if no data, negative on error
*/
int tcp_server_recv(uint8_t *data, uint16_t max_len, uint32_t timeout_ms);
/**
* @brief Check if client is connected
* @return true if connected
*/
bool tcp_server_is_connected(void);
/**
* @brief Get TCP Server status
* @param status Pointer to status structure
*/
void tcp_server_get_status(tcp_server_status_t *status);
/**
* @brief Get TCP Server StreamBuffer handle for UART integration
* @return StreamBuffer handle for receiving data from TCP
*/
void *tcp_server_get_rx_stream(void);
/**
* @brief Get TCP Server TX StreamBuffer handle for UART integration
* @return StreamBuffer handle for sending data to TCP
*/
void *tcp_server_get_tx_stream(void);
/**
* @brief TCP Server task function (for FreeRTOS)
* @param argument Task argument (unused)
*/
void tcp_server_task(void *argument);
#ifdef __cplusplus #ifdef __cplusplus
} }
+113 -82
View File
@@ -1,14 +1,17 @@
/** /**
* @file uart_trans.c * @file uart_trans.c
* @brief Bare-metal UART DMA/IDLE transport layer. * @brief Bare-metal UART DMA/IDLE transport and MUX helpers.
*/ */
#include "uart_trans.h" #include "uart_trans.h"
#include "usart.h" #include "../Core/Inc/usart.h"
#include <string.h> #include <string.h>
#define UART_MUX_SYNC 0x7Eu
#define UART_MUX_TAIL 0x7Fu
typedef struct { typedef struct {
UART_HandleTypeDef *huart; UART_HandleTypeDef *huart;
uint8_t rx_dma_buffer[UART_RX_DMA_BUFFER_SIZE]; uint8_t rx_dma_buffer[UART_RX_DMA_BUFFER_SIZE];
@@ -40,55 +43,23 @@ 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 void apply_default_config(uart_channel_ctx_t *ctx)
{
ctx->config.baudrate = UART_DEFAULT_BAUDRATE;
ctx->config.data_bits = UART_DEFAULT_DATA_BITS;
ctx->config.stop_bits = UART_DEFAULT_STOP_BITS;
ctx->config.parity = UART_DEFAULT_PARITY;
}
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];
UART_HandleTypeDef *huart = ctx->huart; if (ctx->huart == NULL) {
uint32_t word_length;
uint32_t parity;
if (huart == NULL) {
return -1; return -1;
} }
if (ctx->running) { if (ctx->running) {
HAL_UART_DMAStop(huart); HAL_UART_DMAStop(ctx->huart);
ctx->running = false; ctx->running = false;
} }
huart->Init.BaudRate = ctx->config.baudrate; ctx->huart->Init.BaudRate = ctx->config.baudrate;
huart->Init.StopBits = (ctx->config.stop_bits == 2u) ? UART_STOPBITS_2 : UART_STOPBITS_1; ctx->huart->Init.WordLength = UART_WORDLENGTH_8B;
ctx->huart->Init.StopBits = UART_STOPBITS_1;
switch (ctx->config.parity) { ctx->huart->Init.Parity = UART_PARITY_NONE;
case 1: return (HAL_UART_Init(ctx->huart) == HAL_OK) ? 0 : -1;
parity = UART_PARITY_ODD;
break;
case 2:
parity = UART_PARITY_EVEN;
break;
default:
parity = UART_PARITY_NONE;
break;
}
if (parity == UART_PARITY_NONE) {
word_length = (ctx->config.data_bits == 9u) ? UART_WORDLENGTH_9B : UART_WORDLENGTH_8B;
} else {
word_length = (ctx->config.data_bits >= 8u) ? UART_WORDLENGTH_9B : UART_WORDLENGTH_8B;
}
huart->Init.WordLength = word_length;
huart->Init.Parity = parity;
return (HAL_UART_Init(huart) == HAL_OK) ? 0 : -1;
} }
static void process_rx_snapshot(uart_channel_t channel, uint16_t dma_write_index) static void process_rx_snapshot(uart_channel_t channel, uint16_t dma_write_index)
@@ -96,9 +67,7 @@ static void process_rx_snapshot(uart_channel_t channel, uint16_t dma_write_index
uart_channel_ctx_t *ctx = &g_channels[channel]; uart_channel_ctx_t *ctx = &g_channels[channel];
while (ctx->rx_dma_read_index != dma_write_index) { while (ctx->rx_dma_read_index != dma_write_index) {
uint16_t next_head; uint16_t next_head = (uint16_t)((ctx->rx_head + 1u) % UART_RX_RING_BUFFER_SIZE);
next_head = (uint16_t)((ctx->rx_head + 1u) % UART_RX_RING_BUFFER_SIZE);
if (next_head == ctx->rx_tail) { if (next_head == ctx->rx_tail) {
ctx->stats.errors++; ctx->stats.errors++;
break; break;
@@ -149,16 +118,12 @@ static void kick_tx(uart_channel_t channel)
int uart_trans_init(void) int uart_trans_init(void)
{ {
memset(g_channels, 0, sizeof(g_channels)); memset(g_channels, 0, sizeof(g_channels));
g_channels[UART_CHANNEL_U0].huart = &huart2;
g_channels[UART_CHANNEL_SERVER].huart = &huart2; g_channels[UART_CHANNEL_U1].huart = &huart3;
g_channels[UART_CHANNEL_CLIENT].huart = &huart3; g_channels[UART_CHANNEL_U0].config.baudrate = UART_DEFAULT_BAUDRATE;
g_channels[UART_CHANNEL_U1].config.baudrate = UART_DEFAULT_BAUDRATE;
apply_default_config(&g_channels[UART_CHANNEL_SERVER]); g_channels[UART_CHANNEL_U0].initialized = true;
apply_default_config(&g_channels[UART_CHANNEL_CLIENT]); g_channels[UART_CHANNEL_U1].initialized = true;
g_channels[UART_CHANNEL_SERVER].initialized = true;
g_channels[UART_CHANNEL_CLIENT].initialized = true;
return 0; return 0;
} }
@@ -167,7 +132,6 @@ int uart_trans_config(uart_channel_t channel, const uart_config_t *config)
if (channel >= UART_CHANNEL_MAX || config == NULL) { if (channel >= UART_CHANNEL_MAX || config == NULL) {
return -1; return -1;
} }
g_channels[channel].config = *config; g_channels[channel].config = *config;
return apply_uart_config(channel); return apply_uart_config(channel);
} }
@@ -208,29 +172,16 @@ int uart_trans_stop(uart_channel_t channel)
if (channel >= UART_CHANNEL_MAX) { if (channel >= UART_CHANNEL_MAX) {
return -1; return -1;
} }
HAL_UART_DMAStop(g_channels[channel].huart); HAL_UART_DMAStop(g_channels[channel].huart);
g_channels[channel].running = false; g_channels[channel].running = false;
g_channels[channel].tx_busy = false; g_channels[channel].tx_busy = false;
return 0; return 0;
} }
void uart_trans_get_stats(uart_channel_t channel, uart_stats_t *stats) void uart_trans_poll(void)
{ {
if (channel >= UART_CHANNEL_MAX || stats == NULL) { kick_tx(UART_CHANNEL_U0);
return; kick_tx(UART_CHANNEL_U1);
}
*stats = g_channels[channel].stats;
}
void uart_trans_reset_stats(uart_channel_t channel)
{
if (channel >= UART_CHANNEL_MAX) {
return;
}
memset(&g_channels[channel].stats, 0, sizeof(g_channels[channel].stats));
} }
uint16_t uart_trans_rx_available(uart_channel_t channel) uint16_t uart_trans_rx_available(uart_channel_t channel)
@@ -238,7 +189,6 @@ uint16_t uart_trans_rx_available(uart_channel_t channel)
if (channel >= UART_CHANNEL_MAX) { if (channel >= UART_CHANNEL_MAX) {
return 0u; return 0u;
} }
return ring_used(g_channels[channel].rx_head, g_channels[channel].rx_tail, UART_RX_RING_BUFFER_SIZE); return ring_used(g_channels[channel].rx_head, g_channels[channel].rx_tail, UART_RX_RING_BUFFER_SIZE);
} }
@@ -256,11 +206,9 @@ uint16_t uart_trans_read(uart_channel_t channel, uint8_t *data, uint16_t max_len
data[copied++] = ctx->rx_ring[ctx->rx_tail]; data[copied++] = ctx->rx_ring[ctx->rx_tail];
ctx->rx_tail = (uint16_t)((ctx->rx_tail + 1u) % UART_RX_RING_BUFFER_SIZE); ctx->rx_tail = (uint16_t)((ctx->rx_tail + 1u) % UART_RX_RING_BUFFER_SIZE);
} }
if (copied > 0u) { if (copied > 0u) {
ctx->stats.rx_packets++; ctx->stats.rx_packets++;
} }
return copied; return copied;
} }
@@ -287,10 +235,18 @@ uint16_t uart_trans_write(uart_channel_t channel, const uint8_t *data, uint16_t
return written; return written;
} }
void uart_trans_poll(void) void uart_trans_get_stats(uart_channel_t channel, uart_stats_t *stats)
{ {
kick_tx(UART_CHANNEL_SERVER); if (channel < UART_CHANNEL_MAX && stats != NULL) {
kick_tx(UART_CHANNEL_CLIENT); *stats = g_channels[channel].stats;
}
}
void uart_trans_reset_stats(uart_channel_t channel)
{
if (channel < UART_CHANNEL_MAX) {
memset(&g_channels[channel].stats, 0, sizeof(g_channels[channel].stats));
}
} }
void uart_trans_idle_handler(uart_channel_t channel) void uart_trans_idle_handler(uart_channel_t channel)
@@ -301,14 +257,12 @@ void uart_trans_idle_handler(uart_channel_t channel)
if (channel >= UART_CHANNEL_MAX) { if (channel >= UART_CHANNEL_MAX) {
return; return;
} }
huart = g_channels[channel].huart; huart = g_channels[channel].huart;
g_channels[channel].stats.idle_events++; g_channels[channel].stats.idle_events++;
dma_write_index = (uint16_t)(UART_RX_DMA_BUFFER_SIZE - __HAL_DMA_GET_COUNTER(huart->hdmarx)); dma_write_index = (uint16_t)(UART_RX_DMA_BUFFER_SIZE - __HAL_DMA_GET_COUNTER(huart->hdmarx));
if (dma_write_index >= UART_RX_DMA_BUFFER_SIZE) { if (dma_write_index >= UART_RX_DMA_BUFFER_SIZE) {
dma_write_index = 0u; dma_write_index = 0u;
} }
process_rx_snapshot(channel, dma_write_index); process_rx_snapshot(channel, dma_write_index);
} }
@@ -317,7 +271,6 @@ void uart_trans_rx_half_cplt_handler(uart_channel_t channel)
if (channel >= UART_CHANNEL_MAX) { if (channel >= UART_CHANNEL_MAX) {
return; return;
} }
g_channels[channel].stats.rx_half_events++; g_channels[channel].stats.rx_half_events++;
process_rx_snapshot(channel, UART_RX_DMA_BUFFER_SIZE / 2u); process_rx_snapshot(channel, UART_RX_DMA_BUFFER_SIZE / 2u);
} }
@@ -327,7 +280,6 @@ void uart_trans_rx_cplt_handler(uart_channel_t channel)
if (channel >= UART_CHANNEL_MAX) { if (channel >= UART_CHANNEL_MAX) {
return; return;
} }
g_channels[channel].stats.rx_full_events++; g_channels[channel].stats.rx_full_events++;
process_rx_snapshot(channel, 0u); process_rx_snapshot(channel, 0u);
} }
@@ -337,9 +289,88 @@ void uart_trans_tx_cplt_handler(uart_channel_t channel)
if (channel >= UART_CHANNEL_MAX) { if (channel >= UART_CHANNEL_MAX) {
return; return;
} }
g_channels[channel].tx_busy = false; g_channels[channel].tx_busy = false;
g_channels[channel].stats.tx_bytes += g_channels[channel].tx_dma_len; g_channels[channel].stats.tx_bytes += g_channels[channel].tx_dma_len;
g_channels[channel].tx_dma_len = 0u; g_channels[channel].tx_dma_len = 0u;
kick_tx(channel); kick_tx(channel);
} }
bool uart_mux_try_extract_frame(uart_channel_t channel, uart_mux_frame_t *frame)
{
uint8_t header[5];
uint16_t available;
uint16_t payload_len;
if (channel >= UART_CHANNEL_MAX || frame == NULL) {
return false;
}
available = uart_trans_rx_available(channel);
if (available < 6u) {
return false;
}
if (uart_trans_read(channel, header, sizeof(header)) != sizeof(header)) {
return false;
}
if (header[0] != UART_MUX_SYNC) {
return false;
}
payload_len = (uint16_t)(((uint16_t)header[1] << 8) | header[2]);
if (payload_len > sizeof(frame->payload)) {
return false;
}
if (uart_trans_rx_available(channel) < (uint16_t)(payload_len + 1u)) {
return false;
}
frame->src_id = header[3];
frame->dst_mask = header[4];
frame->payload_len = payload_len;
if (payload_len > 0u) {
if (uart_trans_read(channel, frame->payload, payload_len) != payload_len) {
return false;
}
}
{
uint8_t tail = 0u;
if (uart_trans_read(channel, &tail, 1u) != 1u || tail != UART_MUX_TAIL) {
return false;
}
}
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;
if (out == NULL || out_len == NULL) {
return false;
}
frame_len = (uint16_t)(payload_len + 6u);
if (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;
}
+22 -14
View File
@@ -1,6 +1,6 @@
/** /**
* @file uart_trans.h * @file uart_trans.h
* @brief Bare-metal UART DMA/IDLE transport layer. * @brief Bare-metal UART DMA/IDLE transport and MUX framing helpers.
*/ */
#ifndef __UART_TRANS_H__ #ifndef __UART_TRANS_H__
@@ -14,28 +14,28 @@ extern "C" {
#endif #endif
typedef enum { typedef enum {
UART_CHANNEL_SERVER = 0, UART_CHANNEL_U0 = 0,
UART_CHANNEL_CLIENT = 1, UART_CHANNEL_U1 = 1,
UART_CHANNEL_MAX UART_CHANNEL_MAX
} uart_channel_t; } uart_channel_t;
typedef struct {
uint8_t src_id;
uint8_t dst_mask;
uint16_t payload_len;
uint8_t payload[256];
} uart_mux_frame_t;
#define UART_RX_DMA_BUFFER_SIZE 128u #define UART_RX_DMA_BUFFER_SIZE 128u
#define UART_TX_DMA_BUFFER_SIZE 128u #define UART_TX_DMA_BUFFER_SIZE 128u
#define UART_RX_RING_BUFFER_SIZE 512u #define UART_RX_RING_BUFFER_SIZE 256u
#define UART_TX_RING_BUFFER_SIZE 512u #define UART_TX_RING_BUFFER_SIZE 256u
#define UART_DEFAULT_BAUDRATE 115200u
typedef struct { typedef struct {
uint32_t baudrate; uint32_t baudrate;
uint8_t data_bits;
uint8_t stop_bits;
uint8_t parity;
} uart_config_t; } uart_config_t;
#define UART_DEFAULT_BAUDRATE 115200u
#define UART_DEFAULT_DATA_BITS 8u
#define UART_DEFAULT_STOP_BITS 1u
#define UART_DEFAULT_PARITY 0u
typedef struct { typedef struct {
uint32_t rx_bytes; uint32_t rx_bytes;
uint32_t tx_bytes; uint32_t tx_bytes;
@@ -61,9 +61,17 @@ void uart_trans_idle_handler(uart_channel_t channel);
void uart_trans_rx_half_cplt_handler(uart_channel_t channel); void uart_trans_rx_half_cplt_handler(uart_channel_t channel);
void uart_trans_rx_cplt_handler(uart_channel_t channel); void uart_trans_rx_cplt_handler(uart_channel_t channel);
void uart_trans_tx_cplt_handler(uart_channel_t channel); 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_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);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif #endif /* __UART_TRANS_H__ */
+299 -213
View File
@@ -4,16 +4,6 @@
* @file : main.c * @file : main.c
* @brief : Main program body * @brief : Main program body
****************************************************************************** ******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/ */
/* USER CODE END Header */ /* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/ /* Includes ------------------------------------------------------------------*/
@@ -34,7 +24,6 @@
#include "CH390_Interface.h" #include "CH390_Interface.h"
#include "SEGGER_RTT.h" #include "SEGGER_RTT.h"
#include "config.h" #include "config.h"
#include "flash_param.h"
#include "ethernetif.h" #include "ethernetif.h"
#include "ch390_runtime.h" #include "ch390_runtime.h"
#include "lwip/init.h" #include "lwip/init.h"
@@ -44,71 +33,22 @@
#include "uart_trans.h" #include "uart_trans.h"
/* USER CODE END Includes */ /* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */ /* USER CODE BEGIN PD */
/* LED 指示灯 */
#define LED_PIN GPIO_PIN_13 #define LED_PIN GPIO_PIN_13
#define LED_PORT GPIOC #define LED_PORT GPIOC
#define APP_ROUTE_BUFFER_SIZE 256u
#define STACK_GUARD_WORD 0xA5A5A5A5u
/* USER CODE END PD */ /* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */ /* USER CODE BEGIN PV */
static volatile uint16_t g_led_blink_ticks = 0; static volatile uint16_t g_led_blink_ticks = 0;
static uint8_t g_clock_fallback_to_hsi = 0u; static uint8_t g_clock_fallback_to_hsi = 0u;
volatile uint8_t g_uart1_rx_probe_byte = 0u; volatile uint8_t g_uart1_rx_probe_byte = 0u;
static uint8_t g_stack_guard_reported = 0u;
typedef struct { static uint8_t g_mux_response_frame[272];
uint8_t data[256]; static uint8_t g_links_started = 0u;
uint16_t len;
} tcp_bridge_buffer_t;
static tcp_bridge_buffer_t g_server_to_client;
static tcp_bridge_buffer_t g_client_to_server;
static void App_ForwardTcpPair(void)
{
int rc;
if ((g_server_to_client.len == 0u) && tcp_server_is_connected()) {
rc = tcp_server_recv(g_server_to_client.data, sizeof(g_server_to_client.data), 0u);
if (rc > 0) {
g_server_to_client.len = (uint16_t)rc;
}
}
if ((g_server_to_client.len != 0u) && tcp_client_is_connected()) {
rc = tcp_client_send(g_server_to_client.data, g_server_to_client.len);
if (rc == (int)g_server_to_client.len) {
g_server_to_client.len = 0u;
}
}
if ((g_client_to_server.len == 0u) && tcp_client_is_connected()) {
rc = tcp_client_recv(g_client_to_server.data, sizeof(g_client_to_server.data), 0u);
if (rc > 0) {
g_client_to_server.len = (uint16_t)rc;
}
}
if ((g_client_to_server.len != 0u) && tcp_server_is_connected()) {
rc = tcp_server_send(g_client_to_server.data, g_client_to_server.len);
if (rc == (int)g_client_to_server.len) {
g_client_to_server.len = 0u;
}
}
}
/* USER CODE END PV */ /* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/ /* Private function prototypes -----------------------------------------------*/
@@ -120,20 +60,42 @@ static void BootDiag_ReportCh390(void);
static void App_PollUart1ConfigRx(void); static void App_PollUart1ConfigRx(void);
static void App_Init(void); static void App_Init(void);
static void App_Poll(void); static void App_Poll(void);
static void App_ConfigureLinks(const device_config_t *cfg);
static void App_RouteRawUartTraffic(void);
static void App_RouteMuxUartTraffic(void);
static void App_RouteTcpTraffic(void);
static void StackGuard_Init(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);
/* USER CODE END PFP */ /* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/ /* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */ /* USER CODE BEGIN 0 */
extern uint32_t Stack_Mem[];
/**
* @brief LED 初始化(点亮表示系统启动)
*/
static void LED_Init(void) static void LED_Init(void)
{ {
/* LED 灭(PC13 高电平灭,低电平亮) */
HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_SET); HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_SET);
} }
static void StackGuard_Init(void)
{
Stack_Mem[0] = STACK_GUARD_WORD;
g_stack_guard_reported = 0u;
}
static void StackGuard_Check(void)
{
if (Stack_Mem[0] != STACK_GUARD_WORD) {
if (g_stack_guard_reported == 0u) {
g_stack_guard_reported = 1u;
SEGGER_RTT_WriteString(0, "ERROR: Main stack guard overwritten\r\n");
}
__disable_irq();
NVIC_SystemReset();
}
}
static void LED_StartBlink(void) static void LED_StartBlink(void)
{ {
if (HAL_TIM_Base_Start_IT(&htim4) != HAL_OK) { if (HAL_TIM_Base_Start_IT(&htim4) != HAL_OK) {
@@ -141,9 +103,6 @@ static void LED_StartBlink(void)
} }
} }
/**
* @brief LED 闪烁(用于指示系统运行状态)
*/
void LED_Toggle(void) void LED_Toggle(void)
{ {
HAL_GPIO_TogglePin(LED_PORT, LED_PIN); HAL_GPIO_TogglePin(LED_PORT, LED_PIN);
@@ -177,13 +136,11 @@ static void BootDiag_ReportCh390(void)
diag.link_up, diag.link_up,
mac_hw[0], mac_hw[1], mac_hw[2], mac_hw[3], mac_hw[4], mac_hw[5]); mac_hw[0], mac_hw[1], mac_hw[2], mac_hw[3], mac_hw[4], mac_hw[5]);
SEGGER_RTT_printf(0, SEGGER_RTT_printf(0,
"NET cfg IP=%u.%u.%u.%u MASK=%u.%u.%u.%u GW=%u.%u.%u.%u SrvPort=%u Cli=%u.%u.%u.%u:%u\r\n", "NET cfg IP=%u.%u.%u.%u MASK=%u.%u.%u.%u GW=%u.%u.%u.%u MUX=%u\r\n",
cfg->ip[0], cfg->ip[1], cfg->ip[2], cfg->ip[3], cfg->net.ip[0], cfg->net.ip[1], cfg->net.ip[2], cfg->net.ip[3],
cfg->mask[0], cfg->mask[1], cfg->mask[2], cfg->mask[3], cfg->net.mask[0], cfg->net.mask[1], cfg->net.mask[2], cfg->net.mask[3],
cfg->gw[0], cfg->gw[1], cfg->gw[2], cfg->gw[3], cfg->net.gw[0], cfg->net.gw[1], cfg->net.gw[2], cfg->net.gw[3],
cfg->server_port, cfg->mux_mode);
cfg->remote_ip[0], cfg->remote_ip[1], cfg->remote_ip[2], cfg->remote_ip[3],
cfg->remote_port);
} }
static void App_PollUart1ConfigRx(void) static void App_PollUart1ConfigRx(void)
@@ -194,97 +151,302 @@ static void App_PollUart1ConfigRx(void)
} }
} }
static void App_ConfigureLinks(const device_config_t *cfg)
{
tcp_server_instance_config_t server_cfg;
tcp_client_instance_config_t client_cfg;
(void)tcp_server_init_all();
(void)tcp_client_init_all();
server_cfg.enabled = (cfg->links[CONFIG_LINK_S1].enabled != 0u);
server_cfg.port = cfg->links[CONFIG_LINK_S1].local_port;
(void)tcp_server_config(0u, &server_cfg);
server_cfg.enabled = (cfg->links[CONFIG_LINK_S2].enabled != 0u);
server_cfg.port = cfg->links[CONFIG_LINK_S2].local_port;
(void)tcp_server_config(1u, &server_cfg);
memcpy(client_cfg.remote_ip, cfg->links[CONFIG_LINK_C1].remote_ip, sizeof(client_cfg.remote_ip));
client_cfg.local_port = cfg->links[CONFIG_LINK_C1].local_port;
client_cfg.remote_port = cfg->links[CONFIG_LINK_C1].remote_port;
client_cfg.reconnect_interval_ms = TCP_CLIENT_RECONNECT_DELAY_MS;
client_cfg.enabled = (cfg->links[CONFIG_LINK_C1].enabled != 0u);
client_cfg.auto_reconnect = true;
(void)tcp_client_config(0u, &client_cfg);
memcpy(client_cfg.remote_ip, cfg->links[CONFIG_LINK_C2].remote_ip, sizeof(client_cfg.remote_ip));
client_cfg.local_port = cfg->links[CONFIG_LINK_C2].local_port;
client_cfg.remote_port = cfg->links[CONFIG_LINK_C2].remote_port;
client_cfg.enabled = (cfg->links[CONFIG_LINK_C2].enabled != 0u);
(void)tcp_client_config(1u, &client_cfg);
}
static void App_StartLinksIfNeeded(void)
{
if ((g_links_started != 0u) || !netif_is_link_up(&ch390_netif)) {
return;
}
for (uint8_t i = 0; i < TCP_SERVER_INSTANCE_COUNT; ++i) {
(void)tcp_server_start(i);
}
for (uint8_t i = 0; i < TCP_CLIENT_INSTANCE_COUNT; ++i) {
(void)tcp_client_connect(i);
}
g_links_started = 1u;
SEGGER_RTT_WriteString(0, "NET links started after link-up\r\n");
}
static void App_StopLinksIfNeeded(void)
{
if (netif_is_link_up(&ch390_netif)) {
return;
}
if (g_links_started != 0u) {
for (uint8_t i = 0; i < TCP_CLIENT_INSTANCE_COUNT; ++i) {
(void)tcp_client_disconnect(i);
}
for (uint8_t i = 0; i < TCP_SERVER_INSTANCE_COUNT; ++i) {
(void)tcp_server_stop(i);
}
SEGGER_RTT_WriteString(0, "NET links stopped after link-down\r\n");
}
g_links_started = 0u;
}
static void App_Init(void) static void App_Init(void)
{ {
device_config_t *cfg_mut;
const device_config_t *cfg; const device_config_t *cfg;
ip4_addr_t ipaddr; ip4_addr_t ipaddr;
ip4_addr_t netmask; ip4_addr_t netmask;
ip4_addr_t gateway; ip4_addr_t gateway;
uart_config_t uart_cfg; uart_config_t uart_cfg;
tcp_server_config_t server_cfg;
tcp_client_config_t client_cfg;
config_init(); (void)config_init();
cfg_mut = config_get_mutable();
cfg_mut->dhcp_enable = 0u;
cfg_mut->ip[0] = 192u;
cfg_mut->ip[1] = 168u;
cfg_mut->ip[2] = 31u;
cfg_mut->ip[3] = 100u;
cfg_mut->mask[0] = 255u;
cfg_mut->mask[1] = 255u;
cfg_mut->mask[2] = 255u;
cfg_mut->mask[3] = 0u;
cfg_mut->gw[0] = 192u;
cfg_mut->gw[1] = 168u;
cfg_mut->gw[2] = 31u;
cfg_mut->gw[3] = 1u;
cfg_mut->server_port = 8080u;
cfg_mut->remote_port = 8081u;
cfg = config_get(); cfg = config_get();
uart_trans_init(); (void)uart_trans_init();
uart_cfg.baudrate = cfg->uart_baudrate[0];
uart_cfg.baudrate = cfg->uart2_baudrate; (void)uart_trans_config(UART_CHANNEL_U0, &uart_cfg);
uart_cfg.data_bits = cfg->uart2_databits; uart_cfg.baudrate = cfg->uart_baudrate[1];
uart_cfg.stop_bits = cfg->uart2_stopbits; (void)uart_trans_config(UART_CHANNEL_U1, &uart_cfg);
uart_cfg.parity = cfg->uart2_parity; (void)uart_trans_start(UART_CHANNEL_U0);
uart_trans_config(UART_CHANNEL_SERVER, &uart_cfg); (void)uart_trans_start(UART_CHANNEL_U1);
uart_cfg.baudrate = cfg->uart3_baudrate;
uart_cfg.data_bits = cfg->uart3_databits;
uart_cfg.stop_bits = cfg->uart3_stopbits;
uart_cfg.parity = cfg->uart3_parity;
uart_trans_config(UART_CHANNEL_CLIENT, &uart_cfg);
uart_trans_start(UART_CHANNEL_SERVER);
uart_trans_start(UART_CHANNEL_CLIENT);
SEGGER_RTT_Init(); SEGGER_RTT_Init();
StackGuard_Init();
SEGGER_RTT_WriteString(0, "\r\nTCP2UART boot\r\n"); SEGGER_RTT_WriteString(0, "\r\nTCP2UART boot\r\n");
if (g_clock_fallback_to_hsi != 0u) { if (g_clock_fallback_to_hsi != 0u) {
SEGGER_RTT_WriteString(0, "WARN: HSE start failed, fallback to HSI PLL\r\n"); SEGGER_RTT_WriteString(0, "WARN: HSE start failed, fallback to HSI PLL\r\n");
} }
lwip_init(); lwip_init();
IP4_ADDR(&ipaddr, cfg->ip[0], cfg->ip[1], cfg->ip[2], cfg->ip[3]); IP4_ADDR(&ipaddr, cfg->net.ip[0], cfg->net.ip[1], cfg->net.ip[2], cfg->net.ip[3]);
IP4_ADDR(&netmask, cfg->mask[0], cfg->mask[1], cfg->mask[2], cfg->mask[3]); IP4_ADDR(&netmask, cfg->net.mask[0], cfg->net.mask[1], cfg->net.mask[2], cfg->net.mask[3]);
IP4_ADDR(&gateway, cfg->gw[0], cfg->gw[1], cfg->gw[2], cfg->gw[3]); IP4_ADDR(&gateway, cfg->net.gw[0], cfg->net.gw[1], cfg->net.gw[2], cfg->net.gw[3]);
lwip_netif_init(&ipaddr, &netmask, &gateway); lwip_netif_init(&ipaddr, &netmask, &gateway);
App_ConfigureLinks(cfg);
BootDiag_ReportCh390(); BootDiag_ReportCh390();
server_cfg.port = cfg->server_port;
server_cfg.auto_reconnect = true;
(void)tcp_server_init(&server_cfg);
(void)tcp_server_start();
memcpy(client_cfg.server_ip, cfg->remote_ip, sizeof(client_cfg.server_ip));
client_cfg.local_port = 8081u;
client_cfg.server_port = cfg->remote_port;
client_cfg.auto_reconnect = true;
client_cfg.reconnect_interval_ms = cfg->reconnect_interval;
(void)tcp_client_init(&client_cfg);
(void)tcp_client_connect();
SEGGER_RTT_WriteString(0, "TCP bridge enabled\r\n");
/* Arm UART1 RX interrupt path so config commands can enter via USART1. */
if (HAL_UART_Receive_IT(&huart1, (uint8_t *)&g_uart1_rx_probe_byte, 1u) != HAL_OK) { if (HAL_UART_Receive_IT(&huart1, (uint8_t *)&g_uart1_rx_probe_byte, 1u) != HAL_OK) {
Error_Handler(); Error_Handler();
} }
} }
static void 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();
uart_channel_t channel = (uart_index == LINK_UART_U1) ? UART_CHANNEL_U1 : UART_CHANNEL_U0;
if (cfg->mux_mode == MUX_MODE_FRAME) {
uint8_t frame[APP_ROUTE_BUFFER_SIZE + 6u];
uint16_t frame_len = 0u;
if (uart_mux_encode_frame(src_id, dst_mask, data, len, frame, &frame_len, sizeof(frame))) {
(void)uart_trans_write(channel, frame, frame_len);
}
} else {
(void)uart_trans_write(channel, data, len);
}
}
static void App_RouteTcpTraffic(void)
{
const device_config_t *cfg = config_get();
uint8_t buffer[APP_ROUTE_BUFFER_SIZE];
for (uint8_t i = 0; i < TCP_SERVER_INSTANCE_COUNT; ++i) {
int rc = tcp_server_recv(i, buffer, sizeof(buffer));
if (rc > 0) {
uint8_t link_index = (i == 0u) ? CONFIG_LINK_S1 : CONFIG_LINK_S2;
App_SendToUart(cfg->links[link_index].uart,
config_link_index_to_endpoint(link_index),
config_uart_index_to_endpoint(cfg->links[link_index].uart),
buffer,
(uint16_t)rc);
}
}
for (uint8_t i = 0; i < TCP_CLIENT_INSTANCE_COUNT; ++i) {
int rc = tcp_client_recv(i, buffer, sizeof(buffer));
if (rc > 0) {
uint8_t link_index = (i == 0u) ? CONFIG_LINK_C1 : CONFIG_LINK_C2;
App_SendToUart(cfg->links[link_index].uart,
config_link_index_to_endpoint(link_index),
config_uart_index_to_endpoint(cfg->links[link_index].uart),
buffer,
(uint16_t)rc);
}
}
}
static void App_RouteRawUartTraffic(void)
{
const device_config_t *cfg = config_get();
uint8_t buffer[APP_ROUTE_BUFFER_SIZE];
uint16_t len;
len = uart_trans_read(UART_CHANNEL_U0, buffer, sizeof(buffer));
if (len > 0u) {
for (uint8_t i = 0; i < CONFIG_LINK_COUNT; ++i) {
if (cfg->links[i].enabled == 0u || cfg->links[i].uart != LINK_UART_U0) {
continue;
}
if (i == CONFIG_LINK_S1) {
(void)tcp_server_send(0u, buffer, len);
} else if (i == CONFIG_LINK_S2) {
(void)tcp_server_send(1u, buffer, len);
} else if (i == CONFIG_LINK_C1) {
(void)tcp_client_send(0u, buffer, len);
} else if (i == CONFIG_LINK_C2) {
(void)tcp_client_send(1u, buffer, len);
}
}
}
len = uart_trans_read(UART_CHANNEL_U1, buffer, sizeof(buffer));
if (len > 0u) {
for (uint8_t i = 0; i < CONFIG_LINK_COUNT; ++i) {
if (cfg->links[i].enabled == 0u || cfg->links[i].uart != LINK_UART_U1) {
continue;
}
if (i == CONFIG_LINK_S1) {
(void)tcp_server_send(0u, buffer, len);
} else if (i == CONFIG_LINK_S2) {
(void)tcp_server_send(1u, buffer, len);
} else if (i == CONFIG_LINK_C1) {
(void)tcp_client_send(0u, buffer, len);
} else if (i == CONFIG_LINK_C2) {
(void)tcp_client_send(1u, buffer, len);
}
}
}
}
static void App_RouteMuxUartTraffic(void)
{
uart_mux_frame_t frame;
const device_config_t *cfg = config_get();
while (uart_mux_try_extract_frame(UART_CHANNEL_U0, &frame)) {
if (frame.dst_mask == 0u) {
at_result_t result;
char *response_text = (char *)&g_mux_response_frame[5];
if (config_build_response_frame(frame.payload, frame.payload_len, response_text, (uint16_t)(sizeof(g_mux_response_frame) - 6u), &result)) {
uint16_t response_len = (uint16_t)strlen(response_text);
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))) {
(void)uart_trans_write(UART_CHANNEL_U0, g_mux_response_frame, frame_len);
}
if (result == AT_NEED_REBOOT) {
static const char hint[] = "Note: Use AT+SAVE then AT+RESET to apply changes\r\n";
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))) {
(void)uart_trans_write(UART_CHANNEL_U0, g_mux_response_frame, frame_len);
}
}
}
continue;
}
if ((frame.dst_mask & ENDPOINT_S1) != 0u) {
(void)tcp_server_send(0u, frame.payload, frame.payload_len);
}
if ((frame.dst_mask & ENDPOINT_S2) != 0u) {
(void)tcp_server_send(1u, frame.payload, frame.payload_len);
}
if ((frame.dst_mask & ENDPOINT_C1) != 0u) {
(void)tcp_client_send(0u, frame.payload, frame.payload_len);
}
if ((frame.dst_mask & ENDPOINT_C2) != 0u) {
(void)tcp_client_send(1u, frame.payload, frame.payload_len);
}
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);
}
}
while (uart_mux_try_extract_frame(UART_CHANNEL_U1, &frame)) {
if (frame.dst_mask == 0u) {
at_result_t result;
char *response_text = (char *)&g_mux_response_frame[5];
if (config_build_response_frame(frame.payload, frame.payload_len, response_text, (uint16_t)(sizeof(g_mux_response_frame) - 6u), &result)) {
uint16_t response_len = (uint16_t)strlen(response_text);
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))) {
(void)uart_trans_write(UART_CHANNEL_U1, g_mux_response_frame, frame_len);
}
if (result == AT_NEED_REBOOT) {
static const char hint[] = "Note: Use AT+SAVE then AT+RESET to apply changes\r\n";
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))) {
(void)uart_trans_write(UART_CHANNEL_U1, g_mux_response_frame, frame_len);
}
}
}
continue;
}
if ((frame.dst_mask & ENDPOINT_S1) != 0u) {
(void)tcp_server_send(0u, frame.payload, frame.payload_len);
}
if ((frame.dst_mask & ENDPOINT_S2) != 0u) {
(void)tcp_server_send(1u, frame.payload, frame.payload_len);
}
if ((frame.dst_mask & ENDPOINT_C1) != 0u) {
(void)tcp_client_send(0u, frame.payload, frame.payload_len);
}
if ((frame.dst_mask & ENDPOINT_C2) != 0u) {
(void)tcp_client_send(1u, frame.payload, frame.payload_len);
}
if ((frame.dst_mask & ENDPOINT_UART2) != 0u) {
App_SendToUart(LINK_UART_U0, frame.src_id, ENDPOINT_UART2, frame.payload, frame.payload_len);
}
}
}
static void App_Poll(void) static void App_Poll(void)
{ {
ethernetif_poll(); ethernetif_poll();
ethernetif_check_link(); ethernetif_check_link();
sys_check_timeouts(); sys_check_timeouts();
App_StopLinksIfNeeded();
App_StartLinksIfNeeded();
tcp_client_poll(); tcp_client_poll();
App_ForwardTcpPair();
uart_trans_poll(); uart_trans_poll();
App_PollUart1ConfigRx(); App_PollUart1ConfigRx();
StackGuard_Check();
config_poll(); config_poll();
App_RouteTcpTraffic();
if (config_get()->mux_mode == MUX_MODE_FRAME) {
App_RouteMuxUartTraffic();
} else {
App_RouteRawUartTraffic();
}
if (config_is_reset_requested()) { if (config_is_reset_requested()) {
config_clear_reset_requested(); config_clear_reset_requested();
@@ -295,81 +457,36 @@ static void App_Poll(void)
HAL_IWDG_Refresh(&hiwdg); HAL_IWDG_Refresh(&hiwdg);
} }
} }
/* USER CODE END 0 */ /* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void) int main(void)
{ {
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init(); HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config(); SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init(); MX_GPIO_Init();
MX_DMA_Init(); MX_DMA_Init();
// MX_IWDG_Init();
MX_USART1_UART_Init(); MX_USART1_UART_Init();
MX_USART2_UART_Init(); MX_USART2_UART_Init();
MX_USART3_UART_Init(); MX_USART3_UART_Init();
MX_SPI1_Init(); MX_SPI1_Init();
MX_TIM4_Init(); MX_TIM4_Init();
/* USER CODE BEGIN 2 */
/* LED 初始化 */
LED_Init(); LED_Init();
LED_StartBlink(); LED_StartBlink();
App_Init(); App_Init();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1) while (1)
{ {
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
App_Poll(); App_Poll();
} }
/* USER CODE END 3 */
} }
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void) void SystemClock_Config(void)
{ {
RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
g_clock_fallback_to_hsi = 0u; g_clock_fallback_to_hsi = 0u;
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
@@ -379,11 +496,6 @@ void SystemClock_Config(void)
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
/*
* Some bring-up boards fail to start the external crystal cleanly.
* Fall back to HSI-based PLL so the firmware can still boot and expose
* RTT / debugger evidence instead of trapping during clock init.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSEState = RCC_HSE_OFF; RCC_OscInitStruct.HSEState = RCC_HSE_OFF;
RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSIState = RCC_HSI_ON;
@@ -397,8 +509,6 @@ void SystemClock_Config(void)
g_clock_fallback_to_hsi = 1u; g_clock_fallback_to_hsi = 1u;
} }
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
@@ -412,11 +522,6 @@ void SystemClock_Config(void)
} }
} }
/* USER CODE BEGIN 4 */
/**
* @brief 重定向 printf 到 UART1(调试输出)
*/
#ifdef __GNUC__ #ifdef __GNUC__
int _write(int file, char *ptr, int len) int _write(int file, char *ptr, int len)
{ {
@@ -444,35 +549,16 @@ void Debug_TrapWithRttHint(const char *tag)
} }
} }
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void) void Error_Handler(void)
{ {
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
Debug_TrapWithRttHint("Error_Handler"); Debug_TrapWithRttHint("Error_Handler");
/* USER CODE END Error_Handler_Debug */
} }
#ifdef USE_FULL_ASSERT #ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line) void assert_failed(uint8_t *file, uint32_t line)
{ {
/* USER CODE BEGIN 6 */
(void)file; (void)file;
(void)line; (void)line;
Debug_TrapWithRttHint("assert_failed"); Debug_TrapWithRttHint("assert_failed");
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
} }
#endif /* USE_FULL_ASSERT */ #endif
+10 -236
View File
@@ -4,62 +4,15 @@
* @file stm32f1xx_it.c * @file stm32f1xx_it.c
* @brief Interrupt Service Routines. * @brief Interrupt Service Routines.
****************************************************************************** ******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/ */
/* USER CODE END Header */ /* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h" #include "main.h"
#include "stm32f1xx_it.h" #include "stm32f1xx_it.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "ethernetif.h" #include "ethernetif.h"
#include "ch390_runtime.h"
#include "SEGGER_RTT.h"
#include "uart_trans.h" #include "uart_trans.h"
#include "config.h" #include "config.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN TD */
/* USER CODE END TD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/* External variables --------------------------------------------------------*/
extern SPI_HandleTypeDef hspi1; extern SPI_HandleTypeDef hspi1;
extern TIM_HandleTypeDef htim4; extern TIM_HandleTypeDef htim4;
extern DMA_HandleTypeDef hdma_usart1_rx; extern DMA_HandleTypeDef hdma_usart1_rx;
@@ -71,332 +24,153 @@ extern DMA_HandleTypeDef hdma_usart3_tx;
extern UART_HandleTypeDef huart1; extern UART_HandleTypeDef huart1;
extern UART_HandleTypeDef huart2; extern UART_HandleTypeDef huart2;
extern UART_HandleTypeDef huart3; extern UART_HandleTypeDef huart3;
/* USER CODE BEGIN EV */ extern volatile uint8_t g_uart1_rx_probe_byte;
/* USER CODE END EV */
/******************************************************************************/
/* Cortex-M3 Processor Interruption and Exception Handlers */
/******************************************************************************/
/**
* @brief This function handles Non maskable interrupt.
*/
void NMI_Handler(void) void NMI_Handler(void)
{ {
/* USER CODE BEGIN NonMaskableInt_IRQn 0 */
/* USER CODE END NonMaskableInt_IRQn 0 */
/* USER CODE BEGIN NonMaskableInt_IRQn 1 */
Debug_TrapWithRttHint("NMI_Handler"); Debug_TrapWithRttHint("NMI_Handler");
/* USER CODE END NonMaskableInt_IRQn 1 */
} }
/**
* @brief This function handles Hard fault interrupt.
*/
void HardFault_Handler(void) void HardFault_Handler(void)
{ {
/* USER CODE BEGIN HardFault_IRQn 0 */
/* USER CODE END HardFault_IRQn 0 */
Debug_TrapWithRttHint("HardFault_Handler"); Debug_TrapWithRttHint("HardFault_Handler");
} }
/**
* @brief This function handles Memory management fault.
*/
void MemManage_Handler(void) void MemManage_Handler(void)
{ {
/* USER CODE BEGIN MemoryManagement_IRQn 0 */
/* USER CODE END MemoryManagement_IRQn 0 */
Debug_TrapWithRttHint("MemManage_Handler"); Debug_TrapWithRttHint("MemManage_Handler");
} }
/**
* @brief This function handles Prefetch fault, memory access fault.
*/
void BusFault_Handler(void) void BusFault_Handler(void)
{ {
/* USER CODE BEGIN BusFault_IRQn 0 */
/* USER CODE END BusFault_IRQn 0 */
Debug_TrapWithRttHint("BusFault_Handler"); Debug_TrapWithRttHint("BusFault_Handler");
} }
/**
* @brief This function handles Undefined instruction or illegal state.
*/
void UsageFault_Handler(void) void UsageFault_Handler(void)
{ {
/* USER CODE BEGIN UsageFault_IRQn 0 */
/* USER CODE END UsageFault_IRQn 0 */
Debug_TrapWithRttHint("UsageFault_Handler"); Debug_TrapWithRttHint("UsageFault_Handler");
} }
/**
* @brief This function handles Debug monitor.
*/
void DebugMon_Handler(void) void DebugMon_Handler(void)
{ {
/* USER CODE BEGIN DebugMonitor_IRQn 0 */
/* USER CODE END DebugMonitor_IRQn 0 */
/* USER CODE BEGIN DebugMonitor_IRQn 1 */
/* USER CODE END DebugMonitor_IRQn 1 */
} }
/**
* @brief This function handles System tick timer.
*/
void SysTick_Handler(void) void SysTick_Handler(void)
{ {
/* USER CODE BEGIN SysTick_IRQn 0 */
/* USER CODE END SysTick_IRQn 0 */
HAL_IncTick(); HAL_IncTick();
/* USER CODE BEGIN SysTick_IRQn 1 */
/* USER CODE END SysTick_IRQn 1 */
} }
/******************************************************************************/
/* STM32F1xx Peripheral Interrupt Handlers */
/* Add here the Interrupt Handlers for the used peripherals. */
/* For the available peripheral interrupt handler names, */
/* please refer to the startup file (startup_stm32f1xx.s). */
/******************************************************************************/
/**
* @brief This function handles DMA1 channel2 global interrupt.
*/
void DMA1_Channel2_IRQHandler(void) void DMA1_Channel2_IRQHandler(void)
{ {
/* USER CODE BEGIN DMA1_Channel2_IRQn 0 */
/* USER CODE END DMA1_Channel2_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_usart3_tx); HAL_DMA_IRQHandler(&hdma_usart3_tx);
/* USER CODE BEGIN DMA1_Channel2_IRQn 1 */
/* USER CODE END DMA1_Channel2_IRQn 1 */
} }
/**
* @brief This function handles DMA1 channel3 global interrupt.
*/
void DMA1_Channel3_IRQHandler(void) void DMA1_Channel3_IRQHandler(void)
{ {
/* USER CODE BEGIN DMA1_Channel3_IRQn 0 */
/* USER CODE END DMA1_Channel3_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_usart3_rx); HAL_DMA_IRQHandler(&hdma_usart3_rx);
/* USER CODE BEGIN DMA1_Channel3_IRQn 1 */
/* USER CODE END DMA1_Channel3_IRQn 1 */
} }
/**
* @brief This function handles DMA1 channel4 global interrupt.
*/
void DMA1_Channel4_IRQHandler(void) void DMA1_Channel4_IRQHandler(void)
{ {
/* USER CODE BEGIN DMA1_Channel4_IRQn 0 */
/* USER CODE END DMA1_Channel4_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_usart1_tx); HAL_DMA_IRQHandler(&hdma_usart1_tx);
/* USER CODE BEGIN DMA1_Channel4_IRQn 1 */
/* USER CODE END DMA1_Channel4_IRQn 1 */
} }
/**
* @brief This function handles DMA1 channel5 global interrupt.
*/
void DMA1_Channel5_IRQHandler(void) void DMA1_Channel5_IRQHandler(void)
{ {
/* USER CODE BEGIN DMA1_Channel5_IRQn 0 */
/* USER CODE END DMA1_Channel5_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_usart1_rx); HAL_DMA_IRQHandler(&hdma_usart1_rx);
/* USER CODE BEGIN DMA1_Channel5_IRQn 1 */
/* USER CODE END DMA1_Channel5_IRQn 1 */
} }
/**
* @brief This function handles DMA1 channel6 global interrupt.
*/
void DMA1_Channel6_IRQHandler(void) void DMA1_Channel6_IRQHandler(void)
{ {
/* USER CODE BEGIN DMA1_Channel6_IRQn 0 */
/* USER CODE END DMA1_Channel6_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_usart2_rx); HAL_DMA_IRQHandler(&hdma_usart2_rx);
/* USER CODE BEGIN DMA1_Channel6_IRQn 1 */
/* USER CODE END DMA1_Channel6_IRQn 1 */
} }
/**
* @brief This function handles DMA1 channel7 global interrupt.
*/
void DMA1_Channel7_IRQHandler(void) void DMA1_Channel7_IRQHandler(void)
{ {
/* USER CODE BEGIN DMA1_Channel7_IRQn 0 */
/* USER CODE END DMA1_Channel7_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_usart2_tx); HAL_DMA_IRQHandler(&hdma_usart2_tx);
/* USER CODE BEGIN DMA1_Channel7_IRQn 1 */
/* USER CODE END DMA1_Channel7_IRQn 1 */
} }
/**
* @brief This function handles TIM4 global interrupt.
*/
void TIM4_IRQHandler(void) void TIM4_IRQHandler(void)
{ {
/* USER CODE BEGIN TIM4_IRQn 0 */
/* USER CODE END TIM4_IRQn 0 */
HAL_TIM_IRQHandler(&htim4); HAL_TIM_IRQHandler(&htim4);
/* USER CODE BEGIN TIM4_IRQn 1 */
/* USER CODE END TIM4_IRQn 1 */
} }
/**
* @brief This function handles SPI1 global interrupt.
*/
void SPI1_IRQHandler(void) void SPI1_IRQHandler(void)
{ {
/* USER CODE BEGIN SPI1_IRQn 0 */
/* USER CODE END SPI1_IRQn 0 */
HAL_SPI_IRQHandler(&hspi1); HAL_SPI_IRQHandler(&hspi1);
/* USER CODE BEGIN SPI1_IRQn 1 */
/* USER CODE END SPI1_IRQn 1 */
} }
/**
* @brief This function handles USART1 global interrupt.
*/
void USART1_IRQHandler(void) void USART1_IRQHandler(void)
{ {
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1); HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
} }
/**
* @brief This function handles USART2 global interrupt.
*/
void USART2_IRQHandler(void) void USART2_IRQHandler(void)
{ {
/* USER CODE BEGIN USART2_IRQn 0 */
/* Handle IDLE interrupt for Server transparent transmission */
if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE)) if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE))
{ {
__HAL_UART_CLEAR_IDLEFLAG(&huart2); __HAL_UART_CLEAR_IDLEFLAG(&huart2);
uart_trans_idle_handler(UART_CHANNEL_SERVER); uart_trans_idle_handler(UART_CHANNEL_U0);
} }
/* USER CODE END USART2_IRQn 0 */
HAL_UART_IRQHandler(&huart2); HAL_UART_IRQHandler(&huart2);
/* USER CODE BEGIN USART2_IRQn 1 */
/* USER CODE END USART2_IRQn 1 */
} }
/**
* @brief This function handles USART3 global interrupt.
*/
void USART3_IRQHandler(void) void USART3_IRQHandler(void)
{ {
/* USER CODE BEGIN USART3_IRQn 0 */
/* Handle IDLE interrupt for Client transparent transmission */
if (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_IDLE)) if (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_IDLE))
{ {
__HAL_UART_CLEAR_IDLEFLAG(&huart3); __HAL_UART_CLEAR_IDLEFLAG(&huart3);
uart_trans_idle_handler(UART_CHANNEL_CLIENT); uart_trans_idle_handler(UART_CHANNEL_U1);
} }
/* USER CODE END USART3_IRQn 0 */
HAL_UART_IRQHandler(&huart3); HAL_UART_IRQHandler(&huart3);
/* USER CODE BEGIN USART3_IRQn 1 */
/* USER CODE END USART3_IRQn 1 */
} }
/* USER CODE BEGIN 1 */
extern volatile uint8_t g_uart1_rx_probe_byte;
/**
* @brief This function handles EXTI0 interrupt (CH390D INT pin).
*/
void EXTI0_IRQHandler(void) void EXTI0_IRQHandler(void)
{ {
/* Clear interrupt flag */
if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0)) if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0))
{ {
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0); __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);
/* Defer CH390 processing to main loop */
ethernetif_set_irq_pending(); ethernetif_set_irq_pending();
} }
} }
/**
* @brief HAL UART TX Complete callback
*/
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{ {
if (huart == &huart2) if (huart == &huart2)
{ {
uart_trans_tx_cplt_handler(UART_CHANNEL_SERVER); uart_trans_tx_cplt_handler(UART_CHANNEL_U0);
} }
else if (huart == &huart3) else if (huart == &huart3)
{ {
uart_trans_tx_cplt_handler(UART_CHANNEL_CLIENT); uart_trans_tx_cplt_handler(UART_CHANNEL_U1);
} }
} }
/**
* @brief HAL UART RX Complete callback
*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{ {
if (huart == &huart1) if (huart == &huart1)
{ {
config_uart_rx_byte(g_uart1_rx_probe_byte); config_uart_rx_byte(g_uart1_rx_probe_byte);
HAL_UART_Receive_IT(&huart1, (uint8_t *)&g_uart1_rx_probe_byte, 1u); (void)HAL_UART_Receive_IT(&huart1, (uint8_t *)&g_uart1_rx_probe_byte, 1u);
} }
else if (huart == &huart2) else if (huart == &huart2)
{ {
uart_trans_rx_cplt_handler(UART_CHANNEL_SERVER); uart_trans_rx_cplt_handler(UART_CHANNEL_U0);
} }
else if (huart == &huart3) else if (huart == &huart3)
{ {
uart_trans_rx_cplt_handler(UART_CHANNEL_CLIENT); uart_trans_rx_cplt_handler(UART_CHANNEL_U1);
} }
} }
/**
* @brief HAL UART RX Half Complete callback
*/
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart) void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart)
{ {
if (huart == &huart2) if (huart == &huart2)
{ {
uart_trans_rx_half_cplt_handler(UART_CHANNEL_SERVER); uart_trans_rx_half_cplt_handler(UART_CHANNEL_U0);
} }
else if (huart == &huart3) else if (huart == &huart3)
{ {
uart_trans_rx_half_cplt_handler(UART_CHANNEL_CLIENT); uart_trans_rx_half_cplt_handler(UART_CHANNEL_U1);
} }
} }
/* USER CODE END 1 */
+1 -1
View File
@@ -52,7 +52,7 @@ uint8_t ethernetif_is_irq_pending(void)
static void low_level_init(struct netif *netif) static void low_level_init(struct netif *netif)
{ {
ch390_runtime_init(netif, config_get()->mac); ch390_runtime_init(netif, config_get()->net.mac);
} }
static err_t low_level_output(struct netif *netif, struct pbuf *p) static err_t low_level_output(struct netif *netif, struct pbuf *p)
+435 -78
View File
@@ -103,7 +103,7 @@
<bEvRecOn>1</bEvRecOn> <bEvRecOn>1</bEvRecOn>
<bSchkAxf>0</bSchkAxf> <bSchkAxf>0</bSchkAxf>
<bTchkAxf>0</bTchkAxf> <bTchkAxf>0</bTchkAxf>
<nTsel>6</nTsel> <nTsel>3</nTsel>
<sDll></sDll> <sDll></sDll>
<sDllPa></sDllPa> <sDllPa></sDllPa>
<sDlgDll></sDlgDll> <sDlgDll></sDlgDll>
@@ -114,9 +114,34 @@
<tDlgDll></tDlgDll> <tDlgDll></tDlgDll>
<tDlgPa></tDlgPa> <tDlgPa></tDlgPa>
<tIfile></tIfile> <tIfile></tIfile>
<pMon>STLink\ST-LINKIII-KEIL_SWO.dll</pMon> <pMon>BIN\CMSIS_AGDI.dll</pMon>
</DebugOpt> </DebugOpt>
<TargetDriverDllRegistry> <TargetDriverDllRegistry>
<SetRegEntry>
<Number>0</Number>
<Key>ARMRTXEVENTFLAGS</Key>
<Name>-L70 -Z18 -C0 -M0 -T1</Name>
</SetRegEntry>
<SetRegEntry>
<Number>0</Number>
<Key>DLGTARM</Key>
<Name>(1010=-1,-1,-1,-1,0)(1007=-1,-1,-1,-1,0)(1008=-1,-1,-1,-1,0)(1009=-1,-1,-1,-1,0)</Name>
</SetRegEntry>
<SetRegEntry>
<Number>0</Number>
<Key>ARMDBGFLAGS</Key>
<Name></Name>
</SetRegEntry>
<SetRegEntry>
<Number>0</Number>
<Key>DLGUARM</Key>
<Name></Name>
</SetRegEntry>
<SetRegEntry>
<Number>0</Number>
<Key>CMSIS_AGDI</Key>
<Name>-X"Any" -UAny -O206 -S8 -C0 -P00000000 -N00("ARM CoreSight SW-DP") -D00(1BA01477) -L00(0) -TO65554 -TC10000000 -TT10000000 -TP20 -TDS8007 -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -FO7 -FD20000000 -FC1000 -FN1 -FF0STM32F10x_128.FLM -FS08000000 -FL020000 -FP0($$Device:STM32F103R8$Flash\STM32F10x_128.FLM)</Name>
</SetRegEntry>
<SetRegEntry> <SetRegEntry>
<Number>0</Number> <Number>0</Number>
<Key>UL2CM3</Key> <Key>UL2CM3</Key>
@@ -194,8 +219,8 @@
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>startup_stm32f103xe.s</PathWithFileName> <PathWithFileName>startup_stm32f103xb.s</PathWithFileName>
<FilenameWithoutPath>startup_stm32f103xe.s</FilenameWithoutPath> <FilenameWithoutPath>startup_stm32f103xb.s</FilenameWithoutPath>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<bShared>0</bShared> <bShared>0</bShared>
</File> </File>
@@ -238,8 +263,8 @@
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>../Core/Src/freertos.c</PathWithFileName> <PathWithFileName>../Core/Src/dma.c</PathWithFileName>
<FilenameWithoutPath>freertos.c</FilenameWithoutPath> <FilenameWithoutPath>dma.c</FilenameWithoutPath>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<bShared>0</bShared> <bShared>0</bShared>
</File> </File>
@@ -250,8 +275,8 @@
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>../Core/Src/dma.c</PathWithFileName> <PathWithFileName>../Core/Src/iwdg.c</PathWithFileName>
<FilenameWithoutPath>dma.c</FilenameWithoutPath> <FilenameWithoutPath>iwdg.c</FilenameWithoutPath>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<bShared>0</bShared> <bShared>0</bShared>
</File> </File>
@@ -262,8 +287,8 @@
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>../Core/Src/iwdg.c</PathWithFileName> <PathWithFileName>../Core/Src/tim.c</PathWithFileName>
<FilenameWithoutPath>iwdg.c</FilenameWithoutPath> <FilenameWithoutPath>tim.c</FilenameWithoutPath>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<bShared>0</bShared> <bShared>0</bShared>
</File> </File>
@@ -342,6 +367,18 @@
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_iwdg.c</PathWithFileName>
<FilenameWithoutPath>stm32f1xx_hal_iwdg.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>13</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal.c</PathWithFileName> <PathWithFileName>../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal.c</PathWithFileName>
<FilenameWithoutPath>stm32f1xx_hal.c</FilenameWithoutPath> <FilenameWithoutPath>stm32f1xx_hal.c</FilenameWithoutPath>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
@@ -349,7 +386,7 @@
</File> </File>
<File> <File>
<GroupNumber>3</GroupNumber> <GroupNumber>3</GroupNumber>
<FileNumber>13</FileNumber> <FileNumber>14</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@@ -361,7 +398,7 @@
</File> </File>
<File> <File>
<GroupNumber>3</GroupNumber> <GroupNumber>3</GroupNumber>
<FileNumber>14</FileNumber> <FileNumber>15</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@@ -373,7 +410,7 @@
</File> </File>
<File> <File>
<GroupNumber>3</GroupNumber> <GroupNumber>3</GroupNumber>
<FileNumber>15</FileNumber> <FileNumber>16</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@@ -385,7 +422,7 @@
</File> </File>
<File> <File>
<GroupNumber>3</GroupNumber> <GroupNumber>3</GroupNumber>
<FileNumber>16</FileNumber> <FileNumber>17</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@@ -397,7 +434,7 @@
</File> </File>
<File> <File>
<GroupNumber>3</GroupNumber> <GroupNumber>3</GroupNumber>
<FileNumber>17</FileNumber> <FileNumber>18</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@@ -409,7 +446,7 @@
</File> </File>
<File> <File>
<GroupNumber>3</GroupNumber> <GroupNumber>3</GroupNumber>
<FileNumber>18</FileNumber> <FileNumber>19</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@@ -421,7 +458,7 @@
</File> </File>
<File> <File>
<GroupNumber>3</GroupNumber> <GroupNumber>3</GroupNumber>
<FileNumber>19</FileNumber> <FileNumber>20</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@@ -433,7 +470,7 @@
</File> </File>
<File> <File>
<GroupNumber>3</GroupNumber> <GroupNumber>3</GroupNumber>
<FileNumber>20</FileNumber> <FileNumber>21</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@@ -445,7 +482,7 @@
</File> </File>
<File> <File>
<GroupNumber>3</GroupNumber> <GroupNumber>3</GroupNumber>
<FileNumber>21</FileNumber> <FileNumber>22</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@@ -455,18 +492,6 @@
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<bShared>0</bShared> <bShared>0</bShared>
</File> </File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>22</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_iwdg.c</PathWithFileName>
<FilenameWithoutPath>stm32f1xx_hal_iwdg.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File> <File>
<GroupNumber>3</GroupNumber> <GroupNumber>3</GroupNumber>
<FileNumber>23</FileNumber> <FileNumber>23</FileNumber>
@@ -486,6 +511,30 @@
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_tim.c</PathWithFileName>
<FilenameWithoutPath>stm32f1xx_hal_tim.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>25</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_tim_ex.c</PathWithFileName>
<FilenameWithoutPath>stm32f1xx_hal_tim_ex.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>26</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_uart.c</PathWithFileName> <PathWithFileName>../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_uart.c</PathWithFileName>
<FilenameWithoutPath>stm32f1xx_hal_uart.c</FilenameWithoutPath> <FilenameWithoutPath>stm32f1xx_hal_uart.c</FilenameWithoutPath>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
@@ -501,7 +550,7 @@
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<File> <File>
<GroupNumber>4</GroupNumber> <GroupNumber>4</GroupNumber>
<FileNumber>25</FileNumber> <FileNumber>27</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@@ -514,35 +563,11 @@
</Group> </Group>
<Group> <Group>
<GroupName>Middlewares/FreeRTOS</GroupName> <GroupName>Drivers/CH390</GroupName>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<cbSel>0</cbSel> <cbSel>0</cbSel>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<File>
<GroupNumber>5</GroupNumber>
<FileNumber>26</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>../Middlewares/Third_Party/FreeRTOS/Source/croutine.c</PathWithFileName>
<FilenameWithoutPath>croutine.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>5</GroupNumber>
<FileNumber>27</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>../Middlewares/Third_Party/FreeRTOS/Source/event_groups.c</PathWithFileName>
<FilenameWithoutPath>event_groups.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File> <File>
<GroupNumber>5</GroupNumber> <GroupNumber>5</GroupNumber>
<FileNumber>28</FileNumber> <FileNumber>28</FileNumber>
@@ -550,8 +575,8 @@
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>../Middlewares/Third_Party/FreeRTOS/Source/list.c</PathWithFileName> <PathWithFileName>..\Drivers\CH390\CH390.c</PathWithFileName>
<FilenameWithoutPath>list.c</FilenameWithoutPath> <FilenameWithoutPath>CH390.c</FilenameWithoutPath>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<bShared>0</bShared> <bShared>0</bShared>
</File> </File>
@@ -562,8 +587,8 @@
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>../Middlewares/Third_Party/FreeRTOS/Source/queue.c</PathWithFileName> <PathWithFileName>..\Drivers\CH390\CH390_Interface.c</PathWithFileName>
<FilenameWithoutPath>queue.c</FilenameWithoutPath> <FilenameWithoutPath>CH390_Interface.c</FilenameWithoutPath>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<bShared>0</bShared> <bShared>0</bShared>
</File> </File>
@@ -574,68 +599,400 @@
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>../Middlewares/Third_Party/FreeRTOS/Source/stream_buffer.c</PathWithFileName> <PathWithFileName>..\Drivers\CH390\ch390_runtime.c</PathWithFileName>
<FilenameWithoutPath>stream_buffer.c</FilenameWithoutPath> <FilenameWithoutPath>ch390_runtime.c</FilenameWithoutPath>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<bShared>0</bShared> <bShared>0</bShared>
</File> </File>
</Group>
<Group>
<GroupName>Drivers/LwIP/core</GroupName>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<cbSel>0</cbSel>
<RteFlg>0</RteFlg>
<File> <File>
<GroupNumber>5</GroupNumber> <GroupNumber>6</GroupNumber>
<FileNumber>31</FileNumber> <FileNumber>31</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>../Middlewares/Third_Party/FreeRTOS/Source/tasks.c</PathWithFileName> <PathWithFileName>..\Drivers\LwIP\src\core\def.c</PathWithFileName>
<FilenameWithoutPath>tasks.c</FilenameWithoutPath> <FilenameWithoutPath>def.c</FilenameWithoutPath>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<bShared>0</bShared> <bShared>0</bShared>
</File> </File>
<File> <File>
<GroupNumber>5</GroupNumber> <GroupNumber>6</GroupNumber>
<FileNumber>32</FileNumber> <FileNumber>32</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>../Middlewares/Third_Party/FreeRTOS/Source/timers.c</PathWithFileName> <PathWithFileName>..\Drivers\LwIP\src\core\inet_chksum.c</PathWithFileName>
<FilenameWithoutPath>timers.c</FilenameWithoutPath> <FilenameWithoutPath>inet_chksum.c</FilenameWithoutPath>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<bShared>0</bShared> <bShared>0</bShared>
</File> </File>
<File> <File>
<GroupNumber>5</GroupNumber> <GroupNumber>6</GroupNumber>
<FileNumber>33</FileNumber> <FileNumber>33</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.c</PathWithFileName> <PathWithFileName>..\Drivers\LwIP\src\core\init.c</PathWithFileName>
<FilenameWithoutPath>cmsis_os2.c</FilenameWithoutPath> <FilenameWithoutPath>init.c</FilenameWithoutPath>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<bShared>0</bShared> <bShared>0</bShared>
</File> </File>
<File> <File>
<GroupNumber>5</GroupNumber> <GroupNumber>6</GroupNumber>
<FileNumber>34</FileNumber> <FileNumber>34</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>../Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/heap_4.c</PathWithFileName> <PathWithFileName>..\Drivers\LwIP\src\core\ip.c</PathWithFileName>
<FilenameWithoutPath>heap_4.c</FilenameWithoutPath> <FilenameWithoutPath>ip.c</FilenameWithoutPath>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<bShared>0</bShared> <bShared>0</bShared>
</File> </File>
<File> <File>
<GroupNumber>5</GroupNumber> <GroupNumber>6</GroupNumber>
<FileNumber>35</FileNumber> <FileNumber>35</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>../Middlewares/Third_Party/FreeRTOS/Source/portable/RVDS/ARM_CM3/port.c</PathWithFileName> <PathWithFileName>..\Drivers\LwIP\src\core\mem.c</PathWithFileName>
<FilenameWithoutPath>port.c</FilenameWithoutPath> <FilenameWithoutPath>mem.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>36</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\Drivers\LwIP\src\core\memp.c</PathWithFileName>
<FilenameWithoutPath>memp.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>37</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\Drivers\LwIP\src\core\netif.c</PathWithFileName>
<FilenameWithoutPath>netif.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>38</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\Drivers\LwIP\src\core\pbuf.c</PathWithFileName>
<FilenameWithoutPath>pbuf.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>39</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\Drivers\LwIP\src\core\raw.c</PathWithFileName>
<FilenameWithoutPath>raw.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>40</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\Drivers\LwIP\src\core\stats.c</PathWithFileName>
<FilenameWithoutPath>stats.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>41</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\Drivers\LwIP\src\core\sys.c</PathWithFileName>
<FilenameWithoutPath>sys.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>42</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\Drivers\LwIP\src\core\tcp.c</PathWithFileName>
<FilenameWithoutPath>tcp.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>43</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\Drivers\LwIP\src\core\tcp_in.c</PathWithFileName>
<FilenameWithoutPath>tcp_in.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>44</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\Drivers\LwIP\src\core\tcp_out.c</PathWithFileName>
<FilenameWithoutPath>tcp_out.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>45</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\Drivers\LwIP\src\core\timeouts.c</PathWithFileName>
<FilenameWithoutPath>timeouts.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>46</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\Drivers\LwIP\src\core\udp.c</PathWithFileName>
<FilenameWithoutPath>udp.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>47</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\Drivers\LwIP\src\core\ipv4\etharp.c</PathWithFileName>
<FilenameWithoutPath>etharp.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>48</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\Drivers\LwIP\src\core\ipv4\icmp.c</PathWithFileName>
<FilenameWithoutPath>icmp.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>49</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\Drivers\LwIP\src\core\ipv4\ip4.c</PathWithFileName>
<FilenameWithoutPath>ip4.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>50</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\Drivers\LwIP\src\core\ipv4\ip4_addr.c</PathWithFileName>
<FilenameWithoutPath>ip4_addr.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>51</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\Drivers\LwIP\src\core\ipv4\ip4_frag.c</PathWithFileName>
<FilenameWithoutPath>ip4_frag.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
</Group>
<Group>
<GroupName>Drivers/LwIP/netif</GroupName>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<cbSel>0</cbSel>
<RteFlg>0</RteFlg>
<File>
<GroupNumber>7</GroupNumber>
<FileNumber>52</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\Drivers\LwIP\src\netif\ethernet.c</PathWithFileName>
<FilenameWithoutPath>ethernet.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>7</GroupNumber>
<FileNumber>53</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\Drivers\LwIP\src\netif\ethernetif.c</PathWithFileName>
<FilenameWithoutPath>ethernetif.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
</Group>
<Group>
<GroupName>APP</GroupName>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<cbSel>0</cbSel>
<RteFlg>0</RteFlg>
<File>
<GroupNumber>8</GroupNumber>
<FileNumber>54</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\App\config.c</PathWithFileName>
<FilenameWithoutPath>config.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>8</GroupNumber>
<FileNumber>55</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\App\flash_param.c</PathWithFileName>
<FilenameWithoutPath>flash_param.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>8</GroupNumber>
<FileNumber>56</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\App\tcp_client.c</PathWithFileName>
<FilenameWithoutPath>tcp_client.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>8</GroupNumber>
<FileNumber>57</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\App\tcp_server.c</PathWithFileName>
<FilenameWithoutPath>tcp_server.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>8</GroupNumber>
<FileNumber>58</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\App\uart_trans.c</PathWithFileName>
<FilenameWithoutPath>uart_trans.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
</Group>
<Group>
<GroupName>Middlewares/SEGGER_RTT</GroupName>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<cbSel>0</cbSel>
<RteFlg>0</RteFlg>
<File>
<GroupNumber>9</GroupNumber>
<FileNumber>59</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\Middlewares\Third_Party\SEGGER_RTT\SEGGER_RTT.c</PathWithFileName>
<FilenameWithoutPath>SEGGER_RTT.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>9</GroupNumber>
<FileNumber>60</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\Middlewares\Third_Party\SEGGER_RTT\SEGGER_RTT_printf.c</PathWithFileName>
<FilenameWithoutPath>SEGGER_RTT_printf.c</FilenameWithoutPath>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<bShared>0</bShared> <bShared>0</bShared>
</File> </File>
+1 -1
View File
@@ -337,7 +337,7 @@
<v6WtE>0</v6WtE> <v6WtE>0</v6WtE>
<v6Rtti>0</v6Rtti> <v6Rtti>0</v6Rtti>
<VariousControls> <VariousControls>
<MiscControls></MiscControls> <MiscControls>--diag_suppress=111,128</MiscControls>
<Define>USE_HAL_DRIVER,STM32F103xB</Define> <Define>USE_HAL_DRIVER,STM32F103xB</Define>
<Undefine></Undefine> <Undefine></Undefine>
<IncludePath>../Core/Inc;../Drivers/STM32F1xx_HAL_Driver/Inc;../Drivers/STM32F1xx_HAL_Driver/Inc/Legacy;../Drivers/CMSIS/Device/ST/STM32F1xx/Include;../Drivers/CMSIS/Include;../Drivers/CH390;../Drivers/LwIP/src/include;../Drivers/LwIP/src/include/lwip;../Drivers/LwIP/src/include/netif;../Drivers/LwIP/src/include/arch;../Drivers/LwIP/src/netif;../App;../Middlewares/Third_Party/SEGGER_RTT</IncludePath> <IncludePath>../Core/Inc;../Drivers/STM32F1xx_HAL_Driver/Inc;../Drivers/STM32F1xx_HAL_Driver/Inc/Legacy;../Drivers/CMSIS/Device/ST/STM32F1xx/Include;../Drivers/CMSIS/Include;../Drivers/CH390;../Drivers/LwIP/src/include;../Drivers/LwIP/src/include/lwip;../Drivers/LwIP/src/include/netif;../Drivers/LwIP/src/include/arch;../Drivers/LwIP/src/netif;../App;../Middlewares/Third_Party/SEGGER_RTT</IncludePath>
+1
View File
@@ -32,6 +32,7 @@
Stack_Size EQU 0x400 Stack_Size EQU 0x400
AREA STACK, NOINIT, READWRITE, ALIGN=3 AREA STACK, NOINIT, READWRITE, ALIGN=3
EXPORT Stack_Mem
Stack_Mem SPACE Stack_Size Stack_Mem SPACE Stack_Size
__initial_sp __initial_sp
+1 -1
View File
@@ -16,7 +16,7 @@
#endif #endif
#ifndef BUFFER_SIZE_UP #ifndef BUFFER_SIZE_UP
#define BUFFER_SIZE_UP 1024 #define BUFFER_SIZE_UP 256
#endif #endif
#ifndef BUFFER_SIZE_DOWN #ifndef BUFFER_SIZE_DOWN
+398 -170
View File
@@ -1,171 +1,374 @@
# TCP2UART 工程调试指 # TCP2UART 调试指
## 1. 适用范围 ## 1. 适用范围
本指面向当前 `TCP2UART` 工程,目标是指导以下调试场景: 本指面向当前 `TCP2UART` 工程,覆盖以下四类调试场景:
1. `STM32F103R8T6 + CH390D` 的基础 bring-up 1. `STM32F103R8T6 + CH390D` 的基础 bring-up
2. CH390D 的寄存器读写、链路检测、中断与收发调试 2. `SEGGER RTT`、异常陷阱与主循环运行状态确认
3. `lwIP RAW API + NO_SYS=1` 路线下的网络链路问题定位 3. `USART1` 配置口、`USART2/USART3` 数据口与 `MUX / NET / LINK[idx]` 协议联调
4. UART 透传与 TCP 双链路联调 4. `TCP Server / TCP Client / UART` 三层数据通路联调与问题隔离
本指默认基线: 本指默认基线如下
1. 当前工程已切换为裸机主循环架构 1. 当前工程采用裸机主循环架构,未使用 FreeRTOS 参与主业务调度
2. CH390 运行时访问统一由 `ch390_runtime` 持有 2. `CH390` 运行时访问统一由 `ch390_runtime` 持有
3. 调试输出通过 `SEGGER RTT` 3. 调试输出统一使用 `SEGGER RTT`
4. 当前代码已经通过 `MDK-ARM` 构建,且构建结果为 `0 error / 0 warning` 4. 当前应用层协议模型已经收敛到 `MUX / NET / LINK[idx]`
5. 当前代码应以 `MDK-ARM` 工程构建结果为准,而不是 `CMake + MSVC` 结果
## 2. 当前工程调试边界 ---
截至当前版本,工程状态应按以下层级理解: ## 2. 当前工程边界与真实状态
1. MCU 启动、系统时钟、RTT、TIM4 心跳与主循环均可正常工作 在进入现场调试前,先统一以下工程边界,避免沿用过时结论:
2. CH390D 已恢复基础寄存器读写,不再处于“全 `0xFF` / 全 `0x0000`”阶段
3. 实机已读到可信芯片与 PHY 标识:`VID=0x1C00``PID=0x9151``REV=0x2B``PHYID1=0x7371``PHYID2=0x9011`
4. 实机已观察到主机 Realtek USB GbE 网卡为 `Connected 100 Mbps`,且设备侧 `lwIP netif` 标志包含 `LINK_UP`
5. 当前调试重点不再是“SPI 是否完全不通”,而是:
- 默认配置是否完整生效
- MAC 写入与回读是否一致
- PHY 协商、`INT/LINK/RX/TX` 是否进入正常工作态
- 网络链路与 UART 透传是否稳定协同
因此,后续调试应避免继续沿用“CH390 完全无响应”的旧结论,而应转入功能链路验证。 1. 当前项目的主要软件路径已经切换为:
- `NET`:网络基础参数
- `LINK[idx]`:链路配置记录
- `MUX`:数据口承载模式
2. 对外 AT 配置面应只围绕以下命令展开:
- `AT`
- `AT+?`
- `AT+QUERY`
- `AT+MUX`
- `AT+NET`
- `AT+LINK`
- `AT+SAVE`
- `AT+RESET`
- `AT+DEFAULT`
3. 当前 `CH390D` 的历史“全 `0xFF` / 全 `0x0000`”结论不应再直接沿用。
4. 已有结论表明:
- MCU 启动、RTT、主循环、TIM4 心跳路径可工作
- `CH390D` 基础寄存器读写与 `lwIP netif` 基本链路已经打通过一次
- 真实硬件侧曾定位到 `CH390D` 供电滤波电容虚焊问题
5. 因此,当前调试重点不再是“CH390 是否完全不通”,而是:
- 启动阶段是否稳定
- `MUX / NET / LINK[idx]` 协议是否与代码一致
- UART / TCP / CH390 三层通路是否协同稳定
- 参数保存、复位和恢复流程是否可靠
## 3. 代码入口与责任边界 ---
### 3.1 启动路径 ## 3. 代码入口与调试责任边界
当前 CH390 相关启动链路为: ### 3.1 启动与主循环入口
1. `main()` 以下代码路径是 bring-up 的第一现场:
2. `App_Init()`
3. `lwip_netif_init()`
4. `ethernetif_init()` / `low_level_init()`
5. `ch390_runtime_init()`
6. `ch390_gpio_init()`
7. `ch390_spi_init()`
8. `ch390_hardware_reset()`
9. `ch390_runtime_probe_identity()`
10. `ch390_default_config()`
11. `ch390_set_mac_address()` / `ch390_get_mac()`
12. `ch390_interrupt_init()`
### 3.2 运行时责任边界 1. `Core/Src/main.c`
- `main()`:总启动入口
- `SystemClock_Config()`:时钟初始化
- `App_Init()`:应用层初始化
- `App_Poll()`:主循环核心路径
- `BootDiag_ReportCh390()`:启动阶段 CH390 诊断输出
2. `Core/Src/stm32f1xx_it.c`
- 故障与中断入口
- `USART1/2/3``EXTI0`、DMA 回调等联调关键入口
当前代码约束如下: ### 3.2 CH390 责任边界
当前 CH390 调试必须遵守以下责任边界:
1. `Drivers/CH390/CH390_Interface.c` 1. `Drivers/CH390/CH390_Interface.c`
- 只负责底层 GPIOSPI 寄存器/内存访问 - 只负责 GPIO / SPI / 寄存器内存事务
- 当前寄存器读写路径使用 `Mode 3 + bytewise exchange` 事务模型
2. `Drivers/CH390/CH390.c` 2. `Drivers/CH390/CH390.c`
- 只负责芯片级 helper,例如 `default_config`、PHY 访问、MAC 操作 - 只负责芯片级 helper,例如默认配置、PHY、MAC 读写
3. `Drivers/CH390/ch390_runtime.c` 3. `Drivers/CH390/ch390_runtime.c`
- 唯一的 CH390 运行时拥有者 - 唯一的运行时拥有者
- 负责初始化、链路查、IRQ 消费、RX/TX 服务 - 负责初始化、链路查、IRQ 消费、RX/TX 服务与诊断快照
4. `Drivers/LwIP/src/netif/ethernetif.c` 4. `Drivers/LwIP/src/netif/ethernetif.c`
- 不再直接承担复杂 CH390 运行时事务,只做 netif glue - 只承担 netif glue 与轮询桥接,不应重新下沉复杂 CH390 运行时事务
5. `Core/Src/main.c` 5. `Core/Src/main.c`
- 启动后只通过 `BootDiag_ReportCh390()` 读取 runtime 提供的启动快照 - 启动后只通过 runtime 对外暴露的诊断与轮询接口工作
调试时应优先维护这个边界,不要重新把原始寄存器访问散`main.c` 或 EXTI 中断中 调试时不要把原始 CH390 寄存器访问重新散回 `main.c`、中断或多个业务层
## 4. 当前硬件连接事实 ### 3.3 配置口与业务口边界
根据 `PCB/SCH_Schematic1_2026-03-26.pdf`CH390D 关键硬件事实如下: 1. `USART1`
- 配置口
- 负责接收 `AT` 命令
- 当前接收逻辑在:
- `Core/Src/main.c``App_PollUart1ConfigRx()`
- `Core/Src/stm32f1xx_it.c``HAL_UART_RxCpltCallback()`
- `App/config.c``config_uart_rx_byte()` / `config_process_at_cmd()`
2. `USART2 / USART3`
- 数据口
- 负责普通透传或 MUX 承载
- 当前入口在 `App/uart_trans.c`
1. MCU 与 CH390D 的连接关系: ---
- `PA4 -> CH_CS -> U4.SCS`
- `PA5 -> CH_CLK -> R10(22Ω) -> U4.SCK`
- `PA6 <- CH_SDO <- U4.SDO/MISO`
- `PA7 -> CH_SDI -> U4.SDI/MOSI`
- `PB0 <- CH_INT <- U4.INT`
- `PB1 -> CH_RST -> R8(470Ω) -> U4.RSTB`
2. CH390D 使用 `25MHz` 晶振 `X2`
3. CH390D 存在独立相关电源域:
- `VDDK`
- `AVDD33/VDDIO`
- `AVDD33`
4. CH390D 周边去耦电容包括 `C18/C20/C21/C22`
5. 原理图上未看到独立的 `MISO` 外部上拉电阻
6. 当前代码中的 `ch390_hardware_reset()` 采用:
- 复位前等待 `10ms`
- `RSTB` 拉低 `3ms`
- 释放后等待 `50ms`
调试时必须优先在 **CH390 芯片脚侧** 量测,而不是只在 MCU GPIO 侧判断。 ## 4. 当前硬件与调试工具基线
## 5. 推荐调试顺序 ### 4.1 核心硬件对象
### 5.1 P0:先确认基础条件 1. MCU`STM32F103R8T6`
2. 以太网芯片:`CH390D`
3. 配置串口:`USART1`
4. 数据串口:`USART2 / USART3`
5. 调试输出:`SEGGER RTT`
每次进入功能调试前,先确认以下最小基线: ### 4.2 构建与下载基线
1. `MDK` 可成功构建,且当前日志为 `0 error / 0 warning` 当前建议优先使用以下工程与产物:
2. RTT 可输出启动日志
3. `BootDiag_ReportCh390()` 能打印出 `VID/PID/REV/NSR/NCR/RCR/IMR/INTCR/GPR/ISR`
4. `App_Poll()` 正常运行,LED 心跳正常
### 5.2 P1:验证 CH390 初始化状态 1. `MDK-ARM/TCP2UART.uvprojx`
2. `MDK-ARM/TCP2UART/TCP2UART.axf`
3. `MDK-ARM/TCP2UART/TCP2UART.hex`
4. `MDK-ARM/TCP2UART/TCP2UART.map`
5. `MDK-ARM/TCP2UART/TCP2UART.build_log.htm`
6. `build_keil.log`
优先检查以下问题 说明
1. `ETH init: probe/default/mac/getmac/irq/done` 是否完整打印 1. 当前 `CMake configure` 可以完成,但 `CMake + MSVC` 不适合作为 STM32/CMSIS 的最终构建验收依据。
2. `VID/PID/REV` 与 PHY ID 是否稳定、可信 2. 若需要验证“当前代码是否真实可编译”,优先看 `MDK-ARM` 构建产物与日志。
3. MAC 写入与 `ch390_get_mac()` 回读是否一致
4. `RCR/IMR/INTCR/GPR` 是否进入预期工作态
5. `link_up``lwIP netif``LINK_UP` 标志是否与物理网线状态一致
如这一层失败,优先回到芯片侧量测: ### 4.3 常用调试工具
1. `Keil MDK-ARM`
2. `ST-Link / J-Link`
3. `SEGGER RTT Viewer`
4. `PowerShell`
5. `tools/start_tcp_debug_server.ps1`
6. `tools/tcp_debug_server.py`
---
## 5. 启动阶段调试顺序
建议按 P0 ~ P5 顺序推进,不要跳层。
### 5.1 P0:确认最小基础条件
每次现场调试前,先确认:
1. `MDK-ARM` 可构建并产出新的 `axf/hex/map`
2. 板卡可正常下载与复位
3. RTT 可连接并看到启动输出
4. LED 心跳可工作
5. `App_Poll()` 已经进入稳定轮询
这一层若失败,不要进入网络或协议调试。
### 5.2 P1:确认启动日志与 trap 状态
上电或复位后,优先看 RTT 输出中是否出现:
1. `TCP2UART boot`
2. 若 HSE 启动失败,则会出现:
- `WARN: HSE start failed, fallback to HSI PLL`
3. `BootDiag_ReportCh390()` 输出的 CH390 诊断与网络配置快照
若发生异常,优先观察是否打印:
1. `TRAP: Error_Handler`
2. `TRAP: HardFault_Handler`
3. `TRAP: MemManage_Handler`
4. `TRAP: BusFault_Handler`
5. `TRAP: UsageFault_Handler`
当前 trap 统一收敛到:
1. `Core/Src/main.c``Debug_TrapWithRttHint()`
2. 它会打印 RTT、执行 `__BKPT(0)` 并停住
因此,若 RTT 中出现 `TRAP:`,应立即接调试器看断点现场,而不是继续盲猜高层逻辑。
### 5.3 P2:确认 CH390 初始化链路
启动阶段应重点关注 `Drivers/CH390/ch390_runtime.c` 中初始化阶段日志,理想情况下应能依次看到:
1. `ETH init: gpio`
2. `ETH init: spi`
3. `ETH init: reset`
4. `ETH init: probe`
5. `ETH init: default`
6. `ETH init: mac`
7. `ETH init: getmac`
8. `ETH init: irq`
9. `ETH init: done`
此阶段重点判定:
1. `VID / PID / REV` 是否可信
2. PHY 寄存器是否稳定可读
3. MAC 写入与回读是否一致
4. `link_up` 是否与真实网线状态一致
若这一层失败,优先做硬件侧量测,而不是先改业务层:
1. `RSTB` 1. `RSTB`
2. `CS` 2. `CS`
3. `SCK` 3. `SCK`
4. `MOSI` 4. `MOSI`
5. `MISO` 5. `MISO`
6. `VDDK / AVDD33/VDDIO / AVDD33` 6. `INT`
7. `VDDK`
8. `AVDD33 / VDDIO / AVDD33`
9. `XI / XO`
### 5.3 P2:验证 IRQ 与链路检测 ---
在基础寄存器读写可信后,重点验证: ## 6. USART1 配置口调试
1. `PB0/EXTI0` 是否能接收到 CH390 的 `INT` ### 6.1 当前命令面
2. `ISR_LNKCHG` 发生时,`ch390_runtime_poll()` 是否正确更新链路状态,不再依赖阻塞式 `HAL_Delay(65)`
3. `ethernetif_check_link()``ch390_runtime_check_link()` 的结果是否一致
4. 必须区分“启动快照中的 `g_diag.link_up`”与“主循环中实时更新后的 `netif->flags & NETIF_FLAG_LINK_UP`
### 5.4 P3:验证 RX/TX 数据通路 根据当前代码与手册,配置口应围绕以下命令验证:
`link_up` 可信后,再继续验证数据通路: 1. `AT`
2. `AT+?`
3. `AT+QUERY`
4. `AT+MUX=...`
5. `AT+MUX?`
6. `AT+NET=...`
7. `AT+NET?`
8. `AT+LINK=...`
9. `AT+LINK?`
10. `AT+SAVE`
11. `AT+RESET`
12. `AT+DEFAULT`
1. 先确保主机网卡与设备处于同一子网;当前联调基线曾使用主机 `192.168.31.1` 与设备 `192.168.31.x` ### 6.2 现场关键规则
2. `ch390_runtime_input()` 是否能稳定读取 `RX SRAM`
3. `rx_status / rx_len` 是否合理
4. `ch390_runtime_output()` 是否能正确等待 `TCR_TXREQ` 清零并发送帧
5. 网络端与 UART2/UART3 透传是否联通
### 5.4.1 最小 TCP 调试工具 根据已有联调记录,配置口最关键的 bench 规则是:
当需要验证 `TCP server(8080)``TCP client(8081)` 的原始桥接行为时,优先使用仓库内置的最小工具,而不是直接依赖 VOFA 这类带协议/显示假设的上位机工具 1. 当前现场验证时,配置命令必须保证以换行完成帧
2. 若主机侧发送方式不对,现象会很像“配置口完全无响应”。
3. 因此,配置口不响应时,第一优先级不是改 parser,而是先验证主机端发送格式与接线。
推荐工具如下: ### 6.3 最小验证步骤
建议按以下顺序验证:
1. 连接 `USART1`
2. 先发 `AT`
3. 再发 `AT+QUERY`
4. 再发 `AT+NET?`
5. 再发 `AT+LINK?`
6. 修改一个最小参数,例如:
- `AT+MUX=1`
7. 执行:
- `AT+SAVE`
- `AT+RESET`
8. 复位后再次查询,确认配置是否保留
### 6.4 持久化失败时怎么查
优先检查以下路径:
1. `App/config.c`
- `config_save()`
- `config_load()`
- `config_set_defaults()`
2. `App/flash_param.c`
- Flash 解锁
- 页擦除
- 半字编程
- 写后校验
3. 参数页地址:
- `0x0800FC00`
不要在还没证明 `AT+SAVE` 已真正被接受之前,就直接把 `Flash 全 FFFFFFFF` 归因到 Flash 驱动错误。
---
## 7. MUX / NET / LINK[idx] 联调指导
### 7.1 协议总则
当前协议必须按以下模型理解:
1. `MUX`:全局数据承载模式开关
2. `NET`IP / Mask / GW / MAC
3. `LINK[idx]`:链路配置项
固定链路索引映射为:
1. `LINK[0] = S1`
2. `LINK[1] = S2`
3. `LINK[2] = C1`
4. `LINK[3] = C2`
固定端点编码为:
1. `C1 = 0x01`
2. `C2 = 0x02`
3. `UART2 = 0x04`
4. `UART3 = 0x08`
5. `S1 = 0x10`
6. `S2 = 0x20`
### 7.2 MUX 数据口规则
`MUX=1` 时,数据口应使用 MUX 帧。
重点规则:
1. `DSTMASK=0x00` 表示系统控制帧
2. 控制帧中的 AT 文本必须严格按手册要求结束
3. 普通数据帧走业务转发路径,不应进入配置解析器
### 7.3 调试时重点检查什么
若怀疑 `MUX` 模式不工作,优先检查:
1. `App/uart_trans.c`
- `uart_mux_try_extract_frame()`
- `uart_mux_encode_frame()`
2. `Core/Src/main.c`
- `App_RouteMuxUartTraffic()`
- `App_RouteRawUartTraffic()`
- `App_RouteTcpTraffic()`
3. `App/config.c`
- `config_build_response_frame()`
- `config_process_at_cmd()`
推荐最小 MUX 联调顺序:
1. 先在 `MUX=0` 下跑通原始透传
2. 再切换 `MUX=1`
3. 先发一个控制帧,确认 `DSTMASK=0x00` 路径可通
4. 再发一个单目标数据帧,例如只打到 `S1`
5. 最后验证多目标位图转发
---
## 8. TCP / UART / CH390 联调顺序
### 8.1 先做链路,再做业务
`CH390` 初始化、链路和 IRQ 未被证明稳定前,不要先调高层 TCP/UART 业务。
### 8.2 推荐顺序
建议按以下顺序推进:
1. RTT 启动与 trap 状态正常
2. CH390 启动日志完整
3. 链路检测可信
4. `TCP server` / `TCP client` 建链可信
5. UART 原始透传可信
6. 再切入 `MUX` 模式联调
### 8.3 最小 TCP 调试工具
当需要验证板子是否真的把 payload 发到主机时,优先使用仓库内置最小工具:
1. `tools/tcp_debug_server.py` 1. `tools/tcp_debug_server.py`
- 纯 Python 原始 TCP 服务端 - 打印连接、收包、文本视图和十六进制视图
- 可直接打印连接、收包、文本视图和十六进制视图
- 适合确认“板子到底有没有把原始 payload 发到 PC 的 8081 端口”
2. `tools/start_tcp_debug_server.ps1` 2. `tools/start_tcp_debug_server.ps1`
- PowerShell 包装脚本 - 会先清理冲突监听,再启动 Python 服务端
- 会先清理本机 `8081` 端口上的现有监听,再启动 Python 调试服务端
- 适合避免 `ncat`、遗留 Python、VOFA 等进程抢占 `8081`
推荐使用方法 推荐命令
```powershell ```powershell
powershell -ExecutionPolicy Bypass -File ".\tools\start_tcp_debug_server.ps1" -Port 8081 -NoStdin powershell -ExecutionPolicy Bypass -File ".\tools\start_tcp_debug_server.ps1" -Port 8081 -NoStdin
``` ```
如需回显模式 如需回显:
```powershell ```powershell
powershell -ExecutionPolicy Bypass -File ".\tools\start_tcp_debug_server.ps1" -Port 8081 -Echo powershell -ExecutionPolicy Bypass -File ".\tools\start_tcp_debug_server.ps1" -Port 8081 -Echo
@@ -177,92 +380,117 @@ powershell -ExecutionPolicy Bypass -File ".\tools\start_tcp_debug_server.ps1" -P
python .\tools\tcp_debug_server.py --host 0.0.0.0 --port 8081 --no-stdin python .\tools\tcp_debug_server.py --host 0.0.0.0 --port 8081 --no-stdin
``` ```
使用该工具时,推荐调试顺序如下: ### 8.4 推荐验证方法
1. 先关闭 VOFA、`ncat` 和其它可能占用 `8081` 的进程 1. 先关闭 VOFA、`ncat` 和其它可能占用 `8081` 的进程
2. 启动 `start_tcp_debug_server.ps1` 2. 启动 `start_tcp_debug_server.ps1`
3. 让板子连接 `192.168.31.1:8081` 3. 让板子连接主机 `TCP client` 目标端口
4. 然后从 PC 连接板子的 `192.168.31.100:8080`,发送一段明确文本,例如 `hello` 4. 再从主机连接板子的 `TCP server` 端口发送固定测试文本
5. 观察 Python 工具是否打印 5. 同时观察:
- 客户端已连接 - Python 工具是否收到连接与 payload
- 收到的原始字节长度 - 板子 RTT 是否出现连接或错误信息
- 文本视图与十六进制视图
如果板子 RTT 显示 `TCP client connected to ...:8081`,但 Python 工具没有任何连接提示,优先检查本机端口占用 板子 RTT 显示已连接,但主机工具无数据,优先检查本机端口占用而不是先改板端逻辑。
```powershell ---
Get-NetTCPConnection -LocalPort 8081 -ErrorAction SilentlyContinue |
Select-Object LocalAddress,LocalPort,RemoteAddress,RemotePort,State,OwningProcess
```
若存在多个监听者,优先清理后再测,否则板子可能连接到错误的本机进程。 ## 9. 异常、卡死与假死排查
### 5.5 P4:验证系统级联调 ### 9.1 看到 `TRAP:` 时怎么做
最终再验证: 1. 先记录 RTT 中的 trap 标签
2. 立刻用调试器查看当前 PC / LR / 调用栈
3. 结合 `Core/Src/stm32f1xx_it.c` 中对应 handler 定位异常类型
1. TCP Server 与 UART2 双向透传 ### 9.2 没有 `TRAP:` 但系统不工作时怎么做
2. TCP Client 与 UART3 双向透传
3. 配置保存、复位与 MAC 生效路径
4. 长时间运行稳定性
## 6. 推荐的现场观测点 若没有 `TRAP:`,但系统表现异常,应优先区分以下情况:
### 6.1 软件观测点 1. 主循环仍在跑,只是业务路径没反应
2. 中断未到或链路未更新
3. 发生了阻塞式等待或超时问题
4. 上层工具接错端口或被错误进程抢占
优先关注以下函数与状态: ### 9.3 历史上已经确认过的典型软件问题
1. `BootDiag_ReportCh390()` 以下问题在历史排查中已经出现过,应优先复核,不要重复踩坑:
2. `ch390_runtime_probe_identity()`
3. `ch390_runtime_init()`
4. `ch390_runtime_poll()`
5. `ch390_runtime_check_link()`
6. `ch390_runtime_input()`
7. `ch390_runtime_output()`
### 6.2 硬件观测点 1. PHY 访问无超时,导致永久卡死
2. 刷新未初始化的 IWDG 句柄导致 HardFault
3. 在长耗时 SPI 路径中错误扩大临界区,导致看似“系统假死”
4. 在多个层次同时触达 CH390 / SPI,导致运行时边界混乱
5. 配置口命令结束方式不对,导致误判为 parser 无响应
优先关注 CH390 芯片脚侧: ---
1. `RSTB` ## 10. 常见误区
2. `SCS`
3. `SCK`
4. `SDI/MOSI`
5. `SDO/MISO`
6. `INT`
7. `VDDK`
8. `AVDD33/VDDIO`
9. `AVDD33`
10. `XI/XO`
## 7. 常见误区
调试当前工程时,应避免以下误区: 调试当前工程时,应避免以下误区:
1. 不要再直接沿用“CH390 恒为全 `0xFF`”这一过时结论 1. 不要继续沿用“CH390 恒为全 `0xFF`”这一过时结论
2. 不要在 `main.c`、IRQ、netif 多处重新插入原始 CH390 访问 2. 不要在 `main.c`、IRQ、netif 多处重新插入原始 CH390 访问
3. 不要在没有芯片脚侧证据前,只凭 MCU 侧 GPIO 就认定 `RST/CS/SCK/MISO` 正常 3. 不要在没有芯片脚侧证据前,只凭 MCU 侧 GPIO 判断总线正常
4. 不要在基础寄存器读写尚不可信时,直接调高层 `TCP/UART` 业务逻辑 4. 不要在基础寄存器读写尚不可信时,直接调高层 `TCP/UART/MUX` 业务逻辑
5. 不要把一次性 bring-up 实验代码长期留在正式启动路径中 5. 不要把一次性 bring-up 实验代码长期留在正式路径中
6. 不要让 `VOFA``ncat`、自写 Python 服务端等多个进程同时监听 `8081`;否则板子可能连接到错误的本机进程,导致 RTT 显示 `connected` 但目标工具无数据 6. 不要让多个本机进程同时监听板子要连接的 TCP 端口
7. 不要在尚未证明命令已真正进入 parser 之前,直接归因到 Flash、协议或网络层
## 8. 当前推荐结论表达方式 ---
当需要向项目成员同步当前状态时,推荐使用如下表述: ## 11. 推荐的现场记录模板
建议每次现场调试至少记录以下信息:
1. 日期时间
2. 板卡编号
3. 固件产物路径
4. 下载方式
5. RTT 关键日志
6. 串口发送内容
7. TCP 调试工具输出
8. 关键波形或电压量测点
9. 结论
10. 下一步动作
建议记录格式:
```text
时间:
板卡:
固件:
下载方式:
操作步骤:
RTT输出:
串口/TCP现象:
硬件量测:
结论:
下一步:
```
---
## 12. 当前推荐的结论表达方式
若需要向项目成员同步当前状态,建议采用以下口径:
1. 当前工程软件架构已稳定在 `bare-metal + lwIP RAW + ch390_runtime 单一拥有者` 1. 当前工程软件架构已稳定在 `bare-metal + lwIP RAW + ch390_runtime 单一拥有者`
2. 当前 CH390D 已恢复基础寄存器读写,调试重点已转入初始化完整性、链路、中断与收发功能 2. 当前调试重点已经从“CH390 是否完全无响应”转移到协议、链路和系统级联调
3. 硬件验证仍必须以 CH390 芯片脚侧波形与电源域量测为准 3. 当前对外协议和配置模型应以 `MUX / NET / LINK[idx]` 为准
4. 上层 `TCP/UART` 联调应建立在 CH390 初始化、链路与供电稳定三者都可信之后 4. `USART1` 配置口、`USART2/3` 数据口与 TCP 路由必须按最新代码路径调试,不应再参照历史 `IP/MASK/GW/PORT/RIP/RPORT` 公开接口模型
5. 本项目已确认过一次真实硬件根因:CH390D 供电滤波电容虚焊会直接表现为网络收发异常 5. 硬件验证仍必须以 CH390 芯片脚侧波形和供电域量测为准
## 9. 建议配套文档 ---
建议与本指南配套阅读 ## 13. 建议配套阅读
1. `项目技术实现.md` 建议与本指导配套阅读:
2. `CH390D_硬件检查指南.md`
3. `uart-ch390-debug-handoff.md` 1. `AT固件使用手册.md`
4. `PCB/SCH_Schematic1_2026-03-26.pdf` 2. `项目技术实现.md`
5. `tools/tcp_debug_server.py` 3. `项目需求说明.md`
6. `tools/start_tcp_debug_server.ps1` 4. `uart-ch390-debug-handoff.md`
5. `CH390_最终结论报告.md`
6. `build_keil.log`
7. `PCB/SCH_Schematic1_2026-03-26.pdf`
8. `tools/tcp_debug_server.py`
9. `tools/start_tcp_debug_server.ps1`