feat: 保存已验证的CH390网络打通基线

This commit is contained in:
2026-04-17 07:09:55 +08:00
parent 59eecf428f
commit 6aba77df9a
44 changed files with 6428 additions and 3372 deletions
+114
View File
@@ -0,0 +1,114 @@
#ifndef APP_RUNTIME_H
#define APP_RUNTIME_H
#include <stdint.h>
#include "FreeRTOS.h"
#include "queue.h"
#include "semphr.h"
#include "task.h"
#include "config.h"
#ifdef __cplusplus
extern "C" {
#endif
extern QueueHandle_t xTcpRxQueue;
extern QueueHandle_t xConfigQueue;
extern QueueHandle_t xLinkTxQueues[CONFIG_LINK_COUNT];
extern SemaphoreHandle_t xNetSemaphore;
extern TaskHandle_t xUartRxTaskHandle;
extern TaskHandle_t xConfigTaskHandle;
extern volatile BaseType_t g_netif_ready;
extern volatile uint32_t g_netif_phase;
extern volatile int32_t g_netif_add_err;
extern volatile int32_t g_netif_set_default_err;
extern volatile int32_t g_netif_set_link_down_err;
extern volatile int32_t g_netif_set_up_err;
extern volatile int32_t g_netif_init_ok;
extern volatile uint32_t g_eth_poll_count;
extern volatile uint32_t g_eth_isr_pr_count;
extern volatile uint32_t g_eth_rx_count;
extern volatile uint32_t g_eth_rx_drop_count;
extern volatile uint32_t g_eth_tx_count;
extern volatile uint32_t g_eth_link_up_count;
extern volatile uint32_t g_eth_link_down_count;
extern volatile uint32_t g_eth_last_isr;
extern volatile uint32_t g_eth_last_nsr;
extern volatile uint32_t g_eth_last_mrcmdx;
extern volatile uint32_t g_eth_last_mrcmdx1;
extern volatile uint32_t g_eth_last_mrrl;
extern volatile uint32_t g_eth_last_mrrh;
extern volatile uint32_t g_eth_last_bcastcr;
extern volatile uint32_t g_eth_last_mar7;
extern volatile uint32_t g_eth_last_nsr_rxrdy;
extern volatile uint32_t g_eth_last_rx_ready;
extern volatile uint32_t g_eth_last_rx_status;
extern volatile uint32_t g_eth_last_rx_len;
extern volatile uint32_t g_eth_last_rx_head0;
extern volatile uint32_t g_eth_last_rx_head1;
extern volatile uint32_t g_eth_last_rx_head2;
extern volatile uint32_t g_eth_last_rx_head3;
extern volatile uint32_t g_eth_last_rx_fail_stage;
extern volatile uint32_t g_eth_rx_gate_ok_count;
extern volatile uint32_t g_eth_rx_fallback_ok_count;
extern volatile uint32_t g_eth_rx_fallback_reject_count;
extern volatile uint32_t g_eth_probe_attempted;
extern volatile uint32_t g_eth_probe_head0;
extern volatile uint32_t g_eth_probe_head1;
extern volatile uint32_t g_eth_probe_head2;
extern volatile uint32_t g_eth_probe_head3;
extern volatile uint32_t g_eth_probe_rx_status;
extern volatile uint32_t g_eth_probe_rx_len;
extern volatile uint8_t g_eth_probe_dump[32];
extern volatile uint32_t g_eth_probe_drop_count;
extern volatile uint32_t g_eth_reprobe_head0;
extern volatile uint32_t g_eth_reprobe_head1;
extern volatile uint32_t g_eth_reprobe_head2;
extern volatile uint32_t g_eth_reprobe_head3;
extern volatile uint32_t g_eth_reprobe_rx_status;
extern volatile uint32_t g_eth_reprobe_rx_len;
extern volatile uint32_t g_eth_input_ok_count;
extern volatile uint32_t g_eth_input_err_count;
extern volatile int32_t g_eth_last_input_err;
extern volatile uint32_t g_eth_last_frame_len;
extern volatile uint8_t g_eth_last_frame_head[14];
extern volatile uint32_t g_eth_tx_probe_count;
extern volatile uint32_t g_eth_last_tx_len;
extern volatile uint8_t g_eth_last_tx_head[14];
extern volatile uint32_t g_eth_last_tcr_after;
extern volatile uint32_t g_eth_last_nsr_after;
extern volatile uint32_t g_eth_last_tsra;
extern volatile uint32_t g_eth_last_tsrb;
extern volatile uint32_t g_eth_last_txpll_rb;
extern volatile uint32_t g_eth_last_txplh_rb;
extern volatile uint32_t g_eth_arp_rx_count;
extern volatile uint32_t g_eth_arp_tx_count;
extern volatile uint32_t g_eth_arp_rx_op;
extern volatile uint32_t g_eth_arp_tx_op;
extern volatile uint8_t g_eth_local_ip[4];
extern volatile uint8_t g_eth_local_mac[6];
extern volatile uint8_t g_eth_arp_rx_sha[6];
extern volatile uint8_t g_eth_arp_rx_spa[4];
extern volatile uint8_t g_eth_arp_rx_tha[6];
extern volatile uint8_t g_eth_arp_rx_tpa[4];
extern volatile uint8_t g_eth_arp_tx_sha[6];
extern volatile uint8_t g_eth_arp_tx_spa[4];
extern volatile uint8_t g_eth_arp_tx_tha[6];
extern volatile uint8_t g_eth_arp_tx_tpa[4];
extern volatile uint32_t g_eth_lwip_arp_seen_count;
extern volatile uint32_t g_eth_lwip_arp_opcode;
extern volatile uint32_t g_eth_lwip_arp_for_us;
extern volatile uint32_t g_eth_lwip_arp_from_us;
extern volatile uint8_t g_eth_lwip_arp_sip[4];
extern volatile uint8_t g_eth_lwip_arp_dip[4];
extern volatile uint32_t g_eth_lwip_eth_seen_count;
extern volatile uint32_t g_eth_lwip_eth_last_type;
extern volatile uint32_t g_eth_lwip_eth_last_len;
extern volatile uint32_t g_eth_lwip_eth_arp_case_count;
#ifdef __cplusplus
}
#endif
#endif
+541 -629
View File
File diff suppressed because it is too large Load Diff
+64 -157
View File
@@ -1,96 +1,76 @@
/**
* @file config.h
* @brief AT command configuration module 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
#define CONFIG_H
#ifndef __CONFIG_H__
#define __CONFIG_H__
#include <stdint.h>
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Configuration magic number "TCPU" */
#define CONFIG_MAGIC 0x54435055
#define CONFIG_MAGIC 0x54435055u
#define CONFIG_VERSION 0x0003u
/* Configuration version for compatibility */
#define CONFIG_VERSION 0x0001
#define CONFIG_UART_COUNT 2u
#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 {
uint32_t magic; /* Magic number for validation */
uint16_t version; /* Configuration version */
uint16_t reserved; /* Reserved for alignment */
/* Network settings */
uint8_t mac[6]; /* MAC address */
uint8_t dhcp_enable; /* DHCP enable flag */
uint8_t reserved2; /* Reserved for alignment */
uint8_t ip[4]; /* Device IP address */
uint8_t mask[4]; /* Subnet mask */
uint8_t gw[4]; /* Gateway */
/* TCP Server settings */
uint16_t server_port; /* Server listen port */
uint16_t reserved3; /* Reserved for alignment */
/* TCP Client settings */
uint8_t remote_ip[4]; /* Remote server IP */
uint16_t remote_port; /* Remote server port */
uint16_t reconnect_interval;/* Reconnect interval (ms) */
/* 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) */
uint8_t ip[4];
uint8_t mask[4];
uint8_t gw[4];
uint8_t mac[6];
uint8_t reserved[2];
} net_config_t;
typedef struct {
uint8_t enabled;
uint8_t uart;
uint16_t local_port;
uint8_t remote_ip[4];
uint16_t remote_port;
uint16_t reserved;
} link_config_t;
typedef struct {
uint32_t magic;
uint16_t version;
uint8_t mux_mode;
uint8_t reserved0;
net_config_t net;
link_config_t links[CONFIG_LINK_COUNT];
uint32_t uart_baudrate[CONFIG_UART_COUNT];
uint32_t reconnect_interval_ms;
uint32_t crc;
} device_config_t;
/* Default configuration values */
#define DEFAULT_IP {192, 168, 1, 100}
#define DEFAULT_MASK {255, 255, 255, 0}
#define DEFAULT_GW {192, 168, 1, 1}
#define DEFAULT_MAC {0x02, 0x00, 0x00, 0x00, 0x00, 0x01}
#define DEFAULT_SERVER_PORT 8080
#define DEFAULT_REMOTE_IP {192, 168, 1, 200}
#define DEFAULT_REMOTE_PORT 9000
#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
#define DEFAULT_NET_IP {192, 168, 31, 100}
#define DEFAULT_NET_MASK {255, 255, 255, 0}
#define DEFAULT_NET_GW {192, 168, 31, 1}
#define DEFAULT_NET_MAC {0x02, 0x00, 0x00, 0x00, 0x00, 0x01}
#define DEFAULT_UART_BAUDRATE 115200u
#define DIAG_CH390_RAW_POLL 0
/* AT command result codes */
typedef enum {
AT_OK = 0,
AT_ERROR,
@@ -100,99 +80,26 @@ typedef enum {
AT_NEED_REBOOT
} at_result_t;
/**
* @brief Initialize configuration module
* @return 0 on success, negative on error
*/
int config_init(void);
/**
* @brief Load configuration from Flash
* @return 0 on success, negative on error (defaults loaded)
*/
int config_load(void);
/**
* @brief Save configuration to Flash
* @return 0 on success, negative on error
*/
int config_save(void);
/**
* @brief Reset configuration to factory defaults
*/
void config_set_defaults(void);
/**
* @brief Get current configuration
* @return Pointer to current configuration (read-only)
*/
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);
/**
* @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);
/**
* @brief Configuration task (for FreeRTOS)
* Handles UART1 reception and AT command processing
* @param argument Task argument (unused)
*/
void config_task(void *argument);
/**
* @brief UART1 IDLE interrupt handler for config module
*/
void ConfigTask(void *argument);
void config_uart_idle_handler(void);
/**
* @brief Start UART1 reception for configuration
*/
void config_start_reception(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);
/**
* @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);
/**
* @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);
/**
* @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);
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
}
#endif
#endif /* __CONFIG_H__ */
#endif
+174
View File
@@ -0,0 +1,174 @@
#include "route_msg.h"
#include <string.h>
#include "task.h"
typedef struct {
route_msg_t msg;
uint8_t data[ROUTE_MSG_MAX_PAYLOAD];
uint8_t in_use;
} route_slot_t;
static route_slot_t g_route_slots[ROUTE_MSG_POOL_SIZE];
void route_msg_init(void)
{
memset(g_route_slots, 0, sizeof(g_route_slots));
}
static route_msg_t *route_msg_try_alloc_locked(void)
{
uint32_t index;
for (index = 0; index < ROUTE_MSG_POOL_SIZE; ++index) {
if (g_route_slots[index].in_use == 0u) {
g_route_slots[index].in_use = 1u;
g_route_slots[index].msg.data = g_route_slots[index].data;
g_route_slots[index].msg.len = 0u;
g_route_slots[index].msg.src_id = 0u;
g_route_slots[index].msg.dst_mask = 0u;
g_route_slots[index].msg.conn_type = 0u;
return &g_route_slots[index].msg;
}
}
return NULL;
}
route_msg_t *route_msg_alloc(TickType_t wait_ticks)
{
TickType_t start_tick = xTaskGetTickCount();
route_msg_t *msg;
do {
taskENTER_CRITICAL();
msg = route_msg_try_alloc_locked();
taskEXIT_CRITICAL();
if (msg != NULL) {
return msg;
}
if (wait_ticks == 0u) {
break;
}
vTaskDelay(pdMS_TO_TICKS(1));
} while ((xTaskGetTickCount() - start_tick) < wait_ticks);
return NULL;
}
route_msg_t *route_msg_alloc_from_isr(BaseType_t *xHigherPriorityTaskWoken)
{
route_msg_t *msg;
UBaseType_t saved_interrupt_status;
(void)xHigherPriorityTaskWoken;
saved_interrupt_status = taskENTER_CRITICAL_FROM_ISR();
msg = route_msg_try_alloc_locked();
taskEXIT_CRITICAL_FROM_ISR(saved_interrupt_status);
return msg;
}
void route_msg_free(route_msg_t *msg)
{
uint32_t index;
if (msg == NULL) {
return;
}
taskENTER_CRITICAL();
for (index = 0; index < ROUTE_MSG_POOL_SIZE; ++index) {
if (&g_route_slots[index].msg == msg) {
g_route_slots[index].in_use = 0u;
g_route_slots[index].msg.len = 0u;
break;
}
}
taskEXIT_CRITICAL();
}
void route_msg_free_from_isr(route_msg_t *msg)
{
uint32_t index;
UBaseType_t saved_interrupt_status;
if (msg == NULL) {
return;
}
saved_interrupt_status = taskENTER_CRITICAL_FROM_ISR();
for (index = 0; index < ROUTE_MSG_POOL_SIZE; ++index) {
if (&g_route_slots[index].msg == msg) {
g_route_slots[index].in_use = 0u;
g_route_slots[index].msg.len = 0u;
break;
}
}
taskEXIT_CRITICAL_FROM_ISR(saved_interrupt_status);
}
static bool route_prepare(route_msg_t *msg,
uint8_t src_id,
uint8_t dst_mask,
uint8_t conn_type,
const uint8_t *data,
uint16_t len)
{
if (msg == NULL || data == NULL || len == 0u || len > ROUTE_MSG_MAX_PAYLOAD) {
return false;
}
msg->src_id = src_id;
msg->dst_mask = dst_mask;
msg->conn_type = conn_type;
msg->len = len;
memcpy(msg->data, data, len);
return true;
}
bool route_send(QueueHandle_t queue,
uint8_t src_id,
uint8_t dst_mask,
uint8_t conn_type,
const uint8_t *data,
uint16_t len,
TickType_t wait_ticks)
{
route_msg_t *msg = route_msg_alloc(wait_ticks);
if (!route_prepare(msg, src_id, dst_mask, conn_type, data, len)) {
route_msg_free(msg);
return false;
}
if (xQueueSend(queue, &msg, wait_ticks) != pdPASS) {
route_msg_free(msg);
return false;
}
return true;
}
bool route_send_from_isr(QueueHandle_t queue,
uint8_t src_id,
uint8_t dst_mask,
uint8_t conn_type,
const uint8_t *data,
uint16_t len,
BaseType_t *xHigherPriorityTaskWoken)
{
route_msg_t *msg = route_msg_alloc_from_isr(xHigherPriorityTaskWoken);
if (!route_prepare(msg, src_id, dst_mask, conn_type, data, len)) {
route_msg_free_from_isr(msg);
return false;
}
if (xQueueSendFromISR(queue, &msg, xHigherPriorityTaskWoken) != pdPASS) {
route_msg_free_from_isr(msg);
return false;
}
return true;
}
+64
View File
@@ -0,0 +1,64 @@
#ifndef ROUTE_MSG_H
#define ROUTE_MSG_H
#include <stdbool.h>
#include <stdint.h>
#include "FreeRTOS.h"
#include "queue.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifndef ROUTE_MSG_POOL_SIZE
#define ROUTE_MSG_POOL_SIZE 8u
#endif
#ifndef ROUTE_MSG_MAX_PAYLOAD
#define ROUTE_MSG_MAX_PAYLOAD 512u
#endif
typedef enum {
ROUTE_CONN_UART1 = 0,
ROUTE_CONN_UART2,
ROUTE_CONN_UART3,
ROUTE_CONN_S1,
ROUTE_CONN_S2,
ROUTE_CONN_C1,
ROUTE_CONN_C2
} route_conn_type_t;
typedef struct {
uint8_t src_id;
uint8_t dst_mask;
uint16_t len;
uint8_t conn_type;
uint8_t *data;
} route_msg_t;
void route_msg_init(void);
route_msg_t *route_msg_alloc(TickType_t wait_ticks);
route_msg_t *route_msg_alloc_from_isr(BaseType_t *xHigherPriorityTaskWoken);
void route_msg_free(route_msg_t *msg);
void route_msg_free_from_isr(route_msg_t *msg);
bool route_send(QueueHandle_t queue,
uint8_t src_id,
uint8_t dst_mask,
uint8_t conn_type,
const uint8_t *data,
uint16_t len,
TickType_t wait_ticks);
bool route_send_from_isr(QueueHandle_t queue,
uint8_t src_id,
uint8_t dst_mask,
uint8_t conn_type,
const uint8_t *data,
uint16_t len,
BaseType_t *xHigherPriorityTaskWoken);
#ifdef __cplusplus
}
#endif
#endif
+116
View File
@@ -0,0 +1,116 @@
#include "task_net_poll.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "CH390.h"
#include <string.h>
#if !DIAG_CH390_RAW_POLL
#include "lwip/tcpip.h"
#include "lwip/ip4_addr.h"
#endif
#include "ethernetif.h"
#include "config.h"
#include "app_runtime.h"
#include "debug_log.h"
void NetPollTask(void *argument)
{
const device_config_t *cfg;
#if !DIAG_CH390_RAW_POLL
ip4_addr_t ipaddr;
ip4_addr_t netmask;
ip4_addr_t gateway;
#else
static uint8_t s_diag_rx_buffer[CH390_PKT_MAX];
#endif
BaseType_t loop_logged = pdFALSE;
(void)argument;
debug_log_write("[NET] task-entry\r\n");
cfg = config_get();
debug_log_write("[NET] config-ok\r\n");
#if DIAG_CH390_RAW_POLL
g_netif_phase = 1u;
debug_log_write("[NET] diag-ch390-init enter\r\n");
ethernetif_diag_ch390_init();
g_netif_phase = 7u;
debug_log_write("[NET] diag-ch390-init exit\r\n");
if (g_netif_init_ok != 1)
{
for (;;)
{
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
g_netif_ready = pdTRUE;
debug_log_write("[NET] diag-ch390-ready\r\n");
#else
debug_log_write("[NET] tcpip-init enter\r\n");
tcpip_init(NULL, NULL);
debug_log_write("[NET] tcpip-init exit\r\n");
vTaskDelay(pdMS_TO_TICKS(50));
debug_log_write("[NET] post-delay\r\n");
IP4_ADDR(&ipaddr, cfg->net.ip[0], cfg->net.ip[1], cfg->net.ip[2], cfg->net.ip[3]);
IP4_ADDR(&netmask, cfg->net.mask[0], cfg->net.mask[1], cfg->net.mask[2], cfg->net.mask[3]);
IP4_ADDR(&gateway, cfg->net.gw[0], cfg->net.gw[1], cfg->net.gw[2], cfg->net.gw[3]);
g_netif_phase = 1u;
debug_log_printf("[NET] netif-call hwm=%lu\r\n", (unsigned long)uxTaskGetStackHighWaterMark(NULL));
debug_log_write("[NET] netif-init enter\r\n");
lwip_netif_init(&ipaddr, &netmask, &gateway);
g_netif_phase = 7u;
debug_log_write("[NET] netif-init exit\r\n");
if (g_netif_init_ok != 1) {
for (;;) {
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
g_netif_ready = pdTRUE;
debug_log_write("[NET] netif-ready\r\n");
#endif
for (;;) {
if (loop_logged == pdFALSE) {
g_netif_phase = 8u;
debug_log_write("[NET] loop-enter\r\n");
loop_logged = pdTRUE;
}
(void)xSemaphoreTake(xNetSemaphore, pdMS_TO_TICKS(2));
#if DIAG_CH390_RAW_POLL
ethernetif_diag_poll_status();
if (g_eth_last_nsr_rxrdy != 0u)
{
uint8_t rx_status = 0u;
uint32_t rx_len = ch390_runtime_receive_packet(s_diag_rx_buffer, &rx_status);
if (rx_len > 0u)
{
g_eth_rx_count += 1u;
debug_log_printf("[RAW] rx len=%lu st=0x%02X h=%02X %02X %02X %02X\r\n",
(unsigned long)rx_len,
(unsigned int)rx_status,
(unsigned int)s_diag_rx_buffer[0],
(unsigned int)s_diag_rx_buffer[1],
(unsigned int)s_diag_rx_buffer[2],
(unsigned int)s_diag_rx_buffer[3]);
}
}
#else
ethernetif_poll();
ethernetif_check_link();
#endif
}
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef TASK_NET_POLL_H
#define TASK_NET_POLL_H
#ifdef __cplusplus
extern "C" {
#endif
void NetPollTask(void *argument);
#ifdef __cplusplus
}
#endif
#endif
+86 -408
View File
@@ -1,431 +1,109 @@
/**
* @file tcp_client.c
* @brief TCP Client module implementation for transparent transmission with UART3
*/
#include "tcp_client.h"
#include "config.h"
#include "lwip/opt.h"
#include "lwip/tcp.h"
#include "lwip/sys.h"
#include "lwip/sockets.h"
#include "FreeRTOS.h"
#include "task.h"
#include "stream_buffer.h"
#include "queue.h"
#include "lwip/api.h"
#include "lwip/ip_addr.h"
#include <string.h>
#include "app_runtime.h"
#include "config.h"
#include "route_msg.h"
/*---------------------------------------------------------------------------
* Private Variables
*---------------------------------------------------------------------------*/
/* Client configuration */
static tcp_client_config_t client_config = {
.server_ip = {192, 168, 1, 100},
.server_port = TCP_CLIENT_DEFAULT_PORT,
.auto_reconnect = true,
.reconnect_interval_ms = TCP_CLIENT_RECONNECT_DELAY_MS
};
/* Client status */
static tcp_client_status_t client_status = {
.state = TCP_CLIENT_STATE_IDLE,
.rx_bytes = 0,
.tx_bytes = 0,
.reconnect_count = 0,
.errors = 0
};
/* Socket descriptor */
static int client_socket = -1;
/* Stream buffers for UART integration */
static StreamBufferHandle_t rx_stream = NULL; /* TCP RX -> UART TX */
static StreamBufferHandle_t tx_stream = NULL; /* UART RX -> TCP TX */
/*---------------------------------------------------------------------------
* Private Functions
*---------------------------------------------------------------------------*/
static int tcp_client_send_all(int sock, const uint8_t *data, uint16_t len)
static void tcp_client_worker(struct netconn *conn, uint8_t link_index)
{
uint16_t total = 0;
struct netbuf *buf;
const device_config_t *cfg = config_get();
uint8_t uart_endpoint = config_uart_index_to_endpoint(cfg->links[link_index].uart);
uint8_t src_endpoint = config_link_index_to_endpoint(link_index);
err_t err;
route_msg_t *tx_msg;
while (total < len)
{
int sent = send(sock, data + total, len - total, 0);
if (sent > 0)
{
total += (uint16_t)sent;
netconn_set_recvtimeout(conn, 10);
for (;;) {
err = netconn_recv(conn, &buf);
if (err == ERR_OK) {
do {
void *data;
uint16_t len;
netbuf_data(buf, &data, &len);
(void)route_send(xTcpRxQueue,
src_endpoint,
uart_endpoint,
(link_index == CONFIG_LINK_C1) ? ROUTE_CONN_C1 : ROUTE_CONN_C2,
(const uint8_t *)data,
len,
pdMS_TO_TICKS(10));
} while (netbuf_next(buf) >= 0);
netbuf_delete(buf);
} else if (err != ERR_TIMEOUT) {
break;
}
else
{
return -1;
while (xQueueReceive(xLinkTxQueues[link_index], &tx_msg, 0) == pdPASS) {
err = netconn_write(conn, tx_msg->data, tx_msg->len, NETCONN_COPY);
route_msg_free(tx_msg);
if (err != ERR_OK) {
return;
}
}
}
return (int)total;
}
/**
* @brief Internal connect function
*/
static int tcp_client_do_connect(void)
{
struct sockaddr_in server_addr;
int ret;
if (client_socket >= 0)
{
/* Already connected */
return 0;
}
client_status.state = TCP_CLIENT_STATE_CONNECTING;
/* Create socket */
client_socket = socket(AF_INET, SOCK_STREAM, 0);
if (client_socket < 0)
{
client_status.state = TCP_CLIENT_STATE_ERROR;
client_status.errors++;
return -1;
}
/* Prepare server address */
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(client_config.server_port);
server_addr.sin_addr.s_addr = ((uint32_t)client_config.server_ip[0]) |
((uint32_t)client_config.server_ip[1] << 8) |
((uint32_t)client_config.server_ip[2] << 16) |
((uint32_t)client_config.server_ip[3] << 24);
/* Connect to server */
ret = connect(client_socket, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
close(client_socket);
client_socket = -1;
client_status.state = TCP_CLIENT_STATE_DISCONNECTED;
client_status.errors++;
return -1;
}
client_status.state = TCP_CLIENT_STATE_CONNECTED;
return 0;
}
/*---------------------------------------------------------------------------
* Public Functions
*---------------------------------------------------------------------------*/
/**
* @brief Initialize TCP Client module
*/
int tcp_client_init(const tcp_client_config_t *config)
{
if (config != NULL)
{
memcpy(&client_config, config, sizeof(tcp_client_config_t));
}
/* Create stream buffers */
if (rx_stream == NULL)
{
rx_stream = xStreamBufferCreate(TCP_CLIENT_RX_BUFFER_SIZE, 1);
if (rx_stream == NULL)
{
return -1;
}
}
if (tx_stream == NULL)
{
tx_stream = xStreamBufferCreate(TCP_CLIENT_TX_BUFFER_SIZE, 1);
if (tx_stream == NULL)
{
return -1;
}
}
client_status.state = TCP_CLIENT_STATE_IDLE;
return 0;
}
/**
* @brief Connect to remote server
*/
int tcp_client_connect(void)
{
return tcp_client_do_connect();
}
/**
* @brief Disconnect from server
*/
int tcp_client_disconnect(void)
{
if (client_socket >= 0)
{
close(client_socket);
client_socket = -1;
}
client_status.state = TCP_CLIENT_STATE_DISCONNECTED;
return 0;
}
/**
* @brief Send data to server
*/
int tcp_client_send(const uint8_t *data, uint16_t len)
{
int sent;
if (client_socket < 0)
{
return -1;
}
sent = tcp_client_send_all(client_socket, data, len);
if (sent > 0)
{
client_status.tx_bytes += sent;
}
else if (sent < 0)
{
/* Connection error */
close(client_socket);
client_socket = -1;
client_status.state = TCP_CLIENT_STATE_DISCONNECTED;
client_status.errors++;
}
return sent;
}
/**
* @brief Receive data from server
*/
int tcp_client_recv(uint8_t *data, uint16_t max_len, uint32_t timeout_ms)
{
int received;
struct timeval tv;
if (client_socket < 0)
{
return -1;
}
/* Set receive timeout */
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec = (timeout_ms % 1000) * 1000;
setsockopt(client_socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
received = recv(client_socket, data, max_len, 0);
if (received > 0)
{
client_status.rx_bytes += received;
}
else if (received == 0)
{
/* Connection closed by server */
close(client_socket);
client_socket = -1;
client_status.state = TCP_CLIENT_STATE_DISCONNECTED;
}
return received;
}
/**
* @brief Check if connected to server
*/
bool tcp_client_is_connected(void)
{
return (client_socket >= 0);
}
/**
* @brief Update server configuration
*/
int tcp_client_set_server(const uint8_t *ip, uint16_t port)
{
if (ip == NULL)
{
return -1;
}
/* Disconnect if connected */
if (client_socket >= 0)
{
tcp_client_disconnect();
}
memcpy(client_config.server_ip, ip, 4);
client_config.server_port = port;
return 0;
}
/**
* @brief Get TCP Client status
*/
void tcp_client_get_status(tcp_client_status_t *status)
{
if (status != NULL)
{
memcpy(status, &client_status, sizeof(tcp_client_status_t));
}
}
/**
* @brief Get RX StreamBuffer handle
*/
void *tcp_client_get_rx_stream(void)
{
return rx_stream;
}
/**
* @brief Get TX StreamBuffer handle
*/
void *tcp_client_get_tx_stream(void)
{
return tx_stream;
}
/**
* @brief TCP Client task
*/
void tcp_client_task(void *argument)
static void tcp_client_task(uint8_t link_index)
{
const device_config_t *cfg;
tcp_client_config_t task_cfg;
uint8_t rx_buffer[256];
uint8_t tx_buffer[256];
int received;
size_t tx_len;
fd_set read_fds;
struct timeval tv;
uint32_t reconnect_timer = 0;
(void)argument;
/* Initialize client */
task_cfg.server_ip[0] = 192;
task_cfg.server_ip[1] = 168;
task_cfg.server_ip[2] = 1;
task_cfg.server_ip[3] = 100;
task_cfg.server_port = TCP_CLIENT_DEFAULT_PORT;
task_cfg.auto_reconnect = true;
task_cfg.reconnect_interval_ms = TCP_CLIENT_RECONNECT_DELAY_MS;
struct netconn *conn;
ip_addr_t remote_ip;
uint32_t delay_ms;
cfg = config_get();
if (cfg != NULL)
{
memcpy(task_cfg.server_ip, cfg->remote_ip, sizeof(task_cfg.server_ip));
if (cfg->remote_port > 0)
{
task_cfg.server_port = cfg->remote_port;
}
if (cfg->reconnect_interval > 0)
{
task_cfg.reconnect_interval_ms = cfg->reconnect_interval;
}
}
tcp_client_init(&task_cfg);
while (1)
{
/* Handle connection state */
if (client_socket < 0)
{
/* Not connected - try to reconnect */
if (client_config.auto_reconnect)
{
if (xTaskGetTickCount() - reconnect_timer >= pdMS_TO_TICKS(client_config.reconnect_interval_ms))
{
if (tcp_client_do_connect() == 0)
{
/* Connected successfully */
client_status.reconnect_count++;
}
reconnect_timer = xTaskGetTickCount();
}
}
/* Wait before retry */
for (;;) {
while (g_netif_ready == pdFALSE) {
vTaskDelay(pdMS_TO_TICKS(100));
}
cfg = config_get();
if (cfg->links[link_index].enabled == 0u) {
vTaskDelay(pdMS_TO_TICKS(500));
continue;
}
/* Handle data transfer if connected */
/* Check for data from TCP server */
FD_ZERO(&read_fds);
FD_SET(client_socket, &read_fds);
tv.tv_sec = 0;
tv.tv_usec = 10000; /* 10ms timeout */
if (select(client_socket + 1, &read_fds, NULL, NULL, &tv) > 0)
{
if (FD_ISSET(client_socket, &read_fds))
{
received = recv(client_socket, rx_buffer, sizeof(rx_buffer), 0);
if (received > 0)
{
/* Forward to UART via stream buffer */
xStreamBufferSend(rx_stream, rx_buffer, received, pdMS_TO_TICKS(10));
client_status.rx_bytes += received;
}
else if (received == 0)
{
/* Connection closed */
close(client_socket);
client_socket = -1;
client_status.state = TCP_CLIENT_STATE_DISCONNECTED;
reconnect_timer = xTaskGetTickCount();
}
else
{
/* Error */
close(client_socket);
client_socket = -1;
client_status.state = TCP_CLIENT_STATE_DISCONNECTED;
client_status.errors++;
reconnect_timer = xTaskGetTickCount();
}
}
delay_ms = (cfg->reconnect_interval_ms == 0u) ? 3000u : cfg->reconnect_interval_ms;
conn = netconn_new(NETCONN_TCP);
if (conn == NULL) {
vTaskDelay(pdMS_TO_TICKS(delay_ms));
continue;
}
/* Check for data from UART to send to TCP */
tx_len = xStreamBufferReceive(tx_stream, tx_buffer, sizeof(tx_buffer), 0);
if (tx_len > 0)
{
int sent = tcp_client_send_all(client_socket, tx_buffer, (uint16_t)tx_len);
if (sent > 0)
{
client_status.tx_bytes += sent;
}
else if (sent < 0)
{
/* Send error */
close(client_socket);
client_socket = -1;
client_status.state = TCP_CLIENT_STATE_DISCONNECTED;
client_status.errors++;
reconnect_timer = xTaskGetTickCount();
}
if (cfg->links[link_index].local_port != 0u) {
(void)netconn_bind(conn, IP_ADDR_ANY, cfg->links[link_index].local_port);
}
/* Small delay to prevent tight loop */
vTaskDelay(pdMS_TO_TICKS(1));
IP_ADDR4(&remote_ip,
cfg->links[link_index].remote_ip[0],
cfg->links[link_index].remote_ip[1],
cfg->links[link_index].remote_ip[2],
cfg->links[link_index].remote_ip[3]);
if (netconn_connect(conn, &remote_ip, cfg->links[link_index].remote_port) == ERR_OK) {
tcp_client_worker(conn, link_index);
}
netconn_close(conn);
netconn_delete(conn);
vTaskDelay(pdMS_TO_TICKS(delay_ms));
}
}
void TcpCliTask_C1(void *argument)
{
(void)argument;
tcp_client_task(CONFIG_LINK_C1);
}
void TcpCliTask_C2(void *argument)
{
(void)argument;
tcp_client_task(CONFIG_LINK_C2);
}
+5 -122
View File
@@ -1,132 +1,15 @@
/**
* @file tcp_client.h
* @brief TCP Client module for transparent transmission with UART3
*/
#ifndef __TCP_CLIENT_H__
#define __TCP_CLIENT_H__
#include <stdint.h>
#include <stdbool.h>
#ifndef TCP_CLIENT_H
#define TCP_CLIENT_H
#ifdef __cplusplus
extern "C" {
#endif
/* Default TCP Client settings */
#define TCP_CLIENT_DEFAULT_PORT 8081
#define TCP_CLIENT_DEFAULT_SERVER "192.168.1.100"
/* 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 {
TCP_CLIENT_STATE_IDLE,
TCP_CLIENT_STATE_CONNECTING,
TCP_CLIENT_STATE_CONNECTED,
TCP_CLIENT_STATE_DISCONNECTED,
TCP_CLIENT_STATE_ERROR
} tcp_client_state_t;
/* TCP Client configuration */
typedef struct {
uint8_t server_ip[4]; /* Server IP address */
uint16_t server_port; /* Server port */
bool auto_reconnect; /* Auto reconnect on disconnect */
uint16_t reconnect_interval_ms; /* Reconnect interval */
} tcp_client_config_t;
/* TCP Client status */
typedef struct {
tcp_client_state_t state;
uint32_t rx_bytes;
uint32_t tx_bytes;
uint32_t reconnect_count;
uint32_t errors;
} tcp_client_status_t;
/**
* @brief Initialize TCP Client module
* @param config Client configuration
* @return 0 on success, negative on error
*/
int tcp_client_init(const tcp_client_config_t *config);
/**
* @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 TcpCliTask_C1(void *argument);
void TcpCliTask_C2(void *argument);
#ifdef __cplusplus
}
#endif
#endif /* __TCP_CLIENT_H__ */
#endif
+91 -386
View File
@@ -1,405 +1,110 @@
/**
* @file tcp_server.c
* @brief TCP Server module implementation for transparent transmission with UART2
*/
#include "tcp_server.h"
#include "config.h"
#include "lwip/opt.h"
#include "lwip/tcp.h"
#include "lwip/sys.h"
#include "lwip/sockets.h"
#include "FreeRTOS.h"
#include "task.h"
#include "stream_buffer.h"
#include "queue.h"
#include "lwip/api.h"
#include "lwip/ip_addr.h"
#include <string.h>
#include "app_runtime.h"
#include "config.h"
#include "route_msg.h"
/*---------------------------------------------------------------------------
* Private Variables
*---------------------------------------------------------------------------*/
/* Server configuration */
static tcp_server_config_t server_config = {
.port = TCP_SERVER_DEFAULT_PORT,
.auto_reconnect = true
};
/* Server status */
static tcp_server_status_t server_status = {
.state = TCP_SERVER_STATE_IDLE,
.rx_bytes = 0,
.tx_bytes = 0,
.connections = 0,
.errors = 0
};
/* Socket descriptors */
static int listen_socket = -1;
static int client_socket = -1;
/* Stream buffers for UART integration */
static StreamBufferHandle_t rx_stream = NULL; /* TCP RX -> UART TX */
static StreamBufferHandle_t tx_stream = NULL; /* UART RX -> TCP TX */
/*---------------------------------------------------------------------------
* Public Functions
*---------------------------------------------------------------------------*/
static int tcp_server_send_all(int sock, const uint8_t *data, uint16_t len)
static void tcp_server_worker(struct netconn *conn, uint8_t link_index)
{
uint16_t total = 0;
struct netbuf *buf;
const device_config_t *cfg = config_get();
uint8_t uart_endpoint = config_uart_index_to_endpoint(cfg->links[link_index].uart);
uint8_t src_endpoint = config_link_index_to_endpoint(link_index);
err_t err;
route_msg_t *tx_msg;
while (total < len)
{
int sent = send(sock, data + total, len - total, 0);
if (sent > 0)
{
total += (uint16_t)sent;
netconn_set_recvtimeout(conn, 10);
for (;;) {
err = netconn_recv(conn, &buf);
if (err == ERR_OK) {
do {
void *data;
uint16_t len;
netbuf_data(buf, &data, &len);
(void)route_send(xTcpRxQueue,
src_endpoint,
uart_endpoint,
(link_index == CONFIG_LINK_S1) ? ROUTE_CONN_S1 : ROUTE_CONN_S2,
(const uint8_t *)data,
len,
pdMS_TO_TICKS(10));
} while (netbuf_next(buf) >= 0);
netbuf_delete(buf);
} else if (err != ERR_TIMEOUT) {
break;
}
else
{
return -1;
while (xQueueReceive(xLinkTxQueues[link_index], &tx_msg, 0) == pdPASS) {
err = netconn_write(conn, tx_msg->data, tx_msg->len, NETCONN_COPY);
route_msg_free(tx_msg);
if (err != ERR_OK) {
return;
}
}
}
return (int)total;
}
/**
* @brief Initialize TCP Server module
*/
int tcp_server_init(const tcp_server_config_t *config)
{
if (config != NULL)
{
memcpy(&server_config, config, sizeof(tcp_server_config_t));
}
/* Create stream buffers */
if (rx_stream == NULL)
{
rx_stream = xStreamBufferCreate(TCP_SERVER_RX_BUFFER_SIZE, 1);
if (rx_stream == NULL)
{
return -1;
}
}
if (tx_stream == NULL)
{
tx_stream = xStreamBufferCreate(TCP_SERVER_TX_BUFFER_SIZE, 1);
if (tx_stream == NULL)
{
return -1;
}
}
server_status.state = TCP_SERVER_STATE_IDLE;
return 0;
}
/**
* @brief Start TCP Server
*/
int tcp_server_start(void)
{
struct sockaddr_in server_addr;
int opt = 1;
if (listen_socket >= 0)
{
/* Already started */
return 0;
}
/* Create socket */
listen_socket = socket(AF_INET, SOCK_STREAM, 0);
if (listen_socket < 0)
{
server_status.state = TCP_SERVER_STATE_ERROR;
server_status.errors++;
return -1;
}
/* Set socket options */
setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
/* Bind to port */
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(server_config.port);
if (bind(listen_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
{
close(listen_socket);
listen_socket = -1;
server_status.state = TCP_SERVER_STATE_ERROR;
server_status.errors++;
return -1;
}
/* Start listening */
if (listen(listen_socket, TCP_SERVER_MAX_CONNECTIONS) < 0)
{
close(listen_socket);
listen_socket = -1;
server_status.state = TCP_SERVER_STATE_ERROR;
server_status.errors++;
return -1;
}
server_status.state = TCP_SERVER_STATE_LISTENING;
return 0;
}
/**
* @brief Stop TCP Server
*/
int tcp_server_stop(void)
{
if (client_socket >= 0)
{
close(client_socket);
client_socket = -1;
}
if (listen_socket >= 0)
{
close(listen_socket);
listen_socket = -1;
}
server_status.state = TCP_SERVER_STATE_IDLE;
return 0;
}
/**
* @brief Send data to connected client
*/
int tcp_server_send(const uint8_t *data, uint16_t len)
{
int sent;
if (client_socket < 0)
{
return -1;
}
sent = tcp_server_send_all(client_socket, data, len);
if (sent > 0)
{
server_status.tx_bytes += sent;
}
else if (sent < 0)
{
/* Connection error */
close(client_socket);
client_socket = -1;
server_status.state = TCP_SERVER_STATE_LISTENING;
server_status.errors++;
}
return sent;
}
/**
* @brief Receive data from connected client
*/
int tcp_server_recv(uint8_t *data, uint16_t max_len, uint32_t timeout_ms)
{
int received;
struct timeval tv;
if (client_socket < 0)
{
return -1;
}
/* Set receive timeout */
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec = (timeout_ms % 1000) * 1000;
setsockopt(client_socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
received = recv(client_socket, data, max_len, 0);
if (received > 0)
{
server_status.rx_bytes += received;
}
else if (received == 0)
{
/* Connection closed by client */
close(client_socket);
client_socket = -1;
server_status.state = TCP_SERVER_STATE_LISTENING;
}
else if (received < 0)
{
/* Timeout or error - check errno */
/* For timeout, just return 0 */
}
return received;
}
/**
* @brief Check if client is connected
*/
bool tcp_server_is_connected(void)
{
return (client_socket >= 0);
}
/**
* @brief Get TCP Server status
*/
void tcp_server_get_status(tcp_server_status_t *status)
{
if (status != NULL)
{
memcpy(status, &server_status, sizeof(tcp_server_status_t));
}
}
/**
* @brief Get RX StreamBuffer handle
*/
void *tcp_server_get_rx_stream(void)
{
return rx_stream;
}
/**
* @brief Get TX StreamBuffer handle
*/
void *tcp_server_get_tx_stream(void)
{
return tx_stream;
}
/**
* @brief TCP Server task
*/
void tcp_server_task(void *argument)
static void tcp_server_task(uint8_t link_index)
{
const device_config_t *cfg;
tcp_server_config_t task_cfg;
struct sockaddr_in client_addr;
socklen_t addr_len;
uint8_t rx_buffer[256];
uint8_t tx_buffer[256];
int received;
size_t tx_len;
fd_set read_fds;
struct timeval tv;
int max_fd;
(void)argument;
/* Initialize server */
task_cfg.port = TCP_SERVER_DEFAULT_PORT;
task_cfg.auto_reconnect = true;
cfg = config_get();
if (cfg != NULL && cfg->server_port > 0)
{
task_cfg.port = cfg->server_port;
}
tcp_server_init(&task_cfg);
/* Start server */
while (tcp_server_start() != 0)
{
vTaskDelay(pdMS_TO_TICKS(1000));
}
while (1)
{
/* Check if we need to accept a new connection */
if (client_socket < 0 && listen_socket >= 0)
{
/* Use select with timeout to check for incoming connections */
FD_ZERO(&read_fds);
FD_SET(listen_socket, &read_fds);
tv.tv_sec = 0;
tv.tv_usec = 100000; /* 100ms timeout */
if (select(listen_socket + 1, &read_fds, NULL, NULL, &tv) > 0)
{
addr_len = sizeof(client_addr);
client_socket = accept(listen_socket, (struct sockaddr *)&client_addr, &addr_len);
if (client_socket >= 0)
{
server_status.state = TCP_SERVER_STATE_CONNECTED;
server_status.connections++;
}
struct netconn *listener;
struct netconn *newconn;
for (;;) {
while (g_netif_ready == pdFALSE) {
vTaskDelay(pdMS_TO_TICKS(100));
}
cfg = config_get();
if (cfg->links[link_index].enabled == 0u) {
vTaskDelay(pdMS_TO_TICKS(500));
continue;
}
listener = netconn_new(NETCONN_TCP);
if (listener == NULL) {
vTaskDelay(pdMS_TO_TICKS(500));
continue;
}
if (netconn_bind(listener, IP_ADDR_ANY, cfg->links[link_index].local_port) != ERR_OK ||
netconn_listen(listener) != ERR_OK) {
netconn_delete(listener);
vTaskDelay(pdMS_TO_TICKS(500));
continue;
}
for (;;) {
if (cfg->links[link_index].enabled == 0u) {
break;
}
if (netconn_accept(listener, &newconn) == ERR_OK) {
tcp_server_worker(newconn, link_index);
netconn_close(newconn);
netconn_delete(newconn);
}
}
/* Handle data transfer if connected */
if (client_socket >= 0)
{
/* Check for data from TCP client */
FD_ZERO(&read_fds);
FD_SET(client_socket, &read_fds);
max_fd = client_socket;
tv.tv_sec = 0;
tv.tv_usec = 10000; /* 10ms timeout */
if (select(max_fd + 1, &read_fds, NULL, NULL, &tv) > 0)
{
if (FD_ISSET(client_socket, &read_fds))
{
received = recv(client_socket, rx_buffer, sizeof(rx_buffer), 0);
if (received > 0)
{
/* Forward to UART via stream buffer */
xStreamBufferSend(rx_stream, rx_buffer, received, pdMS_TO_TICKS(10));
server_status.rx_bytes += received;
}
else if (received == 0)
{
/* Connection closed */
close(client_socket);
client_socket = -1;
server_status.state = TCP_SERVER_STATE_LISTENING;
}
else
{
/* Error */
close(client_socket);
client_socket = -1;
server_status.state = TCP_SERVER_STATE_LISTENING;
server_status.errors++;
}
}
}
/* Check for data from UART to send to TCP */
tx_len = xStreamBufferReceive(tx_stream, tx_buffer, sizeof(tx_buffer), 0);
if (tx_len > 0)
{
int sent = tcp_server_send_all(client_socket, tx_buffer, (uint16_t)tx_len);
if (sent > 0)
{
server_status.tx_bytes += sent;
}
else if (sent < 0)
{
/* Send error */
close(client_socket);
client_socket = -1;
server_status.state = TCP_SERVER_STATE_LISTENING;
server_status.errors++;
}
}
}
/* Small delay to prevent tight loop */
vTaskDelay(pdMS_TO_TICKS(1));
netconn_close(listener);
netconn_delete(listener);
}
}
void TcpSrvTask_S1(void *argument)
{
(void)argument;
tcp_server_task(CONFIG_LINK_S1);
}
void TcpSrvTask_S2(void *argument)
{
(void)argument;
tcp_server_task(CONFIG_LINK_S2);
}
+5 -109
View File
@@ -1,119 +1,15 @@
/**
* @file tcp_server.h
* @brief TCP Server module for transparent transmission with UART2
*/
#ifndef __TCP_SERVER_H__
#define __TCP_SERVER_H__
#include <stdint.h>
#include <stdbool.h>
#ifndef TCP_SERVER_H
#define TCP_SERVER_H
#ifdef __cplusplus
extern "C" {
#endif
/* Default TCP Server port */
#define TCP_SERVER_DEFAULT_PORT 8080
/* 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 {
TCP_SERVER_STATE_IDLE,
TCP_SERVER_STATE_LISTENING,
TCP_SERVER_STATE_CONNECTED,
TCP_SERVER_STATE_ERROR
} tcp_server_state_t;
/* TCP Server configuration */
typedef struct {
uint16_t port;
bool auto_reconnect;
} tcp_server_config_t;
/* TCP Server status */
typedef struct {
tcp_server_state_t state;
uint32_t rx_bytes;
uint32_t tx_bytes;
uint32_t connections;
uint32_t errors;
} tcp_server_status_t;
/**
* @brief Initialize TCP Server module
* @param config Server configuration
* @return 0 on success, negative on error
*/
int tcp_server_init(const tcp_server_config_t *config);
/**
* @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);
void TcpSrvTask_S1(void *argument);
void TcpSrvTask_S2(void *argument);
#ifdef __cplusplus
}
#endif
#endif /* __TCP_SERVER_H__ */
#endif
+402 -473
View File
@@ -1,528 +1,457 @@
/**
* @file uart_trans.c
* @brief UART transparent transmission module implementation
*
* Uses DMA + IDLE interrupt for efficient variable-length data reception.
* Integrates with TCP modules via FreeRTOS StreamBuffers.
*/
#include "uart_trans.h"
#include "usart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "stream_buffer.h"
#include <string.h>
/*---------------------------------------------------------------------------
* Private Definitions
*---------------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "usart.h"
#include "app_runtime.h"
#include "config.h"
#include "debug_log.h"
#include "route_msg.h"
#define UART_MUX_SYNC 0x7Eu
#define UART_MUX_TAIL 0x7Fu
#define UART_NOTIFY_RX_U0 (1UL << 0)
#define UART_NOTIFY_RX_U1 (1UL << 1)
#define UART_NOTIFY_TX_U0 (1UL << 8)
#define UART_NOTIFY_TX_U1 (1UL << 9)
/* Channel context structure */
typedef struct {
UART_HandleTypeDef *huart; /* HAL UART handle */
DMA_HandleTypeDef *hdma_rx; /* DMA RX handle */
uint8_t rx_dma_buffer[UART_RX_DMA_BUFFER_SIZE]; /* DMA RX buffer */
uint8_t tx_dma_buffer[UART_TX_DMA_BUFFER_SIZE]; /* DMA TX buffer */
volatile uint16_t rx_read_index; /* Last read position */
volatile bool tx_busy; /* TX in progress flag */
StreamBufferHandle_t rx_stream; /* From TCP (for UART TX) */
StreamBufferHandle_t tx_stream; /* To TCP (from UART RX) */
uart_config_t config; /* UART configuration */
uart_stats_t stats; /* Statistics */
bool initialized;
bool running;
UART_HandleTypeDef *huart;
uint8_t rx_dma_buffer[UART_RX_DMA_BUFFER_SIZE];
uint8_t tx_dma_buffer[UART_TX_DMA_BUFFER_SIZE];
uint8_t rx_ring[UART_RX_RING_BUFFER_SIZE];
uint8_t tx_ring[UART_TX_RING_BUFFER_SIZE];
volatile uint16_t rx_dma_read_index;
volatile uint16_t rx_head;
volatile uint16_t rx_tail;
volatile uint16_t tx_head;
volatile uint16_t tx_tail;
volatile uint16_t tx_dma_len;
volatile uint8_t tx_busy;
} uart_channel_ctx_t;
/*---------------------------------------------------------------------------
* Private Variables
*---------------------------------------------------------------------------*/
static uart_channel_ctx_t g_channels[UART_CHANNEL_MAX];
/*---------------------------------------------------------------------------
* Private Functions
*---------------------------------------------------------------------------*/
/**
* @brief Apply UART configuration
*/
static int apply_uart_config(uart_channel_t channel)
static uint16_t ring_used(uint16_t head, uint16_t tail, uint16_t size)
{
uart_channel_ctx_t *ctx = &g_channels[channel];
UART_HandleTypeDef *huart = ctx->huart;
if (huart == NULL)
{
return -1;
}
/* Stop UART if running */
if (ctx->running)
{
HAL_UART_DMAStop(huart);
}
/* Update UART parameters */
huart->Init.BaudRate = ctx->config.baudrate;
/* Data bits */
if (ctx->config.data_bits == 9)
{
huart->Init.WordLength = UART_WORDLENGTH_9B;
}
else
{
huart->Init.WordLength = UART_WORDLENGTH_8B;
}
/* Stop bits */
if (ctx->config.stop_bits == 2)
{
huart->Init.StopBits = UART_STOPBITS_2;
}
else
{
huart->Init.StopBits = UART_STOPBITS_1;
}
/* Parity */
switch (ctx->config.parity)
{
case 1:
huart->Init.Parity = UART_PARITY_ODD;
break;
case 2:
huart->Init.Parity = UART_PARITY_EVEN;
break;
default:
huart->Init.Parity = UART_PARITY_NONE;
break;
}
/* Reinitialize UART */
if (HAL_UART_Init(huart) != HAL_OK)
{
return -1;
}
return 0;
return (head >= tail) ? (head - tail) : (size - tail + head);
}
static void process_rx_data_from_isr(uart_channel_t channel, uint16_t end_index)
static uint16_t ring_free(uint16_t head, uint16_t tail, uint16_t size)
{
return (uint16_t)(size - ring_used(head, tail, size) - 1u);
}
static void process_rx_snapshot(uart_channel_t channel)
{
uart_channel_ctx_t *ctx = &g_channels[channel];
uint16_t start = ctx->rx_read_index;
uint16_t end = end_index;
uint16_t dma_write_index = (uint16_t)(UART_RX_DMA_BUFFER_SIZE - __HAL_DMA_GET_COUNTER(ctx->huart->hdmarx));
if (dma_write_index >= UART_RX_DMA_BUFFER_SIZE) {
dma_write_index = 0u;
}
while (ctx->rx_dma_read_index != dma_write_index) {
uint16_t next_head = (uint16_t)((ctx->rx_head + 1u) % UART_RX_RING_BUFFER_SIZE);
if (next_head == ctx->rx_tail) {
break;
}
ctx->rx_ring[ctx->rx_head] = ctx->rx_dma_buffer[ctx->rx_dma_read_index];
ctx->rx_head = next_head;
ctx->rx_dma_read_index = (uint16_t)((ctx->rx_dma_read_index + 1u) % UART_RX_DMA_BUFFER_SIZE);
}
}
static void kick_tx(uart_channel_t channel)
{
uart_channel_ctx_t *ctx = &g_channels[channel];
uint16_t available;
uint16_t chunk;
uint16_t i;
if (ctx->tx_busy != 0u) {
return;
}
available = ring_used(ctx->tx_head, ctx->tx_tail, UART_TX_RING_BUFFER_SIZE);
if (available == 0u) {
return;
}
chunk = available;
if (chunk > UART_TX_DMA_BUFFER_SIZE) {
chunk = UART_TX_DMA_BUFFER_SIZE;
}
for (i = 0; i < chunk; ++i) {
ctx->tx_dma_buffer[i] = ctx->tx_ring[ctx->tx_tail];
ctx->tx_tail = (uint16_t)((ctx->tx_tail + 1u) % UART_TX_RING_BUFFER_SIZE);
}
ctx->tx_dma_len = chunk;
ctx->tx_busy = 1u;
if (HAL_UART_Transmit_DMA(ctx->huart, ctx->tx_dma_buffer, chunk) != HAL_OK) {
ctx->tx_busy = 0u;
}
}
static uint16_t uart_ring_available(uart_channel_t channel)
{
return ring_used(g_channels[channel].rx_head, g_channels[channel].rx_tail, UART_RX_RING_BUFFER_SIZE);
}
static uint16_t uart_ring_read(uart_channel_t channel, uint8_t *data, uint16_t max_len)
{
uart_channel_ctx_t *ctx = &g_channels[channel];
uint16_t copied = 0u;
while (copied < max_len && ctx->rx_tail != ctx->rx_head) {
data[copied++] = ctx->rx_ring[ctx->rx_tail];
ctx->rx_tail = (uint16_t)((ctx->rx_tail + 1u) % UART_RX_RING_BUFFER_SIZE);
}
return copied;
}
static bool uart_ring_peek_byte(uart_channel_t channel, uint16_t offset, uint8_t *data)
{
uart_channel_ctx_t *ctx = &g_channels[channel];
uint16_t available = ring_used(ctx->rx_head, ctx->rx_tail, UART_RX_RING_BUFFER_SIZE);
if (data == NULL || offset >= available) {
return false;
}
*data = ctx->rx_ring[(ctx->rx_tail + offset) % UART_RX_RING_BUFFER_SIZE];
return true;
}
static void uart_ring_drop(uart_channel_t channel, uint16_t len)
{
uart_channel_ctx_t *ctx = &g_channels[channel];
ctx->rx_tail = (uint16_t)((ctx->rx_tail + len) % UART_RX_RING_BUFFER_SIZE);
}
static void uart_route_raw_channel(uart_channel_t channel)
{
const device_config_t *cfg = config_get();
uint8_t buffer[ROUTE_MSG_MAX_PAYLOAD];
uint16_t len;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
uint8_t uart_endpoint = (channel == UART_CHANNEL_U1) ? ENDPOINT_UART3 : ENDPOINT_UART2;
uint32_t i;
if (start >= UART_RX_DMA_BUFFER_SIZE)
{
start = 0;
len = uart_ring_read(channel, buffer, sizeof(buffer));
if (len == 0u) {
return;
}
if (end > UART_RX_DMA_BUFFER_SIZE)
{
end = UART_RX_DMA_BUFFER_SIZE;
}
if (end >= start)
{
len = end - start;
if (len > 0 && ctx->tx_stream != NULL)
{
xStreamBufferSendFromISR(ctx->tx_stream,
&ctx->rx_dma_buffer[start],
len,
&xHigherPriorityTaskWoken);
ctx->stats.rx_bytes += len;
ctx->stats.rx_packets++;
}
}
else
{
len = UART_RX_DMA_BUFFER_SIZE - start;
if (len > 0 && ctx->tx_stream != NULL)
{
xStreamBufferSendFromISR(ctx->tx_stream,
&ctx->rx_dma_buffer[start],
len,
&xHigherPriorityTaskWoken);
ctx->stats.rx_bytes += len;
for (i = 0; i < CONFIG_LINK_COUNT; ++i) {
if (cfg->links[i].enabled == 0u || cfg->links[i].uart != ((channel == UART_CHANNEL_U1) ? LINK_UART_U1 : LINK_UART_U0)) {
continue;
}
if (end > 0 && ctx->tx_stream != NULL)
{
xStreamBufferSendFromISR(ctx->tx_stream,
ctx->rx_dma_buffer,
end,
&xHigherPriorityTaskWoken);
ctx->stats.rx_bytes += end;
}
ctx->stats.rx_packets++;
(void)route_send(xLinkTxQueues[i],
uart_endpoint,
config_link_index_to_endpoint((uint8_t)i),
(channel == UART_CHANNEL_U1) ? ROUTE_CONN_UART3 : ROUTE_CONN_UART2,
buffer,
len,
pdMS_TO_TICKS(10));
}
ctx->rx_read_index = (end == UART_RX_DMA_BUFFER_SIZE) ? 0 : end;
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
/*---------------------------------------------------------------------------
* Public Functions
*---------------------------------------------------------------------------*/
static void uart_send_tcp_msg_to_uarts(route_msg_t *msg)
{
uint8_t frame[ROUTE_MSG_MAX_PAYLOAD + 6u];
uint16_t frame_len = 0u;
if ((msg->dst_mask & ENDPOINT_UART2) != 0u) {
if (config_get()->mux_mode == MUX_MODE_FRAME) {
if (uart_mux_encode_frame(msg->src_id, ENDPOINT_UART2, msg->data, msg->len, frame, &frame_len, sizeof(frame))) {
(void)uart_trans_send_buffer(UART_CHANNEL_U0, frame, frame_len);
}
} else {
(void)uart_trans_send_buffer(UART_CHANNEL_U0, msg->data, msg->len);
}
}
if ((msg->dst_mask & ENDPOINT_UART3) != 0u) {
if (config_get()->mux_mode == MUX_MODE_FRAME) {
if (uart_mux_encode_frame(msg->src_id, ENDPOINT_UART3, msg->data, msg->len, frame, &frame_len, sizeof(frame))) {
(void)uart_trans_send_buffer(UART_CHANNEL_U1, frame, frame_len);
}
} else {
(void)uart_trans_send_buffer(UART_CHANNEL_U1, msg->data, msg->len);
}
}
}
static void uart_route_mux_frame(uart_channel_t source_channel, const uart_mux_frame_t *frame)
{
uint32_t i;
uint8_t source_conn = (source_channel == UART_CHANNEL_U1) ? ROUTE_CONN_UART3 : ROUTE_CONN_UART2;
uint8_t out_frame[ROUTE_MSG_MAX_PAYLOAD + 6u];
uint16_t out_frame_len = 0u;
if (frame->dst_mask == 0u) {
(void)route_send(xConfigQueue,
frame->src_id,
0u,
source_conn,
frame->payload,
frame->payload_len,
pdMS_TO_TICKS(10));
return;
}
for (i = 0; i < CONFIG_LINK_COUNT; ++i) {
uint8_t endpoint = config_link_index_to_endpoint((uint8_t)i);
if ((frame->dst_mask & endpoint) != 0u) {
(void)route_send(xLinkTxQueues[i], frame->src_id, endpoint, source_conn, frame->payload, frame->payload_len, pdMS_TO_TICKS(10));
}
}
if ((frame->dst_mask & ENDPOINT_UART2) != 0u && source_channel != UART_CHANNEL_U0) {
if (uart_mux_encode_frame(frame->src_id, ENDPOINT_UART2, frame->payload, frame->payload_len, out_frame, &out_frame_len, sizeof(out_frame))) {
(void)uart_trans_send_buffer(UART_CHANNEL_U0, out_frame, out_frame_len);
}
}
if ((frame->dst_mask & ENDPOINT_UART3) != 0u && source_channel != UART_CHANNEL_U1) {
if (uart_mux_encode_frame(frame->src_id, ENDPOINT_UART3, frame->payload, frame->payload_len, out_frame, &out_frame_len, sizeof(out_frame))) {
(void)uart_trans_send_buffer(UART_CHANNEL_U1, out_frame, out_frame_len);
}
}
}
/**
* @brief Initialize UART transparent transmission module
*/
int uart_trans_init(void)
{
/* Initialize Server channel (UART2) */
memset(&g_channels[UART_CHANNEL_SERVER], 0, sizeof(uart_channel_ctx_t));
g_channels[UART_CHANNEL_SERVER].huart = &huart2;
g_channels[UART_CHANNEL_SERVER].config.baudrate = UART_DEFAULT_BAUDRATE;
g_channels[UART_CHANNEL_SERVER].config.data_bits = UART_DEFAULT_DATA_BITS;
g_channels[UART_CHANNEL_SERVER].config.stop_bits = UART_DEFAULT_STOP_BITS;
g_channels[UART_CHANNEL_SERVER].config.parity = UART_DEFAULT_PARITY;
g_channels[UART_CHANNEL_SERVER].initialized = true;
/* Initialize Client channel (UART3) */
memset(&g_channels[UART_CHANNEL_CLIENT], 0, sizeof(uart_channel_ctx_t));
g_channels[UART_CHANNEL_CLIENT].huart = &huart3;
g_channels[UART_CHANNEL_CLIENT].config.baudrate = UART_DEFAULT_BAUDRATE;
g_channels[UART_CHANNEL_CLIENT].config.data_bits = UART_DEFAULT_DATA_BITS;
g_channels[UART_CHANNEL_CLIENT].config.stop_bits = UART_DEFAULT_STOP_BITS;
g_channels[UART_CHANNEL_CLIENT].config.parity = UART_DEFAULT_PARITY;
g_channels[UART_CHANNEL_CLIENT].initialized = true;
memset(g_channels, 0, sizeof(g_channels));
g_channels[UART_CHANNEL_U0].huart = &huart2;
g_channels[UART_CHANNEL_U1].huart = &huart3;
debug_log_printf("[UART] init u0=%p u1=%p\r\n", (void *)g_channels[UART_CHANNEL_U0].huart, (void *)g_channels[UART_CHANNEL_U1].huart);
return 0;
}
/**
* @brief Configure UART channel parameters
*/
int uart_trans_config(uart_channel_t channel, const uart_config_t *config)
int uart_trans_config(uint8_t uart_index, uint32_t baudrate)
{
if (channel >= UART_CHANNEL_MAX || config == NULL)
{
return -1;
UART_HandleTypeDef *huart = (uart_index == LINK_UART_U1) ? &huart3 : &huart2;
huart->Init.BaudRate = baudrate;
return (HAL_UART_Init(huart) == HAL_OK) ? 0 : -1;
}
int uart_trans_start_all(void)
{
uint32_t i;
for (i = 0; i < UART_CHANNEL_MAX; ++i) {
if (g_channels[i].huart == NULL) {
debug_log_printf("[UART] start fail null handle ch=%lu\r\n", (unsigned long)i);
return -1;
}
g_channels[i].rx_dma_read_index = 0u;
g_channels[i].rx_head = 0u;
g_channels[i].rx_tail = 0u;
g_channels[i].tx_head = 0u;
g_channels[i].tx_tail = 0u;
g_channels[i].tx_dma_len = 0u;
g_channels[i].tx_busy = 0u;
__HAL_UART_ENABLE_IT(g_channels[i].huart, UART_IT_IDLE);
if (HAL_UART_Receive_DMA(g_channels[i].huart, g_channels[i].rx_dma_buffer, UART_RX_DMA_BUFFER_SIZE) != HAL_OK) {
debug_log_printf("[UART] dma start fail ch=%lu\r\n", (unsigned long)i);
return -1;
}
}
uart_channel_ctx_t *ctx = &g_channels[channel];
memcpy(&ctx->config, config, sizeof(uart_config_t));
/* Apply configuration if already initialized */
if (ctx->initialized)
{
return apply_uart_config(channel);
}
debug_log_write("[UART] rx dma started\r\n");
return 0;
}
/**
* @brief Start UART reception
*/
int uart_trans_start(uart_channel_t channel)
bool uart_trans_send_buffer(uart_channel_t channel, const uint8_t *data, uint16_t len)
{
if (channel >= UART_CHANNEL_MAX)
{
return -1;
}
uart_channel_ctx_t *ctx = &g_channels[channel];
if (!ctx->initialized || ctx->huart == NULL)
{
return -1;
uint16_t written = 0u;
if (data == NULL || len == 0u) {
return false;
}
/* Reset read index */
ctx->rx_read_index = 0;
ctx->tx_busy = false;
/* Enable IDLE interrupt */
__HAL_UART_ENABLE_IT(ctx->huart, UART_IT_IDLE);
/* Start DMA reception (circular mode) */
HAL_UART_Receive_DMA(ctx->huart, ctx->rx_dma_buffer, UART_RX_DMA_BUFFER_SIZE);
ctx->running = true;
return 0;
while (written < len && ring_free(ctx->tx_head, ctx->tx_tail, UART_TX_RING_BUFFER_SIZE) > 0u) {
ctx->tx_ring[ctx->tx_head] = data[written++];
ctx->tx_head = (uint16_t)((ctx->tx_head + 1u) % UART_TX_RING_BUFFER_SIZE);
}
kick_tx(channel);
return (written == len);
}
/**
* @brief Stop UART reception
*/
int uart_trans_stop(uart_channel_t channel)
void uart_trans_notify_rx_from_isr(uart_channel_t channel, BaseType_t *xHigherPriorityTaskWoken)
{
if (channel >= UART_CHANNEL_MAX)
{
return -1;
}
uart_channel_ctx_t *ctx = &g_channels[channel];
if (ctx->huart == NULL)
{
return -1;
}
/* Disable IDLE interrupt */
__HAL_UART_DISABLE_IT(ctx->huart, UART_IT_IDLE);
/* Stop DMA */
HAL_UART_DMAStop(ctx->huart);
ctx->running = false;
return 0;
}
/**
* @brief Set StreamBuffer handles
*/
void uart_trans_set_streams(uart_channel_t channel,
void *rx_stream,
void *tx_stream)
{
if (channel >= UART_CHANNEL_MAX)
{
return;
}
g_channels[channel].rx_stream = (StreamBufferHandle_t)rx_stream;
g_channels[channel].tx_stream = (StreamBufferHandle_t)tx_stream;
}
/**
* @brief Get UART statistics
*/
void uart_trans_get_stats(uart_channel_t channel, uart_stats_t *stats)
{
if (channel >= UART_CHANNEL_MAX || stats == NULL)
{
return;
}
memcpy(stats, &g_channels[channel].stats, sizeof(uart_stats_t));
}
/**
* @brief Reset UART statistics
*/
void uart_trans_reset_stats(uart_channel_t channel)
{
if (channel >= UART_CHANNEL_MAX)
{
return;
}
memset(&g_channels[channel].stats, 0, sizeof(uart_stats_t));
}
/**
* @brief UART IDLE interrupt handler
*/
void uart_trans_idle_handler(uart_channel_t channel)
{
if (channel >= UART_CHANNEL_MAX)
{
return;
}
uart_channel_ctx_t *ctx = &g_channels[channel];
if (!ctx->running || ctx->huart == NULL)
{
return;
}
/* Get current DMA position */
uint16_t dma_counter = __HAL_DMA_GET_COUNTER(ctx->huart->hdmarx);
uint16_t current_pos = UART_RX_DMA_BUFFER_SIZE - dma_counter;
/* Process received data */
if (current_pos != ctx->rx_read_index)
{
process_rx_data_from_isr(channel, current_pos);
uint32_t notify = (channel == UART_CHANNEL_U1) ? UART_NOTIFY_RX_U1 : UART_NOTIFY_RX_U0;
if (xUartRxTaskHandle != NULL) {
xTaskNotifyFromISR(xUartRxTaskHandle, notify, eSetBits, xHigherPriorityTaskWoken);
}
}
void uart_trans_rx_half_cplt_handler(uart_channel_t channel)
{
if (channel >= UART_CHANNEL_MAX)
{
return;
}
uart_channel_ctx_t *ctx = &g_channels[channel];
if (!ctx->running || ctx->huart == NULL)
{
return;
}
uint16_t dma_counter = __HAL_DMA_GET_COUNTER(ctx->huart->hdmarx);
uint16_t current_pos = UART_RX_DMA_BUFFER_SIZE - dma_counter;
if (current_pos != ctx->rx_read_index)
{
process_rx_data_from_isr(channel, current_pos);
}
}
/**
* @brief UART DMA RX complete callback (buffer half/full)
*/
void uart_trans_rx_cplt_handler(uart_channel_t channel)
{
/* In circular mode, this is called when buffer is full */
/* The IDLE handler already processes data continuously */
/* This is a safety handler for high-speed continuous data */
if (channel >= UART_CHANNEL_MAX)
{
return;
}
uart_channel_ctx_t *ctx = &g_channels[channel];
if (!ctx->running)
{
return;
}
uint16_t dma_counter = __HAL_DMA_GET_COUNTER(ctx->huart->hdmarx);
uint16_t current_pos = UART_RX_DMA_BUFFER_SIZE - dma_counter;
if (current_pos != ctx->rx_read_index)
{
process_rx_data_from_isr(channel, current_pos);
}
}
/**
* @brief UART DMA TX complete callback
*/
void uart_trans_tx_cplt_handler(uart_channel_t channel)
{
if (channel >= UART_CHANNEL_MAX)
{
return;
}
g_channels[channel].tx_busy = false;
}
/**
* @brief Server transparent transmission task (UART2 <-> TCP Server)
*/
void uart_server_trans_task(void *argument)
{
uart_channel_ctx_t *ctx = &g_channels[UART_CHANNEL_SERVER];
uint8_t tx_buffer[128];
size_t len;
(void)argument;
/* Wait for streams to be set */
while (ctx->rx_stream == NULL || ctx->tx_stream == NULL)
{
vTaskDelay(pdMS_TO_TICKS(100));
}
/* Start UART reception */
uart_trans_start(UART_CHANNEL_SERVER);
while (1)
{
/* Check for data from TCP to send to UART */
if (!ctx->tx_busy && ctx->rx_stream != NULL)
{
len = xStreamBufferReceive(ctx->rx_stream, tx_buffer,
sizeof(tx_buffer), pdMS_TO_TICKS(10));
if (len > 0)
{
/* Copy to DMA buffer and send */
memcpy(ctx->tx_dma_buffer, tx_buffer, len);
ctx->tx_busy = true;
if (HAL_UART_Transmit_DMA(ctx->huart, ctx->tx_dma_buffer, len) != HAL_OK)
{
ctx->tx_busy = false;
ctx->stats.errors++;
}
else
{
ctx->stats.tx_bytes += len;
ctx->stats.tx_packets++;
}
}
}
else
{
/* TX busy or no stream, wait a bit */
vTaskDelay(pdMS_TO_TICKS(1));
}
uint32_t notify = (channel == UART_CHANNEL_U1) ? UART_NOTIFY_TX_U1 : UART_NOTIFY_TX_U0;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if (xUartRxTaskHandle != NULL) {
xTaskNotifyFromISR(xUartRxTaskHandle, notify, eSetBits, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
/**
* @brief Client transparent transmission task (UART3 <-> TCP Client)
*/
void uart_client_trans_task(void *argument)
bool uart_mux_try_extract_frame(uart_channel_t channel, uart_mux_frame_t *frame)
{
uart_channel_ctx_t *ctx = &g_channels[UART_CHANNEL_CLIENT];
uint8_t tx_buffer[128];
size_t len;
(void)argument;
/* Wait for streams to be set */
while (ctx->rx_stream == NULL || ctx->tx_stream == NULL)
{
vTaskDelay(pdMS_TO_TICKS(100));
uint16_t available;
uint16_t payload_len;
uint8_t sync_byte;
uint16_t i;
if (frame == NULL) {
return false;
}
/* Start UART reception */
uart_trans_start(UART_CHANNEL_CLIENT);
while (1)
{
/* Check for data from TCP to send to UART */
if (!ctx->tx_busy && ctx->rx_stream != NULL)
{
len = xStreamBufferReceive(ctx->rx_stream, tx_buffer,
sizeof(tx_buffer), pdMS_TO_TICKS(10));
if (len > 0)
{
/* Copy to DMA buffer and send */
memcpy(ctx->tx_dma_buffer, tx_buffer, len);
ctx->tx_busy = true;
if (HAL_UART_Transmit_DMA(ctx->huart, ctx->tx_dma_buffer, len) != HAL_OK)
{
ctx->tx_busy = false;
ctx->stats.errors++;
}
else
{
ctx->stats.tx_bytes += len;
ctx->stats.tx_packets++;
}
available = uart_ring_available(channel);
if (available == 0u) {
return false;
}
if (!uart_ring_peek_byte(channel, 0u, &sync_byte)) {
return false;
}
if (sync_byte != UART_MUX_SYNC) {
uart_ring_drop(channel, 1u);
return false;
}
if (available < 6u) {
return false;
}
if (!uart_ring_peek_byte(channel, 1u, &sync_byte)) {
return false;
}
payload_len = (uint16_t)((uint16_t)sync_byte << 8);
if (!uart_ring_peek_byte(channel, 2u, &sync_byte)) {
return false;
}
payload_len = (uint16_t)(payload_len | sync_byte);
if (payload_len > sizeof(frame->payload)) {
uart_ring_drop(channel, 1u);
return false;
}
if (available < (uint16_t)(payload_len + 6u)) {
return false;
}
if (!uart_ring_peek_byte(channel, 5u + payload_len, &sync_byte)) {
return false;
}
if (sync_byte != UART_MUX_TAIL) {
uart_ring_drop(channel, 1u);
return false;
}
if (!uart_ring_peek_byte(channel, 3u, &frame->src_id) ||
!uart_ring_peek_byte(channel, 4u, &frame->dst_mask)) {
return false;
}
frame->payload_len = payload_len;
for (i = 0u; i < payload_len; ++i) {
if (!uart_ring_peek_byte(channel, (uint16_t)(5u + i), &frame->payload[i])) {
return false;
}
}
uart_ring_drop(channel, (uint16_t)(payload_len + 6u));
return true;
}
bool uart_mux_encode_frame(uint8_t src_id,
uint8_t dst_mask,
const uint8_t *payload,
uint16_t payload_len,
uint8_t *out,
uint16_t *out_len,
uint16_t out_capacity)
{
uint16_t frame_len = (uint16_t)(payload_len + 6u);
if (out == NULL || out_len == NULL || frame_len > out_capacity) {
return false;
}
out[0] = UART_MUX_SYNC;
out[1] = (uint8_t)(payload_len >> 8);
out[2] = (uint8_t)(payload_len & 0xFFu);
out[3] = src_id;
out[4] = dst_mask;
if (payload_len > 0u && payload != NULL) {
memcpy(&out[5], payload, payload_len);
}
out[5 + payload_len] = UART_MUX_TAIL;
*out_len = frame_len;
return true;
}
void UartRxTask(void *argument)
{
uint32_t notify_value;
route_msg_t *msg;
uart_mux_frame_t frame;
const device_config_t *cfg;
(void)argument;
if (uart_trans_start_all() != 0) {
Debug_TrapWithRttHint("uart-start-fail");
vTaskSuspend(NULL);
}
debug_log_boot("uart-task-started");
for (;;) {
(void)xTaskNotifyWait(0u, 0xFFFFFFFFu, &notify_value, pdMS_TO_TICKS(10));
if ((notify_value & UART_NOTIFY_RX_U0) != 0u) {
process_rx_snapshot(UART_CHANNEL_U0);
}
if ((notify_value & UART_NOTIFY_RX_U1) != 0u) {
process_rx_snapshot(UART_CHANNEL_U1);
}
if ((notify_value & UART_NOTIFY_TX_U0) != 0u) {
g_channels[UART_CHANNEL_U0].tx_busy = 0u;
}
if ((notify_value & UART_NOTIFY_TX_U1) != 0u) {
g_channels[UART_CHANNEL_U1].tx_busy = 0u;
}
while (xQueueReceive(xTcpRxQueue, &msg, 0) == pdPASS) {
uart_send_tcp_msg_to_uarts(msg);
route_msg_free(msg);
}
cfg = config_get();
if (cfg->mux_mode == MUX_MODE_FRAME) {
while (uart_mux_try_extract_frame(UART_CHANNEL_U0, &frame)) {
uart_route_mux_frame(UART_CHANNEL_U0, &frame);
}
while (uart_mux_try_extract_frame(UART_CHANNEL_U1, &frame)) {
uart_route_mux_frame(UART_CHANNEL_U1, &frame);
}
} else {
uart_route_raw_channel(UART_CHANNEL_U0);
uart_route_raw_channel(UART_CHANNEL_U1);
}
else
{
/* TX busy or no stream, wait a bit */
vTaskDelay(pdMS_TO_TICKS(1));
}
kick_tx(UART_CHANNEL_U0);
kick_tx(UART_CHANNEL_U1);
}
}
+30 -130
View File
@@ -1,151 +1,51 @@
/**
* @file uart_trans.h
* @brief UART transparent transmission module for TCP2UART
*
* - UART2 <-> TCP Server (via StreamBuffer)
* - UART3 <-> TCP Client (via StreamBuffer)
* - DMA + IDLE interrupt for efficient reception
*/
#ifndef UART_TRANS_H
#define UART_TRANS_H
#ifndef __UART_TRANS_H__
#define __UART_TRANS_H__
#include <stdint.h>
#include <stdbool.h>
#include <stdint.h>
#include "FreeRTOS.h"
#ifdef __cplusplus
extern "C" {
#endif
/* UART channel definitions */
typedef enum {
UART_CHANNEL_SERVER = 0, /* UART2 - TCP Server channel */
UART_CHANNEL_CLIENT = 1, /* UART3 - TCP Client channel */
UART_CHANNEL_U0 = 0,
UART_CHANNEL_U1 = 1,
UART_CHANNEL_MAX
} uart_channel_t;
/* DMA buffer sizes */
#define UART_RX_DMA_BUFFER_SIZE 128
#define UART_TX_DMA_BUFFER_SIZE 128
/* UART configuration */
typedef struct {
uint32_t baudrate;
uint8_t data_bits; /* 8 or 9 */
uint8_t stop_bits; /* 1 or 2 */
uint8_t parity; /* 0=None, 1=Odd, 2=Even */
} uart_config_t;
uint8_t src_id;
uint8_t dst_mask;
uint16_t payload_len;
uint8_t payload[512];
} uart_mux_frame_t;
/* Default configurations */
#define UART_DEFAULT_BAUDRATE 115200
#define UART_DEFAULT_DATA_BITS 8
#define UART_DEFAULT_STOP_BITS 1
#define UART_DEFAULT_PARITY 0
#define UART_RX_DMA_BUFFER_SIZE 256u
#define UART_TX_DMA_BUFFER_SIZE 256u
#define UART_RX_RING_BUFFER_SIZE 512u
#define UART_TX_RING_BUFFER_SIZE 512u
/* UART statistics */
typedef struct {
uint32_t rx_bytes;
uint32_t tx_bytes;
uint32_t rx_packets;
uint32_t tx_packets;
uint32_t errors;
} uart_stats_t;
/**
* @brief Initialize UART transparent transmission module
* @return 0 on success, negative on error
*/
int uart_trans_init(void);
/**
* @brief Configure UART channel parameters
* @param channel UART channel (SERVER or CLIENT)
* @param config UART configuration
* @return 0 on success, negative on error
*/
int uart_trans_config(uart_channel_t channel, const uart_config_t *config);
/**
* @brief Start UART reception (enable DMA + IDLE interrupt)
* @param channel UART channel
* @return 0 on success, negative on error
*/
int uart_trans_start(uart_channel_t channel);
/**
* @brief Stop UART reception
* @param channel UART channel
* @return 0 on success, negative on error
*/
int uart_trans_stop(uart_channel_t channel);
/**
* @brief Set StreamBuffer handles for TCP integration
* @param channel UART channel
* @param rx_stream StreamBuffer to receive data from TCP (for UART TX)
* @param tx_stream StreamBuffer to send data to TCP (from UART RX)
*/
void uart_trans_set_streams(uart_channel_t channel,
void *rx_stream,
void *tx_stream);
/**
* @brief Get UART statistics
* @param channel UART channel
* @param stats Pointer to statistics structure
*/
void uart_trans_get_stats(uart_channel_t channel, uart_stats_t *stats);
/**
* @brief Reset UART statistics
* @param channel UART channel
*/
void uart_trans_reset_stats(uart_channel_t channel);
/**
* @brief UART IDLE interrupt handler - call from stm32f1xx_it.c
* @param channel UART channel
*
* Usage in stm32f1xx_it.c USART2_IRQHandler:
* if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE)) {
* __HAL_UART_CLEAR_IDLEFLAG(&huart2);
* uart_trans_idle_handler(UART_CHANNEL_SERVER);
* }
*/
void uart_trans_idle_handler(uart_channel_t channel);
/**
* @brief UART DMA RX half complete callback - call from HAL callback
* @param channel UART channel
*/
void uart_trans_rx_half_cplt_handler(uart_channel_t channel);
/**
* @brief UART DMA RX complete callback - call from HAL callback
* @param channel UART channel
*/
void uart_trans_rx_cplt_handler(uart_channel_t channel);
/**
* @brief UART DMA TX complete callback - call from HAL callback
* @param channel UART channel
*/
int uart_trans_config(uint8_t uart_index, uint32_t baudrate);
int uart_trans_start_all(void);
bool uart_trans_send_buffer(uart_channel_t channel, const uint8_t *data, uint16_t len);
void uart_trans_notify_rx_from_isr(uart_channel_t channel, BaseType_t *xHigherPriorityTaskWoken);
void uart_trans_tx_cplt_handler(uart_channel_t channel);
/**
* @brief Server transparent transmission task (UART2 <-> TCP Server)
* @param argument Task argument (unused)
*/
void uart_server_trans_task(void *argument);
/**
* @brief Client transparent transmission task (UART3 <-> TCP Client)
* @param argument Task argument (unused)
*/
void uart_client_trans_task(void *argument);
void UartRxTask(void *argument);
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
}
#endif
#endif /* __UART_TRANS_H__ */
#endif