Compare commits
29 Commits
dc277b040b
..
V2.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
| db714471b8 | |||
| 8c204aad77 | |||
| a6040e7d68 | |||
| 60d2af0a27 | |||
| ac0c464910 | |||
| c9ece65182 | |||
| c519f90149 | |||
| d6a1565503 | |||
| ab3b6bfc9a | |||
| c1a0822227 | |||
| 22bc6a7fef | |||
| fe03bee588 | |||
| 00be10f134 | |||
| ccd69a523e | |||
| eeccfb84a0 | |||
| e3450fd0ad | |||
| afd90d357c | |||
| c8f27e21f1 | |||
| 77da670f5c | |||
| 3f91481d00 | |||
| deecc8f1c8 | |||
| 70e78a6ef6 | |||
| cd48a8af68 | |||
| 6aba77df9a | |||
| 59eecf428f | |||
| 229b961f8e | |||
| 4970f17254 | |||
| 5150a77b3e | |||
| c81bd93205 |
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"keil": {
|
||||||
|
"project": "MDK-ARM/TCP2UART.uvprojx",
|
||||||
|
"target": "TCP2UART",
|
||||||
|
"log_dir": ".embeddedskills/build"
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
@@ -27,6 +27,17 @@ Release/
|
|||||||
MDK-ARM/DebugConfig/
|
MDK-ARM/DebugConfig/
|
||||||
MDK-ARM/TCP2UART/
|
MDK-ARM/TCP2UART/
|
||||||
build_keil.log
|
build_keil.log
|
||||||
|
MDK-ARM/build.log
|
||||||
|
MDK-ARM/build_capture.txt
|
||||||
|
MDK-ARM/build_output.txt
|
||||||
|
MDK-ARM/keil-build-viewer.log
|
||||||
|
MDK-ARM/keil-build-viewer-record.txt
|
||||||
|
MDK-ARM/keil-build-viewer.exe
|
||||||
|
MDK-ARM/EventRecorderStub.scvd
|
||||||
|
.embeddedskills/build/
|
||||||
|
.embeddedskills/state.json
|
||||||
|
build_current.log
|
||||||
|
uv4_stdout.txt
|
||||||
|
|
||||||
# OS
|
# OS
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
|||||||
@@ -268,6 +268,9 @@ ROLE,EN,LPORT,RIP,RPORT,UART
|
|||||||
- `Server` 与 `Client` 共用同一条 `LINK` 记录模型
|
- `Server` 与 `Client` 共用同一条 `LINK` 记录模型
|
||||||
- `Server` 中 `RIP/RPORT` 可作为允许接入的对端约束或预设对端信息
|
- `Server` 中 `RIP/RPORT` 可作为允许接入的对端约束或预设对端信息
|
||||||
- `Client` 中 `RIP/RPORT` 表示远端目标地址与端口
|
- `Client` 中 `RIP/RPORT` 表示远端目标地址与端口
|
||||||
|
- `Client` 侧当前保留固定 `LPORT` 语义,用于满足部分上位机或现场网络策略对固定源端口的依赖
|
||||||
|
- 为避免固定 `LPORT` 下频繁重连被 lwIP `TIME_WAIT` 长时间占用阻塞,当前固件对 `Client` 主动断开后的释放路径采用 abortive close(RST)而非优雅 `FIN/ACK` 关闭
|
||||||
|
- 因此 `Client` 重连场景下,对端可能观察到 `RST` 或“连接被重置”,这属于当前产品约束下的有意设计取舍,不影响 `AT+LINK` 对 `LPORT` 的配置语义
|
||||||
|
|
||||||
#### 查询单条 LINK
|
#### 查询单条 LINK
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
#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;
|
||||||
|
|
||||||
|
void app_start_network_tasks(void);
|
||||||
|
void app_request_network_task_stop(void);
|
||||||
|
void app_clear_network_task_stop(void);
|
||||||
|
BaseType_t app_network_task_stop_requested(void);
|
||||||
|
BaseType_t app_network_tasks_are_stopped(void);
|
||||||
|
void app_on_network_task_exit(TaskHandle_t task_handle);
|
||||||
|
void app_request_network_restart(void);
|
||||||
|
void app_clear_network_restart_request(void);
|
||||||
|
BaseType_t app_network_restart_requested(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
+582
-548
File diff suppressed because it is too large
Load Diff
+63
-155
@@ -1,96 +1,76 @@
|
|||||||
/**
|
#ifndef CONFIG_H
|
||||||
* @file config.h
|
#define 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__
|
|
||||||
|
|
||||||
#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 0x0001
|
#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];
|
||||||
|
uint32_t 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) */
|
|
||||||
uint32_t crc;
|
uint32_t crc;
|
||||||
} device_config_t;
|
} device_config_t;
|
||||||
|
|
||||||
/* Default configuration values */
|
#define DEFAULT_NET_IP {192, 168, 31, 100}
|
||||||
#define DEFAULT_IP {192, 168, 1, 100}
|
#define DEFAULT_NET_MASK {255, 255, 255, 0}
|
||||||
#define DEFAULT_MASK {255, 255, 255, 0}
|
#define DEFAULT_NET_GW {192, 168, 31, 1}
|
||||||
#define DEFAULT_GW {192, 168, 1, 1}
|
#define DEFAULT_NET_MAC {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
||||||
#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, 1, 200}
|
#define DIAG_CH390_RAW_POLL 0
|
||||||
#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
|
|
||||||
|
|
||||||
/* AT command result codes */
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
AT_OK = 0,
|
AT_OK = 0,
|
||||||
AT_ERROR,
|
AT_ERROR,
|
||||||
@@ -100,99 +80,27 @@ 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);
|
||||||
|
uint32_t config_get_uart_baudrate(uint8_t uart_index);
|
||||||
/**
|
|
||||||
* @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);
|
||||||
|
void ConfigTask(void *argument);
|
||||||
/**
|
|
||||||
* @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 config_uart_idle_handler(void);
|
void config_uart_idle_handler(void);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Start UART1 reception for configuration
|
|
||||||
*/
|
|
||||||
void config_start_reception(void);
|
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);
|
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
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __CONFIG_H__ */
|
#endif
|
||||||
|
|||||||
+4
-5
@@ -16,13 +16,12 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Flash configuration for STM32F103R8 (64KB Flash) */
|
/* Flash configuration for the current STM32F103RDT6 target (384KB Flash). */
|
||||||
#define FLASH_PARAM_PAGE_SIZE 1024 /* 1KB per page for STM32F103 */
|
#define FLASH_PARAM_PAGE_SIZE 1024 /* 1KB per page for STM32F103 */
|
||||||
#define FLASH_PARAM_START_ADDR 0x0800FC00 /* Last 1KB of 64KB Flash */
|
#define FLASH_PARAM_START_ADDR 0x0805FC00 /* Last 1KB page of 384KB Flash */
|
||||||
#define FLASH_PARAM_END_ADDR 0x08010000 /* End of Flash */
|
#define FLASH_PARAM_END_ADDR 0x08060000 /* End of 384KB Flash */
|
||||||
|
|
||||||
/* For STM32F103RC (256KB), use: 0x0803FC00 */
|
/* Historical reference: STM32F103RCT6 would use 0x0803FC00 as its last page. */
|
||||||
/* For STM32F103RB (128KB), use: 0x0801FC00 */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initialize Flash parameter storage
|
* @brief Initialize Flash parameter storage
|
||||||
|
|||||||
+227
@@ -0,0 +1,227 @@
|
|||||||
|
#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];
|
||||||
|
|
||||||
|
const char *route_send_result_to_str(route_send_result_t result)
|
||||||
|
{
|
||||||
|
switch (result) {
|
||||||
|
case ROUTE_SEND_OK:
|
||||||
|
return "ok";
|
||||||
|
case ROUTE_SEND_INVALID_INPUT:
|
||||||
|
return "invalid";
|
||||||
|
case ROUTE_SEND_POOL_EXHAUSTED:
|
||||||
|
return "pool";
|
||||||
|
case ROUTE_SEND_QUEUE_FULL:
|
||||||
|
return "queue";
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 route_send_result_t 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 ROUTE_SEND_INVALID_INPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg->src_id = src_id;
|
||||||
|
msg->dst_mask = dst_mask;
|
||||||
|
msg->conn_type = conn_type;
|
||||||
|
msg->len = len;
|
||||||
|
memcpy(msg->data, data, len);
|
||||||
|
return ROUTE_SEND_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static route_send_result_t route_validate_args(QueueHandle_t queue,
|
||||||
|
const uint8_t *data,
|
||||||
|
uint16_t len)
|
||||||
|
{
|
||||||
|
if (queue == NULL || data == NULL || len == 0u || len > ROUTE_MSG_MAX_PAYLOAD) {
|
||||||
|
return ROUTE_SEND_INVALID_INPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ROUTE_SEND_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
route_send_result_t 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_send_result_t result;
|
||||||
|
route_msg_t *msg;
|
||||||
|
|
||||||
|
result = route_validate_args(queue, data, len);
|
||||||
|
if (result != ROUTE_SEND_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = route_msg_alloc(wait_ticks);
|
||||||
|
|
||||||
|
if (msg == NULL) {
|
||||||
|
return ROUTE_SEND_POOL_EXHAUSTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = route_prepare(msg, src_id, dst_mask, conn_type, data, len);
|
||||||
|
if (result != ROUTE_SEND_OK) {
|
||||||
|
route_msg_free(msg);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xQueueSend(queue, &msg, wait_ticks) != pdPASS) {
|
||||||
|
route_msg_free(msg);
|
||||||
|
return ROUTE_SEND_QUEUE_FULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ROUTE_SEND_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
route_send_result_t 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_send_result_t result;
|
||||||
|
route_msg_t *msg;
|
||||||
|
|
||||||
|
result = route_validate_args(queue, data, len);
|
||||||
|
if (result != ROUTE_SEND_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = route_msg_alloc_from_isr(xHigherPriorityTaskWoken);
|
||||||
|
|
||||||
|
if (msg == NULL) {
|
||||||
|
return ROUTE_SEND_POOL_EXHAUSTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = route_prepare(msg, src_id, dst_mask, conn_type, data, len);
|
||||||
|
if (result != ROUTE_SEND_OK) {
|
||||||
|
route_msg_free_from_isr(msg);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xQueueSendFromISR(queue, &msg, xHigherPriorityTaskWoken) != pdPASS) {
|
||||||
|
route_msg_free_from_isr(msg);
|
||||||
|
return ROUTE_SEND_QUEUE_FULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ROUTE_SEND_OK;
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
#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 enum {
|
||||||
|
ROUTE_SEND_OK = 0,
|
||||||
|
ROUTE_SEND_INVALID_INPUT,
|
||||||
|
ROUTE_SEND_POOL_EXHAUSTED,
|
||||||
|
ROUTE_SEND_QUEUE_FULL
|
||||||
|
} route_send_result_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);
|
||||||
|
const char *route_send_result_to_str(route_send_result_t result);
|
||||||
|
route_send_result_t 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_send_result_t 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
|
||||||
@@ -0,0 +1,192 @@
|
|||||||
|
#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"
|
||||||
|
|
||||||
|
#define CH390_RESTART_HOLD_DOWN_MS 500u
|
||||||
|
#define NETWORK_TASK_DELETE_SETTLE_MS 50u
|
||||||
|
#define CH390_EXPECTED_VENDOR_ID 0x1C00u
|
||||||
|
#define CH390_EXPECTED_PRODUCT_ID 0x9151u
|
||||||
|
|
||||||
|
static void net_poll_wait_for_network_tasks_stop(void)
|
||||||
|
{
|
||||||
|
while (app_network_tasks_are_stopped() == pdFALSE) {
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(20));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static BaseType_t net_poll_restart_network_stack(const device_config_t *cfg)
|
||||||
|
{
|
||||||
|
#if !DIAG_CH390_RAW_POLL
|
||||||
|
ip4_addr_t ipaddr;
|
||||||
|
ip4_addr_t netmask;
|
||||||
|
ip4_addr_t gateway;
|
||||||
|
uint16_t vendor_id;
|
||||||
|
uint16_t product_id;
|
||||||
|
uint8_t revision;
|
||||||
|
|
||||||
|
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]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ethernetif_force_link_down();
|
||||||
|
g_netif_ready = pdFALSE;
|
||||||
|
app_request_network_task_stop();
|
||||||
|
net_poll_wait_for_network_tasks_stop();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(NETWORK_TASK_DELETE_SETTLE_MS));
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(CH390_RESTART_HOLD_DOWN_MS));
|
||||||
|
|
||||||
|
#if DIAG_CH390_RAW_POLL
|
||||||
|
ethernetif_diag_ch390_init();
|
||||||
|
#else
|
||||||
|
ethernetif_force_full_recovery(&ipaddr, &netmask, &gateway, cfg->net.mac);
|
||||||
|
vendor_id = ethernetif_ch390_get_vendor_id();
|
||||||
|
product_id = ethernetif_ch390_get_product_id();
|
||||||
|
revision = ethernetif_ch390_get_revision();
|
||||||
|
if ((vendor_id != CH390_EXPECTED_VENDOR_ID) || (product_id != CH390_EXPECTED_PRODUCT_ID)) {
|
||||||
|
debug_log_printf("[NET] restart-recovery id-warn vid=0x%04X pid=0x%04X rev=0x%02X free=%lu min=%lu\r\n",
|
||||||
|
(unsigned int)vendor_id,
|
||||||
|
(unsigned int)product_id,
|
||||||
|
(unsigned int)revision,
|
||||||
|
(unsigned long)xPortGetFreeHeapSize(),
|
||||||
|
(unsigned long)xPortGetMinimumEverFreeHeapSize());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
app_clear_network_task_stop();
|
||||||
|
g_netif_ready = pdTRUE;
|
||||||
|
app_start_network_tasks();
|
||||||
|
app_clear_network_restart_request();
|
||||||
|
return pdTRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
app_start_network_tasks();
|
||||||
|
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");
|
||||||
|
debug_log_printf("[NET] post-init ok=%ld hwm=%lu free=%lu min=%lu\r\n",
|
||||||
|
(long)g_netif_init_ok,
|
||||||
|
(unsigned long)uxTaskGetStackHighWaterMark(NULL),
|
||||||
|
(unsigned long)xPortGetFreeHeapSize(),
|
||||||
|
(unsigned long)xPortGetMinimumEverFreeHeapSize());
|
||||||
|
|
||||||
|
if (g_netif_init_ok != 1) {
|
||||||
|
for (;;) {
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_log_write("[NET] pre-ready\r\n");
|
||||||
|
g_netif_ready = pdTRUE;
|
||||||
|
debug_log_write("[NET] start-network-tasks call\r\n");
|
||||||
|
app_start_network_tasks();
|
||||||
|
debug_log_printf("[NET] post-ready free=%lu min=%lu\r\n",
|
||||||
|
(unsigned long)xPortGetFreeHeapSize(),
|
||||||
|
(unsigned long)xPortGetMinimumEverFreeHeapSize());
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (app_network_restart_requested() != pdFALSE) {
|
||||||
|
(void)net_poll_restart_network_stack(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)xSemaphoreTake(xNetSemaphore, pdMS_TO_TICKS(2));
|
||||||
|
|
||||||
|
#if DIAG_CH390_RAW_POLL
|
||||||
|
ethernetif_diag_poll_status();
|
||||||
|
|
||||||
|
if (ch390_read_reg(CH390_NSR) & NSR_RXRDY)
|
||||||
|
{
|
||||||
|
uint8_t rx_status = 0u;
|
||||||
|
uint32_t rx_len = ch390_runtime_receive_packet(s_diag_rx_buffer, &rx_status);
|
||||||
|
|
||||||
|
if (rx_len > 0u)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
if (g_netif_ready != pdFALSE) {
|
||||||
|
ethernetif_poll();
|
||||||
|
ethernetif_check_link();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
+218
-392
@@ -1,431 +1,257 @@
|
|||||||
/**
|
|
||||||
* @file tcp_client.c
|
|
||||||
* @brief TCP Client module implementation for transparent transmission with UART3
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "tcp_client.h"
|
#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 "FreeRTOS.h"
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
#include "stream_buffer.h"
|
#include "queue.h"
|
||||||
|
#include "lwip/api.h"
|
||||||
|
#include "lwip/ip_addr.h"
|
||||||
|
#include "lwip/tcp.h"
|
||||||
|
#include "lwip/tcpip.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include "app_runtime.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "debug_log.h"
|
||||||
|
#include "ethernetif.h"
|
||||||
|
#include "route_msg.h"
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------
|
#define TCP_CLIENT_CONNECT_TIMEOUT_MS 500
|
||||||
* Private Variables
|
#define TCP_CLIENT_STOP_POLL_MS 50u
|
||||||
*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/* Client configuration */
|
static BaseType_t tcp_client_stop_requested(void)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
uint16_t total = 0;
|
return (app_network_task_stop_requested() != pdFALSE) ? pdTRUE : pdFALSE;
|
||||||
|
|
||||||
while (total < len)
|
|
||||||
{
|
|
||||||
int sent = send(sock, data + total, len - total, 0);
|
|
||||||
if (sent > 0)
|
|
||||||
{
|
|
||||||
total += (uint16_t)sent;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
static BaseType_t tcp_client_delay_with_stop(uint32_t delay_ms)
|
||||||
{
|
{
|
||||||
return -1;
|
uint32_t remaining_ms = delay_ms;
|
||||||
|
|
||||||
|
while (remaining_ms > 0u) {
|
||||||
|
uint32_t slice_ms = (remaining_ms > TCP_CLIENT_STOP_POLL_MS) ? TCP_CLIENT_STOP_POLL_MS : remaining_ms;
|
||||||
|
|
||||||
|
if (tcp_client_stop_requested() != pdFALSE) {
|
||||||
|
return pdFALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(slice_ms));
|
||||||
|
remaining_ms -= slice_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (tcp_client_stop_requested() == pdFALSE) ? pdTRUE : pdFALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tcp_client_abort_and_delete(struct netconn *conn, uint8_t link_index)
|
||||||
|
{
|
||||||
|
struct tcp_pcb *pcb;
|
||||||
|
|
||||||
|
if (conn == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pcb = conn->pcb.tcp;
|
||||||
|
if (pcb != NULL) {
|
||||||
|
LOCK_TCPIP_CORE();
|
||||||
|
pcb = conn->pcb.tcp;
|
||||||
|
if (pcb != NULL) {
|
||||||
|
tcp_abort(pcb);
|
||||||
|
conn->pcb.tcp = NULL;
|
||||||
|
conn->state = NETCONN_NONE;
|
||||||
|
debug_log_printf("[CLI] idx=%u abort-close\r\n", (unsigned int)link_index);
|
||||||
|
}
|
||||||
|
UNLOCK_TCPIP_CORE();
|
||||||
|
}
|
||||||
|
|
||||||
|
netconn_delete(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
static err_t tcp_client_worker(struct netconn *conn, uint8_t link_index)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
route_send_result_t route_result;
|
||||||
|
|
||||||
|
netconn_set_recvtimeout(conn, 10);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (tcp_client_stop_requested() != pdFALSE) {
|
||||||
|
return ERR_CLSD;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = netconn_recv(conn, &buf);
|
||||||
|
if (err == ERR_OK) {
|
||||||
|
do {
|
||||||
|
void *data;
|
||||||
|
uint16_t len;
|
||||||
|
netbuf_data(buf, &data, &len);
|
||||||
|
route_result = 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));
|
||||||
|
if (route_result != ROUTE_SEND_OK) {
|
||||||
|
debug_log_printf("[CLI] idx=%u rx-route-fail rc=%s len=%u\r\n",
|
||||||
|
(unsigned int)link_index,
|
||||||
|
route_send_result_to_str(route_result),
|
||||||
|
(unsigned int)len);
|
||||||
|
netbuf_delete(buf);
|
||||||
|
return ERR_CLSD;
|
||||||
|
}
|
||||||
|
} while (netbuf_next(buf) >= 0);
|
||||||
|
netbuf_delete(buf);
|
||||||
|
} else if (err == ERR_TIMEOUT) {
|
||||||
|
if (tcp_client_stop_requested() != pdFALSE) {
|
||||||
|
return ERR_CLSD;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (xQueueReceive(xLinkTxQueues[link_index], &tx_msg, 0) == pdPASS) {
|
||||||
|
if (tcp_client_stop_requested() != pdFALSE) {
|
||||||
|
route_msg_free(tx_msg);
|
||||||
|
return ERR_CLSD;
|
||||||
|
}
|
||||||
|
err = netconn_write(conn, tx_msg->data, tx_msg->len, NETCONN_COPY);
|
||||||
|
route_msg_free(tx_msg);
|
||||||
|
if (err != ERR_OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (int)total;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void tcp_client_task(uint8_t link_index)
|
||||||
* @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)
|
|
||||||
{
|
{
|
||||||
const device_config_t *cfg;
|
const device_config_t *cfg;
|
||||||
tcp_client_config_t task_cfg;
|
struct netconn *conn;
|
||||||
uint8_t rx_buffer[256];
|
ip_addr_t remote_ip;
|
||||||
uint8_t tx_buffer[256];
|
uint32_t delay_ms;
|
||||||
int received;
|
err_t err;
|
||||||
size_t tx_len;
|
uint8_t first_connect_deferred;
|
||||||
fd_set read_fds;
|
|
||||||
struct timeval tv;
|
|
||||||
uint32_t reconnect_timer = 0;
|
|
||||||
|
|
||||||
(void)argument;
|
netconn_thread_init();
|
||||||
|
first_connect_deferred = (link_index == CONFIG_LINK_C1) ? 1u : 0u;
|
||||||
|
|
||||||
/* Initialize client */
|
for (;;) {
|
||||||
task_cfg.server_ip[0] = 192;
|
if (tcp_client_stop_requested() != pdFALSE) {
|
||||||
task_cfg.server_ip[1] = 168;
|
break;
|
||||||
task_cfg.server_ip[2] = 1;
|
}
|
||||||
task_cfg.server_ip[3] = 100;
|
|
||||||
task_cfg.server_port = TCP_CLIENT_DEFAULT_PORT;
|
while ((g_netif_ready == pdFALSE) || (ethernetif_link_is_up() == 0u)) {
|
||||||
task_cfg.auto_reconnect = true;
|
if (tcp_client_stop_requested() != pdFALSE) {
|
||||||
task_cfg.reconnect_interval_ms = TCP_CLIENT_RECONNECT_DELAY_MS;
|
goto exit_task;
|
||||||
|
}
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
|
}
|
||||||
|
|
||||||
cfg = config_get();
|
cfg = config_get();
|
||||||
if (cfg != NULL)
|
if (cfg->links[link_index].enabled == 0u) {
|
||||||
{
|
if (tcp_client_stop_requested() != pdFALSE) {
|
||||||
memcpy(task_cfg.server_ip, cfg->remote_ip, sizeof(task_cfg.server_ip));
|
break;
|
||||||
if (cfg->remote_port > 0)
|
|
||||||
{
|
|
||||||
task_cfg.server_port = cfg->remote_port;
|
|
||||||
}
|
}
|
||||||
if (cfg->reconnect_interval > 0)
|
if (tcp_client_delay_with_stop(500u) == pdFALSE) {
|
||||||
{
|
break;
|
||||||
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 */
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(100));
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle data transfer if connected */
|
delay_ms = (cfg->reconnect_interval_ms == 0u) ? 3000u : cfg->reconnect_interval_ms;
|
||||||
|
|
||||||
/* Check for data from TCP server */
|
if (first_connect_deferred != 0u) {
|
||||||
FD_ZERO(&read_fds);
|
first_connect_deferred = 0u;
|
||||||
FD_SET(client_socket, &read_fds);
|
debug_log_write("[CLI] C1 first-connect defer\r\n");
|
||||||
tv.tv_sec = 0;
|
if (tcp_client_delay_with_stop(delay_ms) == pdFALSE) {
|
||||||
tv.tv_usec = 10000; /* 10ms timeout */
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (select(client_socket + 1, &read_fds, NULL, NULL, &tv) > 0)
|
conn = netconn_new(NETCONN_TCP);
|
||||||
{
|
if (conn == NULL) {
|
||||||
if (FD_ISSET(client_socket, &read_fds))
|
if (tcp_client_delay_with_stop(delay_ms) == pdFALSE) {
|
||||||
{
|
break;
|
||||||
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)
|
continue;
|
||||||
{
|
|
||||||
/* Connection closed */
|
|
||||||
close(client_socket);
|
|
||||||
client_socket = -1;
|
|
||||||
client_status.state = TCP_CLIENT_STATE_DISCONNECTED;
|
|
||||||
reconnect_timer = xTaskGetTickCount();
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
if (cfg->links[link_index].local_port != 0u) {
|
||||||
/* Error */
|
err = netconn_bind(conn, IP_ADDR_ANY, cfg->links[link_index].local_port);
|
||||||
close(client_socket);
|
if (err != ERR_OK) {
|
||||||
client_socket = -1;
|
debug_log_printf("[CLI] idx=%u bind-fail err=%d lport=%u\r\n",
|
||||||
client_status.state = TCP_CLIENT_STATE_DISCONNECTED;
|
(unsigned int)link_index,
|
||||||
client_status.errors++;
|
(int)err,
|
||||||
reconnect_timer = xTaskGetTickCount();
|
(unsigned int)cfg->links[link_index].local_port);
|
||||||
|
netconn_delete(conn);
|
||||||
|
if (tcp_client_delay_with_stop(delay_ms) == pdFALSE) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for data from UART to send to TCP */
|
IP_ADDR4(&remote_ip,
|
||||||
tx_len = xStreamBufferReceive(tx_stream, tx_buffer, sizeof(tx_buffer), 0);
|
cfg->links[link_index].remote_ip[0],
|
||||||
if (tx_len > 0)
|
cfg->links[link_index].remote_ip[1],
|
||||||
{
|
cfg->links[link_index].remote_ip[2],
|
||||||
int sent = tcp_client_send_all(client_socket, tx_buffer, (uint16_t)tx_len);
|
cfg->links[link_index].remote_ip[3]);
|
||||||
if (sent > 0)
|
|
||||||
{
|
netconn_set_recvtimeout(conn, TCP_CLIENT_CONNECT_TIMEOUT_MS);
|
||||||
client_status.tx_bytes += sent;
|
err = netconn_connect(conn, &remote_ip, cfg->links[link_index].remote_port);
|
||||||
}
|
if (err == ERR_OK) {
|
||||||
else if (sent < 0)
|
debug_log_printf("[CLI] idx=%u connect-ok\r\n", (unsigned int)link_index);
|
||||||
{
|
(void)tcp_client_worker(conn, link_index);
|
||||||
/* Send error */
|
} else {
|
||||||
close(client_socket);
|
if (err == ERR_TIMEOUT) {
|
||||||
client_socket = -1;
|
debug_log_printf("[CLI] idx=%u connect-timeout ms=%u rip=%u.%u.%u.%u rport=%u\r\n",
|
||||||
client_status.state = TCP_CLIENT_STATE_DISCONNECTED;
|
(unsigned int)link_index,
|
||||||
client_status.errors++;
|
(unsigned int)TCP_CLIENT_CONNECT_TIMEOUT_MS,
|
||||||
reconnect_timer = xTaskGetTickCount();
|
(unsigned int)cfg->links[link_index].remote_ip[0],
|
||||||
|
(unsigned int)cfg->links[link_index].remote_ip[1],
|
||||||
|
(unsigned int)cfg->links[link_index].remote_ip[2],
|
||||||
|
(unsigned int)cfg->links[link_index].remote_ip[3],
|
||||||
|
(unsigned int)cfg->links[link_index].remote_port);
|
||||||
|
} else {
|
||||||
|
debug_log_printf("[CLI] idx=%u connect-fail err=%d rip=%u.%u.%u.%u rport=%u\r\n",
|
||||||
|
(unsigned int)link_index,
|
||||||
|
(int)err,
|
||||||
|
(unsigned int)cfg->links[link_index].remote_ip[0],
|
||||||
|
(unsigned int)cfg->links[link_index].remote_ip[1],
|
||||||
|
(unsigned int)cfg->links[link_index].remote_ip[2],
|
||||||
|
(unsigned int)cfg->links[link_index].remote_ip[3],
|
||||||
|
(unsigned int)cfg->links[link_index].remote_port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Small delay to prevent tight loop */
|
tcp_client_abort_and_delete(conn, link_index);
|
||||||
vTaskDelay(pdMS_TO_TICKS(1));
|
if (tcp_client_stop_requested() != pdFALSE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (tcp_client_delay_with_stop(delay_ms) == pdFALSE) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exit_task:
|
||||||
|
netconn_thread_cleanup();
|
||||||
|
app_on_network_task_exit(xTaskGetCurrentTaskHandle());
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
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
@@ -1,132 +1,15 @@
|
|||||||
/**
|
#ifndef TCP_CLIENT_H
|
||||||
* @file tcp_client.h
|
#define 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>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Default TCP Client settings */
|
void TcpCliTask_C1(void *argument);
|
||||||
#define TCP_CLIENT_DEFAULT_PORT 8081
|
void TcpCliTask_C2(void *argument);
|
||||||
#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);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __TCP_CLIENT_H__ */
|
#endif
|
||||||
|
|||||||
+152
-372
@@ -1,405 +1,185 @@
|
|||||||
/**
|
|
||||||
* @file tcp_server.c
|
|
||||||
* @brief TCP Server module implementation for transparent transmission with UART2
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "tcp_server.h"
|
#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 "FreeRTOS.h"
|
||||||
#include "task.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 "debug_log.h"
|
||||||
|
#include "route_msg.h"
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------
|
#define TCP_SERVER_ACCEPT_TIMEOUT_MS 100
|
||||||
* Private Variables
|
#define TCP_SERVER_STOP_POLL_MS 50u
|
||||||
*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/* Server configuration */
|
static BaseType_t tcp_server_stop_requested(void)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
uint16_t total = 0;
|
return (app_network_task_stop_requested() != pdFALSE) ? pdTRUE : pdFALSE;
|
||||||
|
|
||||||
while (total < len)
|
|
||||||
{
|
|
||||||
int sent = send(sock, data + total, len - total, 0);
|
|
||||||
if (sent > 0)
|
|
||||||
{
|
|
||||||
total += (uint16_t)sent;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
static BaseType_t tcp_server_delay_with_stop(uint32_t delay_ms)
|
||||||
{
|
{
|
||||||
return -1;
|
uint32_t remaining_ms = delay_ms;
|
||||||
|
|
||||||
|
while (remaining_ms > 0u) {
|
||||||
|
uint32_t slice_ms = (remaining_ms > TCP_SERVER_STOP_POLL_MS) ? TCP_SERVER_STOP_POLL_MS : remaining_ms;
|
||||||
|
|
||||||
|
if (tcp_server_stop_requested() != pdFALSE) {
|
||||||
|
return pdFALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(slice_ms));
|
||||||
|
remaining_ms -= slice_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (tcp_server_stop_requested() == pdFALSE) ? pdTRUE : pdFALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static err_t tcp_server_worker(struct netconn *conn, uint8_t link_index)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
route_send_result_t route_result;
|
||||||
|
|
||||||
|
netconn_set_recvtimeout(conn, 10);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (tcp_server_stop_requested() != pdFALSE) {
|
||||||
|
return ERR_CLSD;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = netconn_recv(conn, &buf);
|
||||||
|
if (err == ERR_OK) {
|
||||||
|
do {
|
||||||
|
void *data;
|
||||||
|
uint16_t len;
|
||||||
|
netbuf_data(buf, &data, &len);
|
||||||
|
route_result = 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));
|
||||||
|
if (route_result != ROUTE_SEND_OK) {
|
||||||
|
debug_log_printf("[SRV] idx=%u rx-route-fail rc=%s len=%u\r\n",
|
||||||
|
(unsigned int)link_index,
|
||||||
|
route_send_result_to_str(route_result),
|
||||||
|
(unsigned int)len);
|
||||||
|
netbuf_delete(buf);
|
||||||
|
return ERR_CLSD;
|
||||||
|
}
|
||||||
|
} while (netbuf_next(buf) >= 0);
|
||||||
|
netbuf_delete(buf);
|
||||||
|
} else if (err == ERR_TIMEOUT) {
|
||||||
|
if (tcp_server_stop_requested() != pdFALSE) {
|
||||||
|
return ERR_CLSD;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (xQueueReceive(xLinkTxQueues[link_index], &tx_msg, 0) == pdPASS) {
|
||||||
|
if (tcp_server_stop_requested() != pdFALSE) {
|
||||||
|
route_msg_free(tx_msg);
|
||||||
|
return ERR_CLSD;
|
||||||
|
}
|
||||||
|
err = netconn_write(conn, tx_msg->data, tx_msg->len, NETCONN_COPY);
|
||||||
|
route_msg_free(tx_msg);
|
||||||
|
if (err != ERR_OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (int)total;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void tcp_server_task(uint8_t link_index)
|
||||||
* @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)
|
|
||||||
{
|
{
|
||||||
const device_config_t *cfg;
|
const device_config_t *cfg;
|
||||||
tcp_server_config_t task_cfg;
|
struct netconn *listener;
|
||||||
struct sockaddr_in client_addr;
|
struct netconn *newconn;
|
||||||
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;
|
netconn_thread_init();
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (tcp_server_stop_requested() != pdFALSE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (g_netif_ready == pdFALSE) {
|
||||||
|
if (tcp_server_stop_requested() != pdFALSE) {
|
||||||
|
goto exit_task;
|
||||||
|
}
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialize server */
|
|
||||||
task_cfg.port = TCP_SERVER_DEFAULT_PORT;
|
|
||||||
task_cfg.auto_reconnect = true;
|
|
||||||
cfg = config_get();
|
cfg = config_get();
|
||||||
if (cfg != NULL && cfg->server_port > 0)
|
if (cfg->links[link_index].enabled == 0u) {
|
||||||
{
|
if (tcp_server_stop_requested() != pdFALSE) {
|
||||||
task_cfg.port = cfg->server_port;
|
break;
|
||||||
}
|
}
|
||||||
tcp_server_init(&task_cfg);
|
if (tcp_server_delay_with_stop(500u) == pdFALSE) {
|
||||||
|
break;
|
||||||
/* Start server */
|
}
|
||||||
while (tcp_server_start() != 0)
|
continue;
|
||||||
{
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1)
|
listener = netconn_new(NETCONN_TCP);
|
||||||
{
|
if (listener == NULL) {
|
||||||
/* Check if we need to accept a new connection */
|
if (tcp_server_delay_with_stop(500u) == pdFALSE) {
|
||||||
if (client_socket < 0 && listen_socket >= 0)
|
break;
|
||||||
{
|
|
||||||
/* 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++;
|
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
netconn_set_recvtimeout(listener, TCP_SERVER_ACCEPT_TIMEOUT_MS);
|
||||||
|
|
||||||
|
if (netconn_bind(listener, IP_ADDR_ANY, cfg->links[link_index].local_port) != ERR_OK ||
|
||||||
|
netconn_listen(listener) != ERR_OK) {
|
||||||
|
netconn_delete(listener);
|
||||||
|
if (tcp_server_delay_with_stop(500u) == pdFALSE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (tcp_server_stop_requested() != pdFALSE || 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 */
|
netconn_close(listener);
|
||||||
if (client_socket >= 0)
|
netconn_delete(listener);
|
||||||
{
|
|
||||||
/* 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 */
|
exit_task:
|
||||||
tx_len = xStreamBufferReceive(tx_stream, tx_buffer, sizeof(tx_buffer), 0);
|
netconn_thread_cleanup();
|
||||||
if (tx_len > 0)
|
app_on_network_task_exit(xTaskGetCurrentTaskHandle());
|
||||||
{
|
vTaskDelete(NULL);
|
||||||
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 */
|
void TcpSrvTask_S1(void *argument)
|
||||||
vTaskDelay(pdMS_TO_TICKS(1));
|
{
|
||||||
|
(void)argument;
|
||||||
|
tcp_server_task(CONFIG_LINK_S1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TcpSrvTask_S2(void *argument)
|
||||||
|
{
|
||||||
|
(void)argument;
|
||||||
|
tcp_server_task(CONFIG_LINK_S2);
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-109
@@ -1,119 +1,15 @@
|
|||||||
/**
|
#ifndef TCP_SERVER_H
|
||||||
* @file tcp_server.h
|
#define 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>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Default TCP Server port */
|
void TcpSrvTask_S1(void *argument);
|
||||||
#define TCP_SERVER_DEFAULT_PORT 8080
|
void TcpSrvTask_S2(void *argument);
|
||||||
|
|
||||||
/* 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);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __TCP_SERVER_H__ */
|
#endif
|
||||||
|
|||||||
+573
-452
File diff suppressed because it is too large
Load Diff
+36
-129
@@ -1,151 +1,58 @@
|
|||||||
/**
|
#ifndef UART_TRANS_H
|
||||||
* @file uart_trans.h
|
#define 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__
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* UART channel definitions */
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
UART_CHANNEL_SERVER = 0, /* UART2 - TCP Server channel */
|
UART_CHANNEL_U0 = 0,
|
||||||
UART_CHANNEL_CLIENT = 1, /* UART3 - TCP Client channel */
|
UART_CHANNEL_U1 = 1,
|
||||||
UART_CHANNEL_MAX
|
UART_CHANNEL_MAX
|
||||||
} uart_channel_t;
|
} uart_channel_t;
|
||||||
|
|
||||||
/* DMA buffer sizes */
|
typedef enum {
|
||||||
#define UART_RX_DMA_BUFFER_SIZE 128
|
UART_TRANS_SEND_OK = 0,
|
||||||
#define UART_TX_DMA_BUFFER_SIZE 128
|
UART_TRANS_SEND_INVALID_INPUT,
|
||||||
|
UART_TRANS_SEND_RING_FULL,
|
||||||
|
UART_TRANS_SEND_KICK_FAILED
|
||||||
|
} uart_trans_send_result_t;
|
||||||
|
|
||||||
/* UART configuration */
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t baudrate;
|
uint8_t src_id;
|
||||||
uint8_t data_bits; /* 8 or 9 */
|
uint8_t dst_mask;
|
||||||
uint8_t stop_bits; /* 1 or 2 */
|
uint16_t payload_len;
|
||||||
uint8_t parity; /* 0=None, 1=Odd, 2=Even */
|
uint8_t payload[256];
|
||||||
} uart_config_t;
|
} uart_mux_frame_t;
|
||||||
|
|
||||||
/* Default configurations */
|
#define UART_RX_DMA_BUFFER_SIZE 128u
|
||||||
#define UART_DEFAULT_BAUDRATE 115200
|
#define UART_TX_DMA_BUFFER_SIZE 128u
|
||||||
#define UART_DEFAULT_DATA_BITS 8
|
#define UART_RX_RING_BUFFER_SIZE 256u
|
||||||
#define UART_DEFAULT_STOP_BITS 1
|
#define UART_TX_RING_BUFFER_SIZE 256u
|
||||||
#define UART_DEFAULT_PARITY 0
|
|
||||||
|
|
||||||
/* 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);
|
int uart_trans_init(void);
|
||||||
|
int uart_trans_start_all(void);
|
||||||
/**
|
const char *uart_trans_send_result_to_str(uart_trans_send_result_t result);
|
||||||
* @brief Configure UART channel parameters
|
uart_trans_send_result_t uart_trans_send_buffer(uart_channel_t channel, const uint8_t *data, uint16_t len);
|
||||||
* @param channel UART channel (SERVER or CLIENT)
|
void uart_trans_notify_rx_from_isr(uart_channel_t channel, BaseType_t *xHigherPriorityTaskWoken);
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
void uart_trans_tx_cplt_handler(uart_channel_t channel);
|
void uart_trans_tx_cplt_handler(uart_channel_t channel);
|
||||||
|
void UartRxTask(void *argument);
|
||||||
/**
|
bool uart_mux_try_extract_frame(uart_channel_t channel, uart_mux_frame_t *frame);
|
||||||
* @brief Server transparent transmission task (UART2 <-> TCP Server)
|
bool uart_mux_encode_frame(uint8_t src_id,
|
||||||
* @param argument Task argument (unused)
|
uint8_t dst_mask,
|
||||||
*/
|
const uint8_t *payload,
|
||||||
void uart_server_trans_task(void *argument);
|
uint16_t payload_len,
|
||||||
|
uint8_t *out,
|
||||||
/**
|
uint16_t *out_len,
|
||||||
* @brief Client transparent transmission task (UART3 <-> TCP Client)
|
uint16_t out_capacity);
|
||||||
* @param argument Task argument (unused)
|
|
||||||
*/
|
|
||||||
void uart_client_trans_task(void *argument);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __UART_TRANS_H__ */
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,245 @@
|
|||||||
|
# CH390 / lwIP 固定次数 ping 失败问题修复复盘
|
||||||
|
|
||||||
|
## 1. 问题现象
|
||||||
|
|
||||||
|
在 TCP2UART 固件运行后,设备初期可以正常 ARP 和 ping,但连续 ping 一段时间后不再响应。
|
||||||
|
|
||||||
|
典型现象:
|
||||||
|
|
||||||
|
- 设备 IP:`192.168.31.100`
|
||||||
|
- 设备 MAC:`02:00:00:00:00:01`
|
||||||
|
- 对端/网关 IP:`192.168.31.1`
|
||||||
|
- 对端/网关 MAC:`00:e0:4c:28:1e:60`
|
||||||
|
- 失败后设备仍持续发送 TCP SYN/RST 或 client timeout 相关流量,说明 TX、任务调度和应用层并未整体死机。
|
||||||
|
- 失败后对端继续向设备 MAC 发送 ICMP/ARP,但设备不再回复。
|
||||||
|
|
||||||
|
关键抓包:
|
||||||
|
|
||||||
|
- `WiresharkLog/04290150.pcapng`
|
||||||
|
- `seq=1884..1891` 共 8 次 ping reply 正常。
|
||||||
|
- 第 9 次 `seq=1892` 开始无 reply。
|
||||||
|
- `WiresharkLog/04290206.pcapng`
|
||||||
|
- 曾把 `PBUF_POOL_SIZE` / `MEMP_NUM_TCPIP_MSG_INPKT` 从 8 临时扩大到 16。
|
||||||
|
- 成功 ping 从 8 次变为 `seq=1900..1915` 共 16 次。
|
||||||
|
- 第 17 次 `seq=1916` 开始无 reply。
|
||||||
|
|
||||||
|
这个“成功次数随池大小移动”的现象证明:问题不是 CH390 随机丢包,也不是 PHY/TX 死掉,而是每次成功处理 ping 后都有某个 pbuf 引用没有释放,最终耗尽 `PBUF_POOL`。
|
||||||
|
|
||||||
|
## 2. 排查过程中的重要结论
|
||||||
|
|
||||||
|
### 2.1 CH390 RX 读包路径曾存在风险,但不是最终根因
|
||||||
|
|
||||||
|
早期排查时发现 CH390 RX 路径与参考驱动存在若干不一致,已修正:
|
||||||
|
|
||||||
|
- `ch390_receive_packet()` 按参考序列读取 RX ready:先读 `MRCMDX` dummy,再读 `MRCMDX1`。
|
||||||
|
- 校验 RX header 的 `Head` 字节必须为 `CH390_PKT_RDY`。
|
||||||
|
- CH390 RX SRAM 中的 `rx_len` 包含 Ethernet FCS,交给 lwIP 前需要减去 4 字节。
|
||||||
|
- `ch390_rx_reset()` 显式写 `MPTRCR_RST_RX` 复位 RX memory pointer。
|
||||||
|
|
||||||
|
这些修正确保 CH390 RX FIFO 读包更接近参考实现,但无法解释“固定 8 次/16 次后失败”。
|
||||||
|
|
||||||
|
### 2.2 扩大 lwIP 池只能延迟问题
|
||||||
|
|
||||||
|
曾临时将如下配置从 8 提到 16:
|
||||||
|
|
||||||
|
```c
|
||||||
|
#define PBUF_POOL_SIZE 16
|
||||||
|
#define MEMP_NUM_PBUF 16
|
||||||
|
#define MEMP_NUM_TCPIP_MSG_INPKT 16
|
||||||
|
```
|
||||||
|
|
||||||
|
结果成功 ping 次数也从 8 变成 16。这说明扩大池子只是延迟耗尽,不能作为根修复。
|
||||||
|
|
||||||
|
最终已恢复为 8:
|
||||||
|
|
||||||
|
```c
|
||||||
|
#define PBUF_POOL_SIZE 8
|
||||||
|
#define MEMP_NUM_PBUF 8
|
||||||
|
#define MEMP_NUM_TCPIP_MSG_INPKT 8
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.3 `tcpip_input()` 异步队列不是最终根因
|
||||||
|
|
||||||
|
项目启用了 lwIP core locking。为避免每个 RX 包占用 `MEMP_TCPIP_MSG_INPKT`,配置已改为同步输入:
|
||||||
|
|
||||||
|
```c
|
||||||
|
#define LWIP_TCPIP_CORE_LOCKING 1
|
||||||
|
#define LWIP_TCPIP_CORE_LOCKING_INPUT 1
|
||||||
|
```
|
||||||
|
|
||||||
|
这样 `tcpip_input()` 会在 core lock 下同步调用 `ethernet_input()`,不再通过 `TCPIP_MSG_INPKT` 邮箱异步排队。
|
||||||
|
|
||||||
|
但用户后续验证仍然固定 8 次后停止,且每次成功 ping 都已经有 reply,因此说明 RX 包确实已经进入 ICMP 处理路径,问题更可能是 reply 输出路径增加了 pbuf 引用但未释放。
|
||||||
|
|
||||||
|
## 3. 最终根因
|
||||||
|
|
||||||
|
最终根因位于:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Drivers/LwIP/src/netif/ethernet.c
|
||||||
|
```
|
||||||
|
|
||||||
|
原 `ethernet_output()` 实现:
|
||||||
|
|
||||||
|
```c
|
||||||
|
q = pbuf_alloc(PBUF_RAW_TX, SIZEOF_ETH_HDR, PBUF_RAM);
|
||||||
|
if (q == NULL) {
|
||||||
|
LINK_STATS_INC(link.memerr);
|
||||||
|
LINK_STATS_INC(link.drop);
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
pbuf_chain(q, p);
|
||||||
|
|
||||||
|
ethhdr = (struct eth_hdr *)q->payload;
|
||||||
|
SMEMCPY(ðhdr->dest, dst, sizeof(struct eth_addr));
|
||||||
|
SMEMCPY(ðhdr->src, src, sizeof(struct eth_addr));
|
||||||
|
ethhdr->type = lwip_htons(eth_type);
|
||||||
|
|
||||||
|
return netif->linkoutput(netif, q);
|
||||||
|
```
|
||||||
|
|
||||||
|
问题在 `pbuf_chain(q, p)`。
|
||||||
|
|
||||||
|
lwIP 的 `pbuf_chain()` 会执行:
|
||||||
|
|
||||||
|
```c
|
||||||
|
pbuf_ref(t);
|
||||||
|
```
|
||||||
|
|
||||||
|
也就是给被挂接的原始 pbuf `p` 引用计数加 1。
|
||||||
|
|
||||||
|
ICMP echo reply 路径会复用 RX pbuf:
|
||||||
|
|
||||||
|
```text
|
||||||
|
ethernetif_poll()
|
||||||
|
-> tcpip_input()
|
||||||
|
-> ethernet_input()
|
||||||
|
-> ip4_input()
|
||||||
|
-> icmp_input()
|
||||||
|
-> ip4_output_if()
|
||||||
|
-> etharp_output()
|
||||||
|
-> ethernet_output()
|
||||||
|
```
|
||||||
|
|
||||||
|
`icmp_input()` 末尾本身会 `pbuf_free(p)`,这部分是正确的。但在原实现中,`ethernet_output()` 通过 `pbuf_chain(q, p)` 给 `p` 额外加了一次引用,却没有在 `linkoutput()` 返回后释放临时 header pbuf `q`。
|
||||||
|
|
||||||
|
因此每次 ping 的引用计数变化是:
|
||||||
|
|
||||||
|
```text
|
||||||
|
RX pbuf 初始 ref = 1
|
||||||
|
pbuf_chain(q, p) 后 ref = 2
|
||||||
|
icmp_input() 末尾 pbuf_free(p) 后 ref = 1
|
||||||
|
=> p 永远没有回到 0,PBUF_POOL 泄漏 1 个
|
||||||
|
```
|
||||||
|
|
||||||
|
所以:
|
||||||
|
|
||||||
|
- `PBUF_POOL_SIZE=8` 时,8 次 ping reply 后耗尽。
|
||||||
|
- 临时扩大到 16 时,16 次 ping reply 后耗尽。
|
||||||
|
|
||||||
|
## 4. 修复方案
|
||||||
|
|
||||||
|
修复 `ethernet_output()`,在同步 `linkoutput()` 完成后释放临时 header pbuf 链:
|
||||||
|
|
||||||
|
```c
|
||||||
|
err_t ethernet_output(struct netif *netif,
|
||||||
|
struct pbuf *p,
|
||||||
|
const struct eth_addr *src,
|
||||||
|
const struct eth_addr *dst,
|
||||||
|
u16_t eth_type)
|
||||||
|
{
|
||||||
|
struct pbuf *q;
|
||||||
|
struct eth_hdr *ethhdr;
|
||||||
|
err_t err;
|
||||||
|
|
||||||
|
LWIP_ASSERT("netif != NULL", netif != NULL);
|
||||||
|
LWIP_ASSERT("p != NULL", p != NULL);
|
||||||
|
LWIP_ASSERT("src != NULL", src != NULL);
|
||||||
|
LWIP_ASSERT("dst != NULL", dst != NULL);
|
||||||
|
|
||||||
|
q = pbuf_alloc(PBUF_RAW_TX, SIZEOF_ETH_HDR, PBUF_RAM);
|
||||||
|
if (q == NULL) {
|
||||||
|
LINK_STATS_INC(link.memerr);
|
||||||
|
LINK_STATS_INC(link.drop);
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
pbuf_chain(q, p);
|
||||||
|
|
||||||
|
ethhdr = (struct eth_hdr *)q->payload;
|
||||||
|
SMEMCPY(ðhdr->dest, dst, sizeof(struct eth_addr));
|
||||||
|
SMEMCPY(ðhdr->src, src, sizeof(struct eth_addr));
|
||||||
|
ethhdr->type = lwip_htons(eth_type);
|
||||||
|
|
||||||
|
err = netif->linkoutput(netif, q);
|
||||||
|
pbuf_free(q);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
为什么这里可以释放 `q`:
|
||||||
|
|
||||||
|
- 本项目 `low_level_output()` 是同步发送。
|
||||||
|
- 它会立即遍历 pbuf 链,把数据复制到 `s_tx_buffer`。
|
||||||
|
- 随后调用 `ch390_runtime_send_packet()` 把连续 buffer 发给 CH390。
|
||||||
|
- `low_level_output()` 返回后不再持有 pbuf 指针。
|
||||||
|
|
||||||
|
因此 `ethernet_output()` 在 `linkoutput()` 返回后释放 `q` 是正确的。
|
||||||
|
|
||||||
|
`pbuf_free(q)` 会同时:
|
||||||
|
|
||||||
|
- 释放临时 Ethernet header pbuf `q`;
|
||||||
|
- 解除 `pbuf_chain()` 对原始 RX pbuf `p` 增加的引用;
|
||||||
|
- 之后 `icmp_input()` 末尾的 `pbuf_free(p)` 可以真正把 RX pbuf 归还 `PBUF_POOL`。
|
||||||
|
|
||||||
|
## 5. 不要做的错误修复
|
||||||
|
|
||||||
|
### 5.1 不要在 `netif->input()` 成功后手动释放 pbuf
|
||||||
|
|
||||||
|
驱动层当前逻辑是正确的:
|
||||||
|
|
||||||
|
```c
|
||||||
|
input_err = ch390_netif.input(p, &ch390_netif);
|
||||||
|
if (input_err != ERR_OK) {
|
||||||
|
pbuf_free(p);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`netif->input()` 返回 `ERR_OK` 时,pbuf ownership 已经交给 lwIP。此时驱动不能再 `pbuf_free(p)`,否则会造成 double-free 或 use-after-free。
|
||||||
|
|
||||||
|
### 5.2 不要只扩大 `PBUF_POOL_SIZE`
|
||||||
|
|
||||||
|
扩大池子只会让失败次数从 8 变 16、32……不会修复泄漏。
|
||||||
|
|
||||||
|
### 5.3 不要继续优先怀疑 CH390 PHY/TX
|
||||||
|
|
||||||
|
抓包中失败后设备仍持续发送 TCP SYN/RST,说明 TX 和任务仍活着。固定次数失败更符合 pbuf 引用泄漏。
|
||||||
|
|
||||||
|
## 6. 验证结果
|
||||||
|
|
||||||
|
修复后 Keil 构建通过:
|
||||||
|
|
||||||
|
```text
|
||||||
|
"TCP2UART\TCP2UART.axf" - 0 Error(s), 0 Warning(s).
|
||||||
|
Program Size: Code=93376 RO-data=2768 RW-data=456 ZI-data=56032
|
||||||
|
```
|
||||||
|
|
||||||
|
用户烧录验证后确认问题已修复。
|
||||||
|
|
||||||
|
## 7. 后续排查建议
|
||||||
|
|
||||||
|
如后续再次出现固定次数网络停止,优先检查:
|
||||||
|
|
||||||
|
1. 是否存在 `pbuf_chain()` / `pbuf_ref()` 后没有配对 `pbuf_free()` 的路径。
|
||||||
|
2. 是否有 ARP pending queue 长时间持有 pbuf。
|
||||||
|
3. 是否有 TCP `recvmbox` / 应用桥接队列背压长期持有 pbuf。
|
||||||
|
4. 是否有人在 `netif->input()` 成功后错误释放 pbuf,导致内存破坏。
|
||||||
|
|
||||||
|
推荐排查点:
|
||||||
|
|
||||||
|
- `Drivers/LwIP/src/netif/ethernet.c`
|
||||||
|
- `Drivers/LwIP/src/core/ipv4/icmp.c`
|
||||||
|
- `Drivers/LwIP/src/core/ipv4/etharp.c`
|
||||||
|
- `Drivers/LwIP/src/core/pbuf.c`
|
||||||
|
- `Drivers/LwIP/src/netif/ethernetif.c`
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
# TCP2UART 当前交接 Prompt
|
||||||
|
|
||||||
|
## 1. 用途
|
||||||
|
|
||||||
|
本文件不再承担“项目从零编码任务说明”的职责,而是作为**当前工程的交接入口 Prompt**使用。
|
||||||
|
|
||||||
|
长期有效的工程知识、调试经验和现状说明,已经分别固化到其它文档,不再全部堆在本文件中。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 接手后先读什么
|
||||||
|
|
||||||
|
请按以下顺序阅读:
|
||||||
|
|
||||||
|
1. `交接清单.md` —— 当前状态、接下来要做什么、怎么做
|
||||||
|
2. `工程调试指南.md` —— 已固化的调试经验与当前工程真实边界
|
||||||
|
3. `项目技术实现.md` —— 架构、任务模型、协议模型
|
||||||
|
4. `项目需求说明.md`
|
||||||
|
5. `AT固件使用手册.md`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 当前工程一句话状态
|
||||||
|
|
||||||
|
当前项目已从早期 bring-up 阶段推进到 full-task 运行期调试阶段;`DIAG_TASK_ISOLATION=1` 稳定,`DIAG_TASK_ISOLATION=0` 仍会卡死,但故障边界已被多轮 discriminator 推进到 enabled 的 `netconn_*` 路径。当前在 `STM32F103RCT6` 上的 RAM/heap 余量过低,已被认定为调试噪声的主要来源之一,因此推荐下一阶段先切到 pin2pin 的 `STM32F103RDT6` 再继续分析。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 下一位 agent 的当前目标
|
||||||
|
|
||||||
|
请不要把当前任务理解成“立刻继续加逻辑修补”。当前更重要的是:
|
||||||
|
|
||||||
|
1. 完成 `STM32F103RCT6 -> STM32F103RDT6` 目标切换
|
||||||
|
2. 使用真实 Keil 日志重新确认构建成功
|
||||||
|
3. 在新器件上复测当前代码基线
|
||||||
|
4. 比较:
|
||||||
|
- 故障是否消失
|
||||||
|
- 是否明显后移
|
||||||
|
- 是否仍停在相同 enabled path
|
||||||
|
5. 只有拿到新器件上的第一轮 RTT / heap / HWM 证据后,再决定下一步最小化改动
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 工作约束
|
||||||
|
|
||||||
|
1. 构建真值以 `MDK-ARM/build_capture.txt`、`TCP2UART.build_log.htm`、`.map` 为准
|
||||||
|
2. 不要再把 viewer 当作当前构建真值
|
||||||
|
3. 不要忽视 `DIAG_TASK_ISOLATION=1 正常、=0 异常` 这个前提
|
||||||
|
4. 在新器件的第一轮复测前,避免继续做大范围代码改动
|
||||||
|
5. 每次只做一个能明显改变故障边界的最小改动,并保留 RTT 证据
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 可直接复制给下一位 agent 的起始 Prompt
|
||||||
|
|
||||||
|
```text
|
||||||
|
请先阅读:`交接清单.md`、`工程调试指南.md`、`项目技术实现.md`。
|
||||||
|
|
||||||
|
当前项目是 STM32F103 + FreeRTOS + lwIP + CH390 的 TCP↔UART 透传工程。此前在 `STM32F103RCT6` 上调试时,`DIAG_TASK_ISOLATION=1` 稳定,`DIAG_TASK_ISOLATION=0` 仍会卡死,但故障边界已被多轮 discriminator 推进到 enabled 的 `netconn_*` 路径。当前最关键的资源事实是:在 `RCT6` 上 full-task 创建完四个 TCP 任务后,FreeRTOS heap 只剩约 944 bytes,静态 RAM 也已逼近物理上限,因此当前推荐先切换到 pin2pin 的 `STM32F103RDT6`,保持现有代码基线基本不变,先完成第一轮换片复测,再根据新器件上的 RTT、free/min heap 和 enabled `S1/C1` 行为决定下一步。
|
||||||
|
|
||||||
|
你的当前目标不是立刻修完所有问题,而是:
|
||||||
|
1. 完成 `RCT6 -> RDT6` 目标切换;
|
||||||
|
2. 用真实 Keil 日志确认构建通过;
|
||||||
|
3. 在新器件上复测当前代码,判断故障是否消失、后移或保持原状;
|
||||||
|
4. 仅在拿到新器件上的第一轮 RTT 后,再继续做最小化的下一步判别。
|
||||||
|
```
|
||||||
@@ -44,6 +44,7 @@
|
|||||||
|
|
||||||
/* USER CODE BEGIN Includes */
|
/* USER CODE BEGIN Includes */
|
||||||
/* Section where include file can be added */
|
/* Section where include file can be added */
|
||||||
|
#include "debug_log.h"
|
||||||
/* USER CODE END Includes */
|
/* USER CODE END Includes */
|
||||||
|
|
||||||
/* Ensure definitions are only used by the compiler, and not by the assembler. */
|
/* Ensure definitions are only used by the compiler, and not by the assembler. */
|
||||||
@@ -59,13 +60,13 @@
|
|||||||
#define configUSE_PREEMPTION 1
|
#define configUSE_PREEMPTION 1
|
||||||
#define configSUPPORT_STATIC_ALLOCATION 1
|
#define configSUPPORT_STATIC_ALLOCATION 1
|
||||||
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||||
#define configUSE_IDLE_HOOK 0
|
#define configUSE_IDLE_HOOK 1
|
||||||
#define configUSE_TICK_HOOK 0
|
#define configUSE_TICK_HOOK 0
|
||||||
#define configCPU_CLOCK_HZ ( SystemCoreClock )
|
#define configCPU_CLOCK_HZ ( SystemCoreClock )
|
||||||
#define configTICK_RATE_HZ ((TickType_t)1000)
|
#define configTICK_RATE_HZ ((TickType_t)1000)
|
||||||
#define configMAX_PRIORITIES ( 56 )
|
#define configMAX_PRIORITIES ( 7 )
|
||||||
#define configMINIMAL_STACK_SIZE ((uint16_t)128)
|
#define configMINIMAL_STACK_SIZE ((uint16_t)128)
|
||||||
#define configTOTAL_HEAP_SIZE ((size_t)8192) /* Fit R8 RAM budget with dynamic tasks */
|
#define configTOTAL_HEAP_SIZE ((size_t)21760)
|
||||||
#define configMAX_TASK_NAME_LEN ( 16 )
|
#define configMAX_TASK_NAME_LEN ( 16 )
|
||||||
#define configUSE_TRACE_FACILITY 1
|
#define configUSE_TRACE_FACILITY 1
|
||||||
#define configUSE_16_BIT_TICKS 0
|
#define configUSE_16_BIT_TICKS 0
|
||||||
@@ -86,6 +87,8 @@
|
|||||||
#define configTIMER_TASK_PRIORITY ( 2 )
|
#define configTIMER_TASK_PRIORITY ( 2 )
|
||||||
#define configTIMER_QUEUE_LENGTH 10
|
#define configTIMER_QUEUE_LENGTH 10
|
||||||
#define configTIMER_TASK_STACK_DEPTH 256
|
#define configTIMER_TASK_STACK_DEPTH 256
|
||||||
|
#define configCHECK_FOR_STACK_OVERFLOW 2
|
||||||
|
#define configUSE_MALLOC_FAILED_HOOK 1
|
||||||
|
|
||||||
/* Set the following definitions to 1 to include the API function, or zero
|
/* Set the following definitions to 1 to include the API function, or zero
|
||||||
to exclude the API function. */
|
to exclude the API function. */
|
||||||
@@ -137,7 +140,7 @@ See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
|
|||||||
/* Normal assert() semantics without relying on the provision of an assert.h
|
/* Normal assert() semantics without relying on the provision of an assert.h
|
||||||
header file. */
|
header file. */
|
||||||
/* USER CODE BEGIN 1 */
|
/* USER CODE BEGIN 1 */
|
||||||
#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); for( ;; );}
|
#define configASSERT( x ) do { if ((x) == 0) { debug_log_fault_context("config-assert", __FILE__, __LINE__); taskDISABLE_INTERRUPTS(); for( ;; ) { } } } while (0)
|
||||||
/* USER CODE END 1 */
|
/* USER CODE END 1 */
|
||||||
|
|
||||||
/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
|
/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
|
||||||
@@ -151,6 +154,33 @@ standard names. */
|
|||||||
|
|
||||||
/* USER CODE BEGIN Defines */
|
/* USER CODE BEGIN Defines */
|
||||||
/* Section where parameter definitions can be added (for instance, to override default ones in FreeRTOS.h) */
|
/* Section where parameter definitions can be added (for instance, to override default ones in FreeRTOS.h) */
|
||||||
|
|
||||||
|
/* Application task priorities (higher number = higher priority) */
|
||||||
|
#define TASK_PRIORITY_TCPIP 6
|
||||||
|
#define TASK_PRIORITY_NET_POLL 5
|
||||||
|
#define TASK_PRIORITY_TCP_SERVER 4
|
||||||
|
#define TASK_PRIORITY_TCP_CLIENT 4
|
||||||
|
#define TASK_PRIORITY_UART_RX 4
|
||||||
|
#define TASK_PRIORITY_ROUTE 3
|
||||||
|
#define TASK_PRIORITY_CONFIG 2
|
||||||
|
#define TASK_PRIORITY_DEFAULT 1
|
||||||
|
|
||||||
|
/* Application task stack sizes (in words) */
|
||||||
|
#define TASK_STACK_TCPIP 512
|
||||||
|
#define TASK_STACK_NET_POLL 512
|
||||||
|
#define TASK_STACK_TCP_SERVER 512
|
||||||
|
#define TASK_STACK_TCP_CLIENT 512
|
||||||
|
#define TASK_STACK_UART_RX 384
|
||||||
|
#define TASK_STACK_ROUTE 512
|
||||||
|
#define TASK_STACK_CONFIG 384
|
||||||
|
#define TASK_STACK_DEFAULT 192
|
||||||
|
|
||||||
|
/* Route message pool for zero-copy inter-task communication */
|
||||||
|
#define ROUTE_MSG_POOL_SIZE 8
|
||||||
|
#define ROUTE_MSG_MAX_PAYLOAD 512
|
||||||
|
|
||||||
|
#define DIAG_TASK_ISOLATION 0
|
||||||
|
|
||||||
/* USER CODE END Defines */
|
/* USER CODE END Defines */
|
||||||
|
|
||||||
#endif /* FREERTOS_CONFIG_H */
|
#endif /* FREERTOS_CONFIG_H */
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#ifndef DEBUG_LOG_H
|
||||||
|
#define DEBUG_LOG_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern volatile uint32_t g_rtt_log_seq;
|
||||||
|
extern volatile uint32_t g_rtt_log_drop_count;
|
||||||
|
extern volatile uint32_t g_rtt_log_last_drop_seq;
|
||||||
|
|
||||||
|
void debug_log_init(void);
|
||||||
|
void debug_log_write(const char *msg);
|
||||||
|
void debug_log_printf(const char *fmt, ...);
|
||||||
|
void debug_log_boot(const char *tag);
|
||||||
|
void debug_log_fault(const char *tag);
|
||||||
|
void debug_log_runtime_snapshot(void);
|
||||||
|
void debug_log_fault_context(const char *tag, const char *file, int line);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
+1
-1
@@ -38,7 +38,7 @@ extern IWDG_HandleTypeDef hiwdg;
|
|||||||
|
|
||||||
/* USER CODE END Private defines */
|
/* USER CODE END Private defines */
|
||||||
|
|
||||||
void MX_IWDG_Init(void);
|
HAL_StatusTypeDef MX_IWDG_Init(void);
|
||||||
|
|
||||||
/* USER CODE BEGIN Prototypes */
|
/* USER CODE BEGIN Prototypes */
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ extern "C" {
|
|||||||
|
|
||||||
/* Exported functions prototypes ---------------------------------------------*/
|
/* Exported functions prototypes ---------------------------------------------*/
|
||||||
void Error_Handler(void);
|
void Error_Handler(void);
|
||||||
|
void Debug_TrapWithRttHint(const char *tag);
|
||||||
|
|
||||||
/* USER CODE BEGIN EFP */
|
/* USER CODE BEGIN EFP */
|
||||||
|
|
||||||
|
|||||||
+5
-48
@@ -1,74 +1,31 @@
|
|||||||
/* USER CODE BEGIN Header */
|
#ifndef __STM32F1XX_IT_H
|
||||||
/**
|
#define __STM32F1XX_IT_H
|
||||||
******************************************************************************
|
|
||||||
* @file stm32f1xx_it.h
|
|
||||||
* @brief This file contains the headers of the interrupt handlers.
|
|
||||||
******************************************************************************
|
|
||||||
* @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 */
|
|
||||||
|
|
||||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
|
||||||
#ifndef __STM32F1xx_IT_H
|
|
||||||
#define __STM32F1xx_IT_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Private includes ----------------------------------------------------------*/
|
|
||||||
/* USER CODE BEGIN Includes */
|
|
||||||
|
|
||||||
/* USER CODE END Includes */
|
|
||||||
|
|
||||||
/* Exported types ------------------------------------------------------------*/
|
|
||||||
/* USER CODE BEGIN ET */
|
|
||||||
|
|
||||||
/* USER CODE END ET */
|
|
||||||
|
|
||||||
/* Exported constants --------------------------------------------------------*/
|
|
||||||
/* USER CODE BEGIN EC */
|
|
||||||
|
|
||||||
/* USER CODE END EC */
|
|
||||||
|
|
||||||
/* Exported macro ------------------------------------------------------------*/
|
|
||||||
/* USER CODE BEGIN EM */
|
|
||||||
|
|
||||||
/* USER CODE END EM */
|
|
||||||
|
|
||||||
/* Exported functions prototypes ---------------------------------------------*/
|
|
||||||
void NMI_Handler(void);
|
void NMI_Handler(void);
|
||||||
void HardFault_Handler(void);
|
void HardFault_Handler(void);
|
||||||
void MemManage_Handler(void);
|
void MemManage_Handler(void);
|
||||||
void BusFault_Handler(void);
|
void BusFault_Handler(void);
|
||||||
void UsageFault_Handler(void);
|
void UsageFault_Handler(void);
|
||||||
void DebugMon_Handler(void);
|
void DebugMon_Handler(void);
|
||||||
void SysTick_Handler(void);
|
|
||||||
void DMA1_Channel2_IRQHandler(void);
|
void DMA1_Channel2_IRQHandler(void);
|
||||||
void DMA1_Channel3_IRQHandler(void);
|
void DMA1_Channel3_IRQHandler(void);
|
||||||
void DMA1_Channel4_IRQHandler(void);
|
void DMA1_Channel4_IRQHandler(void);
|
||||||
void DMA1_Channel5_IRQHandler(void);
|
void DMA1_Channel5_IRQHandler(void);
|
||||||
void DMA1_Channel6_IRQHandler(void);
|
void DMA1_Channel6_IRQHandler(void);
|
||||||
void DMA1_Channel7_IRQHandler(void);
|
void DMA1_Channel7_IRQHandler(void);
|
||||||
|
void EXTI0_IRQHandler(void);
|
||||||
void SPI1_IRQHandler(void);
|
void SPI1_IRQHandler(void);
|
||||||
void USART1_IRQHandler(void);
|
void USART1_IRQHandler(void);
|
||||||
void USART2_IRQHandler(void);
|
void USART2_IRQHandler(void);
|
||||||
void USART3_IRQHandler(void);
|
void USART3_IRQHandler(void);
|
||||||
/* USER CODE BEGIN EFP */
|
void TIM4_IRQHandler(void);
|
||||||
|
|
||||||
/* USER CODE END EFP */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __STM32F1xx_IT_H */
|
#endif
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ void MX_USART2_UART_Init(void);
|
|||||||
void MX_USART3_UART_Init(void);
|
void MX_USART3_UART_Init(void);
|
||||||
|
|
||||||
/* USER CODE BEGIN Prototypes */
|
/* USER CODE BEGIN Prototypes */
|
||||||
|
void USART_SetConfiguredBaudrates(uint32_t usart2_baudrate, uint32_t usart3_baudrate);
|
||||||
|
|
||||||
/* USER CODE END Prototypes */
|
/* USER CODE END Prototypes */
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
#include "debug_log.h"
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "SEGGER_RTT.h"
|
||||||
|
#include "task.h"
|
||||||
|
|
||||||
|
volatile uint32_t g_rtt_log_seq = 0u;
|
||||||
|
volatile uint32_t g_rtt_log_drop_count = 0u;
|
||||||
|
volatile uint32_t g_rtt_log_last_drop_seq = 0u;
|
||||||
|
|
||||||
|
static void debug_backend_write(const char *msg)
|
||||||
|
{
|
||||||
|
unsigned len;
|
||||||
|
unsigned written;
|
||||||
|
|
||||||
|
if ((msg == NULL) || (msg[0] == '\0')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = (unsigned)strlen(msg);
|
||||||
|
g_rtt_log_seq += 1u;
|
||||||
|
written = SEGGER_RTT_Write(0u, msg, len);
|
||||||
|
if (written < len) {
|
||||||
|
g_rtt_log_drop_count += 1u;
|
||||||
|
g_rtt_log_last_drop_seq = g_rtt_log_seq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void debug_log_init(void)
|
||||||
|
{
|
||||||
|
SEGGER_RTT_Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void debug_log_write(const char *msg)
|
||||||
|
{
|
||||||
|
if (msg == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_backend_write(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void debug_log_printf(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
char buffer[256];
|
||||||
|
va_list args;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
if (fmt == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
va_start(args, fmt);
|
||||||
|
len = vsnprintf(buffer, sizeof(buffer), fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
if (len < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[sizeof(buffer) - 1u] = '\0';
|
||||||
|
debug_backend_write(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void debug_log_boot(const char *tag)
|
||||||
|
{
|
||||||
|
debug_log_printf("[BOOT] %s\r\n", (tag != NULL) ? tag : "(null)");
|
||||||
|
}
|
||||||
|
|
||||||
|
void debug_log_fault(const char *tag)
|
||||||
|
{
|
||||||
|
debug_log_printf("[FAULT] %s\r\n", (tag != NULL) ? tag : "(null)");
|
||||||
|
}
|
||||||
|
|
||||||
|
void debug_log_fault_context(const char *tag, const char *file, int line)
|
||||||
|
{
|
||||||
|
debug_log_printf("[FAULT] %s file=%s line=%d free=%lu min=%lu seq=%lu drop=%lu last_drop=%lu\r\n",
|
||||||
|
(tag != NULL) ? tag : "(null)",
|
||||||
|
(file != NULL) ? file : "(null)",
|
||||||
|
line,
|
||||||
|
(unsigned long)xPortGetFreeHeapSize(),
|
||||||
|
(unsigned long)xPortGetMinimumEverFreeHeapSize(),
|
||||||
|
(unsigned long)g_rtt_log_seq,
|
||||||
|
(unsigned long)g_rtt_log_drop_count,
|
||||||
|
(unsigned long)g_rtt_log_last_drop_seq);
|
||||||
|
}
|
||||||
|
|
||||||
|
void debug_log_runtime_snapshot(void)
|
||||||
|
{
|
||||||
|
UBaseType_t default_hwm;
|
||||||
|
size_t free_heap;
|
||||||
|
size_t min_heap;
|
||||||
|
|
||||||
|
free_heap = xPortGetFreeHeapSize();
|
||||||
|
min_heap = xPortGetMinimumEverFreeHeapSize();
|
||||||
|
default_hwm = uxTaskGetStackHighWaterMark(NULL);
|
||||||
|
|
||||||
|
debug_log_printf("[RTOS] free=%lu min=%lu self_hwm=%lu\r\n",
|
||||||
|
(unsigned long)free_heap,
|
||||||
|
(unsigned long)min_heap,
|
||||||
|
(unsigned long)default_hwm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lwip_platform_assert(const char *msg, const char *file, int line)
|
||||||
|
{
|
||||||
|
debug_log_printf("[FAULT] lwip-assert msg=%s file=%s line=%d\r\n",
|
||||||
|
(msg != NULL) ? msg : "(null)",
|
||||||
|
(file != NULL) ? file : "(null)",
|
||||||
|
line);
|
||||||
|
|
||||||
|
taskDISABLE_INTERRUPTS();
|
||||||
|
while (1) {
|
||||||
|
}
|
||||||
|
}
|
||||||
+189
-325
@@ -1,370 +1,234 @@
|
|||||||
/* USER CODE BEGIN Header */
|
|
||||||
/**
|
|
||||||
******************************************************************************
|
|
||||||
* File Name : freertos.c
|
|
||||||
* Description : Code for freertos applications
|
|
||||||
******************************************************************************
|
|
||||||
* @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 */
|
|
||||||
|
|
||||||
/* Includes ------------------------------------------------------------------*/
|
|
||||||
#include "FreeRTOS.h"
|
#include "FreeRTOS.h"
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
#include "main.h"
|
#include "queue.h"
|
||||||
#include "cmsis_os.h"
|
|
||||||
|
|
||||||
/* Private includes ----------------------------------------------------------*/
|
|
||||||
/* USER CODE BEGIN Includes */
|
|
||||||
#include "semphr.h"
|
#include "semphr.h"
|
||||||
#include "stream_buffer.h"
|
#include "main.h"
|
||||||
|
#include "gpio.h"
|
||||||
|
#include "iwdg.h"
|
||||||
|
|
||||||
/* Application modules */
|
#include "config.h"
|
||||||
|
#include "debug_log.h"
|
||||||
|
#include "route_msg.h"
|
||||||
|
#include "app_runtime.h"
|
||||||
|
#include "task_net_poll.h"
|
||||||
#include "tcp_server.h"
|
#include "tcp_server.h"
|
||||||
#include "tcp_client.h"
|
#include "tcp_client.h"
|
||||||
#include "uart_trans.h"
|
#include "uart_trans.h"
|
||||||
#include "config.h"
|
|
||||||
#include "ethernetif.h"
|
|
||||||
|
|
||||||
/* LwIP includes */
|
QueueHandle_t xTcpRxQueue = NULL;
|
||||||
#include "lwip/tcpip.h"
|
QueueHandle_t xConfigQueue = NULL;
|
||||||
#include "lwip/ip4_addr.h"
|
QueueHandle_t xLinkTxQueues[CONFIG_LINK_COUNT] = {0};
|
||||||
#include "lwip/dhcp.h"
|
SemaphoreHandle_t xNetSemaphore = NULL;
|
||||||
#include "lwip/timeouts.h"
|
|
||||||
/* USER CODE END Includes */
|
|
||||||
|
|
||||||
/* Private typedef -----------------------------------------------------------*/
|
TaskHandle_t xUartRxTaskHandle = NULL;
|
||||||
/* USER CODE BEGIN PTD */
|
TaskHandle_t xConfigTaskHandle = NULL;
|
||||||
|
volatile BaseType_t g_netif_ready = pdFALSE;
|
||||||
|
volatile uint32_t g_netif_phase = 0u;
|
||||||
|
volatile int32_t g_netif_add_err = 0x7FFFFFFF;
|
||||||
|
volatile int32_t g_netif_set_default_err = 0x7FFFFFFF;
|
||||||
|
volatile int32_t g_netif_set_link_down_err = 0x7FFFFFFF;
|
||||||
|
volatile int32_t g_netif_set_up_err = 0x7FFFFFFF;
|
||||||
|
volatile int32_t g_netif_init_ok = 0;
|
||||||
|
|
||||||
/* USER CODE END PTD */
|
static TaskHandle_t xNetPollTaskHandle = NULL;
|
||||||
|
static TaskHandle_t xTcpSrvTaskS1Handle = NULL;
|
||||||
|
static TaskHandle_t xTcpSrvTaskS2Handle = NULL;
|
||||||
|
static TaskHandle_t xTcpCliTaskC1Handle = NULL;
|
||||||
|
static TaskHandle_t xTcpCliTaskC2Handle = NULL;
|
||||||
|
static TaskHandle_t xDefaultTaskHandle = NULL;
|
||||||
|
static BaseType_t xNetworkTasksStarted = pdFALSE;
|
||||||
|
static volatile BaseType_t xNetworkTaskStopRequested = pdFALSE;
|
||||||
|
static volatile BaseType_t xNetworkRestartRequested = pdFALSE;
|
||||||
|
|
||||||
/* Private define ------------------------------------------------------------*/
|
void app_start_network_tasks(void)
|
||||||
/* USER CODE BEGIN PD */
|
|
||||||
/* Task stack sizes (words, not bytes) */
|
|
||||||
#define LWIP_TASK_STACK_SIZE 384
|
|
||||||
#define TCP_SERVER_TASK_STACK_SIZE 320
|
|
||||||
#define TCP_CLIENT_TASK_STACK_SIZE 320
|
|
||||||
#define UART_TRANS_TASK_STACK_SIZE 192
|
|
||||||
#define CONFIG_TASK_STACK_SIZE 256
|
|
||||||
#define DEFAULT_TASK_STACK_SIZE 128
|
|
||||||
|
|
||||||
/* Task priorities */
|
|
||||||
#define LWIP_TASK_PRIORITY (osPriorityAboveNormal)
|
|
||||||
#define TCP_SERVER_TASK_PRIORITY (osPriorityNormal)
|
|
||||||
#define TCP_CLIENT_TASK_PRIORITY (osPriorityNormal)
|
|
||||||
#define UART_TRANS_TASK_PRIORITY (osPriorityNormal)
|
|
||||||
#define CONFIG_TASK_PRIORITY (osPriorityBelowNormal)
|
|
||||||
#define DEFAULT_TASK_PRIORITY (osPriorityLow)
|
|
||||||
/* USER CODE END PD */
|
|
||||||
|
|
||||||
/* Private macro -------------------------------------------------------------*/
|
|
||||||
/* USER CODE BEGIN PM */
|
|
||||||
|
|
||||||
/* USER CODE END PM */
|
|
||||||
|
|
||||||
/* Private variables ---------------------------------------------------------*/
|
|
||||||
/* USER CODE BEGIN Variables */
|
|
||||||
/* Task handles */
|
|
||||||
TaskHandle_t lwipTaskHandle = NULL;
|
|
||||||
TaskHandle_t tcpServerTaskHandle = NULL;
|
|
||||||
TaskHandle_t tcpClientTaskHandle = NULL;
|
|
||||||
TaskHandle_t uartServerTransTaskHandle = NULL;
|
|
||||||
TaskHandle_t uartClientTransTaskHandle = NULL;
|
|
||||||
TaskHandle_t configTaskHandle = NULL;
|
|
||||||
|
|
||||||
/* SPI mutex for CH390 access */
|
|
||||||
SemaphoreHandle_t ch390SpiMutex = NULL;
|
|
||||||
|
|
||||||
/* CH390 interrupt notification semaphore */
|
|
||||||
SemaphoreHandle_t ch390IntSemaphore = NULL;
|
|
||||||
/* USER CODE END Variables */
|
|
||||||
|
|
||||||
/* Definitions for defaultTask */
|
|
||||||
osThreadId_t defaultTaskHandle;
|
|
||||||
const osThreadAttr_t defaultTask_attributes = {
|
|
||||||
.name = "defaultTask",
|
|
||||||
.stack_size = DEFAULT_TASK_STACK_SIZE * 4,
|
|
||||||
.priority = (osPriority_t) DEFAULT_TASK_PRIORITY,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Private function prototypes -----------------------------------------------*/
|
|
||||||
/* USER CODE BEGIN FunctionPrototypes */
|
|
||||||
void LwIPTask(void *argument);
|
|
||||||
/* USER CODE END FunctionPrototypes */
|
|
||||||
|
|
||||||
void StartDefaultTask(void *argument);
|
|
||||||
|
|
||||||
void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief FreeRTOS initialization
|
|
||||||
* @param None
|
|
||||||
* @retval None
|
|
||||||
*/
|
|
||||||
void MX_FREERTOS_Init(void) {
|
|
||||||
/* USER CODE BEGIN Init */
|
|
||||||
|
|
||||||
/* USER CODE END Init */
|
|
||||||
|
|
||||||
/* USER CODE BEGIN RTOS_MUTEX */
|
|
||||||
/* Create SPI mutex for CH390 access */
|
|
||||||
ch390SpiMutex = xSemaphoreCreateMutex();
|
|
||||||
configASSERT(ch390SpiMutex != NULL);
|
|
||||||
/* USER CODE END RTOS_MUTEX */
|
|
||||||
|
|
||||||
/* USER CODE BEGIN RTOS_SEMAPHORES */
|
|
||||||
/* Create CH390 interrupt notification semaphore */
|
|
||||||
ch390IntSemaphore = xSemaphoreCreateBinary();
|
|
||||||
configASSERT(ch390IntSemaphore != NULL);
|
|
||||||
/* USER CODE END RTOS_SEMAPHORES */
|
|
||||||
|
|
||||||
/* USER CODE BEGIN RTOS_TIMERS */
|
|
||||||
/* start timers, add new ones, ... */
|
|
||||||
/* USER CODE END RTOS_TIMERS */
|
|
||||||
|
|
||||||
/* USER CODE BEGIN RTOS_QUEUES */
|
|
||||||
/* add queues, ... */
|
|
||||||
/* USER CODE END RTOS_QUEUES */
|
|
||||||
|
|
||||||
/* Create the thread(s) */
|
|
||||||
/* creation of defaultTask */
|
|
||||||
defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
|
|
||||||
|
|
||||||
/* USER CODE BEGIN RTOS_THREADS */
|
|
||||||
BaseType_t task_created;
|
|
||||||
|
|
||||||
/* Create LwIP task (handles network stack + TCP server/client) */
|
|
||||||
task_created = xTaskCreate(LwIPTask, "LwIP", LWIP_TASK_STACK_SIZE, NULL,
|
|
||||||
tskIDLE_PRIORITY + 3, &lwipTaskHandle);
|
|
||||||
configASSERT(task_created == pdPASS);
|
|
||||||
|
|
||||||
/* Create TCP Server task */
|
|
||||||
task_created = xTaskCreate(tcp_server_task, "TCPServer", TCP_SERVER_TASK_STACK_SIZE, NULL,
|
|
||||||
tskIDLE_PRIORITY + 2, &tcpServerTaskHandle);
|
|
||||||
configASSERT(task_created == pdPASS);
|
|
||||||
|
|
||||||
/* Create TCP Client task */
|
|
||||||
task_created = xTaskCreate(tcp_client_task, "TCPClient", TCP_CLIENT_TASK_STACK_SIZE, NULL,
|
|
||||||
tskIDLE_PRIORITY + 2, &tcpClientTaskHandle);
|
|
||||||
configASSERT(task_created == pdPASS);
|
|
||||||
|
|
||||||
/* Create UART Server transparent transmission task */
|
|
||||||
task_created = xTaskCreate(uart_server_trans_task, "UartSrvTx", UART_TRANS_TASK_STACK_SIZE, NULL,
|
|
||||||
tskIDLE_PRIORITY + 2, &uartServerTransTaskHandle);
|
|
||||||
configASSERT(task_created == pdPASS);
|
|
||||||
|
|
||||||
/* Create UART Client transparent transmission task */
|
|
||||||
task_created = xTaskCreate(uart_client_trans_task, "UartCliTx", UART_TRANS_TASK_STACK_SIZE, NULL,
|
|
||||||
tskIDLE_PRIORITY + 2, &uartClientTransTaskHandle);
|
|
||||||
configASSERT(task_created == pdPASS);
|
|
||||||
|
|
||||||
/* Create Configuration task (AT commands via UART1) */
|
|
||||||
task_created = xTaskCreate(config_task, "Config", CONFIG_TASK_STACK_SIZE, NULL,
|
|
||||||
tskIDLE_PRIORITY + 1, &configTaskHandle);
|
|
||||||
configASSERT(task_created == pdPASS);
|
|
||||||
/* USER CODE END RTOS_THREADS */
|
|
||||||
|
|
||||||
/* USER CODE BEGIN RTOS_EVENTS */
|
|
||||||
/* add events, ... */
|
|
||||||
/* USER CODE END RTOS_EVENTS */
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* USER CODE BEGIN Header_StartDefaultTask */
|
|
||||||
/**
|
|
||||||
* @brief Function implementing the defaultTask thread.
|
|
||||||
* LED blinking for system status indication.
|
|
||||||
* @param argument: Not used
|
|
||||||
* @retval None
|
|
||||||
*/
|
|
||||||
/* USER CODE END Header_StartDefaultTask */
|
|
||||||
void StartDefaultTask(void *argument)
|
|
||||||
{
|
{
|
||||||
/* USER CODE BEGIN StartDefaultTask */
|
#if !DIAG_TASK_ISOLATION
|
||||||
(void)argument;
|
BaseType_t rc;
|
||||||
|
|
||||||
/* Infinite loop - LED heartbeat */
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
/* Toggle LED (PC13, active low) */
|
|
||||||
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
|
|
||||||
|
|
||||||
/* 500ms toggle = 1Hz blink rate */
|
|
||||||
osDelay(500);
|
|
||||||
}
|
|
||||||
/* USER CODE END StartDefaultTask */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Private application code --------------------------------------------------*/
|
|
||||||
/* USER CODE BEGIN Application */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief LwIP task - handles network stack initialization and processing
|
|
||||||
*/
|
|
||||||
void LwIPTask(void *argument)
|
|
||||||
{
|
|
||||||
(void)argument;
|
|
||||||
|
|
||||||
ip4_addr_t ipaddr, netmask, gw;
|
|
||||||
uart_config_t uart_server_cfg;
|
|
||||||
uart_config_t uart_client_cfg;
|
|
||||||
uint8_t use_dhcp = 0;
|
|
||||||
const device_config_t *cfg;
|
const device_config_t *cfg;
|
||||||
|
|
||||||
/* Wait for configuration to be loaded */
|
if (xNetworkTasksStarted != pdFALSE) {
|
||||||
vTaskDelay(pdMS_TO_TICKS(100));
|
debug_log_write("[NET] start-network-tasks already\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xNetworkTaskStopRequested != pdFALSE) {
|
||||||
|
debug_log_write("[NET] start-network-tasks stop-pending\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Get device configuration */
|
|
||||||
cfg = config_get();
|
cfg = config_get();
|
||||||
|
|
||||||
/* Initialize UART transparent transmission module */
|
debug_log_printf("[NET] start-network-tasks enter free=%lu min=%lu\r\n",
|
||||||
uart_trans_init();
|
(unsigned long)xPortGetFreeHeapSize(),
|
||||||
|
(unsigned long)xPortGetMinimumEverFreeHeapSize());
|
||||||
|
|
||||||
/* Apply UART settings from configuration */
|
if (cfg->links[CONFIG_LINK_S1].enabled != 0u) {
|
||||||
uart_server_cfg.baudrate = UART_DEFAULT_BAUDRATE;
|
rc = xTaskCreate(TcpSrvTask_S1, "TcpSrvS1", TASK_STACK_TCP_SERVER, NULL, TASK_PRIORITY_TCP_SERVER, &xTcpSrvTaskS1Handle);
|
||||||
uart_server_cfg.data_bits = UART_DEFAULT_DATA_BITS;
|
debug_log_printf("[NET] create TcpSrvS1 rc=%ld free=%lu min=%lu\r\n",
|
||||||
uart_server_cfg.stop_bits = UART_DEFAULT_STOP_BITS;
|
(long)rc,
|
||||||
uart_server_cfg.parity = UART_DEFAULT_PARITY;
|
(unsigned long)xPortGetFreeHeapSize(),
|
||||||
|
(unsigned long)xPortGetMinimumEverFreeHeapSize());
|
||||||
|
configASSERT(rc == pdPASS);
|
||||||
|
} else {
|
||||||
|
debug_log_write("[NET] skip TcpSrvS1 en=0\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
uart_client_cfg.baudrate = UART_DEFAULT_BAUDRATE;
|
if (cfg->links[CONFIG_LINK_S2].enabled != 0u) {
|
||||||
uart_client_cfg.data_bits = UART_DEFAULT_DATA_BITS;
|
rc = xTaskCreate(TcpSrvTask_S2, "TcpSrvS2", TASK_STACK_TCP_SERVER, NULL, TASK_PRIORITY_TCP_SERVER, &xTcpSrvTaskS2Handle);
|
||||||
uart_client_cfg.stop_bits = UART_DEFAULT_STOP_BITS;
|
debug_log_printf("[NET] create TcpSrvS2 rc=%ld free=%lu min=%lu\r\n",
|
||||||
uart_client_cfg.parity = UART_DEFAULT_PARITY;
|
(long)rc,
|
||||||
|
(unsigned long)xPortGetFreeHeapSize(),
|
||||||
|
(unsigned long)xPortGetMinimumEverFreeHeapSize());
|
||||||
|
configASSERT(rc == pdPASS);
|
||||||
|
} else {
|
||||||
|
debug_log_write("[NET] skip TcpSrvS2 en=0\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (cfg != NULL)
|
if (cfg->links[CONFIG_LINK_C1].enabled != 0u) {
|
||||||
|
rc = xTaskCreate(TcpCliTask_C1, "TcpCliC1", TASK_STACK_TCP_CLIENT, NULL, TASK_PRIORITY_TCP_CLIENT, &xTcpCliTaskC1Handle);
|
||||||
|
debug_log_printf("[NET] create TcpCliC1 rc=%ld free=%lu min=%lu\r\n",
|
||||||
|
(long)rc,
|
||||||
|
(unsigned long)xPortGetFreeHeapSize(),
|
||||||
|
(unsigned long)xPortGetMinimumEverFreeHeapSize());
|
||||||
|
configASSERT(rc == pdPASS);
|
||||||
|
} else {
|
||||||
|
debug_log_write("[NET] skip TcpCliC1 en=0\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cfg->links[CONFIG_LINK_C2].enabled != 0u) {
|
||||||
|
rc = xTaskCreate(TcpCliTask_C2, "TcpCliC2", TASK_STACK_TCP_CLIENT, NULL, TASK_PRIORITY_TCP_CLIENT, &xTcpCliTaskC2Handle);
|
||||||
|
debug_log_printf("[NET] create TcpCliC2 rc=%ld free=%lu min=%lu\r\n",
|
||||||
|
(long)rc,
|
||||||
|
(unsigned long)xPortGetFreeHeapSize(),
|
||||||
|
(unsigned long)xPortGetMinimumEverFreeHeapSize());
|
||||||
|
configASSERT(rc == pdPASS);
|
||||||
|
} else {
|
||||||
|
debug_log_write("[NET] skip TcpCliC2 en=0\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
xNetworkTasksStarted = pdTRUE;
|
||||||
|
|
||||||
|
debug_log_printf("[NET] start-network-tasks exit free=%lu min=%lu\r\n",
|
||||||
|
(unsigned long)xPortGetFreeHeapSize(),
|
||||||
|
(unsigned long)xPortGetMinimumEverFreeHeapSize());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_request_network_task_stop(void)
|
||||||
{
|
{
|
||||||
uart_server_cfg.baudrate = cfg->uart2_baudrate;
|
xNetworkTaskStopRequested = pdTRUE;
|
||||||
uart_server_cfg.data_bits = cfg->uart2_databits;
|
|
||||||
uart_server_cfg.stop_bits = cfg->uart2_stopbits;
|
|
||||||
uart_server_cfg.parity = cfg->uart2_parity;
|
|
||||||
|
|
||||||
uart_client_cfg.baudrate = cfg->uart3_baudrate;
|
|
||||||
uart_client_cfg.data_bits = cfg->uart3_databits;
|
|
||||||
uart_client_cfg.stop_bits = cfg->uart3_stopbits;
|
|
||||||
uart_client_cfg.parity = cfg->uart3_parity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(void)uart_trans_config(UART_CHANNEL_SERVER, &uart_server_cfg);
|
void app_clear_network_task_stop(void)
|
||||||
(void)uart_trans_config(UART_CHANNEL_CLIENT, &uart_client_cfg);
|
|
||||||
|
|
||||||
/* Wait for TCP tasks to initialize their StreamBuffers */
|
|
||||||
/* TCP Server and TCP Client tasks call tcp_server_init() / tcp_client_init() */
|
|
||||||
/* which create the StreamBuffers. We need to wait until they're ready. */
|
|
||||||
while (tcp_server_get_rx_stream() == NULL ||
|
|
||||||
tcp_server_get_tx_stream() == NULL ||
|
|
||||||
tcp_client_get_rx_stream() == NULL ||
|
|
||||||
tcp_client_get_tx_stream() == NULL)
|
|
||||||
{
|
{
|
||||||
vTaskDelay(pdMS_TO_TICKS(50));
|
xNetworkTaskStopRequested = pdFALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Connect StreamBuffers between TCP and UART modules */
|
BaseType_t app_network_task_stop_requested(void)
|
||||||
/* Server: TCP Server RX -> UART2 TX, UART2 RX -> TCP Server TX */
|
|
||||||
uart_trans_set_streams(UART_CHANNEL_SERVER,
|
|
||||||
tcp_server_get_rx_stream(), /* TCP RX -> UART TX */
|
|
||||||
tcp_server_get_tx_stream()); /* UART RX -> TCP TX */
|
|
||||||
|
|
||||||
/* Client: TCP Client RX -> UART3 TX, UART3 RX -> TCP Client TX */
|
|
||||||
uart_trans_set_streams(UART_CHANNEL_CLIENT,
|
|
||||||
tcp_client_get_rx_stream(), /* TCP RX -> UART TX */
|
|
||||||
tcp_client_get_tx_stream()); /* UART RX -> TCP TX */
|
|
||||||
|
|
||||||
/* Initialize LwIP stack (calls tcpip_init internally) */
|
|
||||||
tcpip_init(NULL, NULL);
|
|
||||||
|
|
||||||
/* Wait for tcpip thread to initialize */
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(100));
|
|
||||||
|
|
||||||
/* Set IP addresses */
|
|
||||||
if (cfg != NULL && cfg->dhcp_enable != 0)
|
|
||||||
{
|
{
|
||||||
use_dhcp = 1;
|
return xNetworkTaskStopRequested;
|
||||||
IP4_ADDR(&ipaddr, 0, 0, 0, 0);
|
|
||||||
IP4_ADDR(&netmask, 0, 0, 0, 0);
|
|
||||||
IP4_ADDR(&gw, 0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
else if (cfg != NULL)
|
|
||||||
{
|
|
||||||
IP4_ADDR(&ipaddr, cfg->ip[0], cfg->ip[1], cfg->ip[2], cfg->ip[3]);
|
|
||||||
IP4_ADDR(&netmask, cfg->mask[0], cfg->mask[1], cfg->mask[2], cfg->mask[3]);
|
|
||||||
IP4_ADDR(&gw, cfg->gw[0], cfg->gw[1], cfg->gw[2], cfg->gw[3]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Default IP if no config */
|
|
||||||
IP4_ADDR(&ipaddr, 192, 168, 1, 200);
|
|
||||||
IP4_ADDR(&netmask, 255, 255, 255, 0);
|
|
||||||
IP4_ADDR(&gw, 192, 168, 1, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize network interface */
|
BaseType_t app_network_tasks_are_stopped(void)
|
||||||
lwip_netif_init(&ipaddr, &netmask, &gw);
|
|
||||||
|
|
||||||
if (use_dhcp)
|
|
||||||
{
|
{
|
||||||
dhcp_start(&ch390_netif);
|
return (xTcpSrvTaskS1Handle == NULL &&
|
||||||
|
xTcpSrvTaskS2Handle == NULL &&
|
||||||
|
xTcpCliTaskC1Handle == NULL &&
|
||||||
|
xTcpCliTaskC2Handle == NULL) ? pdTRUE : pdFALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Main loop - handle network events */
|
void app_on_network_task_exit(TaskHandle_t task_handle)
|
||||||
for (;;)
|
|
||||||
{
|
{
|
||||||
/* Wait for CH390 interrupt or timeout */
|
taskENTER_CRITICAL();
|
||||||
if (xSemaphoreTake(ch390IntSemaphore, pdMS_TO_TICKS(10)) == pdTRUE)
|
|
||||||
{
|
if (task_handle == xTcpSrvTaskS1Handle) {
|
||||||
/* Process network input - poll all pending packets */
|
xTcpSrvTaskS1Handle = NULL;
|
||||||
ethernetif_poll();
|
} else if (task_handle == xTcpSrvTaskS2Handle) {
|
||||||
|
xTcpSrvTaskS2Handle = NULL;
|
||||||
|
} else if (task_handle == xTcpCliTaskC1Handle) {
|
||||||
|
xTcpCliTaskC1Handle = NULL;
|
||||||
|
} else if (task_handle == xTcpCliTaskC2Handle) {
|
||||||
|
xTcpCliTaskC2Handle = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check link status periodically */
|
if (xTcpSrvTaskS1Handle == NULL &&
|
||||||
ethernetif_check_link();
|
xTcpSrvTaskS2Handle == NULL &&
|
||||||
|
xTcpCliTaskC1Handle == NULL &&
|
||||||
|
xTcpCliTaskC2Handle == NULL) {
|
||||||
|
xNetworkTasksStarted = pdFALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
taskEXIT_CRITICAL();
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_request_network_restart(void)
|
||||||
|
{
|
||||||
|
xNetworkRestartRequested = pdTRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_clear_network_restart_request(void)
|
||||||
|
{
|
||||||
|
xNetworkRestartRequested = pdFALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseType_t app_network_restart_requested(void)
|
||||||
|
{
|
||||||
|
return xNetworkRestartRequested;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void StartDefaultTask(void *argument)
|
||||||
|
{
|
||||||
|
BaseType_t iwdg_ready = pdFALSE;
|
||||||
|
|
||||||
|
(void)argument;
|
||||||
|
debug_log_boot("default-task");
|
||||||
|
|
||||||
|
if (MX_IWDG_Init() == HAL_OK) {
|
||||||
|
debug_log_write("[BOOT] iwdg-started\r\n");
|
||||||
|
iwdg_ready = pdTRUE;
|
||||||
|
} else {
|
||||||
|
debug_log_write("[BOOT] iwdg-init-fail\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
|
||||||
|
if (iwdg_ready == pdTRUE) {
|
||||||
|
HAL_IWDG_Refresh(&hiwdg);
|
||||||
|
}
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(500));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void MX_FREERTOS_Init(void)
|
||||||
* @brief Get SPI mutex handle for CH390 driver
|
|
||||||
*/
|
|
||||||
SemaphoreHandle_t get_ch390_spi_mutex(void)
|
|
||||||
{
|
{
|
||||||
return ch390SpiMutex;
|
uint32_t i;
|
||||||
|
|
||||||
|
route_msg_init();
|
||||||
|
configASSERT(uart_trans_init() == 0);
|
||||||
|
debug_log_boot("uart-trans-init");
|
||||||
|
|
||||||
|
xNetSemaphore = xSemaphoreCreateBinary();
|
||||||
|
xTcpRxQueue = xQueueCreate(6, sizeof(route_msg_t *));
|
||||||
|
xConfigQueue = xQueueCreate(2, sizeof(route_msg_t *));
|
||||||
|
for (i = 0; i < CONFIG_LINK_COUNT; ++i) {
|
||||||
|
xLinkTxQueues[i] = xQueueCreate(4, sizeof(route_msg_t *));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
configASSERT(xNetSemaphore != NULL);
|
||||||
* @brief Notify LwIP task of CH390 interrupt (call from ISR)
|
configASSERT(xTcpRxQueue != NULL);
|
||||||
*/
|
configASSERT(xConfigQueue != NULL);
|
||||||
void notify_ch390_interrupt_from_isr(void)
|
for (i = 0; i < CONFIG_LINK_COUNT; ++i) {
|
||||||
{
|
configASSERT(xLinkTxQueues[i] != NULL);
|
||||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
|
||||||
|
|
||||||
if (ch390IntSemaphore != NULL)
|
|
||||||
{
|
|
||||||
xSemaphoreGiveFromISR(ch390IntSemaphore, &xHigherPriorityTaskWoken);
|
|
||||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
configASSERT(xTaskCreate(StartDefaultTask, "defaultTask", TASK_STACK_DEFAULT, NULL, TASK_PRIORITY_DEFAULT, &xDefaultTaskHandle) == pdPASS);
|
||||||
* @brief Get UART Server transparent task handle
|
|
||||||
*/
|
|
||||||
TaskHandle_t get_uart_server_task_handle(void)
|
|
||||||
{
|
|
||||||
return uartServerTransTaskHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
configASSERT(xTaskCreate(NetPollTask, "NetPoll", TASK_STACK_NET_POLL, NULL, TASK_PRIORITY_NET_POLL, &xNetPollTaskHandle) == pdPASS);
|
||||||
* @brief Get UART Client transparent task handle
|
#if !DIAG_TASK_ISOLATION
|
||||||
*/
|
configASSERT(xTaskCreate(UartRxTask, "UartRx", TASK_STACK_UART_RX, NULL, TASK_PRIORITY_UART_RX, &xUartRxTaskHandle) == pdPASS);
|
||||||
TaskHandle_t get_uart_client_task_handle(void)
|
configASSERT(xTaskCreate(ConfigTask, "Config", TASK_STACK_CONFIG, NULL, TASK_PRIORITY_CONFIG, &xConfigTaskHandle) == pdPASS);
|
||||||
{
|
#else
|
||||||
return uartClientTransTaskHandle;
|
debug_log_write("[DIAG] task-isolation enabled\r\n");
|
||||||
|
#endif
|
||||||
|
debug_log_boot("tasks-created");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* USER CODE END Application */
|
|
||||||
|
|||||||
+5
-1
@@ -65,7 +65,7 @@ void MX_GPIO_Init(void)
|
|||||||
|
|
||||||
/*Configure GPIO pin : PB0 */
|
/*Configure GPIO pin : PB0 */
|
||||||
GPIO_InitStruct.Pin = GPIO_PIN_0;
|
GPIO_InitStruct.Pin = GPIO_PIN_0;
|
||||||
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
|
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
|
||||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||||
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
||||||
|
|
||||||
@@ -76,6 +76,10 @@ void MX_GPIO_Init(void)
|
|||||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||||
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
||||||
|
|
||||||
|
/* EXTI interrupt init*/
|
||||||
|
HAL_NVIC_SetPriority(EXTI0_IRQn, 6, 0);
|
||||||
|
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* USER CODE BEGIN 2 */
|
/* USER CODE BEGIN 2 */
|
||||||
|
|||||||
+4
-4
@@ -27,7 +27,7 @@
|
|||||||
IWDG_HandleTypeDef hiwdg;
|
IWDG_HandleTypeDef hiwdg;
|
||||||
|
|
||||||
/* IWDG init function */
|
/* IWDG init function */
|
||||||
void MX_IWDG_Init(void)
|
HAL_StatusTypeDef MX_IWDG_Init(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* USER CODE BEGIN IWDG_Init 0 */
|
/* USER CODE BEGIN IWDG_Init 0 */
|
||||||
@@ -38,16 +38,16 @@ void MX_IWDG_Init(void)
|
|||||||
|
|
||||||
/* USER CODE END IWDG_Init 1 */
|
/* USER CODE END IWDG_Init 1 */
|
||||||
hiwdg.Instance = IWDG;
|
hiwdg.Instance = IWDG;
|
||||||
hiwdg.Init.Prescaler = IWDG_PRESCALER_4;
|
hiwdg.Init.Prescaler = IWDG_PRESCALER_64;
|
||||||
hiwdg.Init.Reload = 4095;
|
hiwdg.Init.Reload = 4095;
|
||||||
if (HAL_IWDG_Init(&hiwdg) != HAL_OK)
|
if (HAL_IWDG_Init(&hiwdg) != HAL_OK)
|
||||||
{
|
{
|
||||||
Error_Handler();
|
return HAL_ERROR;
|
||||||
}
|
}
|
||||||
/* USER CODE BEGIN IWDG_Init 2 */
|
/* USER CODE BEGIN IWDG_Init 2 */
|
||||||
|
|
||||||
/* USER CODE END IWDG_Init 2 */
|
/* USER CODE END IWDG_Init 2 */
|
||||||
|
return HAL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* USER CODE BEGIN 1 */
|
/* USER CODE BEGIN 1 */
|
||||||
|
|||||||
+40
-17
@@ -29,10 +29,8 @@
|
|||||||
/* USER CODE BEGIN Includes */
|
/* USER CODE BEGIN Includes */
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "CH390.h"
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "flash_param.h"
|
#include "debug_log.h"
|
||||||
#include "uart_trans.h"
|
|
||||||
/* USER CODE END Includes */
|
/* USER CODE END Includes */
|
||||||
|
|
||||||
/* Private typedef -----------------------------------------------------------*/
|
/* Private typedef -----------------------------------------------------------*/
|
||||||
@@ -70,6 +68,8 @@ void MX_FREERTOS_Init(void);
|
|||||||
/* USER CODE BEGIN PFP */
|
/* USER CODE BEGIN PFP */
|
||||||
static void CH390_HardwareReset(void);
|
static void CH390_HardwareReset(void);
|
||||||
static void LED_Init(void);
|
static void LED_Init(void);
|
||||||
|
static void ApplyConfiguredUartBaudrates(void);
|
||||||
|
void Debug_TrapWithRttHint(const char *tag);
|
||||||
/* USER CODE END PFP */
|
/* USER CODE END PFP */
|
||||||
|
|
||||||
/* Private user code ---------------------------------------------------------*/
|
/* Private user code ---------------------------------------------------------*/
|
||||||
@@ -110,6 +110,12 @@ void LED_Toggle(void)
|
|||||||
HAL_GPIO_TogglePin(LED_PORT, LED_PIN);
|
HAL_GPIO_TogglePin(LED_PORT, LED_PIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ApplyConfiguredUartBaudrates(void)
|
||||||
|
{
|
||||||
|
USART_SetConfiguredBaudrates(config_get_uart_baudrate(LINK_UART_U0),
|
||||||
|
config_get_uart_baudrate(LINK_UART_U1));
|
||||||
|
}
|
||||||
|
|
||||||
/* USER CODE END 0 */
|
/* USER CODE END 0 */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -129,25 +135,28 @@ int main(void)
|
|||||||
HAL_Init();
|
HAL_Init();
|
||||||
|
|
||||||
/* USER CODE BEGIN Init */
|
/* USER CODE BEGIN Init */
|
||||||
|
debug_log_init();
|
||||||
|
debug_log_boot("hal-init");
|
||||||
/* USER CODE END Init */
|
/* USER CODE END Init */
|
||||||
|
|
||||||
/* Configure the system clock */
|
/* Configure the system clock */
|
||||||
SystemClock_Config();
|
SystemClock_Config();
|
||||||
|
|
||||||
/* USER CODE BEGIN SysInit */
|
/* USER CODE BEGIN SysInit */
|
||||||
|
debug_log_boot("clock-config");
|
||||||
/* USER CODE END SysInit */
|
/* USER CODE END SysInit */
|
||||||
|
|
||||||
/* Initialize all configured peripherals */
|
/* 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();
|
||||||
|
config_init();
|
||||||
|
ApplyConfiguredUartBaudrates();
|
||||||
MX_USART2_UART_Init();
|
MX_USART2_UART_Init();
|
||||||
MX_USART3_UART_Init();
|
MX_USART3_UART_Init();
|
||||||
MX_SPI1_Init();
|
MX_SPI1_Init();
|
||||||
/* USER CODE BEGIN 2 */
|
/* USER CODE BEGIN 2 */
|
||||||
|
debug_log_boot("peripherals-ready");
|
||||||
|
|
||||||
/* LED 初始化 */
|
/* LED 初始化 */
|
||||||
LED_Init();
|
LED_Init();
|
||||||
@@ -155,16 +164,17 @@ int main(void)
|
|||||||
/* CH390 硬件复位 */
|
/* CH390 硬件复位 */
|
||||||
CH390_HardwareReset();
|
CH390_HardwareReset();
|
||||||
|
|
||||||
/* Initialize configuration from Flash (fallback to defaults on invalid data) */
|
debug_log_boot("config-ready");
|
||||||
config_init();
|
|
||||||
|
|
||||||
/* USER CODE END 2 */
|
/* USER CODE END 2 */
|
||||||
|
|
||||||
/* Init scheduler */
|
/* Init scheduler */
|
||||||
osKernelInitialize(); /* Call init function for freertos objects (in cmsis_os2.c) */
|
osKernelInitialize(); /* Call init function for freertos objects (in cmsis_os2.c) */
|
||||||
MX_FREERTOS_Init();
|
MX_FREERTOS_Init();
|
||||||
|
debug_log_boot("freertos-init");
|
||||||
|
|
||||||
/* Start scheduler */
|
/* Start scheduler */
|
||||||
|
debug_log_boot("scheduler-start");
|
||||||
osKernelStart();
|
osKernelStart();
|
||||||
|
|
||||||
/* We should never get here as control is now taken by the scheduler */
|
/* We should never get here as control is now taken by the scheduler */
|
||||||
@@ -225,19 +235,31 @@ void SystemClock_Config(void)
|
|||||||
/**
|
/**
|
||||||
* @brief 重定向 printf 到 UART1(调试输出)
|
* @brief 重定向 printf 到 UART1(调试输出)
|
||||||
*/
|
*/
|
||||||
#ifdef __GNUC__
|
void Debug_TrapWithRttHint(const char *tag)
|
||||||
int _write(int file, char *ptr, int len)
|
|
||||||
{
|
{
|
||||||
HAL_UART_Transmit(&huart1, (uint8_t *)ptr, len, HAL_MAX_DELAY);
|
debug_log_fault_context(tag, __FILE__, __LINE__);
|
||||||
return len;
|
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
int fputc(int ch, FILE *f)
|
void vApplicationMallocFailedHook(void)
|
||||||
|
{
|
||||||
|
debug_log_fault_context("malloc-failed", __FILE__, __LINE__);
|
||||||
|
__disable_irq();
|
||||||
|
for (;;)
|
||||||
{
|
{
|
||||||
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
|
|
||||||
return ch;
|
|
||||||
}
|
}
|
||||||
#endif
|
}
|
||||||
|
|
||||||
|
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
|
||||||
|
{
|
||||||
|
debug_log_printf("[FAULT] stack-overflow task=%s\r\n",
|
||||||
|
(pcTaskName != NULL) ? pcTaskName : "(null)");
|
||||||
|
debug_log_fault_context("stack-overflow", __FILE__, __LINE__);
|
||||||
|
(void)xTask;
|
||||||
|
__disable_irq();
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* USER CODE END 4 */
|
/* USER CODE END 4 */
|
||||||
|
|
||||||
@@ -249,6 +271,7 @@ void Error_Handler(void)
|
|||||||
{
|
{
|
||||||
/* USER CODE BEGIN Error_Handler_Debug */
|
/* USER CODE BEGIN Error_Handler_Debug */
|
||||||
/* User can add his own implementation to report the HAL error return state */
|
/* User can add his own implementation to report the HAL error return state */
|
||||||
|
debug_log_fault_context("error-handler", __FILE__, __LINE__);
|
||||||
__disable_irq();
|
__disable_irq();
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
#include <rt_sys.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#pragma import(__use_no_semihosting)
|
||||||
|
|
||||||
|
const char __stdin_name[] = ":tt";
|
||||||
|
const char __stdout_name[] = ":tt";
|
||||||
|
const char __stderr_name[] = ":tt";
|
||||||
|
|
||||||
|
#define NULL_FH_STDIN 0x8001
|
||||||
|
#define NULL_FH_STDOUT 0x8002
|
||||||
|
#define NULL_FH_STDERR 0x8003
|
||||||
|
|
||||||
|
static int rtt_is_terminal_name(const char *name)
|
||||||
|
{
|
||||||
|
return (name != NULL) && (strcmp(name, ":tt") == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
FILEHANDLE _sys_open(const char *name, int openmode)
|
||||||
|
{
|
||||||
|
if (!rtt_is_terminal_name(name)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((openmode & OPEN_W) == OPEN_W) {
|
||||||
|
return NULL_FH_STDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((openmode & OPEN_A) == OPEN_A) {
|
||||||
|
return NULL_FH_STDERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL_FH_STDIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _sys_close(FILEHANDLE fh)
|
||||||
|
{
|
||||||
|
(void)fh;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _sys_write(FILEHANDLE fh, const unsigned char *buf, unsigned len, int mode)
|
||||||
|
{
|
||||||
|
(void)mode;
|
||||||
|
|
||||||
|
if ((fh != NULL_FH_STDOUT) && (fh != NULL_FH_STDERR)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((buf == NULL) || (len == 0u)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)buf;
|
||||||
|
(void)len;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _sys_read(FILEHANDLE fh, unsigned char *buf, unsigned len, int mode)
|
||||||
|
{
|
||||||
|
(void)fh;
|
||||||
|
(void)buf;
|
||||||
|
(void)len;
|
||||||
|
(void)mode;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _sys_istty(FILEHANDLE fh)
|
||||||
|
{
|
||||||
|
return (fh == NULL_FH_STDIN) || (fh == NULL_FH_STDOUT) || (fh == NULL_FH_STDERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
int _sys_seek(FILEHANDLE fh, long pos)
|
||||||
|
{
|
||||||
|
(void)fh;
|
||||||
|
(void)pos;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _sys_ensure(FILEHANDLE fh)
|
||||||
|
{
|
||||||
|
(void)fh;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
long _sys_flen(FILEHANDLE fh)
|
||||||
|
{
|
||||||
|
(void)fh;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _sys_tmpnam(char *name, int sig, unsigned maxlen)
|
||||||
|
{
|
||||||
|
(void)name;
|
||||||
|
(void)sig;
|
||||||
|
(void)maxlen;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *_sys_command_string(char *cmd, int len)
|
||||||
|
{
|
||||||
|
(void)cmd;
|
||||||
|
(void)len;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _ttywrch(int ch)
|
||||||
|
{
|
||||||
|
(void)ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _sys_exit(int returncode)
|
||||||
|
{
|
||||||
|
(void)returncode;
|
||||||
|
while (1) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
#include "stm32f1xx_hal.h"
|
||||||
|
|
||||||
|
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
|
||||||
|
{
|
||||||
|
RCC_ClkInitTypeDef clkconfig;
|
||||||
|
uint32_t pFLatency;
|
||||||
|
uint32_t uwTimclock;
|
||||||
|
uint32_t uwPrescalerValue;
|
||||||
|
|
||||||
|
__HAL_RCC_TIM4_CLK_ENABLE();
|
||||||
|
|
||||||
|
HAL_RCC_GetClockConfig(&clkconfig, &pFLatency);
|
||||||
|
uwTimclock = HAL_RCC_GetPCLK1Freq();
|
||||||
|
if (clkconfig.APB1CLKDivider != RCC_HCLK_DIV1) {
|
||||||
|
uwTimclock *= 2u;
|
||||||
|
}
|
||||||
|
|
||||||
|
uwPrescalerValue = (uwTimclock / 1000000u) - 1u;
|
||||||
|
|
||||||
|
TIM4->PSC = uwPrescalerValue;
|
||||||
|
TIM4->ARR = 1000u - 1u;
|
||||||
|
TIM4->EGR = TIM_EGR_UG;
|
||||||
|
TIM4->DIER |= TIM_DIER_UIE;
|
||||||
|
TIM4->CR1 |= TIM_CR1_CEN;
|
||||||
|
|
||||||
|
HAL_NVIC_SetPriority(TIM4_IRQn, TickPriority, 0u);
|
||||||
|
HAL_NVIC_EnableIRQ(TIM4_IRQn);
|
||||||
|
return HAL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HAL_StatusTypeDef HAL_DeInitTick(void)
|
||||||
|
{
|
||||||
|
TIM4->CR1 &= ~TIM_CR1_CEN;
|
||||||
|
TIM4->DIER &= ~TIM_DIER_UIE;
|
||||||
|
HAL_NVIC_DisableIRQ(TIM4_IRQn);
|
||||||
|
return HAL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HAL_SuspendTick(void)
|
||||||
|
{
|
||||||
|
TIM4->DIER &= ~TIM_DIER_UIE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HAL_ResumeTick(void)
|
||||||
|
{
|
||||||
|
TIM4->DIER |= TIM_DIER_UIE;
|
||||||
|
}
|
||||||
+43
-297
@@ -1,67 +1,14 @@
|
|||||||
/* USER CODE BEGIN Header */
|
|
||||||
/**
|
|
||||||
******************************************************************************
|
|
||||||
* @file stm32f1xx_it.c
|
|
||||||
* @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 */
|
|
||||||
|
|
||||||
/* Includes ------------------------------------------------------------------*/
|
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "stm32f1xx_it.h"
|
#include "stm32f1xx_it.h"
|
||||||
|
|
||||||
#include "FreeRTOS.h"
|
#include "FreeRTOS.h"
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
/* Private includes ----------------------------------------------------------*/
|
|
||||||
/* USER CODE BEGIN Includes */
|
#include "app_runtime.h"
|
||||||
#include "uart_trans.h"
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "debug_log.h"
|
||||||
|
#include "uart_trans.h"
|
||||||
|
|
||||||
/* External functions from freertos.c */
|
|
||||||
extern void notify_ch390_interrupt_from_isr(void);
|
|
||||||
/* 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 DMA_HandleTypeDef hdma_usart1_rx;
|
extern DMA_HandleTypeDef hdma_usart1_rx;
|
||||||
extern DMA_HandleTypeDef hdma_usart1_tx;
|
extern DMA_HandleTypeDef hdma_usart1_tx;
|
||||||
@@ -72,343 +19,142 @@ 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 */
|
|
||||||
|
|
||||||
/* 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 */
|
while (1) {
|
||||||
|
|
||||||
/* USER CODE END NonMaskableInt_IRQn 0 */
|
|
||||||
/* USER CODE BEGIN NonMaskableInt_IRQn 1 */
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
/* 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 */
|
Debug_TrapWithRttHint("hardfault");
|
||||||
|
while (1) {
|
||||||
/* USER CODE END HardFault_IRQn 0 */
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
/* USER CODE BEGIN W1_HardFault_IRQn 0 */
|
|
||||||
/* USER CODE END W1_HardFault_IRQn 0 */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This function handles Memory management fault.
|
|
||||||
*/
|
|
||||||
void MemManage_Handler(void)
|
void MemManage_Handler(void)
|
||||||
{
|
{
|
||||||
/* USER CODE BEGIN MemoryManagement_IRQn 0 */
|
Debug_TrapWithRttHint("memmanage");
|
||||||
|
while (1) {
|
||||||
/* USER CODE END MemoryManagement_IRQn 0 */
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
/* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */
|
|
||||||
/* USER CODE END W1_MemoryManagement_IRQn 0 */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This function handles Prefetch fault, memory access fault.
|
|
||||||
*/
|
|
||||||
void BusFault_Handler(void)
|
void BusFault_Handler(void)
|
||||||
{
|
{
|
||||||
/* USER CODE BEGIN BusFault_IRQn 0 */
|
Debug_TrapWithRttHint("busfault");
|
||||||
|
while (1) {
|
||||||
/* USER CODE END BusFault_IRQn 0 */
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
/* USER CODE BEGIN W1_BusFault_IRQn 0 */
|
|
||||||
/* USER CODE END W1_BusFault_IRQn 0 */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This function handles Undefined instruction or illegal state.
|
|
||||||
*/
|
|
||||||
void UsageFault_Handler(void)
|
void UsageFault_Handler(void)
|
||||||
{
|
{
|
||||||
/* USER CODE BEGIN UsageFault_IRQn 0 */
|
Debug_TrapWithRttHint("usagefault");
|
||||||
|
while (1) {
|
||||||
/* USER CODE END UsageFault_IRQn 0 */
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
/* USER CODE BEGIN W1_UsageFault_IRQn 0 */
|
|
||||||
/* USER CODE END W1_UsageFault_IRQn 0 */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @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 */
|
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
|
||||||
|
|
||||||
/* USER CODE END SysTick_IRQn 0 */
|
|
||||||
HAL_IncTick();
|
|
||||||
#if (INCLUDE_xTaskGetSchedulerState == 1 )
|
|
||||||
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
|
|
||||||
{
|
|
||||||
#endif /* INCLUDE_xTaskGetSchedulerState */
|
|
||||||
xPortSysTickHandler();
|
xPortSysTickHandler();
|
||||||
#if (INCLUDE_xTaskGetSchedulerState == 1 )
|
|
||||||
}
|
}
|
||||||
#endif /* INCLUDE_xTaskGetSchedulerState */
|
|
||||||
/* 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 */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void EXTI0_IRQHandler(void)
|
||||||
* @brief This function handles SPI1 global interrupt.
|
{
|
||||||
*/
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||||
|
|
||||||
|
if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0) != RESET) {
|
||||||
|
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);
|
||||||
|
xSemaphoreGiveFromISR(xNetSemaphore, &xHigherPriorityTaskWoken);
|
||||||
|
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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 */
|
if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) != RESET) {
|
||||||
/* Handle IDLE interrupt for configuration */
|
|
||||||
if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE))
|
|
||||||
{
|
|
||||||
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
|
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
|
||||||
config_uart_idle_handler();
|
config_uart_idle_handler();
|
||||||
}
|
}
|
||||||
/* 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 */
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||||
/* Handle IDLE interrupt for Server transparent transmission */
|
if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE) != RESET) {
|
||||||
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_notify_rx_from_isr(UART_CHANNEL_U0, &xHigherPriorityTaskWoken);
|
||||||
|
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||||
}
|
}
|
||||||
/* 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 */
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||||
/* Handle IDLE interrupt for Client transparent transmission */
|
if (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_IDLE) != RESET) {
|
||||||
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_notify_rx_from_isr(UART_CHANNEL_U1, &xHigherPriorityTaskWoken);
|
||||||
|
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||||
}
|
}
|
||||||
/* 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 */
|
void TIM4_IRQHandler(void)
|
||||||
/**
|
|
||||||
* @brief This function handles EXTI0 interrupt (CH390D INT pin).
|
|
||||||
*/
|
|
||||||
void EXTI0_IRQHandler(void)
|
|
||||||
{
|
{
|
||||||
/* Clear interrupt flag */
|
if ((TIM4->SR & TIM_SR_UIF) != 0u) {
|
||||||
if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0))
|
TIM4->SR &= ~TIM_SR_UIF;
|
||||||
{
|
|
||||||
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);
|
|
||||||
|
|
||||||
/* Notify LwIP task */
|
|
||||||
notify_ch390_interrupt_from_isr();
|
|
||||||
}
|
}
|
||||||
|
HAL_IncTick();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @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_U0);
|
||||||
uart_trans_tx_cplt_handler(UART_CHANNEL_SERVER);
|
} else if (huart == &huart3) {
|
||||||
}
|
uart_trans_tx_cplt_handler(UART_CHANNEL_U1);
|
||||||
else if (huart == &huart3)
|
|
||||||
{
|
|
||||||
uart_trans_tx_cplt_handler(UART_CHANNEL_CLIENT);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief HAL UART RX Complete callback
|
|
||||||
*/
|
|
||||||
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
|
|
||||||
{
|
|
||||||
if (huart == &huart2)
|
|
||||||
{
|
|
||||||
uart_trans_rx_cplt_handler(UART_CHANNEL_SERVER);
|
|
||||||
}
|
|
||||||
else if (huart == &huart3)
|
|
||||||
{
|
|
||||||
uart_trans_rx_cplt_handler(UART_CHANNEL_CLIENT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief HAL UART RX Half Complete callback
|
|
||||||
*/
|
|
||||||
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart)
|
|
||||||
{
|
|
||||||
if (huart == &huart2)
|
|
||||||
{
|
|
||||||
uart_trans_rx_half_cplt_handler(UART_CHANNEL_SERVER);
|
|
||||||
}
|
|
||||||
else if (huart == &huart3)
|
|
||||||
{
|
|
||||||
uart_trans_rx_half_cplt_handler(UART_CHANNEL_CLIENT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* USER CODE END 1 */
|
|
||||||
|
|||||||
+11
-2
@@ -22,6 +22,9 @@
|
|||||||
|
|
||||||
/* USER CODE BEGIN 0 */
|
/* USER CODE BEGIN 0 */
|
||||||
|
|
||||||
|
static uint32_t g_usart2_baudrate = 115200u;
|
||||||
|
static uint32_t g_usart3_baudrate = 115200u;
|
||||||
|
|
||||||
/* USER CODE END 0 */
|
/* USER CODE END 0 */
|
||||||
|
|
||||||
UART_HandleTypeDef huart1;
|
UART_HandleTypeDef huart1;
|
||||||
@@ -76,7 +79,7 @@ void MX_USART2_UART_Init(void)
|
|||||||
|
|
||||||
/* USER CODE END USART2_Init 1 */
|
/* USER CODE END USART2_Init 1 */
|
||||||
huart2.Instance = USART2;
|
huart2.Instance = USART2;
|
||||||
huart2.Init.BaudRate = 115200;
|
huart2.Init.BaudRate = g_usart2_baudrate;
|
||||||
huart2.Init.WordLength = UART_WORDLENGTH_8B;
|
huart2.Init.WordLength = UART_WORDLENGTH_8B;
|
||||||
huart2.Init.StopBits = UART_STOPBITS_1;
|
huart2.Init.StopBits = UART_STOPBITS_1;
|
||||||
huart2.Init.Parity = UART_PARITY_NONE;
|
huart2.Init.Parity = UART_PARITY_NONE;
|
||||||
@@ -105,7 +108,7 @@ void MX_USART3_UART_Init(void)
|
|||||||
|
|
||||||
/* USER CODE END USART3_Init 1 */
|
/* USER CODE END USART3_Init 1 */
|
||||||
huart3.Instance = USART3;
|
huart3.Instance = USART3;
|
||||||
huart3.Init.BaudRate = 115200;
|
huart3.Init.BaudRate = g_usart3_baudrate;
|
||||||
huart3.Init.WordLength = UART_WORDLENGTH_8B;
|
huart3.Init.WordLength = UART_WORDLENGTH_8B;
|
||||||
huart3.Init.StopBits = UART_STOPBITS_1;
|
huart3.Init.StopBits = UART_STOPBITS_1;
|
||||||
huart3.Init.Parity = UART_PARITY_NONE;
|
huart3.Init.Parity = UART_PARITY_NONE;
|
||||||
@@ -396,4 +399,10 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
|
|||||||
|
|
||||||
/* USER CODE BEGIN 1 */
|
/* USER CODE BEGIN 1 */
|
||||||
|
|
||||||
|
void USART_SetConfiguredBaudrates(uint32_t usart2_baudrate, uint32_t usart3_baudrate)
|
||||||
|
{
|
||||||
|
g_usart2_baudrate = usart2_baudrate;
|
||||||
|
g_usart3_baudrate = usart3_baudrate;
|
||||||
|
}
|
||||||
|
|
||||||
/* USER CODE END 1 */
|
/* USER CODE END 1 */
|
||||||
|
|||||||
+182
-31
@@ -12,6 +12,75 @@
|
|||||||
#include "CH390.h"
|
#include "CH390.h"
|
||||||
#include "CH390_Interface.h"
|
#include "CH390_Interface.h"
|
||||||
|
|
||||||
|
#define CH390_EPCR_POLL_LIMIT 100000u
|
||||||
|
|
||||||
|
static int ch390_wait_epcr_ready(void)
|
||||||
|
{
|
||||||
|
uint32_t poll_count = CH390_EPCR_POLL_LIMIT;
|
||||||
|
|
||||||
|
while ((ch390_read_reg(CH390_EPCR) & 0x01u) != 0u)
|
||||||
|
{
|
||||||
|
if (poll_count == 0u)
|
||||||
|
{
|
||||||
|
ch390_write_reg(CH390_EPCR, 0x00u);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
--poll_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ch390_probe_rx_header(uint8_t *head)
|
||||||
|
{
|
||||||
|
if (head == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ch390_read_mem(head, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ch390_peek_packet(uint8_t *rx_status, uint16_t *rx_len)
|
||||||
|
{
|
||||||
|
uint8_t nsr;
|
||||||
|
uint8_t header[4];
|
||||||
|
uint16_t mrr;
|
||||||
|
|
||||||
|
if (rx_status != 0)
|
||||||
|
{
|
||||||
|
*rx_status = 0u;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rx_len != 0)
|
||||||
|
{
|
||||||
|
*rx_len = 0u;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsr = ch390_read_reg(CH390_NSR);
|
||||||
|
if ((nsr & NSR_RXRDY) == 0u)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
mrr = (uint16_t)ch390_read_mrrl() | ((uint16_t)ch390_read_mrrh() << 8);
|
||||||
|
ch390_read_mem(header, 4);
|
||||||
|
ch390_write_reg(CH390_MRRL, (uint8_t)(mrr & 0xffu));
|
||||||
|
ch390_write_reg(CH390_MRRH, (uint8_t)((mrr >> 8) & 0xffu));
|
||||||
|
|
||||||
|
if (rx_status != 0)
|
||||||
|
{
|
||||||
|
*rx_status = header[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rx_len != 0)
|
||||||
|
{
|
||||||
|
*rx_len = (uint16_t)header[2] | ((uint16_t)header[3] << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name ch390_receive_packet
|
* @name ch390_receive_packet
|
||||||
* @brief Receive packet
|
* @brief Receive packet
|
||||||
@@ -22,46 +91,54 @@
|
|||||||
*/
|
*/
|
||||||
uint32_t ch390_receive_packet(uint8_t *buff, uint8_t *rx_status)
|
uint32_t ch390_receive_packet(uint8_t *buff, uint8_t *rx_status)
|
||||||
{
|
{
|
||||||
uint8_t rx_ready;
|
uint8_t nsr;
|
||||||
|
uint8_t ready;
|
||||||
uint16_t rx_len = 0;
|
uint16_t rx_len = 0;
|
||||||
uint8_t ReceiveData[4];
|
uint8_t ReceiveData[4];
|
||||||
|
|
||||||
// Check packet ready or not
|
if (rx_status != 0)
|
||||||
ch390_read_reg(CH390_MRCMDX);
|
{
|
||||||
rx_ready = ch390_read_reg(CH390_MRCMDX);
|
*rx_status = 0u;
|
||||||
|
}
|
||||||
// if rxbyte != 1 or 0 reset pointer
|
|
||||||
if (rx_ready & CH390_PKT_ERR)
|
nsr = ch390_read_reg(CH390_NSR);
|
||||||
|
|
||||||
|
if ((nsr & NSR_RXRDY) == 0u)
|
||||||
{
|
{
|
||||||
// Reset RX FIFO pointer
|
|
||||||
uint8_t rcr = ch390_read_reg(CH390_RCR);
|
|
||||||
ch390_write_reg(CH390_RCR, rcr & ~RCR_RXEN); //RX disable
|
|
||||||
ch390_write_reg(CH390_MPTRCR, 0x01); //Reset RX FIFO pointer
|
|
||||||
ch390_write_reg(CH390_MRRH, 0x0c);
|
|
||||||
ch390_delay_us(1000);
|
|
||||||
ch390_write_reg(CH390_RCR, rcr | RCR_RXEN); //RX Enable
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (!(rx_ready & CH390_PKT_RDY))
|
|
||||||
|
(void)ch390_read_mrcmdx();
|
||||||
|
ready = ch390_read_mrcmdx1();
|
||||||
|
if (ready == 0u)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (ready != CH390_PKT_RDY)
|
||||||
|
{
|
||||||
|
ch390_rx_reset();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
ch390_read_mem(ReceiveData, 4);
|
ch390_read_mem(ReceiveData, 4);
|
||||||
|
|
||||||
|
if (rx_status != 0)
|
||||||
|
{
|
||||||
*rx_status = ReceiveData[1];
|
*rx_status = ReceiveData[1];
|
||||||
rx_len = ReceiveData[2] | (ReceiveData[3] << 8);
|
|
||||||
|
|
||||||
if(rx_len <= CH390_PKT_MAX)
|
|
||||||
{
|
|
||||||
ch390_read_mem(buff, rx_len);
|
|
||||||
}
|
}
|
||||||
|
rx_len = (uint16_t)ReceiveData[2] | ((uint16_t)ReceiveData[3] << 8);
|
||||||
|
|
||||||
if ((*rx_status & 0x3f) || (rx_len > CH390_PKT_MAX))
|
if ((ReceiveData[0] != CH390_PKT_RDY) ||
|
||||||
|
((ReceiveData[1] & 0x3Fu) != 0u) ||
|
||||||
|
(rx_len < (uint16_t)(14u + CH390_PKT_CRC_LEN)) ||
|
||||||
|
(rx_len > CH390_PKT_MAX))
|
||||||
{
|
{
|
||||||
|
ch390_rx_reset();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return rx_len;
|
|
||||||
|
ch390_read_mem(buff, rx_len);
|
||||||
|
return (uint32_t)(rx_len - CH390_PKT_CRC_LEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -70,17 +147,27 @@ uint32_t ch390_receive_packet(uint8_t *buff, uint8_t *rx_status)
|
|||||||
* @param buff - Data to be sent
|
* @param buff - Data to be sent
|
||||||
* @param length - Less than 3k bytes.
|
* @param length - Less than 3k bytes.
|
||||||
*/
|
*/
|
||||||
void ch390_send_packet(uint8_t *buff, uint16_t length)
|
int ch390_send_packet(uint8_t *buff, uint16_t length)
|
||||||
{
|
{
|
||||||
|
uint32_t spin_count = 0u;
|
||||||
|
|
||||||
// Write data to SRAM
|
// Write data to SRAM
|
||||||
ch390_write_mem(buff, length);
|
ch390_write_mem(buff, length);
|
||||||
// Wait until last transmit complete
|
// Wait until last transmit complete
|
||||||
while(ch390_read_reg(CH390_TCR) & TCR_TXREQ);
|
while ((ch390_read_reg(CH390_TCR) & TCR_TXREQ) != 0u)
|
||||||
|
{
|
||||||
|
++spin_count;
|
||||||
|
if (spin_count >= 4096u)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
// Set current packet length
|
// Set current packet length
|
||||||
ch390_write_reg(CH390_TXPLL, length & 0xff);
|
ch390_write_reg(CH390_TXPLL, length & 0xff);
|
||||||
ch390_write_reg(CH390_TXPLH, (length >> 8) & 0xff);
|
ch390_write_reg(CH390_TXPLH, (length >> 8) & 0xff);
|
||||||
// Issue transmit request
|
// Issue transmit request
|
||||||
ch390_send_request();
|
ch390_send_request();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -101,7 +188,7 @@ void ch390_send_request()
|
|||||||
*/
|
*/
|
||||||
void ch390_drop_packet(uint16_t len)
|
void ch390_drop_packet(uint16_t len)
|
||||||
{
|
{
|
||||||
uint16_t mdr = ch390_read_reg(CH390_MRRL) | (ch390_read_reg(CH390_MRRH) << 8);
|
uint16_t mdr = (uint16_t)ch390_read_mrrl() | ((uint16_t)ch390_read_mrrh() << 8);
|
||||||
#ifdef CH390_INTERFACE_16_BIT
|
#ifdef CH390_INTERFACE_16_BIT
|
||||||
mdr = mdr + (len + 1) / 2 * 2;
|
mdr = mdr + (len + 1) / 2 * 2;
|
||||||
#else
|
#else
|
||||||
@@ -112,6 +199,17 @@ void ch390_drop_packet(uint16_t len)
|
|||||||
ch390_write_reg(CH390_MRRH, (mdr >> 8) & 0xff);
|
ch390_write_reg(CH390_MRRH, (mdr >> 8) & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ch390_rx_reset(void)
|
||||||
|
{
|
||||||
|
uint8_t rcr = ch390_read_reg(CH390_RCR);
|
||||||
|
|
||||||
|
ch390_write_reg(CH390_RCR, (uint8_t)(rcr & (uint8_t)(~RCR_RXEN)));
|
||||||
|
ch390_write_reg(CH390_MPTRCR, MPTRCR_RST_RX);
|
||||||
|
ch390_write_reg(CH390_NSR, NSR_RXOV);
|
||||||
|
ch390_write_reg(CH390_ISR, (uint8_t)(ISR_ROS | ISR_ROO | ISR_PR));
|
||||||
|
ch390_write_reg(CH390_RCR, (uint8_t)(rcr | RCR_RXEN));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name ch390_read_phy
|
* @name ch390_read_phy
|
||||||
* @brief Read PHY register
|
* @brief Read PHY register
|
||||||
@@ -122,7 +220,10 @@ uint16_t ch390_read_phy(uint8_t reg)
|
|||||||
ch390_write_reg(CH390_EPAR, CH390_PHY | reg);
|
ch390_write_reg(CH390_EPAR, CH390_PHY | reg);
|
||||||
// Chose PHY, send read command
|
// Chose PHY, send read command
|
||||||
ch390_write_reg(CH390_EPCR, EPCR_ERPRR | EPCR_EPOS);
|
ch390_write_reg(CH390_EPCR, EPCR_ERPRR | EPCR_EPOS);
|
||||||
while(ch390_read_reg(CH390_EPCR) & 0x01);
|
if (ch390_wait_epcr_ready() != 0)
|
||||||
|
{
|
||||||
|
return 0xFFFFu;
|
||||||
|
}
|
||||||
// Clear read command
|
// Clear read command
|
||||||
ch390_write_reg(CH390_EPCR, 0x00);
|
ch390_write_reg(CH390_EPCR, 0x00);
|
||||||
return (ch390_read_reg(CH390_EPDRH) << 8) |
|
return (ch390_read_reg(CH390_EPDRH) << 8) |
|
||||||
@@ -142,7 +243,10 @@ void ch390_write_phy(uint8_t reg, uint16_t value)
|
|||||||
ch390_write_reg(CH390_EPDRH, ((value >> 8) & 0xff)); // High byte
|
ch390_write_reg(CH390_EPDRH, ((value >> 8) & 0xff)); // High byte
|
||||||
// Chose PHY, send write command
|
// Chose PHY, send write command
|
||||||
ch390_write_reg(CH390_EPCR, 0x0A);
|
ch390_write_reg(CH390_EPCR, 0x0A);
|
||||||
while(ch390_read_reg(CH390_EPCR) & 0x01);
|
if (ch390_wait_epcr_ready() != 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Clear write command
|
// Clear write command
|
||||||
ch390_write_reg(CH390_EPCR, 0x00);
|
ch390_write_reg(CH390_EPCR, 0x00);
|
||||||
}
|
}
|
||||||
@@ -160,7 +264,10 @@ void ch390_write_eeprom(uint8_t reg, uint16_t value)
|
|||||||
ch390_write_reg(CH390_EPDRH, ((value >> 8) & 0xff)); // High byte
|
ch390_write_reg(CH390_EPDRH, ((value >> 8) & 0xff)); // High byte
|
||||||
// Chose EEPROM, send write command
|
// Chose EEPROM, send write command
|
||||||
ch390_write_reg(CH390_EPCR, EPCR_ERPRW);
|
ch390_write_reg(CH390_EPCR, EPCR_ERPRW);
|
||||||
while(ch390_read_reg(CH390_EPCR) & 0x01);
|
if (ch390_wait_epcr_ready() != 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Clear write command
|
// Clear write command
|
||||||
ch390_write_reg(CH390_EPCR, 0x00);
|
ch390_write_reg(CH390_EPCR, 0x00);
|
||||||
}
|
}
|
||||||
@@ -191,20 +298,23 @@ void ch390_default_config()
|
|||||||
// CH390 has built-in MAC, this is not necessary
|
// CH390 has built-in MAC, this is not necessary
|
||||||
// uint8_t mac_addr[6] = { 0x50, 0x54, 0x7B, 0x84, 0x00, 0x73 };
|
// uint8_t mac_addr[6] = { 0x50, 0x54, 0x7B, 0x84, 0x00, 0x73 };
|
||||||
// Multicast address hash table
|
// Multicast address hash table
|
||||||
uint8_t multicase_addr[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
uint8_t multicase_addr[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
ch390_set_phy_mode(CH390_AUTO);
|
ch390_set_phy_mode(CH390_AUTO);
|
||||||
// Clear status
|
// Clear status
|
||||||
ch390_write_reg(CH390_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
|
ch390_write_reg(CH390_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
|
||||||
ch390_write_reg(CH390_ISR, 0xFF); // Clear interrupt status
|
ch390_write_reg(CH390_ISR, 0xFF); // Clear interrupt status
|
||||||
|
ch390_write_reg(CH390_INTCR, (uint8_t)(INCR_TYPE_OD | INCR_POL_L));
|
||||||
ch390_write_reg(CH390_TCR2, 0x80); // LED mode 1
|
ch390_write_reg(CH390_TCR2, 0x80); // LED mode 1
|
||||||
ch390_write_reg(CH390_TCSCR, TCSCR_ALL); // Enable check sum generation
|
ch390_write_reg(CH390_TCSCR, TCSCR_ALL); // Enable check sum generation
|
||||||
|
|
||||||
// ch390_set_mac_address(mac_addr);
|
// ch390_set_mac_address(mac_addr);
|
||||||
ch390_set_multicast(multicase_addr);
|
ch390_set_multicast(multicase_addr);
|
||||||
|
ch390_write_reg(CH390_BCASTCR, 0x00);
|
||||||
|
ch390_write_reg(CH390_MAR + 7, 0x80);
|
||||||
|
|
||||||
// Enable all interrupt and PAR
|
// Keep pointer auto-return enabled to stay aligned with the reference behavior.
|
||||||
ch390_write_reg(CH390_IMR, IMR_ALL);
|
ch390_write_reg(CH390_IMR, (uint8_t)(IMR_PAR | IMR_PRI | IMR_LNKCHGI | IMR_ROOI | IMR_ROI));
|
||||||
// Enable RX
|
// Enable RX
|
||||||
ch390_write_reg(CH390_RCR, RCR_DIS_CRC | RCR_RXEN);
|
ch390_write_reg(CH390_RCR, RCR_DIS_CRC | RCR_RXEN);
|
||||||
}
|
}
|
||||||
@@ -613,3 +723,44 @@ uint8_t ch390_get_int_status()
|
|||||||
ch390_write_reg(CH390_ISR, int_status);
|
ch390_write_reg(CH390_ISR, int_status);
|
||||||
return int_status;
|
return int_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t ch390_runtime_poll(struct ch390_runtime_status *status)
|
||||||
|
{
|
||||||
|
uint8_t int_status = ch390_read_reg(CH390_ISR);
|
||||||
|
|
||||||
|
if (status != 0)
|
||||||
|
{
|
||||||
|
status->int_status = int_status;
|
||||||
|
status->nsr = ch390_read_reg(CH390_NSR);
|
||||||
|
status->bcastcr = ch390_read_reg(CH390_BCASTCR);
|
||||||
|
status->mar7 = ch390_read_reg(CH390_MAR + 7u);
|
||||||
|
status->mrcmdx = 0u;
|
||||||
|
status->mrcmdx1 = 0u;
|
||||||
|
status->mrrl = 0u;
|
||||||
|
status->mrrh = 0u;
|
||||||
|
status->link_up = ((status->nsr & NSR_LINKST) != 0u) ? 1u : 0u;
|
||||||
|
}
|
||||||
|
|
||||||
|
ch390_write_reg(CH390_ISR, int_status);
|
||||||
|
return int_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ch390_runtime_link_up_from_status(const struct ch390_runtime_status *status)
|
||||||
|
{
|
||||||
|
if (status == 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (status->link_up != 0u) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ch390_runtime_receive_packet(uint8_t *buff, uint8_t *rx_status)
|
||||||
|
{
|
||||||
|
return ch390_receive_packet(buff, rx_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ch390_runtime_send_packet(uint8_t *buff, uint16_t length)
|
||||||
|
{
|
||||||
|
return ch390_send_packet(buff, length);
|
||||||
|
}
|
||||||
|
|||||||
+75
-1
@@ -150,6 +150,8 @@ enum ch390_phy_mode
|
|||||||
#define CH390_BCASTCR 0x53
|
#define CH390_BCASTCR 0x53
|
||||||
#define CH390_INTCKCR 0x54
|
#define CH390_INTCKCR 0x54
|
||||||
#define CH390_MPTRCR 0x55
|
#define CH390_MPTRCR 0x55
|
||||||
|
#define MPTRCR_RST_TX (1<<1)
|
||||||
|
#define MPTRCR_RST_RX (1<<0)
|
||||||
#define CH390_MLEDCR 0x57
|
#define CH390_MLEDCR 0x57
|
||||||
#define CH390_MRCMDX 0x70
|
#define CH390_MRCMDX 0x70
|
||||||
#define CH390_MRCMDX1 0x71
|
#define CH390_MRCMDX1 0x71
|
||||||
@@ -302,6 +304,8 @@ enum ch390_phy_mode
|
|||||||
#define CH390_RLENCR 0x52
|
#define CH390_RLENCR 0x52
|
||||||
#define CH390_BCASTCR 0x53
|
#define CH390_BCASTCR 0x53
|
||||||
#define CH390_MPTRCR 0x55
|
#define CH390_MPTRCR 0x55
|
||||||
|
#define MPTRCR_RST_TX (1<<1)
|
||||||
|
#define MPTRCR_RST_RX (1<<0)
|
||||||
#define CH390_MRCMDX 0xF0
|
#define CH390_MRCMDX 0xF0
|
||||||
#define CH390_MRCMDX1 0xF1
|
#define CH390_MRCMDX1 0xF1
|
||||||
#define CH390_MRCMD 0xF2
|
#define CH390_MRCMD 0xF2
|
||||||
@@ -356,9 +360,23 @@ enum ch390_phy_mode
|
|||||||
#define CH390_PKT_NONE 0x00 /* No packet received */
|
#define CH390_PKT_NONE 0x00 /* No packet received */
|
||||||
#define CH390_PKT_RDY 0x01 /* Packet ready to receive */
|
#define CH390_PKT_RDY 0x01 /* Packet ready to receive */
|
||||||
#define CH390_PKT_ERR 0xFE /* Un-stable states */
|
#define CH390_PKT_ERR 0xFE /* Un-stable states */
|
||||||
|
#define CH390_PKT_CRC_LEN 4u /* Ethernet FCS stored in RX SRAM */
|
||||||
#define CH390_PKT_MAX 1536 /* Received packet max size */
|
#define CH390_PKT_MAX 1536 /* Received packet max size */
|
||||||
#define CH390_PKT_MIN 64
|
#define CH390_PKT_MIN 64
|
||||||
|
|
||||||
|
struct ch390_runtime_status
|
||||||
|
{
|
||||||
|
uint8_t int_status;
|
||||||
|
uint8_t nsr;
|
||||||
|
uint8_t bcastcr;
|
||||||
|
uint8_t mar7;
|
||||||
|
uint8_t mrcmdx;
|
||||||
|
uint8_t mrcmdx1;
|
||||||
|
uint8_t mrrl;
|
||||||
|
uint8_t mrrh;
|
||||||
|
uint8_t link_up;
|
||||||
|
};
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Functions
|
* Functions
|
||||||
*/
|
*/
|
||||||
@@ -379,7 +397,7 @@ uint32_t ch390_receive_packet(uint8_t *buff, uint8_t *rx_status);
|
|||||||
* @param buff - Data to be sent
|
* @param buff - Data to be sent
|
||||||
* @param length - Less than 3k bytes.
|
* @param length - Less than 3k bytes.
|
||||||
*/
|
*/
|
||||||
void ch390_send_packet(uint8_t *buff, uint16_t length);
|
int ch390_send_packet(uint8_t *buff, uint16_t length);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name ch390_send_request
|
* @name ch390_send_request
|
||||||
@@ -620,4 +638,60 @@ void ch390_int_pin_config(uint8_t type, uint8_t pol);
|
|||||||
*/
|
*/
|
||||||
uint8_t ch390_get_int_status(void);
|
uint8_t ch390_get_int_status(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name ch390_runtime_poll
|
||||||
|
* @brief Poll runtime state, sample diagnostic registers, and clear ISR flags.
|
||||||
|
* @param status - Output runtime status snapshot
|
||||||
|
* @return Interrupt status snapshot
|
||||||
|
*/
|
||||||
|
uint8_t ch390_runtime_poll(struct ch390_runtime_status *status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name ch390_runtime_link_up_from_status
|
||||||
|
* @brief Get link state from a runtime status snapshot
|
||||||
|
* @param status - Runtime status snapshot
|
||||||
|
* @return 0: Link down 1: Link up
|
||||||
|
*/
|
||||||
|
int ch390_runtime_link_up_from_status(const struct ch390_runtime_status *status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name ch390_probe_rx_header
|
||||||
|
* @brief Diagnostic helper: read 4-byte RX header directly from RX SRAM.
|
||||||
|
* Caller must restore MRR if a non-destructive probe is required.
|
||||||
|
* @param head - Output buffer with at least 4 bytes.
|
||||||
|
*/
|
||||||
|
void ch390_probe_rx_header(uint8_t *head);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name ch390_peek_packet
|
||||||
|
* @brief Peek current RX header without consuming the packet.
|
||||||
|
* @param rx_status - Output abnormal status while receiving packet
|
||||||
|
* @param rx_len - Output packet length from RX header
|
||||||
|
* @return 0: no packet pending 1: header sampled
|
||||||
|
*/
|
||||||
|
int ch390_peek_packet(uint8_t *rx_status, uint16_t *rx_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name ch390_rx_reset
|
||||||
|
* @brief Repair RX datapath after overflow/corruption without full chip reset.
|
||||||
|
*/
|
||||||
|
void ch390_rx_reset(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name ch390_runtime_receive_packet
|
||||||
|
* @brief Runtime RX entry point for packet receive
|
||||||
|
* @param buff - Size equal to CH390_PKT_MAX
|
||||||
|
* @param rx_status - Output abnormal status while receiving packet
|
||||||
|
* @return Packet length
|
||||||
|
*/
|
||||||
|
uint32_t ch390_runtime_receive_packet(uint8_t *buff, uint8_t *rx_status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name ch390_runtime_send_packet
|
||||||
|
* @brief Runtime TX entry point for packet transmit
|
||||||
|
* @param buff - Data to be sent
|
||||||
|
* @param length - Less than 3k bytes.
|
||||||
|
*/
|
||||||
|
int ch390_runtime_send_packet(uint8_t *buff, uint16_t length);
|
||||||
|
|
||||||
#endif /* __CH390_H */
|
#endif /* __CH390_H */
|
||||||
|
|||||||
+104
-27
@@ -12,6 +12,7 @@
|
|||||||
* Modified for STM32F103 HAL Library with FreeRTOS support.
|
* Modified for STM32F103 HAL Library with FreeRTOS support.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
#include "stm32f1xx_hal.h"
|
#include "stm32f1xx_hal.h"
|
||||||
|
#include "main.h"
|
||||||
#include "CH390.h"
|
#include "CH390.h"
|
||||||
#include "CH390_Interface.h"
|
#include "CH390_Interface.h"
|
||||||
|
|
||||||
@@ -51,6 +52,15 @@ extern SPI_HandleTypeDef hspi1;
|
|||||||
|
|
||||||
/* Timeout for SPI operations (ms) */
|
/* Timeout for SPI operations (ms) */
|
||||||
#define SPI_TIMEOUT 100
|
#define SPI_TIMEOUT 100
|
||||||
|
#define CH390_SPI_CHUNK_SIZE 64u
|
||||||
|
|
||||||
|
#ifdef USE_FREERTOS
|
||||||
|
#define CH390_SPI_ATOMIC_ENTER() taskENTER_CRITICAL()
|
||||||
|
#define CH390_SPI_ATOMIC_EXIT() taskEXIT_CRITICAL()
|
||||||
|
#else
|
||||||
|
#define CH390_SPI_ATOMIC_ENTER() ((void)0)
|
||||||
|
#define CH390_SPI_ATOMIC_EXIT() ((void)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------
|
/*----------------------------------------------------------------------------
|
||||||
* Low-level GPIO operations
|
* Low-level GPIO operations
|
||||||
@@ -64,6 +74,7 @@ static inline void ch390_cs(uint8_t state)
|
|||||||
{
|
{
|
||||||
HAL_GPIO_WritePin(CH390_CS_PORT, CH390_CS_PIN,
|
HAL_GPIO_WritePin(CH390_CS_PORT, CH390_CS_PIN,
|
||||||
state ? GPIO_PIN_SET : GPIO_PIN_RESET);
|
state ? GPIO_PIN_SET : GPIO_PIN_RESET);
|
||||||
|
ch390_delay_us(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -88,10 +99,43 @@ static inline void ch390_rst(uint8_t state)
|
|||||||
static uint8_t ch390_spi_exchange_byte(uint8_t byte)
|
static uint8_t ch390_spi_exchange_byte(uint8_t byte)
|
||||||
{
|
{
|
||||||
uint8_t rx_data = 0;
|
uint8_t rx_data = 0;
|
||||||
HAL_SPI_TransmitReceive(&hspi1, &byte, &rx_data, 1, SPI_TIMEOUT);
|
if (HAL_SPI_TransmitReceive(&hspi1, &byte, &rx_data, 1, SPI_TIMEOUT) != HAL_OK)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return rx_data;
|
return rx_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ch390_spi_read_bytes(uint8_t *data, uint16_t length)
|
||||||
|
{
|
||||||
|
static const uint8_t dummy_tx[CH390_SPI_CHUNK_SIZE] = {0};
|
||||||
|
|
||||||
|
while (length > 0u)
|
||||||
|
{
|
||||||
|
uint16_t chunk = (length > CH390_SPI_CHUNK_SIZE) ? CH390_SPI_CHUNK_SIZE : length;
|
||||||
|
if (HAL_SPI_TransmitReceive(&hspi1, (uint8_t *)dummy_tx, data, chunk, SPI_TIMEOUT) != HAL_OK)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
data += chunk;
|
||||||
|
length = (uint16_t)(length - chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ch390_spi_apply_mode(uint32_t polarity, uint32_t phase)
|
||||||
|
{
|
||||||
|
hspi1.Init.CLKPolarity = polarity;
|
||||||
|
hspi1.Init.CLKPhase = phase;
|
||||||
|
hspi1.Init.NSS = SPI_NSS_SOFT;
|
||||||
|
|
||||||
|
if (HAL_SPI_Init(&hspi1) != HAL_OK)
|
||||||
|
{
|
||||||
|
Error_Handler();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read a dummy byte (send 0x00)
|
* @brief Read a dummy byte (send 0x00)
|
||||||
* @return Received byte
|
* @return Received byte
|
||||||
@@ -155,21 +199,8 @@ void ch390_interrupt_init(void)
|
|||||||
*/
|
*/
|
||||||
void ch390_spi_init(void)
|
void ch390_spi_init(void)
|
||||||
{
|
{
|
||||||
/* SPI1 is initialized by MX_SPI1_Init() in main.c */
|
/* Reference CH390 SPI path uses mode 3. */
|
||||||
/* We need to ensure correct SPI mode for CH390: */
|
ch390_spi_apply_mode(SPI_POLARITY_HIGH, SPI_PHASE_2EDGE);
|
||||||
/* - CPOL = High (idle clock is high) */
|
|
||||||
/* - CPHA = 2Edge (data captured on second edge) */
|
|
||||||
|
|
||||||
/* Reconfigure SPI for CH390 if needed */
|
|
||||||
hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH;
|
|
||||||
hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;
|
|
||||||
hspi1.Init.NSS = SPI_NSS_SOFT; /* We control CS manually */
|
|
||||||
|
|
||||||
if (HAL_SPI_Init(&hspi1) != HAL_OK)
|
|
||||||
{
|
|
||||||
/* Handle error */
|
|
||||||
Error_Handler();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -220,10 +251,11 @@ void ch390_delay_us(uint32_t time)
|
|||||||
*/
|
*/
|
||||||
void ch390_hardware_reset(void)
|
void ch390_hardware_reset(void)
|
||||||
{
|
{
|
||||||
|
ch390_delay_us(10000); /* Short delay before reset */
|
||||||
ch390_rst(0); /* Assert reset (low) */
|
ch390_rst(0); /* Assert reset (low) */
|
||||||
ch390_delay_us(100); /* Hold reset for 100us (min 10us required) */
|
ch390_delay_us(3000); /* Hold reset for 3ms to satisfy datasheet minimum */
|
||||||
ch390_rst(1); /* Release reset (high) */
|
ch390_rst(1); /* Release reset (high) */
|
||||||
ch390_delay_us(10000); /* Wait 10ms for CH390 to initialize */
|
ch390_delay_us(50000); /* Wait 50ms for CH390 to initialize reliably */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------
|
/*----------------------------------------------------------------------------
|
||||||
@@ -239,14 +271,50 @@ uint8_t ch390_read_reg(uint8_t reg)
|
|||||||
{
|
{
|
||||||
uint8_t value;
|
uint8_t value;
|
||||||
|
|
||||||
|
CH390_SPI_ATOMIC_ENTER();
|
||||||
ch390_cs(0); /* CS low - select */
|
ch390_cs(0); /* CS low - select */
|
||||||
ch390_spi_exchange_byte(reg | OPC_REG_R); /* Send read command */
|
ch390_spi_exchange_byte(reg | OPC_REG_R); /* Send read command */
|
||||||
value = ch390_spi_dummy_read(); /* Read register value */
|
value = ch390_spi_dummy_read(); /* Read register value */
|
||||||
ch390_cs(1); /* CS high - deselect */
|
ch390_cs(1); /* CS high - deselect */
|
||||||
|
CH390_SPI_ATOMIC_EXIT();
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint8_t ch390_read_rx_reg(uint8_t reg)
|
||||||
|
{
|
||||||
|
uint8_t value;
|
||||||
|
|
||||||
|
CH390_SPI_ATOMIC_ENTER();
|
||||||
|
ch390_cs(0);
|
||||||
|
ch390_spi_exchange_byte(reg | OPC_REG_R);
|
||||||
|
value = ch390_spi_dummy_read();
|
||||||
|
ch390_cs(1);
|
||||||
|
CH390_SPI_ATOMIC_EXIT();
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ch390_read_mrcmdx(void)
|
||||||
|
{
|
||||||
|
return ch390_read_rx_reg(CH390_MRCMDX);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ch390_read_mrcmdx1(void)
|
||||||
|
{
|
||||||
|
return ch390_read_rx_reg(CH390_MRCMDX1);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ch390_read_mrrl(void)
|
||||||
|
{
|
||||||
|
return ch390_read_rx_reg(CH390_MRRL);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ch390_read_mrrh(void)
|
||||||
|
{
|
||||||
|
return ch390_read_rx_reg(CH390_MRRH);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Write a CH390 register
|
* @brief Write a CH390 register
|
||||||
* @param reg Register address
|
* @param reg Register address
|
||||||
@@ -254,10 +322,12 @@ uint8_t ch390_read_reg(uint8_t reg)
|
|||||||
*/
|
*/
|
||||||
void ch390_write_reg(uint8_t reg, uint8_t value)
|
void ch390_write_reg(uint8_t reg, uint8_t value)
|
||||||
{
|
{
|
||||||
|
CH390_SPI_ATOMIC_ENTER();
|
||||||
ch390_cs(0); /* CS low - select */
|
ch390_cs(0); /* CS low - select */
|
||||||
ch390_spi_exchange_byte(reg | OPC_REG_W); /* Send write command */
|
ch390_spi_exchange_byte(reg | OPC_REG_W); /* Send write command */
|
||||||
ch390_spi_exchange_byte(value); /* Write register value */
|
ch390_spi_exchange_byte(value); /* Write register value */
|
||||||
ch390_cs(1); /* CS high - deselect */
|
ch390_cs(1); /* CS high - deselect */
|
||||||
|
CH390_SPI_ATOMIC_EXIT();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -267,18 +337,19 @@ void ch390_write_reg(uint8_t reg, uint8_t value)
|
|||||||
*/
|
*/
|
||||||
void ch390_read_mem(uint8_t *data, int length)
|
void ch390_read_mem(uint8_t *data, int length)
|
||||||
{
|
{
|
||||||
int i;
|
if ((data == NULL) || (length <= 0))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CH390_SPI_ATOMIC_ENTER();
|
||||||
ch390_cs(0); /* CS low - select */
|
ch390_cs(0); /* CS low - select */
|
||||||
ch390_spi_exchange_byte(OPC_MEM_READ); /* Send memory read command */
|
ch390_spi_exchange_byte(OPC_MEM_READ); /* Send memory read command */
|
||||||
|
|
||||||
/* Read data bytes */
|
(void)ch390_spi_read_bytes(data, (uint16_t)length);
|
||||||
for (i = 0; i < length; i++)
|
|
||||||
{
|
|
||||||
data[i] = ch390_spi_dummy_read();
|
|
||||||
}
|
|
||||||
|
|
||||||
ch390_cs(1); /* CS high - deselect */
|
ch390_cs(1); /* CS high - deselect */
|
||||||
|
CH390_SPI_ATOMIC_EXIT();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -310,16 +381,22 @@ void ch390_write_mem(uint8_t *data, int length)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if ((data == NULL) || (length <= 0))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CH390_SPI_ATOMIC_ENTER();
|
||||||
ch390_cs(0); /* CS low - select */
|
ch390_cs(0); /* CS low - select */
|
||||||
ch390_spi_exchange_byte(OPC_MEM_WRITE); /* Send memory write command */
|
ch390_spi_exchange_byte(OPC_MEM_WRITE); /* Send memory write command */
|
||||||
|
|
||||||
/* Write data bytes */
|
for (i = 0; i < length; ++i)
|
||||||
for (i = 0; i < length; i++)
|
|
||||||
{
|
{
|
||||||
ch390_spi_exchange_byte(data[i]);
|
(void)ch390_spi_exchange_byte(data[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
ch390_cs(1); /* CS high - deselect */
|
ch390_cs(1); /* CS high - deselect */
|
||||||
|
CH390_SPI_ATOMIC_EXIT();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -28,6 +28,34 @@ void ch390_hardware_reset(void);
|
|||||||
*/
|
*/
|
||||||
uint8_t ch390_read_reg(uint8_t reg);
|
uint8_t ch390_read_reg(uint8_t reg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name ch390_read_mrcmdx
|
||||||
|
* @brief Read MRCMDX receive-ready latch
|
||||||
|
* @return Register value
|
||||||
|
*/
|
||||||
|
uint8_t ch390_read_mrcmdx(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name ch390_read_mrcmdx1
|
||||||
|
* @brief Read MRCMDX1 receive-ready latch
|
||||||
|
* @return Register value
|
||||||
|
*/
|
||||||
|
uint8_t ch390_read_mrcmdx1(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name ch390_read_mrrl
|
||||||
|
* @brief Read MRRL receive memory pointer register
|
||||||
|
* @return Register value
|
||||||
|
*/
|
||||||
|
uint8_t ch390_read_mrrl(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name ch390_read_mrrh
|
||||||
|
* @brief Read MRRH receive memory pointer register
|
||||||
|
* @return Register value
|
||||||
|
*/
|
||||||
|
uint8_t ch390_read_mrrh(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name ch390_write_reg
|
* @name ch390_write_reg
|
||||||
* @brief Write register
|
* @brief Write register
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
|
|||||||
*/
|
*/
|
||||||
err_t sys_mutex_new(sys_mutex_t *mutex)
|
err_t sys_mutex_new(sys_mutex_t *mutex)
|
||||||
{
|
{
|
||||||
*mutex = xSemaphoreCreateMutex();
|
*mutex = xSemaphoreCreateRecursiveMutex();
|
||||||
if (*mutex == NULL)
|
if (*mutex == NULL)
|
||||||
{
|
{
|
||||||
SYS_STATS_INC(mutex.err);
|
SYS_STATS_INC(mutex.err);
|
||||||
@@ -159,7 +159,7 @@ void sys_mutex_free(sys_mutex_t *mutex)
|
|||||||
*/
|
*/
|
||||||
void sys_mutex_lock(sys_mutex_t *mutex)
|
void sys_mutex_lock(sys_mutex_t *mutex)
|
||||||
{
|
{
|
||||||
xSemaphoreTake(*mutex, portMAX_DELAY);
|
xSemaphoreTakeRecursive(*mutex, portMAX_DELAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -168,7 +168,7 @@ void sys_mutex_lock(sys_mutex_t *mutex)
|
|||||||
*/
|
*/
|
||||||
void sys_mutex_unlock(sys_mutex_t *mutex)
|
void sys_mutex_unlock(sys_mutex_t *mutex)
|
||||||
{
|
{
|
||||||
xSemaphoreGive(*mutex);
|
xSemaphoreGiveRecursive(*mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------
|
/*---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -1395,7 +1395,13 @@ lwip_netconn_do_connect(void *m)
|
|||||||
#if LWIP_TCPIP_CORE_LOCKING
|
#if LWIP_TCPIP_CORE_LOCKING
|
||||||
LWIP_ASSERT("state!", msg->conn->state == NETCONN_CONNECT);
|
LWIP_ASSERT("state!", msg->conn->state == NETCONN_CONNECT);
|
||||||
UNLOCK_TCPIP_CORE();
|
UNLOCK_TCPIP_CORE();
|
||||||
sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
|
if (sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), msg->conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
|
||||||
|
if (msg->conn->state == NETCONN_CONNECT) {
|
||||||
|
msg->conn->current_msg = NULL;
|
||||||
|
msg->conn->state = NETCONN_NONE;
|
||||||
|
msg->err = ERR_TIMEOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
LOCK_TCPIP_CORE();
|
LOCK_TCPIP_CORE();
|
||||||
LWIP_ASSERT("state!", msg->conn->state != NETCONN_CONNECT);
|
LWIP_ASSERT("state!", msg->conn->state != NETCONN_CONNECT);
|
||||||
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
||||||
|
|||||||
@@ -11,6 +11,23 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "lwip/errno.h"
|
#include "lwip/errno.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void lwip_platform_assert(const char *msg, const char *file, int line);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FreeRTOSConfig.h injects a global sys_now() macro. App sources that include
|
||||||
|
* FreeRTOS before lwIP would otherwise corrupt this declaration and the type
|
||||||
|
* aliases below. Remove the macro so lwIP uses the real port function.
|
||||||
|
*/
|
||||||
|
#ifdef sys_now
|
||||||
|
#undef sys_now
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Use standard integer types from stdint.h */
|
/* Use standard integer types from stdint.h */
|
||||||
#define LWIP_NO_STDINT_H 0
|
#define LWIP_NO_STDINT_H 0
|
||||||
|
|
||||||
@@ -68,8 +85,7 @@ typedef uintptr_t mem_ptr_t;
|
|||||||
/* Platform specific assertion handling */
|
/* Platform specific assertion handling */
|
||||||
#ifndef LWIP_PLATFORM_ASSERT
|
#ifndef LWIP_PLATFORM_ASSERT
|
||||||
#define LWIP_PLATFORM_ASSERT(x) do { \
|
#define LWIP_PLATFORM_ASSERT(x) do { \
|
||||||
printf("Assertion \"%s\" failed at line %d in %s\n", x, __LINE__, __FILE__); \
|
lwip_platform_assert((x), __FILE__, __LINE__); \
|
||||||
while(1); \
|
|
||||||
} while(0)
|
} while(0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
/**
|
/**
|
||||||
* @file lwipopts.h
|
* @file lwipopts.h
|
||||||
* @brief LwIP configuration for STM32F103 + FreeRTOS + CH390 Ethernet
|
* @brief LwIP configuration for STM32F103RCT6 + FreeRTOS + CH390 Ethernet
|
||||||
*
|
*
|
||||||
* This configuration is optimized for:
|
* Path A: NO_SYS=0, netconn API, multi-task TCP architecture.
|
||||||
* - STM32F103 with limited RAM (~20KB available)
|
* Optimized for STM32F103RCT6 (48KB SRAM) with pin-to-pin backup STM32F103RDT6 (64KB SRAM).
|
||||||
* - FreeRTOS integration (NO_SYS=0)
|
*
|
||||||
* - TCP Server + Client dual link transparent transmission
|
* Key design decisions:
|
||||||
* - CH390 Ethernet controller
|
* - netconn API for thread-safe multi-connection TCP
|
||||||
|
* - tcpip_thread handles netconn API and timers
|
||||||
|
* - core locking lets the poll task process RX packets synchronously
|
||||||
|
* - Conservative memory footprint: target ~16KB for lwIP
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef LWIP_LWIPOPTS_H
|
#ifndef LWIP_LWIPOPTS_H
|
||||||
@@ -19,10 +22,14 @@
|
|||||||
/* Use FreeRTOS - this enables the sequential API (netconn, sockets) */
|
/* Use FreeRTOS - this enables the sequential API (netconn, sockets) */
|
||||||
#define NO_SYS 0
|
#define NO_SYS 0
|
||||||
|
|
||||||
/* Enable socket API */
|
/* Enable netconn API (primary), disable socket API to save RAM */
|
||||||
#define LWIP_SOCKET 1
|
#define LWIP_SOCKET 0
|
||||||
#define LWIP_NETCONN 1
|
#define LWIP_NETCONN 1
|
||||||
#define LWIP_NETIF_API 0
|
#define LWIP_NETIF_API 1
|
||||||
|
|
||||||
|
/* Core locking: process netif RX synchronously instead of consuming TCPIP_MSG_INPKT slots. */
|
||||||
|
#define LWIP_TCPIP_CORE_LOCKING 1
|
||||||
|
#define LWIP_TCPIP_CORE_LOCKING_INPUT 1
|
||||||
|
|
||||||
/* Critical section protection */
|
/* Critical section protection */
|
||||||
#define SYS_LIGHTWEIGHT_PROT 1
|
#define SYS_LIGHTWEIGHT_PROT 1
|
||||||
@@ -35,16 +42,19 @@
|
|||||||
#define LWIP_PROVIDE_ERRNO 1
|
#define LWIP_PROVIDE_ERRNO 1
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------
|
/*-----------------------------------------------------------------------------
|
||||||
* Memory Configuration (optimized for STM32F103 with ~20KB RAM)
|
* Memory Configuration (optimized for STM32F103RCT6 with 48KB SRAM)
|
||||||
*---------------------------------------------------------------------------*/
|
*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
/* Memory alignment (ARM Cortex-M3 = 4 byte alignment) */
|
/* Memory alignment (ARM Cortex-M3 = 4 byte alignment) */
|
||||||
#define MEM_ALIGNMENT 4
|
#define MEM_ALIGNMENT 4
|
||||||
|
|
||||||
/* Heap size for dynamic memory allocation */
|
/* Heap size for dynamic memory allocation.
|
||||||
#define MEM_SIZE (4 * 1024) /* 4KB for LwIP heap */
|
* With netconn: larger heap needed for netbuf allocation and connection management.
|
||||||
|
* 8KB provides headroom for 4 concurrent TCP connections. */
|
||||||
|
#define MEM_SIZE (7 * 1024)
|
||||||
|
|
||||||
/* Number of pbufs in pool */
|
/* Number of pbufs in pool.
|
||||||
|
* RX is processed synchronously under the core lock, so a small pool is sufficient. */
|
||||||
#define PBUF_POOL_SIZE 8
|
#define PBUF_POOL_SIZE 8
|
||||||
|
|
||||||
/* Size of each pbuf in pool (must hold one Ethernet frame) */
|
/* Size of each pbuf in pool (must hold one Ethernet frame) */
|
||||||
@@ -65,19 +75,20 @@
|
|||||||
/* Number of listening TCP connections */
|
/* Number of listening TCP connections */
|
||||||
#define MEMP_NUM_TCP_PCB_LISTEN 2
|
#define MEMP_NUM_TCP_PCB_LISTEN 2
|
||||||
|
|
||||||
/* Number of simultaneously queued TCP segments */
|
/* Number of simultaneously queued TCP segments
|
||||||
#define MEMP_NUM_TCP_SEG 17
|
* Increased for 4 concurrent connections */
|
||||||
|
#define MEMP_NUM_TCP_SEG 12
|
||||||
|
|
||||||
/* Number of simultaneously active timeouts */
|
/* Number of simultaneously active timeouts */
|
||||||
#define MEMP_NUM_SYS_TIMEOUT 8
|
#define MEMP_NUM_SYS_TIMEOUT 12
|
||||||
|
|
||||||
/* Number of netbufs (for sequential API) */
|
/* Number of netbufs (for netconn API, one per pending recv) */
|
||||||
#define MEMP_NUM_NETBUF 4
|
#define MEMP_NUM_NETBUF 8
|
||||||
|
|
||||||
/* Number of netconns */
|
/* Number of netconns: 2 listeners + 2 accepted + 2 clients + 2 margin = 8 */
|
||||||
#define MEMP_NUM_NETCONN 6
|
#define MEMP_NUM_NETCONN 8
|
||||||
|
|
||||||
/* TCPIP message queue size */
|
/* TCPIP message queue size (must be >= max simultaneous API calls) */
|
||||||
#define MEMP_NUM_TCPIP_MSG_API 8
|
#define MEMP_NUM_TCPIP_MSG_API 8
|
||||||
#define MEMP_NUM_TCPIP_MSG_INPKT 8
|
#define MEMP_NUM_TCPIP_MSG_INPKT 8
|
||||||
|
|
||||||
@@ -118,15 +129,14 @@
|
|||||||
* DHCP Configuration
|
* DHCP Configuration
|
||||||
*---------------------------------------------------------------------------*/
|
*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#define LWIP_DHCP 1
|
#define LWIP_DHCP 0 /* Static IP only */
|
||||||
#define DHCP_DOES_ARP_CHECK 1
|
#define DHCP_DOES_ARP_CHECK 0
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------
|
/*-----------------------------------------------------------------------------
|
||||||
* UDP Configuration
|
* UDP Configuration
|
||||||
*---------------------------------------------------------------------------*/
|
*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#define LWIP_UDP 1
|
#define LWIP_UDP 0 /* UDP not used in this project */
|
||||||
#define UDP_TTL 255
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------
|
/*-----------------------------------------------------------------------------
|
||||||
* TCP Configuration (optimized for transparent transmission)
|
* TCP Configuration (optimized for transparent transmission)
|
||||||
@@ -138,14 +148,21 @@
|
|||||||
/* TCP Maximum Segment Size */
|
/* TCP Maximum Segment Size */
|
||||||
#define TCP_MSS 536 /* Conservative value for compatibility */
|
#define TCP_MSS 536 /* Conservative value for compatibility */
|
||||||
|
|
||||||
/* TCP sender buffer space (bytes) */
|
/* TCP sender buffer space - increased for bridge throughput */
|
||||||
#define TCP_SND_BUF (4 * TCP_MSS)
|
#define TCP_SND_BUF (2 * TCP_MSS)
|
||||||
|
|
||||||
/* TCP sender buffer space (pbufs) */
|
/* TCP sender buffer space (pbufs) */
|
||||||
#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS))
|
#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS))
|
||||||
|
|
||||||
/* TCP receive window */
|
/*
|
||||||
#define TCP_WND (4 * TCP_MSS)
|
* Temporary phase-1 exception: current TCP queue sizing trips lwIP's compile-time
|
||||||
|
* sanity guard on this memory-constrained target. Keep the bypass in project
|
||||||
|
* configuration instead of patching lwIP core source logic.
|
||||||
|
*/
|
||||||
|
#define LWIP_DISABLE_TCP_SANITY_CHECKS 1
|
||||||
|
|
||||||
|
/* TCP receive window - increased for bridge throughput */
|
||||||
|
#define TCP_WND (2 * TCP_MSS)
|
||||||
|
|
||||||
/* TCP writable space threshold */
|
/* TCP writable space threshold */
|
||||||
#define TCP_SNDLOWAT LWIP_MIN(LWIP_MAX(((TCP_SND_BUF)/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF) - 1)
|
#define TCP_SNDLOWAT LWIP_MIN(LWIP_MAX(((TCP_SND_BUF)/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF) - 1)
|
||||||
@@ -188,8 +205,8 @@
|
|||||||
* Callback Configuration
|
* Callback Configuration
|
||||||
*---------------------------------------------------------------------------*/
|
*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#define LWIP_NETIF_STATUS_CALLBACK 1
|
#define LWIP_NETIF_STATUS_CALLBACK 0
|
||||||
#define LWIP_NETIF_LINK_CALLBACK 1
|
#define LWIP_NETIF_LINK_CALLBACK 0
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------
|
/*-----------------------------------------------------------------------------
|
||||||
* Checksum Configuration
|
* Checksum Configuration
|
||||||
@@ -264,11 +281,11 @@
|
|||||||
#define DEFAULT_THREAD_PRIO (configMAX_PRIORITIES - 3)
|
#define DEFAULT_THREAD_PRIO (configMAX_PRIORITIES - 3)
|
||||||
|
|
||||||
/* Mailbox sizes */
|
/* Mailbox sizes */
|
||||||
#define TCPIP_MBOX_SIZE 8
|
#define TCPIP_MBOX_SIZE 12
|
||||||
#define DEFAULT_RAW_RECVMBOX_SIZE 4
|
#define DEFAULT_RAW_RECVMBOX_SIZE 4
|
||||||
#define DEFAULT_UDP_RECVMBOX_SIZE 4
|
#define DEFAULT_UDP_RECVMBOX_SIZE 4
|
||||||
#define DEFAULT_TCP_RECVMBOX_SIZE 8
|
#define DEFAULT_TCP_RECVMBOX_SIZE 6
|
||||||
#define DEFAULT_ACCEPTMBOX_SIZE 4
|
#define DEFAULT_ACCEPTMBOX_SIZE 6
|
||||||
|
|
||||||
/* Thread name length */
|
/* Thread name length */
|
||||||
#define LWIP_NETCONN_SEM_PER_THREAD 1
|
#define LWIP_NETCONN_SEM_PER_THREAD 1
|
||||||
|
|||||||
@@ -13,6 +13,36 @@
|
|||||||
#include "lwip/arch.h"
|
#include "lwip/arch.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FreeRTOSConfig.h currently injects lwIP-related helper macros globally.
|
||||||
|
* Those overrides break the normal lwIP sys.h/sys_arch contract by replacing
|
||||||
|
* function declarations such as sys_now() with object-like macros.
|
||||||
|
* Undefine them here so lwIP uses the port's real sys_arch implementation.
|
||||||
|
*/
|
||||||
|
#ifdef sys_now
|
||||||
|
#undef sys_now
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef sys_arch_protect
|
||||||
|
#undef sys_arch_protect
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef sys_arch_unprotect
|
||||||
|
#undef sys_arch_unprotect
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SYS_ARCH_DECL_PROTECT
|
||||||
|
#undef SYS_ARCH_DECL_PROTECT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SYS_ARCH_PROTECT
|
||||||
|
#undef SYS_ARCH_PROTECT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SYS_ARCH_UNPROTECT
|
||||||
|
#undef SYS_ARCH_UNPROTECT
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
#define _ETHERNETIF_H_
|
#define _ETHERNETIF_H_
|
||||||
|
|
||||||
#include "lwip/netif.h"
|
#include "lwip/netif.h"
|
||||||
|
#include "lwip/err.h"
|
||||||
|
#include "lwip/ip4_addr.h"
|
||||||
|
|
||||||
extern struct netif ch390_netif;
|
extern struct netif ch390_netif;
|
||||||
|
|
||||||
@@ -18,9 +20,28 @@ struct ethernetif {
|
|||||||
uint8_t rx_status;
|
uint8_t rx_status;
|
||||||
};
|
};
|
||||||
|
|
||||||
void init_lwip_netif(const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw);
|
|
||||||
err_t ethernetif_init(struct netif *netif);
|
err_t ethernetif_init(struct netif *netif);
|
||||||
void ethernetif_input(struct netif *netif);
|
void ethernetif_input(struct netif *netif);
|
||||||
|
void lwip_netif_init(const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw);
|
||||||
|
void ethernetif_diag_ch390_init(void);
|
||||||
|
void ethernetif_diag_poll_status(void);
|
||||||
|
void ethernetif_check_link(void);
|
||||||
|
void ethernetif_apply_runtime_netif_config(const ip4_addr_t *ipaddr,
|
||||||
|
const ip4_addr_t *netmask,
|
||||||
|
const ip4_addr_t *gw,
|
||||||
|
const uint8_t *mac);
|
||||||
|
void ethernetif_force_full_recovery(const ip4_addr_t *ipaddr,
|
||||||
|
const ip4_addr_t *netmask,
|
||||||
|
const ip4_addr_t *gw,
|
||||||
|
const uint8_t *mac);
|
||||||
|
void ethernetif_force_link_down(void);
|
||||||
|
uint16_t ethernetif_ch390_get_vendor_id(void);
|
||||||
|
uint16_t ethernetif_ch390_get_product_id(void);
|
||||||
|
uint8_t ethernetif_ch390_get_revision(void);
|
||||||
|
uint8_t ethernetif_ch390_health_ok(void);
|
||||||
|
uint8_t ethernetif_get_effective_mac(uint8_t *mac);
|
||||||
|
uint8_t ethernetif_link_is_up(void);
|
||||||
|
void ethernetif_poll(void);
|
||||||
|
|
||||||
void print_netif(struct netif *netif);
|
void print_netif(struct netif *netif);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,128 @@
|
|||||||
|
/**
|
||||||
|
* @file ethernet.c
|
||||||
|
* @brief Minimal lwIP Ethernet helper implementation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
|
||||||
|
#if LWIP_ARP || LWIP_ETHERNET
|
||||||
|
|
||||||
|
#include "netif/ethernet.h"
|
||||||
|
|
||||||
|
#include "lwip/def.h"
|
||||||
|
#include "lwip/ip.h"
|
||||||
|
#include "lwip/pbuf.h"
|
||||||
|
#include "lwip/stats.h"
|
||||||
|
#include "lwip/prot/ethernet.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if LWIP_IPV4 && LWIP_ARP
|
||||||
|
#include "lwip/etharp.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LWIP_IPV6
|
||||||
|
#include "lwip/ip6.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const struct eth_addr ethbroadcast = ETH_ADDR(0xff, 0xff, 0xff, 0xff, 0xff, 0xff);
|
||||||
|
const struct eth_addr ethzero = ETH_ADDR(0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
|
||||||
|
|
||||||
|
err_t ethernet_output(struct netif *netif,
|
||||||
|
struct pbuf *p,
|
||||||
|
const struct eth_addr *src,
|
||||||
|
const struct eth_addr *dst,
|
||||||
|
u16_t eth_type)
|
||||||
|
{
|
||||||
|
struct pbuf *q;
|
||||||
|
struct eth_hdr *ethhdr;
|
||||||
|
err_t err;
|
||||||
|
|
||||||
|
LWIP_ASSERT("netif != NULL", netif != NULL);
|
||||||
|
LWIP_ASSERT("p != NULL", p != NULL);
|
||||||
|
LWIP_ASSERT("src != NULL", src != NULL);
|
||||||
|
LWIP_ASSERT("dst != NULL", dst != NULL);
|
||||||
|
|
||||||
|
q = pbuf_alloc(PBUF_RAW_TX, SIZEOF_ETH_HDR, PBUF_RAM);
|
||||||
|
if (q == NULL) {
|
||||||
|
LINK_STATS_INC(link.memerr);
|
||||||
|
LINK_STATS_INC(link.drop);
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
pbuf_chain(q, p);
|
||||||
|
|
||||||
|
ethhdr = (struct eth_hdr *)q->payload;
|
||||||
|
SMEMCPY(ðhdr->dest, dst, sizeof(struct eth_addr));
|
||||||
|
SMEMCPY(ðhdr->src, src, sizeof(struct eth_addr));
|
||||||
|
ethhdr->type = lwip_htons(eth_type);
|
||||||
|
|
||||||
|
err = netif->linkoutput(netif, q);
|
||||||
|
pbuf_free(q);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err_t ethernet_input(struct pbuf *p, struct netif *netif)
|
||||||
|
{
|
||||||
|
struct eth_hdr *ethhdr;
|
||||||
|
u16_t type;
|
||||||
|
|
||||||
|
LWIP_ASSERT("p != NULL", p != NULL);
|
||||||
|
LWIP_ASSERT("netif != NULL", netif != NULL);
|
||||||
|
|
||||||
|
if (p->len < SIZEOF_ETH_HDR) {
|
||||||
|
LINK_STATS_INC(link.lenerr);
|
||||||
|
LINK_STATS_INC(link.drop);
|
||||||
|
pbuf_free(p);
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ethhdr = (struct eth_hdr *)p->payload;
|
||||||
|
type = lwip_htons(ethhdr->type);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
#if LWIP_IPV4 && LWIP_ARP
|
||||||
|
case ETHTYPE_ARP:
|
||||||
|
if (netif->flags & NETIF_FLAG_ETHARP) {
|
||||||
|
if (pbuf_remove_header(p, SIZEOF_ETH_HDR)) {
|
||||||
|
pbuf_free(p);
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
etharp_input(p, netif);
|
||||||
|
} else {
|
||||||
|
pbuf_free(p);
|
||||||
|
}
|
||||||
|
return ERR_OK;
|
||||||
|
|
||||||
|
case ETHTYPE_IP:
|
||||||
|
if (netif->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {
|
||||||
|
if (pbuf_remove_header(p, SIZEOF_ETH_HDR)) {
|
||||||
|
pbuf_free(p);
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
return ip_input(p, netif);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LWIP_IPV6
|
||||||
|
case ETHTYPE_IPV6:
|
||||||
|
if (netif->flags & NETIF_FLAG_ETHERNET) {
|
||||||
|
if (pbuf_remove_header(p, SIZEOF_ETH_HDR)) {
|
||||||
|
pbuf_free(p);
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
return ip6_input(p, netif);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pbuf_free(p);
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* LWIP_ARP || LWIP_ETHERNET */
|
||||||
+716
-108
File diff suppressed because it is too large
Load Diff
@@ -6,8 +6,11 @@
|
|||||||
#ifndef __ETHERNETIF_H__
|
#ifndef __ETHERNETIF_H__
|
||||||
#define __ETHERNETIF_H__
|
#define __ETHERNETIF_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "lwip/netif.h"
|
#include "lwip/netif.h"
|
||||||
#include "lwip/err.h"
|
#include "lwip/err.h"
|
||||||
|
#include "lwip/ip4_addr.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -44,11 +47,41 @@ void ethernetif_input(struct netif *netif);
|
|||||||
*/
|
*/
|
||||||
void lwip_netif_init(const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw);
|
void lwip_netif_init(const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize CH390 hardware without lwIP netif bring-up
|
||||||
|
*/
|
||||||
|
void ethernetif_diag_ch390_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Poll CH390 status and update diagnostic globals without lwIP RX handoff
|
||||||
|
*/
|
||||||
|
void ethernetif_diag_poll_status(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check and handle CH390 interrupt status
|
* @brief Check and handle CH390 interrupt status
|
||||||
* @note Call this from the LwIP task periodically or on interrupt
|
* @note Call this from the LwIP task periodically or on interrupt
|
||||||
*/
|
*/
|
||||||
void ethernetif_check_link(void);
|
void ethernetif_check_link(void);
|
||||||
|
void ethernetif_apply_runtime_netif_config(const ip4_addr_t *ipaddr,
|
||||||
|
const ip4_addr_t *netmask,
|
||||||
|
const ip4_addr_t *gw,
|
||||||
|
const uint8_t *mac);
|
||||||
|
void ethernetif_force_full_recovery(const ip4_addr_t *ipaddr,
|
||||||
|
const ip4_addr_t *netmask,
|
||||||
|
const ip4_addr_t *gw,
|
||||||
|
const uint8_t *mac);
|
||||||
|
void ethernetif_force_link_down(void);
|
||||||
|
uint16_t ethernetif_ch390_get_vendor_id(void);
|
||||||
|
uint16_t ethernetif_ch390_get_product_id(void);
|
||||||
|
uint8_t ethernetif_ch390_get_revision(void);
|
||||||
|
uint8_t ethernetif_ch390_health_ok(void);
|
||||||
|
uint8_t ethernetif_get_effective_mac(uint8_t *mac);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Query whether physical Ethernet link is currently up
|
||||||
|
* @return 1 if link is up, 0 otherwise
|
||||||
|
*/
|
||||||
|
uint8_t ethernetif_link_is_up(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Process all pending RX packets
|
* @brief Process all pending RX packets
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,520 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* SEGGER Microcontroller GmbH *
|
||||||
|
* The Embedded Experts *
|
||||||
|
**********************************************************************
|
||||||
|
* *
|
||||||
|
* (c) 1995 - 2021 SEGGER Microcontroller GmbH *
|
||||||
|
* *
|
||||||
|
* www.segger.com Support: support@segger.com *
|
||||||
|
* *
|
||||||
|
**********************************************************************
|
||||||
|
* *
|
||||||
|
* SEGGER RTT * Real Time Transfer for embedded targets *
|
||||||
|
* *
|
||||||
|
**********************************************************************
|
||||||
|
* *
|
||||||
|
* All rights reserved. *
|
||||||
|
* *
|
||||||
|
* SEGGER strongly recommends to not make any changes *
|
||||||
|
* to or modify the source code of this software in order to stay *
|
||||||
|
* compatible with the RTT protocol and J-Link. *
|
||||||
|
* *
|
||||||
|
* Redistribution and use in source and binary forms, with or *
|
||||||
|
* without modification, are permitted provided that the following *
|
||||||
|
* condition is met: *
|
||||||
|
* *
|
||||||
|
* o Redistributions of source code must retain the above copyright *
|
||||||
|
* notice, this condition and the following disclaimer. *
|
||||||
|
* *
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
|
||||||
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
|
||||||
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
|
||||||
|
* DAMAGE. *
|
||||||
|
* *
|
||||||
|
**********************************************************************
|
||||||
|
* *
|
||||||
|
* RTT version: 8.56a *
|
||||||
|
* *
|
||||||
|
**********************************************************************
|
||||||
|
|
||||||
|
---------------------------END-OF-HEADER------------------------------
|
||||||
|
File : SEGGER_RTT.h
|
||||||
|
Purpose : Implementation of SEGGER real-time transfer which allows
|
||||||
|
real-time communication on targets which support debugger
|
||||||
|
memory accesses while the CPU is running.
|
||||||
|
Revision: $Rev: 25842 $
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SEGGER_RTT_H
|
||||||
|
#define SEGGER_RTT_H
|
||||||
|
|
||||||
|
#include "SEGGER_RTT_Conf.h"
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* Defines, defaults
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RTT_USE_ASM
|
||||||
|
//
|
||||||
|
// Some cores support out-of-order memory accesses (reordering of memory accesses in the core)
|
||||||
|
// For such cores, we need to define a memory barrier to guarantee the order of certain accesses to the RTT ring buffers.
|
||||||
|
// Needed for:
|
||||||
|
// Cortex-M7 (ARMv7-M)
|
||||||
|
// Cortex-M23 (ARM-v8M)
|
||||||
|
// Cortex-M33 (ARM-v8M)
|
||||||
|
// Cortex-A/R (ARM-v7A/R)
|
||||||
|
//
|
||||||
|
// We do not explicitly check for "Embedded Studio" as the compiler in use determines what we support.
|
||||||
|
// You can use an external toolchain like IAR inside ES. So there is no point in checking for "Embedded Studio"
|
||||||
|
//
|
||||||
|
#if (defined __CROSSWORKS_ARM) // Rowley Crossworks
|
||||||
|
#define _CC_HAS_RTT_ASM_SUPPORT 1
|
||||||
|
#if (defined __ARM_ARCH_7M__) // Cortex-M3
|
||||||
|
#define _CORE_HAS_RTT_ASM_SUPPORT 1
|
||||||
|
#elif (defined __ARM_ARCH_7EM__) // Cortex-M4/M7
|
||||||
|
#define _CORE_HAS_RTT_ASM_SUPPORT 1
|
||||||
|
#define _CORE_NEEDS_DMB 1
|
||||||
|
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
|
||||||
|
#elif (defined __ARM_ARCH_8M_BASE__) // Cortex-M23
|
||||||
|
#define _CORE_HAS_RTT_ASM_SUPPORT 0
|
||||||
|
#define _CORE_NEEDS_DMB 1
|
||||||
|
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
|
||||||
|
#elif (defined __ARM_ARCH_8M_MAIN__) // Cortex-M33
|
||||||
|
#define _CORE_HAS_RTT_ASM_SUPPORT 1
|
||||||
|
#define _CORE_NEEDS_DMB 1
|
||||||
|
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
|
||||||
|
#elif (defined(__ARM_ARCH_8_1M_MAIN__)) // Cortex-M85
|
||||||
|
#define _CORE_HAS_RTT_ASM_SUPPORT 1
|
||||||
|
#define _CORE_NEEDS_DMB 1
|
||||||
|
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
|
||||||
|
#else
|
||||||
|
#define _CORE_HAS_RTT_ASM_SUPPORT 0
|
||||||
|
#endif
|
||||||
|
#elif (defined __ARMCC_VERSION)
|
||||||
|
//
|
||||||
|
// ARM compiler
|
||||||
|
// ARM compiler V6.0 and later is clang based.
|
||||||
|
// Our ASM part is compatible to clang.
|
||||||
|
//
|
||||||
|
#if (__ARMCC_VERSION >= 6000000)
|
||||||
|
#define _CC_HAS_RTT_ASM_SUPPORT 1
|
||||||
|
#else
|
||||||
|
#define _CC_HAS_RTT_ASM_SUPPORT 0
|
||||||
|
#endif
|
||||||
|
#if (defined __ARM_ARCH_6M__) // Cortex-M0 / M1
|
||||||
|
#define _CORE_HAS_RTT_ASM_SUPPORT 0 // No ASM support for this architecture
|
||||||
|
#elif (defined __ARM_ARCH_7M__) // Cortex-M3
|
||||||
|
#define _CORE_HAS_RTT_ASM_SUPPORT 1
|
||||||
|
#elif (defined __ARM_ARCH_7EM__) // Cortex-M4/M7
|
||||||
|
#define _CORE_HAS_RTT_ASM_SUPPORT 1
|
||||||
|
#define _CORE_NEEDS_DMB 1
|
||||||
|
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
|
||||||
|
#elif (defined __ARM_ARCH_8M_BASE__) // Cortex-M23
|
||||||
|
#define _CORE_HAS_RTT_ASM_SUPPORT 0
|
||||||
|
#define _CORE_NEEDS_DMB 1
|
||||||
|
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
|
||||||
|
#elif (defined __ARM_ARCH_8M_MAIN__) // Cortex-M33
|
||||||
|
#define _CORE_HAS_RTT_ASM_SUPPORT 1
|
||||||
|
#define _CORE_NEEDS_DMB 1
|
||||||
|
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
|
||||||
|
#elif (defined __ARM_ARCH_8_1M_MAIN__) // Cortex-M85
|
||||||
|
#define _CORE_HAS_RTT_ASM_SUPPORT 1
|
||||||
|
#define _CORE_NEEDS_DMB 1
|
||||||
|
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
|
||||||
|
#elif \
|
||||||
|
((defined __ARM_ARCH_7A__) || (defined __ARM_ARCH_7R__)) || \
|
||||||
|
((defined __ARM_ARCH_8A__) || (defined __ARM_ARCH_8R__))
|
||||||
|
//
|
||||||
|
// Cortex-A/R ARMv7-A/R & ARMv8-A/R
|
||||||
|
//
|
||||||
|
#define _CORE_NEEDS_DMB 1
|
||||||
|
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
|
||||||
|
#else
|
||||||
|
#define _CORE_HAS_RTT_ASM_SUPPORT 0
|
||||||
|
#endif
|
||||||
|
#elif ((defined __GNUC__) || (defined __clang__))
|
||||||
|
//
|
||||||
|
// GCC / Clang
|
||||||
|
//
|
||||||
|
#define _CC_HAS_RTT_ASM_SUPPORT 1
|
||||||
|
// ARM 7/9: __ARM_ARCH_5__ / __ARM_ARCH_5E__ / __ARM_ARCH_5T__ / __ARM_ARCH_5T__ / __ARM_ARCH_5TE__
|
||||||
|
#if (defined __ARM_ARCH_7M__) // Cortex-M3
|
||||||
|
#define _CORE_HAS_RTT_ASM_SUPPORT 1
|
||||||
|
#elif (defined __ARM_ARCH_7EM__) // Cortex-M4/M7
|
||||||
|
#define _CORE_HAS_RTT_ASM_SUPPORT 1
|
||||||
|
#define _CORE_NEEDS_DMB 1 // Only Cortex-M7 needs a DMB but we cannot distinguish M4 and M7 here...
|
||||||
|
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
|
||||||
|
#elif (defined __ARM_ARCH_8M_BASE__) // Cortex-M23
|
||||||
|
#define _CORE_HAS_RTT_ASM_SUPPORT 0
|
||||||
|
#define _CORE_NEEDS_DMB 1
|
||||||
|
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
|
||||||
|
#elif (defined __ARM_ARCH_8M_MAIN__) // Cortex-M33
|
||||||
|
#define _CORE_HAS_RTT_ASM_SUPPORT 1
|
||||||
|
#define _CORE_NEEDS_DMB 1
|
||||||
|
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
|
||||||
|
#elif (defined __ARM_ARCH_8_1M_MAIN__) // Cortex-M85
|
||||||
|
#define _CORE_HAS_RTT_ASM_SUPPORT 1
|
||||||
|
#define _CORE_NEEDS_DMB 1
|
||||||
|
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
|
||||||
|
#elif \
|
||||||
|
(defined __ARM_ARCH_7A__) || (defined __ARM_ARCH_7R__) || \
|
||||||
|
(defined __ARM_ARCH_8A__) || (defined __ARM_ARCH_8R__)
|
||||||
|
//
|
||||||
|
// Cortex-A/R ARMv7-A/R & ARMv8-A/R
|
||||||
|
//
|
||||||
|
#define _CORE_NEEDS_DMB 1
|
||||||
|
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
|
||||||
|
#else
|
||||||
|
#define _CORE_HAS_RTT_ASM_SUPPORT 0
|
||||||
|
#endif
|
||||||
|
#elif ((defined __IASMARM__) || (defined __ICCARM__))
|
||||||
|
//
|
||||||
|
// IAR assembler/compiler
|
||||||
|
//
|
||||||
|
#define _CC_HAS_RTT_ASM_SUPPORT 1
|
||||||
|
#if (__VER__ < 6300000)
|
||||||
|
#define VOLATILE
|
||||||
|
#else
|
||||||
|
#define VOLATILE volatile
|
||||||
|
#endif
|
||||||
|
#if (defined __ARM7M__) // Needed for old versions that do not know the define yet
|
||||||
|
#if (__CORE__ == __ARM7M__) // Cortex-M3
|
||||||
|
#define _CORE_HAS_RTT_ASM_SUPPORT 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#if (defined __ARM7EM__)
|
||||||
|
#if (__CORE__ == __ARM7EM__) // Cortex-M4/M7
|
||||||
|
#define _CORE_HAS_RTT_ASM_SUPPORT 1
|
||||||
|
#define _CORE_NEEDS_DMB 1
|
||||||
|
#define RTT__DMB() asm VOLATILE ("DMB");
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#if (defined __ARM8M_BASELINE__)
|
||||||
|
#if (__CORE__ == __ARM8M_BASELINE__) // Cortex-M23
|
||||||
|
#define _CORE_HAS_RTT_ASM_SUPPORT 0
|
||||||
|
#define _CORE_NEEDS_DMB 1
|
||||||
|
#define RTT__DMB() asm VOLATILE ("DMB");
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#if (defined __ARM8M_MAINLINE__)
|
||||||
|
#if (__CORE__ == __ARM8M_MAINLINE__) // Cortex-M33
|
||||||
|
#define _CORE_HAS_RTT_ASM_SUPPORT 1
|
||||||
|
#define _CORE_NEEDS_DMB 1
|
||||||
|
#define RTT__DMB() asm VOLATILE ("DMB");
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#if (defined __ARM8EM_MAINLINE__)
|
||||||
|
#if (__CORE__ == __ARM8EM_MAINLINE__) // Cortex-???
|
||||||
|
#define _CORE_HAS_RTT_ASM_SUPPORT 1
|
||||||
|
#define _CORE_NEEDS_DMB 1
|
||||||
|
#define RTT__DMB() asm VOLATILE ("DMB");
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#if\
|
||||||
|
((defined __ARM7A__) && (__CORE__ == __ARM7A__)) || \
|
||||||
|
((defined __ARM7R__) && (__CORE__ == __ARM7R__)) || \
|
||||||
|
((defined __ARM8A__) && (__CORE__ == __ARM8A__)) || \
|
||||||
|
((defined __ARM8R__) && (__CORE__ == __ARM8R__))
|
||||||
|
//
|
||||||
|
// Cortex-A/R ARMv7-A/R & ARMv8-A/R
|
||||||
|
//
|
||||||
|
#define _CORE_NEEDS_DMB 1
|
||||||
|
#define RTT__DMB() asm VOLATILE ("DMB");
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
//
|
||||||
|
// Other compilers
|
||||||
|
//
|
||||||
|
#define _CC_HAS_RTT_ASM_SUPPORT 0
|
||||||
|
#define _CORE_HAS_RTT_ASM_SUPPORT 0
|
||||||
|
#endif
|
||||||
|
//
|
||||||
|
// If IDE and core support the ASM version, enable ASM version by default
|
||||||
|
//
|
||||||
|
#ifndef _CORE_HAS_RTT_ASM_SUPPORT
|
||||||
|
#define _CORE_HAS_RTT_ASM_SUPPORT 0 // Default for unknown cores
|
||||||
|
#endif
|
||||||
|
#if (_CC_HAS_RTT_ASM_SUPPORT && _CORE_HAS_RTT_ASM_SUPPORT)
|
||||||
|
#define RTT_USE_ASM (1)
|
||||||
|
#else
|
||||||
|
#define RTT_USE_ASM (0)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _CORE_NEEDS_DMB
|
||||||
|
#define _CORE_NEEDS_DMB 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef RTT__DMB
|
||||||
|
#if _CORE_NEEDS_DMB
|
||||||
|
#error "Don't know how to place inline assembly for DMB"
|
||||||
|
#else
|
||||||
|
#define RTT__DMB()
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SEGGER_RTT_CPU_CACHE_LINE_SIZE
|
||||||
|
#define SEGGER_RTT_CPU_CACHE_LINE_SIZE (0) // On most target systems where RTT is used, we do not have a CPU cache, therefore 0 is a good default here
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SEGGER_RTT_UNCACHED_OFF
|
||||||
|
#if SEGGER_RTT_CPU_CACHE_LINE_SIZE
|
||||||
|
#error "SEGGER_RTT_UNCACHED_OFF must be defined when setting SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0"
|
||||||
|
#else
|
||||||
|
#define SEGGER_RTT_UNCACHED_OFF (0)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#if RTT_USE_ASM
|
||||||
|
#if SEGGER_RTT_CPU_CACHE_LINE_SIZE
|
||||||
|
#error "RTT_USE_ASM is not available if SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SEGGER_RTT_ASM // defined when SEGGER_RTT.h is included from assembly file
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* Defines, fixed
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// Determine how much we must pad the control block to make it a multiple of a cache line in size
|
||||||
|
// Assuming: U8 = 1B
|
||||||
|
// U16 = 2B
|
||||||
|
// U32 = 4B
|
||||||
|
// U8/U16/U32* = 4B
|
||||||
|
//
|
||||||
|
#if SEGGER_RTT_CPU_CACHE_LINE_SIZE // Avoid division by zero in case we do not have any cache
|
||||||
|
#define SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(NumBytes) (((NumBytes + SEGGER_RTT_CPU_CACHE_LINE_SIZE - 1) / SEGGER_RTT_CPU_CACHE_LINE_SIZE) * SEGGER_RTT_CPU_CACHE_LINE_SIZE)
|
||||||
|
#else
|
||||||
|
#define SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(NumBytes) (NumBytes)
|
||||||
|
#endif
|
||||||
|
#define SEGGER_RTT__CB_SIZE (16 + 4 + 4 + (SEGGER_RTT_MAX_NUM_UP_BUFFERS * 24) + (SEGGER_RTT_MAX_NUM_DOWN_BUFFERS * 24))
|
||||||
|
#define SEGGER_RTT__CB_PADDING (SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(SEGGER_RTT__CB_SIZE) - SEGGER_RTT__CB_SIZE)
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* Types
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// Description for a circular buffer (also called "ring buffer")
|
||||||
|
// which is used as up-buffer (T->H)
|
||||||
|
//
|
||||||
|
typedef struct {
|
||||||
|
const char* sName; // Optional name. Standard names so far are: "Terminal", "SysView", "J-Scope_t4i4"
|
||||||
|
char* pBuffer; // Pointer to start of buffer
|
||||||
|
unsigned SizeOfBuffer; // Buffer size in bytes. Note that one byte is lost, as this implementation does not fill up the buffer in order to avoid the problem of being unable to distinguish between full and empty.
|
||||||
|
unsigned WrOff; // Position of next item to be written by either target.
|
||||||
|
volatile unsigned RdOff; // Position of next item to be read by host. Must be volatile since it may be modified by host.
|
||||||
|
unsigned Flags; // Contains configuration flags. Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT operating mode.
|
||||||
|
} SEGGER_RTT_BUFFER_UP;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Description for a circular buffer (also called "ring buffer")
|
||||||
|
// which is used as down-buffer (H->T)
|
||||||
|
//
|
||||||
|
typedef struct {
|
||||||
|
const char* sName; // Optional name. Standard names so far are: "Terminal", "SysView", "J-Scope_t4i4"
|
||||||
|
char* pBuffer; // Pointer to start of buffer
|
||||||
|
unsigned SizeOfBuffer; // Buffer size in bytes. Note that one byte is lost, as this implementation does not fill up the buffer in order to avoid the problem of being unable to distinguish between full and empty.
|
||||||
|
volatile unsigned WrOff; // Position of next item to be written by host. Must be volatile since it may be modified by host.
|
||||||
|
unsigned RdOff; // Position of next item to be read by target (down-buffer).
|
||||||
|
unsigned Flags; // Contains configuration flags. Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT operating mode.
|
||||||
|
} SEGGER_RTT_BUFFER_DOWN;
|
||||||
|
|
||||||
|
//
|
||||||
|
// RTT control block which describes the number of buffers available
|
||||||
|
// as well as the configuration for each buffer
|
||||||
|
//
|
||||||
|
//
|
||||||
|
typedef struct {
|
||||||
|
char acID[16]; // Initialized to "SEGGER RTT"
|
||||||
|
int MaxNumUpBuffers; // Initialized to SEGGER_RTT_MAX_NUM_UP_BUFFERS (type. 2)
|
||||||
|
int MaxNumDownBuffers; // Initialized to SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (type. 2)
|
||||||
|
SEGGER_RTT_BUFFER_UP aUp[SEGGER_RTT_MAX_NUM_UP_BUFFERS]; // Up buffers, transferring information up from target via debug probe to host
|
||||||
|
SEGGER_RTT_BUFFER_DOWN aDown[SEGGER_RTT_MAX_NUM_DOWN_BUFFERS]; // Down buffers, transferring information down from host via debug probe to target
|
||||||
|
#if SEGGER_RTT__CB_PADDING
|
||||||
|
unsigned char aDummy[SEGGER_RTT__CB_PADDING];
|
||||||
|
#endif
|
||||||
|
} SEGGER_RTT_CB;
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* Global data
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
extern SEGGER_RTT_CB _SEGGER_RTT;
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* RTT API functions
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
int SEGGER_RTT_AllocDownBuffer (const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags);
|
||||||
|
int SEGGER_RTT_AllocUpBuffer (const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags);
|
||||||
|
int SEGGER_RTT_ConfigUpBuffer (unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags);
|
||||||
|
int SEGGER_RTT_ConfigDownBuffer (unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags);
|
||||||
|
int SEGGER_RTT_GetKey (void);
|
||||||
|
unsigned SEGGER_RTT_HasData (unsigned BufferIndex);
|
||||||
|
int SEGGER_RTT_HasKey (void);
|
||||||
|
unsigned SEGGER_RTT_HasDataUp (unsigned BufferIndex);
|
||||||
|
void SEGGER_RTT_Init (void);
|
||||||
|
unsigned SEGGER_RTT_Read (unsigned BufferIndex, void* pBuffer, unsigned BufferSize);
|
||||||
|
unsigned SEGGER_RTT_ReadNoLock (unsigned BufferIndex, void* pData, unsigned BufferSize);
|
||||||
|
int SEGGER_RTT_SetNameDownBuffer (unsigned BufferIndex, const char* sName);
|
||||||
|
int SEGGER_RTT_SetNameUpBuffer (unsigned BufferIndex, const char* sName);
|
||||||
|
int SEGGER_RTT_SetFlagsDownBuffer (unsigned BufferIndex, unsigned Flags);
|
||||||
|
int SEGGER_RTT_SetFlagsUpBuffer (unsigned BufferIndex, unsigned Flags);
|
||||||
|
int SEGGER_RTT_WaitKey (void);
|
||||||
|
unsigned SEGGER_RTT_Write (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
|
||||||
|
unsigned SEGGER_RTT_WriteNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
|
||||||
|
unsigned SEGGER_RTT_WriteSkipNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
|
||||||
|
unsigned SEGGER_RTT_ASM_WriteSkipNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
|
||||||
|
unsigned SEGGER_RTT_WriteString (unsigned BufferIndex, const char* s);
|
||||||
|
void SEGGER_RTT_WriteWithOverwriteNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
|
||||||
|
unsigned SEGGER_RTT_PutChar (unsigned BufferIndex, char c);
|
||||||
|
unsigned SEGGER_RTT_PutCharSkip (unsigned BufferIndex, char c);
|
||||||
|
unsigned SEGGER_RTT_PutCharSkipNoLock (unsigned BufferIndex, char c);
|
||||||
|
unsigned SEGGER_RTT_GetAvailWriteSpace (unsigned BufferIndex);
|
||||||
|
unsigned SEGGER_RTT_GetBytesInBuffer (unsigned BufferIndex);
|
||||||
|
//
|
||||||
|
// Function macro for performance optimization
|
||||||
|
//
|
||||||
|
#define SEGGER_RTT_HASDATA(n) (((SEGGER_RTT_BUFFER_DOWN*)((uintptr_t)&_SEGGER_RTT.aDown[n] + SEGGER_RTT_UNCACHED_OFF))->WrOff - ((SEGGER_RTT_BUFFER_DOWN*)((uintptr_t)&_SEGGER_RTT.aDown[n] + SEGGER_RTT_UNCACHED_OFF))->RdOff)
|
||||||
|
|
||||||
|
#if RTT_USE_ASM
|
||||||
|
#define SEGGER_RTT_WriteSkipNoLock SEGGER_RTT_ASM_WriteSkipNoLock
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* RTT transfer functions to send RTT data via other channels.
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
unsigned SEGGER_RTT_ReadUpBuffer (unsigned BufferIndex, void* pBuffer, unsigned BufferSize);
|
||||||
|
unsigned SEGGER_RTT_ReadUpBufferNoLock (unsigned BufferIndex, void* pData, unsigned BufferSize);
|
||||||
|
unsigned SEGGER_RTT_WriteDownBuffer (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
|
||||||
|
unsigned SEGGER_RTT_WriteDownBufferNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
|
||||||
|
|
||||||
|
#define SEGGER_RTT_HASDATA_UP(n) (((SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[n] + SEGGER_RTT_UNCACHED_OFF))->WrOff - ((SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[n] + SEGGER_RTT_UNCACHED_OFF))->RdOff) // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* RTT "Terminal" API functions
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
int SEGGER_RTT_SetTerminal (unsigned char TerminalId);
|
||||||
|
int SEGGER_RTT_TerminalOut (unsigned char TerminalId, const char* s);
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* RTT printf functions (require SEGGER_RTT_printf.c)
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...);
|
||||||
|
int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // ifndef(SEGGER_RTT_ASM)
|
||||||
|
|
||||||
|
//
|
||||||
|
// For some environments, NULL may not be defined until certain headers are included
|
||||||
|
//
|
||||||
|
#ifndef NULL
|
||||||
|
#define NULL ((void*)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* Defines
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// Operating modes. Define behavior if buffer is full (not enough space for entire message)
|
||||||
|
//
|
||||||
|
#define SEGGER_RTT_MODE_NO_BLOCK_SKIP (0) // Skip. Do not block, output nothing. (Default)
|
||||||
|
#define SEGGER_RTT_MODE_NO_BLOCK_TRIM (1) // Trim: Do not block, output as much as fits.
|
||||||
|
#define SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL (2) // Block: Wait until there is space in the buffer.
|
||||||
|
#define SEGGER_RTT_MODE_MASK (3)
|
||||||
|
|
||||||
|
//
|
||||||
|
// Control sequences, based on ANSI.
|
||||||
|
// Can be used to control color, and clear the screen
|
||||||
|
//
|
||||||
|
#define RTT_CTRL_RESET "\x1B[0m" // Reset to default colors
|
||||||
|
#define RTT_CTRL_CLEAR "\x1B[2J" // Clear screen, reposition cursor to top left
|
||||||
|
|
||||||
|
#define RTT_CTRL_TEXT_BLACK "\x1B[2;30m"
|
||||||
|
#define RTT_CTRL_TEXT_RED "\x1B[2;31m"
|
||||||
|
#define RTT_CTRL_TEXT_GREEN "\x1B[2;32m"
|
||||||
|
#define RTT_CTRL_TEXT_YELLOW "\x1B[2;33m"
|
||||||
|
#define RTT_CTRL_TEXT_BLUE "\x1B[2;34m"
|
||||||
|
#define RTT_CTRL_TEXT_MAGENTA "\x1B[2;35m"
|
||||||
|
#define RTT_CTRL_TEXT_CYAN "\x1B[2;36m"
|
||||||
|
#define RTT_CTRL_TEXT_WHITE "\x1B[2;37m"
|
||||||
|
|
||||||
|
#define RTT_CTRL_TEXT_BRIGHT_BLACK "\x1B[1;30m"
|
||||||
|
#define RTT_CTRL_TEXT_BRIGHT_RED "\x1B[1;31m"
|
||||||
|
#define RTT_CTRL_TEXT_BRIGHT_GREEN "\x1B[1;32m"
|
||||||
|
#define RTT_CTRL_TEXT_BRIGHT_YELLOW "\x1B[1;33m"
|
||||||
|
#define RTT_CTRL_TEXT_BRIGHT_BLUE "\x1B[1;34m"
|
||||||
|
#define RTT_CTRL_TEXT_BRIGHT_MAGENTA "\x1B[1;35m"
|
||||||
|
#define RTT_CTRL_TEXT_BRIGHT_CYAN "\x1B[1;36m"
|
||||||
|
#define RTT_CTRL_TEXT_BRIGHT_WHITE "\x1B[1;37m"
|
||||||
|
|
||||||
|
#define RTT_CTRL_BG_BLACK "\x1B[24;40m"
|
||||||
|
#define RTT_CTRL_BG_RED "\x1B[24;41m"
|
||||||
|
#define RTT_CTRL_BG_GREEN "\x1B[24;42m"
|
||||||
|
#define RTT_CTRL_BG_YELLOW "\x1B[24;43m"
|
||||||
|
#define RTT_CTRL_BG_BLUE "\x1B[24;44m"
|
||||||
|
#define RTT_CTRL_BG_MAGENTA "\x1B[24;45m"
|
||||||
|
#define RTT_CTRL_BG_CYAN "\x1B[24;46m"
|
||||||
|
#define RTT_CTRL_BG_WHITE "\x1B[24;47m"
|
||||||
|
|
||||||
|
#define RTT_CTRL_BG_BRIGHT_BLACK "\x1B[4;40m"
|
||||||
|
#define RTT_CTRL_BG_BRIGHT_RED "\x1B[4;41m"
|
||||||
|
#define RTT_CTRL_BG_BRIGHT_GREEN "\x1B[4;42m"
|
||||||
|
#define RTT_CTRL_BG_BRIGHT_YELLOW "\x1B[4;43m"
|
||||||
|
#define RTT_CTRL_BG_BRIGHT_BLUE "\x1B[4;44m"
|
||||||
|
#define RTT_CTRL_BG_BRIGHT_MAGENTA "\x1B[4;45m"
|
||||||
|
#define RTT_CTRL_BG_BRIGHT_CYAN "\x1B[4;46m"
|
||||||
|
#define RTT_CTRL_BG_BRIGHT_WHITE "\x1B[4;47m"
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*************************** End of file ****************************/
|
||||||
@@ -0,0 +1,440 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* SEGGER Microcontroller GmbH *
|
||||||
|
* The Embedded Experts *
|
||||||
|
**********************************************************************
|
||||||
|
* *
|
||||||
|
* (c) 1995 - 2021 SEGGER Microcontroller GmbH *
|
||||||
|
* *
|
||||||
|
* www.segger.com Support: support@segger.com *
|
||||||
|
* *
|
||||||
|
**********************************************************************
|
||||||
|
* *
|
||||||
|
* SEGGER RTT * Real Time Transfer for embedded targets *
|
||||||
|
* *
|
||||||
|
**********************************************************************
|
||||||
|
* *
|
||||||
|
* All rights reserved. *
|
||||||
|
* *
|
||||||
|
* SEGGER strongly recommends to not make any changes *
|
||||||
|
* to or modify the source code of this software in order to stay *
|
||||||
|
* compatible with the RTT protocol and J-Link. *
|
||||||
|
* *
|
||||||
|
* Redistribution and use in source and binary forms, with or *
|
||||||
|
* without modification, are permitted provided that the following *
|
||||||
|
* condition is met: *
|
||||||
|
* *
|
||||||
|
* o Redistributions of source code must retain the above copyright *
|
||||||
|
* notice, this condition and the following disclaimer. *
|
||||||
|
* *
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
|
||||||
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
|
||||||
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
|
||||||
|
* DAMAGE. *
|
||||||
|
* *
|
||||||
|
**********************************************************************
|
||||||
|
* *
|
||||||
|
* RTT version: 8.56a *
|
||||||
|
* *
|
||||||
|
**********************************************************************
|
||||||
|
|
||||||
|
---------------------------END-OF-HEADER------------------------------
|
||||||
|
File : SEGGER_RTT_Conf.h
|
||||||
|
Purpose : Implementation of SEGGER real-time transfer (RTT) which
|
||||||
|
allows real-time communication on targets which support
|
||||||
|
debugger memory accesses while the CPU is running.
|
||||||
|
Revision: $Rev: 24316 $
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SEGGER_RTT_CONF_H
|
||||||
|
#define SEGGER_RTT_CONF_H
|
||||||
|
|
||||||
|
#ifdef __IAR_SYSTEMS_ICC__
|
||||||
|
#include <intrinsics.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* Defines, configurable
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// Take in and set to correct values for Cortex-A systems with CPU cache
|
||||||
|
//
|
||||||
|
//#define SEGGER_RTT_CPU_CACHE_LINE_SIZE (32) // Largest cache line size (in bytes) in the current system
|
||||||
|
//#define SEGGER_RTT_UNCACHED_OFF (0xFB000000) // Address alias where RTT CB and buffers can be accessed uncached
|
||||||
|
//
|
||||||
|
// Most common case:
|
||||||
|
// Up-channel 0: RTT
|
||||||
|
// Up-channel 1: SystemView
|
||||||
|
//
|
||||||
|
#ifndef SEGGER_RTT_MAX_NUM_UP_BUFFERS
|
||||||
|
#define SEGGER_RTT_MAX_NUM_UP_BUFFERS (1) // Max. number of up-buffers (T->H) available on this target (Default: 3)
|
||||||
|
#endif
|
||||||
|
//
|
||||||
|
// Most common case:
|
||||||
|
// Down-channel 0: RTT
|
||||||
|
// Down-channel 1: SystemView
|
||||||
|
//
|
||||||
|
#ifndef SEGGER_RTT_MAX_NUM_DOWN_BUFFERS
|
||||||
|
#define SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (1) // Max. number of down-buffers (H->T) available on this target (Default: 3)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef BUFFER_SIZE_UP
|
||||||
|
#define BUFFER_SIZE_UP (2048) // Size of the buffer for terminal output of target, up to host (Default: 1k)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef BUFFER_SIZE_DOWN
|
||||||
|
#define BUFFER_SIZE_DOWN (16) // Size of the buffer for terminal input to target from host (Usually keyboard input) (Default: 16)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SEGGER_RTT_PRINTF_BUFFER_SIZE
|
||||||
|
#define SEGGER_RTT_PRINTF_BUFFER_SIZE (128u) // Size of buffer for RTT printf to bulk-send chars via RTT (Default: 64)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SEGGER_RTT_MODE_DEFAULT
|
||||||
|
#define SEGGER_RTT_MODE_DEFAULT SEGGER_RTT_MODE_NO_BLOCK_SKIP // Mode for pre-initialized terminal channel (buffer 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* RTT memcpy configuration
|
||||||
|
*
|
||||||
|
* memcpy() is good for large amounts of data,
|
||||||
|
* but the overhead is big for small amounts, which are usually stored via RTT.
|
||||||
|
* With SEGGER_RTT_MEMCPY_USE_BYTELOOP a simple byte loop can be used instead.
|
||||||
|
*
|
||||||
|
* SEGGER_RTT_MEMCPY() can be used to replace standard memcpy() in RTT functions.
|
||||||
|
* This is may be required with memory access restrictions,
|
||||||
|
* such as on Cortex-A devices with MMU.
|
||||||
|
*/
|
||||||
|
#ifndef SEGGER_RTT_MEMCPY_USE_BYTELOOP
|
||||||
|
#define SEGGER_RTT_MEMCPY_USE_BYTELOOP 0 // 0: Use memcpy/SEGGER_RTT_MEMCPY, 1: Use a simple byte-loop
|
||||||
|
#endif
|
||||||
|
//
|
||||||
|
// Example definition of SEGGER_RTT_MEMCPY to external memcpy with GCC toolchains and Cortex-A targets
|
||||||
|
//
|
||||||
|
//#if ((defined __SES_ARM) || (defined __CROSSWORKS_ARM) || (defined __GNUC__)) && (defined (__ARM_ARCH_7A__))
|
||||||
|
// #define SEGGER_RTT_MEMCPY(pDest, pSrc, NumBytes) SEGGER_memcpy((pDest), (pSrc), (NumBytes))
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
// Target is not allowed to perform other RTT operations while string still has not been stored completely.
|
||||||
|
// Otherwise we would probably end up with a mixed string in the buffer.
|
||||||
|
// If using RTT from within interrupts, multiple tasks or multi processors, define the SEGGER_RTT_LOCK() and SEGGER_RTT_UNLOCK() function here.
|
||||||
|
//
|
||||||
|
// SEGGER_RTT_MAX_INTERRUPT_PRIORITY can be used in the sample lock routines on Cortex-M3/4.
|
||||||
|
// Make sure to mask all interrupts which can send RTT data, i.e. generate SystemView events, or cause task switches.
|
||||||
|
// When high-priority interrupts must not be masked while sending RTT data, SEGGER_RTT_MAX_INTERRUPT_PRIORITY needs to be adjusted accordingly.
|
||||||
|
// (Higher priority = lower priority number)
|
||||||
|
// Default value for embOS: 128u
|
||||||
|
// Default configuration in FreeRTOS: configMAX_SYSCALL_INTERRUPT_PRIORITY: ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
|
||||||
|
// In case of doubt mask all interrupts: 1 << (8 - BASEPRI_PRIO_BITS) i.e. 1 << 5 when 3 bits are implemented in NVIC
|
||||||
|
// or define SEGGER_RTT_LOCK() to completely disable interrupts.
|
||||||
|
//
|
||||||
|
#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY
|
||||||
|
#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) // Interrupt priority to lock on SEGGER_RTT_LOCK on Cortex-M3/4 (Default: 0x20)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* RTT lock configuration for SEGGER Embedded Studio,
|
||||||
|
* Rowley CrossStudio and GCC
|
||||||
|
*/
|
||||||
|
#if ((defined(__SES_ARM) || defined(__SES_RISCV) || defined(__CROSSWORKS_ARM) || defined(__GNUC__) || defined(__clang__)) && !defined (__CC_ARM) && !defined(WIN32))
|
||||||
|
#if (defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_8M_BASE__))
|
||||||
|
#define SEGGER_RTT_LOCK() { \
|
||||||
|
unsigned int _SEGGER_RTT__LockState; \
|
||||||
|
__asm volatile ("mrs %0, primask \n\t" \
|
||||||
|
"movs r1, #1 \n\t" \
|
||||||
|
"msr primask, r1 \n\t" \
|
||||||
|
: "=r" (_SEGGER_RTT__LockState) \
|
||||||
|
: \
|
||||||
|
: "r1", "cc" \
|
||||||
|
);
|
||||||
|
|
||||||
|
#define SEGGER_RTT_UNLOCK() __asm volatile ("msr primask, %0 \n\t" \
|
||||||
|
: \
|
||||||
|
: "r" (_SEGGER_RTT__LockState) \
|
||||||
|
: \
|
||||||
|
); \
|
||||||
|
}
|
||||||
|
#elif (defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8_1M_MAIN__))
|
||||||
|
#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY
|
||||||
|
#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20)
|
||||||
|
#endif
|
||||||
|
#define SEGGER_RTT_LOCK() { \
|
||||||
|
unsigned int _SEGGER_RTT__LockState; \
|
||||||
|
__asm volatile ("mrs %0, basepri \n\t" \
|
||||||
|
"mov r1, %1 \n\t" \
|
||||||
|
"msr basepri, r1 \n\t" \
|
||||||
|
: "=r" (_SEGGER_RTT__LockState) \
|
||||||
|
: "i"(SEGGER_RTT_MAX_INTERRUPT_PRIORITY) \
|
||||||
|
: "r1", "cc" \
|
||||||
|
);
|
||||||
|
|
||||||
|
#define SEGGER_RTT_UNLOCK() __asm volatile ("msr basepri, %0 \n\t" \
|
||||||
|
: \
|
||||||
|
: "r" (_SEGGER_RTT__LockState) \
|
||||||
|
: \
|
||||||
|
); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif (defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__))
|
||||||
|
#define SEGGER_RTT_LOCK() { \
|
||||||
|
unsigned int _SEGGER_RTT__LockState; \
|
||||||
|
__asm volatile ("mrs r1, CPSR \n\t" \
|
||||||
|
"mov %0, r1 \n\t" \
|
||||||
|
"orr r1, r1, #0xC0 \n\t" \
|
||||||
|
"msr CPSR_c, r1 \n\t" \
|
||||||
|
: "=r" (_SEGGER_RTT__LockState) \
|
||||||
|
: \
|
||||||
|
: "r1", "cc" \
|
||||||
|
);
|
||||||
|
|
||||||
|
#define SEGGER_RTT_UNLOCK() __asm volatile ("mov r0, %0 \n\t" \
|
||||||
|
"mrs r1, CPSR \n\t" \
|
||||||
|
"bic r1, r1, #0xC0 \n\t" \
|
||||||
|
"and r0, r0, #0xC0 \n\t" \
|
||||||
|
"orr r1, r1, r0 \n\t" \
|
||||||
|
"msr CPSR_c, r1 \n\t" \
|
||||||
|
: \
|
||||||
|
: "r" (_SEGGER_RTT__LockState) \
|
||||||
|
: "r0", "r1", "cc" \
|
||||||
|
); \
|
||||||
|
}
|
||||||
|
#elif defined(__riscv) || defined(__riscv_xlen)
|
||||||
|
#define SEGGER_RTT_LOCK() { \
|
||||||
|
unsigned int _SEGGER_RTT__LockState; \
|
||||||
|
__asm volatile ("csrr %0, mstatus \n\t" \
|
||||||
|
"csrci mstatus, 8 \n\t" \
|
||||||
|
"andi %0, %0, 8 \n\t" \
|
||||||
|
: "=r" (_SEGGER_RTT__LockState) \
|
||||||
|
: \
|
||||||
|
: \
|
||||||
|
);
|
||||||
|
|
||||||
|
#define SEGGER_RTT_UNLOCK() __asm volatile ("csrr a1, mstatus \n\t" \
|
||||||
|
"or %0, %0, a1 \n\t" \
|
||||||
|
"csrs mstatus, %0 \n\t" \
|
||||||
|
: \
|
||||||
|
: "r" (_SEGGER_RTT__LockState) \
|
||||||
|
: "a1" \
|
||||||
|
); \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define SEGGER_RTT_LOCK()
|
||||||
|
#define SEGGER_RTT_UNLOCK()
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* RTT lock configuration for IAR EWARM
|
||||||
|
*/
|
||||||
|
#ifdef __ICCARM__
|
||||||
|
#if (defined (__ARM6M__) && (__CORE__ == __ARM6M__)) || \
|
||||||
|
(defined (__ARM8M_BASELINE__) && (__CORE__ == __ARM8M_BASELINE__))
|
||||||
|
#define SEGGER_RTT_LOCK() { \
|
||||||
|
unsigned int _SEGGER_RTT__LockState; \
|
||||||
|
_SEGGER_RTT__LockState = __get_PRIMASK(); \
|
||||||
|
__set_PRIMASK(1);
|
||||||
|
|
||||||
|
#define SEGGER_RTT_UNLOCK() __set_PRIMASK(_SEGGER_RTT__LockState); \
|
||||||
|
}
|
||||||
|
#elif (defined (__ARM7EM__) && (__CORE__ == __ARM7EM__)) || \
|
||||||
|
(defined (__ARM7M__) && (__CORE__ == __ARM7M__)) || \
|
||||||
|
(defined (__ARM8M_MAINLINE__) && (__CORE__ == __ARM8M_MAINLINE__)) || \
|
||||||
|
(defined (__ARM8M_MAINLINE__) && (__CORE__ == __ARM8M_MAINLINE__))
|
||||||
|
#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY
|
||||||
|
#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20)
|
||||||
|
#endif
|
||||||
|
#define SEGGER_RTT_LOCK() { \
|
||||||
|
unsigned int _SEGGER_RTT__LockState; \
|
||||||
|
_SEGGER_RTT__LockState = __get_BASEPRI(); \
|
||||||
|
__set_BASEPRI(SEGGER_RTT_MAX_INTERRUPT_PRIORITY);
|
||||||
|
|
||||||
|
#define SEGGER_RTT_UNLOCK() __set_BASEPRI(_SEGGER_RTT__LockState); \
|
||||||
|
}
|
||||||
|
#elif (defined (__ARM7A__) && (__CORE__ == __ARM7A__)) || \
|
||||||
|
(defined (__ARM7R__) && (__CORE__ == __ARM7R__))
|
||||||
|
#define SEGGER_RTT_LOCK() { \
|
||||||
|
unsigned int _SEGGER_RTT__LockState; \
|
||||||
|
__asm volatile ("mrs r1, CPSR \n\t" \
|
||||||
|
"mov %0, r1 \n\t" \
|
||||||
|
"orr r1, r1, #0xC0 \n\t" \
|
||||||
|
"msr CPSR_c, r1 \n\t" \
|
||||||
|
: "=r" (_SEGGER_RTT__LockState) \
|
||||||
|
: \
|
||||||
|
: "r1", "cc" \
|
||||||
|
);
|
||||||
|
|
||||||
|
#define SEGGER_RTT_UNLOCK() __asm volatile ("mov r0, %0 \n\t" \
|
||||||
|
"mrs r1, CPSR \n\t" \
|
||||||
|
"bic r1, r1, #0xC0 \n\t" \
|
||||||
|
"and r0, r0, #0xC0 \n\t" \
|
||||||
|
"orr r1, r1, r0 \n\t" \
|
||||||
|
"msr CPSR_c, r1 \n\t" \
|
||||||
|
: \
|
||||||
|
: "r" (_SEGGER_RTT__LockState) \
|
||||||
|
: "r0", "r1", "cc" \
|
||||||
|
); \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* RTT lock configuration for IAR RX
|
||||||
|
*/
|
||||||
|
#ifdef __ICCRX__
|
||||||
|
#define SEGGER_RTT_LOCK() { \
|
||||||
|
unsigned long _SEGGER_RTT__LockState; \
|
||||||
|
_SEGGER_RTT__LockState = __get_interrupt_state(); \
|
||||||
|
__disable_interrupt();
|
||||||
|
|
||||||
|
#define SEGGER_RTT_UNLOCK() __set_interrupt_state(_SEGGER_RTT__LockState); \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* RTT lock configuration for IAR RL78
|
||||||
|
*/
|
||||||
|
#ifdef __ICCRL78__
|
||||||
|
#define SEGGER_RTT_LOCK() { \
|
||||||
|
__istate_t _SEGGER_RTT__LockState; \
|
||||||
|
_SEGGER_RTT__LockState = __get_interrupt_state(); \
|
||||||
|
__disable_interrupt();
|
||||||
|
|
||||||
|
#define SEGGER_RTT_UNLOCK() __set_interrupt_state(_SEGGER_RTT__LockState); \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* RTT lock configuration for KEIL ARM
|
||||||
|
*/
|
||||||
|
#ifdef __CC_ARM
|
||||||
|
#if (defined __TARGET_ARCH_6S_M)
|
||||||
|
#define SEGGER_RTT_LOCK() { \
|
||||||
|
unsigned int _SEGGER_RTT__LockState; \
|
||||||
|
register unsigned char _SEGGER_RTT__PRIMASK __asm( "primask"); \
|
||||||
|
_SEGGER_RTT__LockState = _SEGGER_RTT__PRIMASK; \
|
||||||
|
_SEGGER_RTT__PRIMASK = 1u; \
|
||||||
|
__schedule_barrier();
|
||||||
|
|
||||||
|
#define SEGGER_RTT_UNLOCK() _SEGGER_RTT__PRIMASK = _SEGGER_RTT__LockState; \
|
||||||
|
__schedule_barrier(); \
|
||||||
|
}
|
||||||
|
#elif (defined(__TARGET_ARCH_7_M) || defined(__TARGET_ARCH_7E_M))
|
||||||
|
#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY
|
||||||
|
#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20)
|
||||||
|
#endif
|
||||||
|
#define SEGGER_RTT_LOCK() { \
|
||||||
|
unsigned int _SEGGER_RTT__LockState; \
|
||||||
|
register unsigned char BASEPRI __asm( "basepri"); \
|
||||||
|
_SEGGER_RTT__LockState = BASEPRI; \
|
||||||
|
BASEPRI = SEGGER_RTT_MAX_INTERRUPT_PRIORITY; \
|
||||||
|
__schedule_barrier();
|
||||||
|
|
||||||
|
#define SEGGER_RTT_UNLOCK() BASEPRI = _SEGGER_RTT__LockState; \
|
||||||
|
__schedule_barrier(); \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* RTT lock configuration for TI ARM
|
||||||
|
*/
|
||||||
|
#ifdef __TI_ARM__
|
||||||
|
#if defined (__TI_ARM_V6M0__)
|
||||||
|
#define SEGGER_RTT_LOCK() { \
|
||||||
|
unsigned int _SEGGER_RTT__LockState; \
|
||||||
|
_SEGGER_RTT__LockState = __get_PRIMASK(); \
|
||||||
|
__set_PRIMASK(1);
|
||||||
|
|
||||||
|
#define SEGGER_RTT_UNLOCK() __set_PRIMASK(_SEGGER_RTT__LockState); \
|
||||||
|
}
|
||||||
|
#elif (defined (__TI_ARM_V7M3__) || defined (__TI_ARM_V7M4__))
|
||||||
|
#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY
|
||||||
|
#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20)
|
||||||
|
#endif
|
||||||
|
#define SEGGER_RTT_LOCK() { \
|
||||||
|
unsigned int _SEGGER_RTT__LockState; \
|
||||||
|
_SEGGER_RTT__LockState = _set_interrupt_priority(SEGGER_RTT_MAX_INTERRUPT_PRIORITY);
|
||||||
|
|
||||||
|
#define SEGGER_RTT_UNLOCK() _set_interrupt_priority(_SEGGER_RTT__LockState); \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* RTT lock configuration for CCRX
|
||||||
|
*/
|
||||||
|
#ifdef __RX
|
||||||
|
#include <machine.h>
|
||||||
|
#define SEGGER_RTT_LOCK() { \
|
||||||
|
unsigned long _SEGGER_RTT__LockState; \
|
||||||
|
_SEGGER_RTT__LockState = get_psw() & 0x010000; \
|
||||||
|
clrpsw_i();
|
||||||
|
|
||||||
|
#define SEGGER_RTT_UNLOCK() set_psw(get_psw() | _SEGGER_RTT__LockState); \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* RTT lock configuration for embOS Simulation on Windows
|
||||||
|
* (Can also be used for generic RTT locking with embOS)
|
||||||
|
*/
|
||||||
|
#if defined(WIN32) || defined(SEGGER_RTT_LOCK_EMBOS)
|
||||||
|
|
||||||
|
void OS_SIM_EnterCriticalSection(void);
|
||||||
|
void OS_SIM_LeaveCriticalSection(void);
|
||||||
|
|
||||||
|
#define SEGGER_RTT_LOCK() { \
|
||||||
|
OS_SIM_EnterCriticalSection();
|
||||||
|
|
||||||
|
#define SEGGER_RTT_UNLOCK() OS_SIM_LeaveCriticalSection(); \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* RTT lock configuration fallback
|
||||||
|
*/
|
||||||
|
#ifndef SEGGER_RTT_LOCK
|
||||||
|
#define SEGGER_RTT_LOCK() // Lock RTT (nestable) (i.e. disable interrupts)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SEGGER_RTT_UNLOCK
|
||||||
|
#define SEGGER_RTT_UNLOCK() // Unlock RTT (nestable) (i.e. enable previous interrupt lock state)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
*
|
||||||
|
* If SEGGER_RTT_SECTION is defined but SEGGER_RTT_BUFFER_SECTION
|
||||||
|
* is not, use the same section for SEGGER_RTT_BUFFER_SECTION.
|
||||||
|
*/
|
||||||
|
#ifndef SEGGER_RTT_BUFFER_SECTION
|
||||||
|
#if defined(SEGGER_RTT_SECTION)
|
||||||
|
#define SEGGER_RTT_BUFFER_SECTION SEGGER_RTT_SECTION
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
/*************************** End of file ****************************/
|
||||||
+3
-3
@@ -113,8 +113,8 @@ USE_HAL_DRIVER,STM32F103xE
|
|||||||
========================================
|
========================================
|
||||||
|
|
||||||
确认 ROM 和 RAM 配置正确:
|
确认 ROM 和 RAM 配置正确:
|
||||||
- IROM1: 0x08000000, Size: 0x40000 (256KB)
|
- IROM1: 0x08000000, Size: 0x60000 (384KB)
|
||||||
- IRAM1: 0x20000000, Size: 0xC000 (48KB)
|
- IRAM1: 0x20000000, Size: 0x10000 (64KB)
|
||||||
|
|
||||||
========================================
|
========================================
|
||||||
六、编译验证
|
六、编译验证
|
||||||
@@ -138,7 +138,7 @@ Debug 选项卡:
|
|||||||
|
|
||||||
Utilities 选项卡:
|
Utilities 选项卡:
|
||||||
- 选择正确的 Flash 算法
|
- 选择正确的 Flash 算法
|
||||||
- STM32F10x High-density Flash (256KB)
|
- STM32F10x High-density Flash (384KB / 0x60000)
|
||||||
|
|
||||||
========================================
|
========================================
|
||||||
快速添加方法(可选)
|
快速添加方法(可选)
|
||||||
|
|||||||
@@ -1,652 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
|
|
||||||
<ProjectOpt xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="project_optx.xsd">
|
|
||||||
|
|
||||||
<SchemaVersion>1.0</SchemaVersion>
|
|
||||||
|
|
||||||
<Header>### uVision Project, (C) Keil Software</Header>
|
|
||||||
|
|
||||||
<Extensions>
|
|
||||||
<cExt>*.c</cExt>
|
|
||||||
<aExt>*.s*; *.src; *.a*</aExt>
|
|
||||||
<oExt>*.obj; *.o</oExt>
|
|
||||||
<lExt>*.lib</lExt>
|
|
||||||
<tExt>*.txt; *.h; *.inc; *.md</tExt>
|
|
||||||
<pExt>*.plm</pExt>
|
|
||||||
<CppX>*.cpp</CppX>
|
|
||||||
<nMigrate>0</nMigrate>
|
|
||||||
</Extensions>
|
|
||||||
|
|
||||||
<DaveTm>
|
|
||||||
<dwLowDateTime>0</dwLowDateTime>
|
|
||||||
<dwHighDateTime>0</dwHighDateTime>
|
|
||||||
</DaveTm>
|
|
||||||
|
|
||||||
<Target>
|
|
||||||
<TargetName>TCP2UART</TargetName>
|
|
||||||
<ToolsetNumber>0x4</ToolsetNumber>
|
|
||||||
<ToolsetName>ARM-ADS</ToolsetName>
|
|
||||||
<TargetOption>
|
|
||||||
<CLKADS>8000000</CLKADS>
|
|
||||||
<OPTTT>
|
|
||||||
<gFlags>1</gFlags>
|
|
||||||
<BeepAtEnd>1</BeepAtEnd>
|
|
||||||
<RunSim>0</RunSim>
|
|
||||||
<RunTarget>1</RunTarget>
|
|
||||||
<RunAbUc>0</RunAbUc>
|
|
||||||
</OPTTT>
|
|
||||||
<OPTHX>
|
|
||||||
<HexSelection>1</HexSelection>
|
|
||||||
<FlashByte>65535</FlashByte>
|
|
||||||
<HexRangeLowAddress>0</HexRangeLowAddress>
|
|
||||||
<HexRangeHighAddress>0</HexRangeHighAddress>
|
|
||||||
<HexOffset>0</HexOffset>
|
|
||||||
</OPTHX>
|
|
||||||
<OPTLEX>
|
|
||||||
<PageWidth>79</PageWidth>
|
|
||||||
<PageLength>66</PageLength>
|
|
||||||
<TabStop>8</TabStop>
|
|
||||||
<ListingPath></ListingPath>
|
|
||||||
</OPTLEX>
|
|
||||||
<ListingPage>
|
|
||||||
<CreateCListing>1</CreateCListing>
|
|
||||||
<CreateAListing>1</CreateAListing>
|
|
||||||
<CreateLListing>1</CreateLListing>
|
|
||||||
<CreateIListing>0</CreateIListing>
|
|
||||||
<AsmCond>1</AsmCond>
|
|
||||||
<AsmSymb>1</AsmSymb>
|
|
||||||
<AsmXref>0</AsmXref>
|
|
||||||
<CCond>1</CCond>
|
|
||||||
<CCode>0</CCode>
|
|
||||||
<CListInc>0</CListInc>
|
|
||||||
<CSymb>0</CSymb>
|
|
||||||
<LinkerCodeListing>0</LinkerCodeListing>
|
|
||||||
</ListingPage>
|
|
||||||
<OPTXL>
|
|
||||||
<LMap>1</LMap>
|
|
||||||
<LComments>1</LComments>
|
|
||||||
<LGenerateSymbols>1</LGenerateSymbols>
|
|
||||||
<LLibSym>1</LLibSym>
|
|
||||||
<LLines>1</LLines>
|
|
||||||
<LLocSym>1</LLocSym>
|
|
||||||
<LPubSym>1</LPubSym>
|
|
||||||
<LXref>0</LXref>
|
|
||||||
<LExpSel>0</LExpSel>
|
|
||||||
</OPTXL>
|
|
||||||
<OPTFL>
|
|
||||||
<tvExp>1</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<IsCurrentTarget>1</IsCurrentTarget>
|
|
||||||
</OPTFL>
|
|
||||||
<CpuCode>18</CpuCode>
|
|
||||||
<DebugOpt>
|
|
||||||
<uSim>0</uSim>
|
|
||||||
<uTrg>1</uTrg>
|
|
||||||
<sLdApp>1</sLdApp>
|
|
||||||
<sGomain>1</sGomain>
|
|
||||||
<sRbreak>1</sRbreak>
|
|
||||||
<sRwatch>1</sRwatch>
|
|
||||||
<sRmem>1</sRmem>
|
|
||||||
<sRfunc>1</sRfunc>
|
|
||||||
<sRbox>1</sRbox>
|
|
||||||
<tLdApp>1</tLdApp>
|
|
||||||
<tGomain>1</tGomain>
|
|
||||||
<tRbreak>1</tRbreak>
|
|
||||||
<tRwatch>1</tRwatch>
|
|
||||||
<tRmem>1</tRmem>
|
|
||||||
<tRfunc>1</tRfunc>
|
|
||||||
<tRbox>1</tRbox>
|
|
||||||
<tRtrace>1</tRtrace>
|
|
||||||
<sRSysVw>1</sRSysVw>
|
|
||||||
<tRSysVw>1</tRSysVw>
|
|
||||||
<sRunDeb>0</sRunDeb>
|
|
||||||
<sLrtime>0</sLrtime>
|
|
||||||
<bEvRecOn>1</bEvRecOn>
|
|
||||||
<bSchkAxf>0</bSchkAxf>
|
|
||||||
<bTchkAxf>0</bTchkAxf>
|
|
||||||
<nTsel>6</nTsel>
|
|
||||||
<sDll></sDll>
|
|
||||||
<sDllPa></sDllPa>
|
|
||||||
<sDlgDll></sDlgDll>
|
|
||||||
<sDlgPa></sDlgPa>
|
|
||||||
<sIfile></sIfile>
|
|
||||||
<tDll></tDll>
|
|
||||||
<tDllPa></tDllPa>
|
|
||||||
<tDlgDll></tDlgDll>
|
|
||||||
<tDlgPa></tDlgPa>
|
|
||||||
<tIfile></tIfile>
|
|
||||||
<pMon>STLink\ST-LINKIII-KEIL_SWO.dll</pMon>
|
|
||||||
</DebugOpt>
|
|
||||||
<TargetDriverDllRegistry>
|
|
||||||
<SetRegEntry>
|
|
||||||
<Number>0</Number>
|
|
||||||
<Key>UL2CM3</Key>
|
|
||||||
<Name>UL2CM3(-S0 -C0 -P0 ) -FN1 -FC1000 -FD20000000 -FF0STM32F10x_128 -FL020000 -FS08000000 -FP0($$Device:STM32F103R8$Flash\STM32F10x_128.FLM)</Name>
|
|
||||||
</SetRegEntry>
|
|
||||||
<SetRegEntry>
|
|
||||||
<Number>0</Number>
|
|
||||||
<Key>ST-LINKIII-KEIL_SWO</Key>
|
|
||||||
<Name>UL2CM3(-S0 -C0 -P0 ) -FN1 -FC1000 -FD20000000 -FF0STM32F10x_128 -FL020000 -FS08000000 -FP0($$Device:STM32F103R8$Flash\STM32F10x_128.FLM)</Name>
|
|
||||||
</SetRegEntry>
|
|
||||||
</TargetDriverDllRegistry>
|
|
||||||
<Breakpoint/>
|
|
||||||
<Tracepoint>
|
|
||||||
<THDelay>0</THDelay>
|
|
||||||
</Tracepoint>
|
|
||||||
<DebugFlag>
|
|
||||||
<trace>0</trace>
|
|
||||||
<periodic>1</periodic>
|
|
||||||
<aLwin>1</aLwin>
|
|
||||||
<aCover>0</aCover>
|
|
||||||
<aSer1>0</aSer1>
|
|
||||||
<aSer2>0</aSer2>
|
|
||||||
<aPa>0</aPa>
|
|
||||||
<viewmode>1</viewmode>
|
|
||||||
<vrSel>0</vrSel>
|
|
||||||
<aSym>0</aSym>
|
|
||||||
<aTbox>0</aTbox>
|
|
||||||
<AscS1>0</AscS1>
|
|
||||||
<AscS2>0</AscS2>
|
|
||||||
<AscS3>0</AscS3>
|
|
||||||
<aSer3>0</aSer3>
|
|
||||||
<eProf>0</eProf>
|
|
||||||
<aLa>0</aLa>
|
|
||||||
<aPa1>0</aPa1>
|
|
||||||
<AscS4>0</AscS4>
|
|
||||||
<aSer4>0</aSer4>
|
|
||||||
<StkLoc>1</StkLoc>
|
|
||||||
<TrcWin>0</TrcWin>
|
|
||||||
<newCpu>0</newCpu>
|
|
||||||
<uProt>0</uProt>
|
|
||||||
</DebugFlag>
|
|
||||||
<LintExecutable></LintExecutable>
|
|
||||||
<LintConfigFile></LintConfigFile>
|
|
||||||
<bLintAuto>0</bLintAuto>
|
|
||||||
<bAutoGenD>0</bAutoGenD>
|
|
||||||
<LntExFlags>0</LntExFlags>
|
|
||||||
<pMisraName></pMisraName>
|
|
||||||
<pszMrule></pszMrule>
|
|
||||||
<pSingCmds></pSingCmds>
|
|
||||||
<pMultCmds></pMultCmds>
|
|
||||||
<pMisraNamep></pMisraNamep>
|
|
||||||
<pszMrulep></pszMrulep>
|
|
||||||
<pSingCmdsp></pSingCmdsp>
|
|
||||||
<pMultCmdsp></pMultCmdsp>
|
|
||||||
<DebugDescription>
|
|
||||||
<Enable>1</Enable>
|
|
||||||
<EnableFlashSeq>0</EnableFlashSeq>
|
|
||||||
<EnableLog>0</EnableLog>
|
|
||||||
<Protocol>2</Protocol>
|
|
||||||
<DbgClock>10000000</DbgClock>
|
|
||||||
</DebugDescription>
|
|
||||||
</TargetOption>
|
|
||||||
</Target>
|
|
||||||
|
|
||||||
<Group>
|
|
||||||
<GroupName>Application/MDK-ARM</GroupName>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<cbSel>0</cbSel>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>1</GroupNumber>
|
|
||||||
<FileNumber>1</FileNumber>
|
|
||||||
<FileType>2</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>startup_stm32f103xe.s</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>startup_stm32f103xe.s</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
</Group>
|
|
||||||
|
|
||||||
<Group>
|
|
||||||
<GroupName>Application/User/Core</GroupName>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<cbSel>0</cbSel>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>2</GroupNumber>
|
|
||||||
<FileNumber>2</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Core/Src/main.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>main.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>2</GroupNumber>
|
|
||||||
<FileNumber>3</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Core/Src/gpio.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>gpio.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>2</GroupNumber>
|
|
||||||
<FileNumber>4</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Core/Src/freertos.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>freertos.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>2</GroupNumber>
|
|
||||||
<FileNumber>5</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Core/Src/dma.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>dma.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>2</GroupNumber>
|
|
||||||
<FileNumber>6</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Core/Src/iwdg.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>iwdg.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>2</GroupNumber>
|
|
||||||
<FileNumber>7</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Core/Src/spi.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>spi.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>2</GroupNumber>
|
|
||||||
<FileNumber>8</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Core/Src/usart.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>usart.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>2</GroupNumber>
|
|
||||||
<FileNumber>9</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Core/Src/stm32f1xx_it.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>stm32f1xx_it.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>2</GroupNumber>
|
|
||||||
<FileNumber>10</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Core/Src/stm32f1xx_hal_msp.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>stm32f1xx_hal_msp.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
</Group>
|
|
||||||
|
|
||||||
<Group>
|
|
||||||
<GroupName>Drivers/STM32F1xx_HAL_Driver</GroupName>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<cbSel>0</cbSel>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>3</GroupNumber>
|
|
||||||
<FileNumber>11</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_gpio_ex.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>stm32f1xx_hal_gpio_ex.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>3</GroupNumber>
|
|
||||||
<FileNumber>12</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>stm32f1xx_hal.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_rcc.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>stm32f1xx_hal_rcc.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>3</GroupNumber>
|
|
||||||
<FileNumber>14</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc_ex.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>stm32f1xx_hal_rcc_ex.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>3</GroupNumber>
|
|
||||||
<FileNumber>15</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_gpio.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>stm32f1xx_hal_gpio.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>3</GroupNumber>
|
|
||||||
<FileNumber>16</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_dma.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>stm32f1xx_hal_dma.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>3</GroupNumber>
|
|
||||||
<FileNumber>17</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_cortex.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>stm32f1xx_hal_cortex.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>3</GroupNumber>
|
|
||||||
<FileNumber>18</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_pwr.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>stm32f1xx_hal_pwr.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>3</GroupNumber>
|
|
||||||
<FileNumber>19</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_flash.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>stm32f1xx_hal_flash.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>3</GroupNumber>
|
|
||||||
<FileNumber>20</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_flash_ex.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>stm32f1xx_hal_flash_ex.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>3</GroupNumber>
|
|
||||||
<FileNumber>21</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_exti.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>stm32f1xx_hal_exti.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</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>
|
|
||||||
<GroupNumber>3</GroupNumber>
|
|
||||||
<FileNumber>23</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_spi.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>stm32f1xx_hal_spi.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>3</GroupNumber>
|
|
||||||
<FileNumber>24</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_uart.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>stm32f1xx_hal_uart.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
</Group>
|
|
||||||
|
|
||||||
<Group>
|
|
||||||
<GroupName>Drivers/CMSIS</GroupName>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<cbSel>0</cbSel>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>4</GroupNumber>
|
|
||||||
<FileNumber>25</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Core/Src/system_stm32f1xx.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>system_stm32f1xx.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
</Group>
|
|
||||||
|
|
||||||
<Group>
|
|
||||||
<GroupName>Middlewares/FreeRTOS</GroupName>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<cbSel>0</cbSel>
|
|
||||||
<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>
|
|
||||||
<GroupNumber>5</GroupNumber>
|
|
||||||
<FileNumber>28</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Middlewares/Third_Party/FreeRTOS/Source/list.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>list.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>5</GroupNumber>
|
|
||||||
<FileNumber>29</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Middlewares/Third_Party/FreeRTOS/Source/queue.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>queue.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>5</GroupNumber>
|
|
||||||
<FileNumber>30</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Middlewares/Third_Party/FreeRTOS/Source/stream_buffer.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>stream_buffer.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>5</GroupNumber>
|
|
||||||
<FileNumber>31</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Middlewares/Third_Party/FreeRTOS/Source/tasks.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>tasks.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>5</GroupNumber>
|
|
||||||
<FileNumber>32</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Middlewares/Third_Party/FreeRTOS/Source/timers.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>timers.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>5</GroupNumber>
|
|
||||||
<FileNumber>33</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>cmsis_os2.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>5</GroupNumber>
|
|
||||||
<FileNumber>34</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/heap_4.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>heap_4.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>5</GroupNumber>
|
|
||||||
<FileNumber>35</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>../Middlewares/Third_Party/FreeRTOS/Source/portable/RVDS/ARM_CM3/port.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>port.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
</Group>
|
|
||||||
|
|
||||||
<Group>
|
|
||||||
<GroupName>::CMSIS</GroupName>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<cbSel>0</cbSel>
|
|
||||||
<RteFlg>1</RteFlg>
|
|
||||||
</Group>
|
|
||||||
|
|
||||||
</ProjectOpt>
|
|
||||||
+53
-13
@@ -14,16 +14,16 @@
|
|||||||
<uAC6>0</uAC6>
|
<uAC6>0</uAC6>
|
||||||
<TargetOption>
|
<TargetOption>
|
||||||
<TargetCommonOption>
|
<TargetCommonOption>
|
||||||
<Device>STM32F103RC</Device>
|
<Device>STM32F103RD</Device>
|
||||||
<Vendor>STMicroelectronics</Vendor>
|
<Vendor>STMicroelectronics</Vendor>
|
||||||
<PackID>Keil.STM32F1xx_DFP.2.4.1</PackID>
|
<PackID>Keil.STM32F1xx_DFP.2.4.1</PackID>
|
||||||
<PackURL>https://www.keil.com/pack/</PackURL>
|
<PackURL>https://www.keil.com/pack/</PackURL>
|
||||||
<Cpu>IRAM(0x20000000,0x0000C000) IROM(0x08000000,0x00040000) CPUTYPE("Cortex-M3") CLOCK(12000000) ELITTLE</Cpu>
|
<Cpu>IRAM(0x20000000,0x00010000) IROM(0x08000000,0x00060000) CPUTYPE("Cortex-M3") CLOCK(12000000) ELITTLE</Cpu>
|
||||||
<FlashUtilSpec></FlashUtilSpec>
|
<FlashUtilSpec></FlashUtilSpec>
|
||||||
<StartupFile></StartupFile>
|
<StartupFile></StartupFile>
|
||||||
<FlashDriverDll>UL2CM3(-S0 -C0 -P0 -FD20000000 -FC1000 -FN1 -FF0STM32F10x_HD -FS08000000 -FL040000 -FP0($$Device:STM32F103RC$Flash\STM32F10x_HD.FLM))</FlashDriverDll>
|
<FlashDriverDll>UL2CM3(-S0 -C0 -P0 -FD20000000 -FC1000 -FN1 -FF0STM32F10x_512 -FS08000000 -FL080000 -FP0($$Device:STM32F103RD$Flash\STM32F10x_512.FLM))</FlashDriverDll>
|
||||||
<DeviceId>0</DeviceId>
|
<DeviceId>0</DeviceId>
|
||||||
<RegisterFile>$$Device:STM32F103RC$Device\Include\stm32f10x.h</RegisterFile>
|
<RegisterFile>$$Device:STM32F103RD$Device\Include\stm32f10x.h</RegisterFile>
|
||||||
<MemoryEnv></MemoryEnv>
|
<MemoryEnv></MemoryEnv>
|
||||||
<Cmp></Cmp>
|
<Cmp></Cmp>
|
||||||
<Asm></Asm>
|
<Asm></Asm>
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
<SLE66CMisc></SLE66CMisc>
|
<SLE66CMisc></SLE66CMisc>
|
||||||
<SLE66AMisc></SLE66AMisc>
|
<SLE66AMisc></SLE66AMisc>
|
||||||
<SLE66LinkerMisc></SLE66LinkerMisc>
|
<SLE66LinkerMisc></SLE66LinkerMisc>
|
||||||
<SFDFile>$$Device:STM32F103RC$SVD\STM32F103xx.svd</SFDFile>
|
<SFDFile>$$Device:STM32F103RD$SVD\STM32F103xx.svd</SFDFile>
|
||||||
<bCustSvd>0</bCustSvd>
|
<bCustSvd>0</bCustSvd>
|
||||||
<UseEnv>0</UseEnv>
|
<UseEnv>0</UseEnv>
|
||||||
<BinPath></BinPath>
|
<BinPath></BinPath>
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
<CreateHexFile>1</CreateHexFile>
|
<CreateHexFile>1</CreateHexFile>
|
||||||
<DebugInformation>1</DebugInformation>
|
<DebugInformation>1</DebugInformation>
|
||||||
<BrowseInformation>1</BrowseInformation>
|
<BrowseInformation>1</BrowseInformation>
|
||||||
<ListingPath></ListingPath>
|
<ListingPath>.\TCP2UART\</ListingPath>
|
||||||
<HexFormatSelection>1</HexFormatSelection>
|
<HexFormatSelection>1</HexFormatSelection>
|
||||||
<Merge32K>0</Merge32K>
|
<Merge32K>0</Merge32K>
|
||||||
<CreateBatchFile>0</CreateBatchFile>
|
<CreateBatchFile>0</CreateBatchFile>
|
||||||
@@ -81,7 +81,7 @@
|
|||||||
</BeforeMake>
|
</BeforeMake>
|
||||||
<AfterMake>
|
<AfterMake>
|
||||||
<RunUserProg1>0</RunUserProg1>
|
<RunUserProg1>0</RunUserProg1>
|
||||||
<RunUserProg2>1</RunUserProg2>
|
<RunUserProg2>0</RunUserProg2>
|
||||||
<UserProg1Name></UserProg1Name>
|
<UserProg1Name></UserProg1Name>
|
||||||
<UserProg2Name></UserProg2Name>
|
<UserProg2Name></UserProg2Name>
|
||||||
<UserProg1Dos16Mode>0</UserProg1Dos16Mode>
|
<UserProg1Dos16Mode>0</UserProg1Dos16Mode>
|
||||||
@@ -134,7 +134,7 @@
|
|||||||
<RunIndependent>0</RunIndependent>
|
<RunIndependent>0</RunIndependent>
|
||||||
<UpdateFlashBeforeDebugging>1</UpdateFlashBeforeDebugging>
|
<UpdateFlashBeforeDebugging>1</UpdateFlashBeforeDebugging>
|
||||||
<Capability>1</Capability>
|
<Capability>1</Capability>
|
||||||
<DriverSelection>4101</DriverSelection>
|
<DriverSelection>4096</DriverSelection>
|
||||||
</Flash1>
|
</Flash1>
|
||||||
<bUseTDR>1</bUseTDR>
|
<bUseTDR>1</bUseTDR>
|
||||||
<Flash2>BIN\UL2CM3.DLL</Flash2>
|
<Flash2>BIN\UL2CM3.DLL</Flash2>
|
||||||
@@ -247,12 +247,12 @@
|
|||||||
<IRAM>
|
<IRAM>
|
||||||
<Type>0</Type>
|
<Type>0</Type>
|
||||||
<StartAddress>0x20000000</StartAddress>
|
<StartAddress>0x20000000</StartAddress>
|
||||||
<Size>0xC000</Size>
|
<Size>0x10000</Size>
|
||||||
</IRAM>
|
</IRAM>
|
||||||
<IROM>
|
<IROM>
|
||||||
<Type>1</Type>
|
<Type>1</Type>
|
||||||
<StartAddress>0x8000000</StartAddress>
|
<StartAddress>0x8000000</StartAddress>
|
||||||
<Size>0x40000</Size>
|
<Size>0x60000</Size>
|
||||||
</IROM>
|
</IROM>
|
||||||
<XRAM>
|
<XRAM>
|
||||||
<Type>0</Type>
|
<Type>0</Type>
|
||||||
@@ -277,7 +277,7 @@
|
|||||||
<OCR_RVCT4>
|
<OCR_RVCT4>
|
||||||
<Type>1</Type>
|
<Type>1</Type>
|
||||||
<StartAddress>0x8000000</StartAddress>
|
<StartAddress>0x8000000</StartAddress>
|
||||||
<Size>0x40000</Size>
|
<Size>0x60000</Size>
|
||||||
</OCR_RVCT4>
|
</OCR_RVCT4>
|
||||||
<OCR_RVCT5>
|
<OCR_RVCT5>
|
||||||
<Type>1</Type>
|
<Type>1</Type>
|
||||||
@@ -302,7 +302,7 @@
|
|||||||
<OCR_RVCT9>
|
<OCR_RVCT9>
|
||||||
<Type>0</Type>
|
<Type>0</Type>
|
||||||
<StartAddress>0x20000000</StartAddress>
|
<StartAddress>0x20000000</StartAddress>
|
||||||
<Size>0xC000</Size>
|
<Size>0x10000</Size>
|
||||||
</OCR_RVCT9>
|
</OCR_RVCT9>
|
||||||
<OCR_RVCT10>
|
<OCR_RVCT10>
|
||||||
<Type>0</Type>
|
<Type>0</Type>
|
||||||
@@ -340,7 +340,7 @@
|
|||||||
<MiscControls></MiscControls>
|
<MiscControls></MiscControls>
|
||||||
<Define>USE_HAL_DRIVER,STM32F103xE</Define>
|
<Define>USE_HAL_DRIVER,STM32F103xE</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;../Middlewares/Third_Party/FreeRTOS/Source/include;../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2;../Middlewares/Third_Party/FreeRTOS/Source/portable/RVDS/ARM_CM3;..\Drivers\CH390;..\Drivers\LwIP\src\include;..\Drivers\LwIP\src\include\lwip;..\Drivers\LwIP\src\include\netif;..\Drivers\LwIP\src\include\arch;..\Drivers\LwIP\port;..\App</IncludePath>
|
<IncludePath>../Core/Inc;../Drivers/STM32F1xx_HAL_Driver/Inc;../Drivers/STM32F1xx_HAL_Driver/Inc/Legacy;../Drivers/CMSIS/Device/ST/STM32F1xx/Include;../Drivers/CMSIS/Include;../Middlewares/Third_Party/FreeRTOS/Source/include;../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2;../Middlewares/Third_Party/FreeRTOS/Source/portable/RVDS/ARM_CM3;..\Drivers\CH390;..\Drivers\LwIP\src\include;..\Drivers\LwIP\src\include\lwip;..\Drivers\LwIP\src\include\netif;..\Drivers\LwIP\src\include\arch;..\Drivers\LwIP\port;..\Drivers\SEGGER\RTT;..\App</IncludePath>
|
||||||
</VariousControls>
|
</VariousControls>
|
||||||
</Cads>
|
</Cads>
|
||||||
<Aads>
|
<Aads>
|
||||||
@@ -485,11 +485,26 @@
|
|||||||
<FileType>1</FileType>
|
<FileType>1</FileType>
|
||||||
<FilePath>../Core/Src/stm32f1xx_it.c</FilePath>
|
<FilePath>../Core/Src/stm32f1xx_it.c</FilePath>
|
||||||
</File>
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>stm32f1xx_hal_timebase_tim.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>../Core/Src/stm32f1xx_hal_timebase_tim.c</FilePath>
|
||||||
|
</File>
|
||||||
<File>
|
<File>
|
||||||
<FileName>stm32f1xx_hal_msp.c</FileName>
|
<FileName>stm32f1xx_hal_msp.c</FileName>
|
||||||
<FileType>1</FileType>
|
<FileType>1</FileType>
|
||||||
<FilePath>../Core/Src/stm32f1xx_hal_msp.c</FilePath>
|
<FilePath>../Core/Src/stm32f1xx_hal_msp.c</FilePath>
|
||||||
</File>
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>debug_log.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>../Core/Src/debug_log.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>retarget_rtt.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>../Core/Src/retarget_rtt.c</FilePath>
|
||||||
|
</File>
|
||||||
</Files>
|
</Files>
|
||||||
</Group>
|
</Group>
|
||||||
<Group>
|
<Group>
|
||||||
@@ -1429,6 +1444,11 @@
|
|||||||
<Group>
|
<Group>
|
||||||
<GroupName>Drivers/LwIP/netif</GroupName>
|
<GroupName>Drivers/LwIP/netif</GroupName>
|
||||||
<Files>
|
<Files>
|
||||||
|
<File>
|
||||||
|
<FileName>ethernet.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\Drivers\LwIP\src\netif\ethernet.c</FilePath>
|
||||||
|
</File>
|
||||||
<File>
|
<File>
|
||||||
<FileName>ethernetif.c</FileName>
|
<FileName>ethernetif.c</FileName>
|
||||||
<FileType>1</FileType>
|
<FileType>1</FileType>
|
||||||
@@ -1446,6 +1466,16 @@
|
|||||||
</File>
|
</File>
|
||||||
</Files>
|
</Files>
|
||||||
</Group>
|
</Group>
|
||||||
|
<Group>
|
||||||
|
<GroupName>Drivers/SEGGER_RTT</GroupName>
|
||||||
|
<Files>
|
||||||
|
<File>
|
||||||
|
<FileName>SEGGER_RTT.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\Drivers\SEGGER\RTT\SEGGER_RTT.c</FilePath>
|
||||||
|
</File>
|
||||||
|
</Files>
|
||||||
|
</Group>
|
||||||
<Group>
|
<Group>
|
||||||
<GroupName>APP</GroupName>
|
<GroupName>APP</GroupName>
|
||||||
<Files>
|
<Files>
|
||||||
@@ -1459,6 +1489,16 @@
|
|||||||
<FileType>1</FileType>
|
<FileType>1</FileType>
|
||||||
<FilePath>..\App\flash_param.c</FilePath>
|
<FilePath>..\App\flash_param.c</FilePath>
|
||||||
</File>
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>route_msg.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\App\route_msg.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>task_net_poll.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\App\task_net_poll.c</FilePath>
|
||||||
|
</File>
|
||||||
<File>
|
<File>
|
||||||
<FileName>tcp_client.c</FileName>
|
<FileName>tcp_client.c</FileName>
|
||||||
<FileType>1</FileType>
|
<FileType>1</FileType>
|
||||||
|
|||||||
+151
-88
@@ -13,7 +13,7 @@
|
|||||||
[target name] TCP2UART
|
[target name] TCP2UART
|
||||||
[final target name] TCP2UART
|
[final target name] TCP2UART
|
||||||
|
|
||||||
[Device] STM32F103R8
|
[Device] STM32F103RC
|
||||||
[Target name]
|
[Target name]
|
||||||
[Output name] TCP2UART
|
[Output name] TCP2UART
|
||||||
[Output path] TCP2UART\
|
[Output path] TCP2UART\
|
||||||
@@ -23,38 +23,45 @@
|
|||||||
[Is has user library] 0
|
[Is has user library] 0
|
||||||
[Is custom scatter file] 0
|
[Is custom scatter file] 0
|
||||||
|
|
||||||
[TCP2UART.uvprojx] [TCP2UART] [STM32F103R8] [LTO disable]
|
[TCP2UART.uvprojx] [TCP2UART] [STM32F103RC] [LTO disable]
|
||||||
|
|
||||||
[memory info]
|
[memory info]
|
||||||
[name] IRAM [base addr] 0x20000000 [size] 0x00005000 [type] 1 [off-chip] 0 [is pack] 1 [ID] 2
|
[name] IRAM [base addr] 0x20000000 [size] 0x0000C000 [type] 1 [off-chip] 0 [is pack] 1 [ID] 2
|
||||||
[name] IROM [base addr] 0x08000000 [size] 0x00010000 [type] 2 [off-chip] 0 [is pack] 1 [ID] 3
|
[name] IROM [base addr] 0x08000000 [size] 0x00040000 [type] 2 [off-chip] 0 [is pack] 1 [ID] 3
|
||||||
|
|
||||||
|
|
||||||
[map file path] D:\code\STM32Project\TCP2UART\MDK-ARM\TCP2UART\TCP2UART.map
|
[map file path] D:\code\STM32Project\TCP2UART\MDK-ARM\TCP2UART\TCP2UART.map
|
||||||
|
|
||||||
[region info]
|
[region info]
|
||||||
[load region] LR_IROM1
|
[load region] LR_IROM1
|
||||||
[execution region] ER_IROM1, 0x08000000, 0x00010000, 0x0000D178 [memory type] 2 [memory ID] 3
|
[execution region] ER_IROM1, 0x08000000, 0x00040000, 0x00015410 [memory type] 2 [memory ID] 3
|
||||||
|
|
||||||
[execution region] RW_IRAM1, 0x20000000, 0x00005000, 0x00004FF8 [memory type] 1 [memory ID] 2
|
[execution region] RW_IRAM1, 0x20000000, 0x0000C000, 0x0000B980 [memory type] 1 [memory ID] 2
|
||||||
[ZI block] addr: 0x2000015C, size: 0x00004E9C (20124)
|
[ZI block] addr: 0x200001B0, size: 0x0000B7D0 (47056)
|
||||||
|
|
||||||
|
|
||||||
[object name max length] 24
|
[object name max length] 28
|
||||||
[object path max length] 60
|
[object path max length] 71
|
||||||
|
|
||||||
[object in map file]
|
[object in map file]
|
||||||
|
[object name] altcp.o [path] ..\Drivers\LwIP\src\core\altcp.c
|
||||||
|
[object name] api_lib.o [path] ..\Drivers\LwIP\src\api\api_lib.c
|
||||||
|
[object name] api_msg.o [path] ..\Drivers\LwIP\src\api\api_msg.c
|
||||||
[object name] ch390.o [path] ..\Drivers\CH390\CH390.c
|
[object name] ch390.o [path] ..\Drivers\CH390\CH390.c
|
||||||
[object name] ch390_interface.o [path] ..\Drivers\CH390\CH390_Interface.c
|
[object name] ch390_interface.o [path] ..\Drivers\CH390\CH390_Interface.c
|
||||||
[object name] ch390_runtime.o [path] ..\Drivers\CH390\ch390_runtime.c
|
[object name] cmsis_os2.o [path] ../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.c
|
||||||
[object name] config.o [path] ..\App\config.c
|
[object name] config.o [path] ..\App\config.c
|
||||||
|
[object name] debug_log.o [path] ../Core/Src/debug_log.c
|
||||||
[object name] def.o [path] ..\Drivers\LwIP\src\core\def.c
|
[object name] def.o [path] ..\Drivers\LwIP\src\core\def.c
|
||||||
[object name] dma.o [path] ../Core/Src/dma.c
|
[object name] dma.o [path] ../Core/Src/dma.c
|
||||||
[object name] etharp.o [path] ..\Drivers\LwIP\src\core\ipv4\etharp.c
|
[object name] etharp.o [path] ..\Drivers\LwIP\src\core\ipv4\etharp.c
|
||||||
[object name] ethernet.o [path] ..\Drivers\LwIP\src\netif\ethernet.c
|
[object name] ethernet.o [path] ..\Drivers\LwIP\src\netif\ethernet.c
|
||||||
[object name] ethernetif.o [path] ..\Drivers\LwIP\src\netif\ethernetif.c
|
[object name] ethernetif.o [path] ..\Drivers\LwIP\src\netif\ethernetif.c
|
||||||
|
[object name] event_groups.o [path] ../Middlewares/Third_Party/FreeRTOS/Source/event_groups.c
|
||||||
[object name] flash_param.o [path] ..\App\flash_param.c
|
[object name] flash_param.o [path] ..\App\flash_param.c
|
||||||
|
[object name] freertos.o [path] ../Core/Src/freertos.c
|
||||||
[object name] gpio.o [path] ../Core/Src/gpio.c
|
[object name] gpio.o [path] ../Core/Src/gpio.c
|
||||||
|
[object name] heap_4.o [path] ../Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/heap_4.c
|
||||||
[object name] icmp.o [path] ..\Drivers\LwIP\src\core\ipv4\icmp.c
|
[object name] icmp.o [path] ..\Drivers\LwIP\src\core\ipv4\icmp.c
|
||||||
[object name] inet_chksum.o [path] ..\Drivers\LwIP\src\core\inet_chksum.c
|
[object name] inet_chksum.o [path] ..\Drivers\LwIP\src\core\inet_chksum.c
|
||||||
[object name] init.o [path] ..\Drivers\LwIP\src\core\init.c
|
[object name] init.o [path] ..\Drivers\LwIP\src\core\init.c
|
||||||
@@ -62,16 +69,22 @@
|
|||||||
[object name] ip4.o [path] ..\Drivers\LwIP\src\core\ipv4\ip4.c
|
[object name] ip4.o [path] ..\Drivers\LwIP\src\core\ipv4\ip4.c
|
||||||
[object name] ip4_addr.o [path] ..\Drivers\LwIP\src\core\ipv4\ip4_addr.c
|
[object name] ip4_addr.o [path] ..\Drivers\LwIP\src\core\ipv4\ip4_addr.c
|
||||||
[object name] iwdg.o [path] ../Core/Src/iwdg.c
|
[object name] iwdg.o [path] ../Core/Src/iwdg.c
|
||||||
|
[object name] list.o [path] ../Middlewares/Third_Party/FreeRTOS/Source/list.c
|
||||||
[object name] main.o [path] ../Core/Src/main.c
|
[object name] main.o [path] ../Core/Src/main.c
|
||||||
[object name] mem.o [path] ..\Drivers\LwIP\src\core\mem.c
|
[object name] mem.o [path] ..\Drivers\LwIP\src\core\mem.c
|
||||||
[object name] memp.o [path] ..\Drivers\LwIP\src\core\memp.c
|
[object name] memp.o [path] ..\Drivers\LwIP\src\core\memp.c
|
||||||
|
[object name] netbuf.o [path] ..\Drivers\LwIP\src\api\netbuf.c
|
||||||
[object name] netif.o [path] ..\Drivers\LwIP\src\core\netif.c
|
[object name] netif.o [path] ..\Drivers\LwIP\src\core\netif.c
|
||||||
|
[object name] netifapi.o [path] ..\Drivers\LwIP\src\api\netifapi.c
|
||||||
[object name] pbuf.o [path] ..\Drivers\LwIP\src\core\pbuf.c
|
[object name] pbuf.o [path] ..\Drivers\LwIP\src\core\pbuf.c
|
||||||
|
[object name] port.o [path] ../Middlewares/Third_Party/FreeRTOS/Source/portable/RVDS/ARM_CM3/port.c
|
||||||
|
[object name] queue.o [path] ../Middlewares/Third_Party/FreeRTOS/Source/queue.c
|
||||||
[object name] raw.o [path] ..\Drivers\LwIP\src\core\raw.c
|
[object name] raw.o [path] ..\Drivers\LwIP\src\core\raw.c
|
||||||
[object name] segger_rtt.o [path] ..\Middlewares\Third_Party\SEGGER_RTT\SEGGER_RTT.c
|
[object name] retarget_rtt.o [path] ../Core/Src/retarget_rtt.c
|
||||||
[object name] segger_rtt_printf.o [path] ..\Middlewares\Third_Party\SEGGER_RTT\SEGGER_RTT_printf.c
|
[object name] route_msg.o [path] ..\App\route_msg.c
|
||||||
|
[object name] segger_rtt.o [path] ..\Drivers\SEGGER\RTT\SEGGER_RTT.c
|
||||||
[object name] spi.o [path] ../Core/Src/spi.c
|
[object name] spi.o [path] ../Core/Src/spi.c
|
||||||
[object name] startup_stm32f103xb.o [path] startup_stm32f103xb.s
|
[object name] startup_stm32f103xe.o [path] startup_stm32f103xe.s
|
||||||
[object name] stm32f1xx_hal.o [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal.c
|
[object name] stm32f1xx_hal.o [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal.c
|
||||||
[object name] stm32f1xx_hal_cortex.o [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_cortex.c
|
[object name] stm32f1xx_hal_cortex.o [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_cortex.c
|
||||||
[object name] stm32f1xx_hal_dma.o [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_dma.c
|
[object name] stm32f1xx_hal_dma.o [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_dma.c
|
||||||
@@ -82,34 +95,40 @@
|
|||||||
[object name] stm32f1xx_hal_msp.o [path] ../Core/Src/stm32f1xx_hal_msp.c
|
[object name] stm32f1xx_hal_msp.o [path] ../Core/Src/stm32f1xx_hal_msp.c
|
||||||
[object name] stm32f1xx_hal_rcc.o [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc.c
|
[object name] stm32f1xx_hal_rcc.o [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc.c
|
||||||
[object name] stm32f1xx_hal_spi.o [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_spi.c
|
[object name] stm32f1xx_hal_spi.o [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_spi.c
|
||||||
[object name] stm32f1xx_hal_tim.o [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_tim.c
|
[object name] stm32f1xx_hal_timebase_tim.o [path] ../Core/Src/stm32f1xx_hal_timebase_tim.c
|
||||||
[object name] stm32f1xx_hal_tim_ex.o [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_tim_ex.c
|
|
||||||
[object name] stm32f1xx_hal_uart.o [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_uart.c
|
[object name] stm32f1xx_hal_uart.o [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_uart.c
|
||||||
[object name] stm32f1xx_it.o [path] ../Core/Src/stm32f1xx_it.c
|
[object name] stm32f1xx_it.o [path] ../Core/Src/stm32f1xx_it.c
|
||||||
|
[object name] stream_buffer.o [path] ../Middlewares/Third_Party/FreeRTOS/Source/stream_buffer.c
|
||||||
|
[object name] sys_arch.o [path] ..\Drivers\LwIP\port\sys_arch.c
|
||||||
[object name] system_stm32f1xx.o [path] ../Core/Src/system_stm32f1xx.c
|
[object name] system_stm32f1xx.o [path] ../Core/Src/system_stm32f1xx.c
|
||||||
|
[object name] task_net_poll.o [path] ..\App\task_net_poll.c
|
||||||
|
[object name] tasks.o [path] ../Middlewares/Third_Party/FreeRTOS/Source/tasks.c
|
||||||
[object name] tcp.o [path] ..\Drivers\LwIP\src\core\tcp.c
|
[object name] tcp.o [path] ..\Drivers\LwIP\src\core\tcp.c
|
||||||
[object name] tcp_client.o [path] ..\App\tcp_client.c
|
[object name] tcp_client.o [path] ..\App\tcp_client.c
|
||||||
[object name] tcp_in.o [path] ..\Drivers\LwIP\src\core\tcp_in.c
|
[object name] tcp_in.o [path] ..\Drivers\LwIP\src\core\tcp_in.c
|
||||||
[object name] tcp_out.o [path] ..\Drivers\LwIP\src\core\tcp_out.c
|
[object name] tcp_out.o [path] ..\Drivers\LwIP\src\core\tcp_out.c
|
||||||
[object name] tcp_server.o [path] ..\App\tcp_server.c
|
[object name] tcp_server.o [path] ..\App\tcp_server.c
|
||||||
[object name] tim.o [path] ../Core/Src/tim.c
|
[object name] tcpip.o [path] ..\Drivers\LwIP\src\api\tcpip.c
|
||||||
[object name] timeouts.o [path] ..\Drivers\LwIP\src\core\timeouts.c
|
[object name] timeouts.o [path] ..\Drivers\LwIP\src\core\timeouts.c
|
||||||
|
[object name] timers.o [path] ../Middlewares/Third_Party/FreeRTOS/Source/timers.c
|
||||||
[object name] uart_trans.o [path] ..\App\uart_trans.c
|
[object name] uart_trans.o [path] ..\App\uart_trans.c
|
||||||
[object name] usart.o [path] ../Core/Src/usart.c
|
[object name] usart.o [path] ../Core/Src/usart.c
|
||||||
|
|
||||||
[file path in keil project]
|
[file path in keil project]
|
||||||
[old name] startup_stm32f103xb.s [type] 1 [path] startup_stm32f103xb.s
|
[old name] startup_stm32f103xe.s [type] 1 [path] startup_stm32f103xe.s
|
||||||
[old name] main.c [type] 1 [path] ../Core/Src/main.c
|
[old name] main.c [type] 1 [path] ../Core/Src/main.c
|
||||||
[old name] gpio.c [type] 1 [path] ../Core/Src/gpio.c
|
[old name] gpio.c [type] 1 [path] ../Core/Src/gpio.c
|
||||||
|
[old name] freertos.c [type] 1 [path] ../Core/Src/freertos.c
|
||||||
[old name] dma.c [type] 1 [path] ../Core/Src/dma.c
|
[old name] dma.c [type] 1 [path] ../Core/Src/dma.c
|
||||||
[old name] iwdg.c [type] 1 [path] ../Core/Src/iwdg.c
|
[old name] iwdg.c [type] 1 [path] ../Core/Src/iwdg.c
|
||||||
[old name] tim.c [type] 1 [path] ../Core/Src/tim.c
|
|
||||||
[old name] spi.c [type] 1 [path] ../Core/Src/spi.c
|
[old name] spi.c [type] 1 [path] ../Core/Src/spi.c
|
||||||
[old name] usart.c [type] 1 [path] ../Core/Src/usart.c
|
[old name] usart.c [type] 1 [path] ../Core/Src/usart.c
|
||||||
[old name] stm32f1xx_it.c [type] 1 [path] ../Core/Src/stm32f1xx_it.c
|
[old name] stm32f1xx_it.c [type] 1 [path] ../Core/Src/stm32f1xx_it.c
|
||||||
|
[old name] stm32f1xx_hal_timebase_tim.c [type] 1 [path] ../Core/Src/stm32f1xx_hal_timebase_tim.c
|
||||||
[old name] stm32f1xx_hal_msp.c [type] 1 [path] ../Core/Src/stm32f1xx_hal_msp.c
|
[old name] stm32f1xx_hal_msp.c [type] 1 [path] ../Core/Src/stm32f1xx_hal_msp.c
|
||||||
|
[old name] debug_log.c [type] 1 [path] ../Core/Src/debug_log.c
|
||||||
|
[old name] retarget_rtt.c [type] 1 [path] ../Core/Src/retarget_rtt.c
|
||||||
[old name] stm32f1xx_hal_gpio_ex.c [type] 1 [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_gpio_ex.c
|
[old name] stm32f1xx_hal_gpio_ex.c [type] 1 [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_gpio_ex.c
|
||||||
[old name] stm32f1xx_hal_iwdg.c [type] 1 [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_iwdg.c
|
|
||||||
[old name] stm32f1xx_hal.c [type] 1 [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal.c
|
[old name] stm32f1xx_hal.c [type] 1 [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal.c
|
||||||
[old name] stm32f1xx_hal_rcc.c [type] 1 [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc.c
|
[old name] stm32f1xx_hal_rcc.c [type] 1 [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc.c
|
||||||
[old name] stm32f1xx_hal_rcc_ex.c [type] 1 [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc_ex.c
|
[old name] stm32f1xx_hal_rcc_ex.c [type] 1 [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc_ex.c
|
||||||
@@ -120,15 +139,27 @@
|
|||||||
[old name] stm32f1xx_hal_flash.c [type] 1 [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_flash.c
|
[old name] stm32f1xx_hal_flash.c [type] 1 [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_flash.c
|
||||||
[old name] stm32f1xx_hal_flash_ex.c [type] 1 [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_flash_ex.c
|
[old name] stm32f1xx_hal_flash_ex.c [type] 1 [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_flash_ex.c
|
||||||
[old name] stm32f1xx_hal_exti.c [type] 1 [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_exti.c
|
[old name] stm32f1xx_hal_exti.c [type] 1 [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_exti.c
|
||||||
|
[old name] stm32f1xx_hal_iwdg.c [type] 1 [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_iwdg.c
|
||||||
[old name] stm32f1xx_hal_spi.c [type] 1 [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_spi.c
|
[old name] stm32f1xx_hal_spi.c [type] 1 [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_spi.c
|
||||||
[old name] stm32f1xx_hal_tim.c [type] 1 [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_tim.c
|
|
||||||
[old name] stm32f1xx_hal_tim_ex.c [type] 1 [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_tim_ex.c
|
|
||||||
[old name] stm32f1xx_hal_uart.c [type] 1 [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_uart.c
|
[old name] stm32f1xx_hal_uart.c [type] 1 [path] ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_uart.c
|
||||||
[old name] system_stm32f1xx.c [type] 1 [path] ../Core/Src/system_stm32f1xx.c
|
[old name] system_stm32f1xx.c [type] 1 [path] ../Core/Src/system_stm32f1xx.c
|
||||||
|
[old name] croutine.c [type] 1 [path] ../Middlewares/Third_Party/FreeRTOS/Source/croutine.c
|
||||||
|
[old name] event_groups.c [type] 1 [path] ../Middlewares/Third_Party/FreeRTOS/Source/event_groups.c
|
||||||
|
[old name] list.c [type] 1 [path] ../Middlewares/Third_Party/FreeRTOS/Source/list.c
|
||||||
|
[old name] queue.c [type] 1 [path] ../Middlewares/Third_Party/FreeRTOS/Source/queue.c
|
||||||
|
[old name] stream_buffer.c [type] 1 [path] ../Middlewares/Third_Party/FreeRTOS/Source/stream_buffer.c
|
||||||
|
[old name] tasks.c [type] 1 [path] ../Middlewares/Third_Party/FreeRTOS/Source/tasks.c
|
||||||
|
[old name] timers.c [type] 1 [path] ../Middlewares/Third_Party/FreeRTOS/Source/timers.c
|
||||||
|
[old name] cmsis_os2.c [type] 1 [path] ../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.c
|
||||||
|
[old name] heap_4.c [type] 1 [path] ../Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/heap_4.c
|
||||||
|
[old name] port.c [type] 1 [path] ../Middlewares/Third_Party/FreeRTOS/Source/portable/RVDS/ARM_CM3/port.c
|
||||||
[old name] CH390.c [type] 1 [path] ..\Drivers\CH390\CH390.c
|
[old name] CH390.c [type] 1 [path] ..\Drivers\CH390\CH390.c
|
||||||
[old name] CH390_Interface.c [type] 1 [path] ..\Drivers\CH390\CH390_Interface.c
|
[old name] CH390_Interface.c [type] 1 [path] ..\Drivers\CH390\CH390_Interface.c
|
||||||
[old name] ch390_runtime.c [type] 1 [path] ..\Drivers\CH390\ch390_runtime.c
|
[old name] altcp.c [type] 1 [path] ..\Drivers\LwIP\src\core\altcp.c
|
||||||
|
[old name] altcp_alloc.c [type] 1 [path] ..\Drivers\LwIP\src\core\altcp_alloc.c
|
||||||
|
[old name] altcp_tcp.c [type] 1 [path] ..\Drivers\LwIP\src\core\altcp_tcp.c
|
||||||
[old name] def.c [type] 1 [path] ..\Drivers\LwIP\src\core\def.c
|
[old name] def.c [type] 1 [path] ..\Drivers\LwIP\src\core\def.c
|
||||||
|
[old name] dns.c [type] 1 [path] ..\Drivers\LwIP\src\core\dns.c
|
||||||
[old name] inet_chksum.c [type] 1 [path] ..\Drivers\LwIP\src\core\inet_chksum.c
|
[old name] inet_chksum.c [type] 1 [path] ..\Drivers\LwIP\src\core\inet_chksum.c
|
||||||
[old name] init.c [type] 1 [path] ..\Drivers\LwIP\src\core\init.c
|
[old name] init.c [type] 1 [path] ..\Drivers\LwIP\src\core\init.c
|
||||||
[old name] ip.c [type] 1 [path] ..\Drivers\LwIP\src\core\ip.c
|
[old name] ip.c [type] 1 [path] ..\Drivers\LwIP\src\core\ip.c
|
||||||
@@ -144,93 +175,125 @@
|
|||||||
[old name] tcp_out.c [type] 1 [path] ..\Drivers\LwIP\src\core\tcp_out.c
|
[old name] tcp_out.c [type] 1 [path] ..\Drivers\LwIP\src\core\tcp_out.c
|
||||||
[old name] timeouts.c [type] 1 [path] ..\Drivers\LwIP\src\core\timeouts.c
|
[old name] timeouts.c [type] 1 [path] ..\Drivers\LwIP\src\core\timeouts.c
|
||||||
[old name] udp.c [type] 1 [path] ..\Drivers\LwIP\src\core\udp.c
|
[old name] udp.c [type] 1 [path] ..\Drivers\LwIP\src\core\udp.c
|
||||||
|
[old name] acd.c [type] 1 [path] ..\Drivers\LwIP\src\core\ipv4\acd.c
|
||||||
|
[old name] autoip.c [type] 1 [path] ..\Drivers\LwIP\src\core\ipv4\autoip.c
|
||||||
|
[old name] dhcp.c [type] 1 [path] ..\Drivers\LwIP\src\core\ipv4\dhcp.c
|
||||||
[old name] etharp.c [type] 1 [path] ..\Drivers\LwIP\src\core\ipv4\etharp.c
|
[old name] etharp.c [type] 1 [path] ..\Drivers\LwIP\src\core\ipv4\etharp.c
|
||||||
[old name] icmp.c [type] 1 [path] ..\Drivers\LwIP\src\core\ipv4\icmp.c
|
[old name] icmp.c [type] 1 [path] ..\Drivers\LwIP\src\core\ipv4\icmp.c
|
||||||
|
[old name] igmp.c [type] 1 [path] ..\Drivers\LwIP\src\core\ipv4\igmp.c
|
||||||
[old name] ip4.c [type] 1 [path] ..\Drivers\LwIP\src\core\ipv4\ip4.c
|
[old name] ip4.c [type] 1 [path] ..\Drivers\LwIP\src\core\ipv4\ip4.c
|
||||||
[old name] ip4_addr.c [type] 1 [path] ..\Drivers\LwIP\src\core\ipv4\ip4_addr.c
|
[old name] ip4_addr.c [type] 1 [path] ..\Drivers\LwIP\src\core\ipv4\ip4_addr.c
|
||||||
[old name] ip4_frag.c [type] 1 [path] ..\Drivers\LwIP\src\core\ipv4\ip4_frag.c
|
[old name] ip4_frag.c [type] 1 [path] ..\Drivers\LwIP\src\core\ipv4\ip4_frag.c
|
||||||
|
[old name] api_lib.c [type] 1 [path] ..\Drivers\LwIP\src\api\api_lib.c
|
||||||
|
[old name] api_msg.c [type] 1 [path] ..\Drivers\LwIP\src\api\api_msg.c
|
||||||
|
[old name] err.c [type] 1 [path] ..\Drivers\LwIP\src\api\err.c
|
||||||
|
[old name] if_api.c [type] 1 [path] ..\Drivers\LwIP\src\api\if_api.c
|
||||||
|
[old name] netbuf.c [type] 1 [path] ..\Drivers\LwIP\src\api\netbuf.c
|
||||||
|
[old name] netdb.c [type] 1 [path] ..\Drivers\LwIP\src\api\netdb.c
|
||||||
|
[old name] netifapi.c [type] 1 [path] ..\Drivers\LwIP\src\api\netifapi.c
|
||||||
|
[old name] sockets.c [type] 1 [path] ..\Drivers\LwIP\src\api\sockets.c
|
||||||
|
[old name] tcpip.c [type] 1 [path] ..\Drivers\LwIP\src\api\tcpip.c
|
||||||
[old name] ethernet.c [type] 1 [path] ..\Drivers\LwIP\src\netif\ethernet.c
|
[old name] ethernet.c [type] 1 [path] ..\Drivers\LwIP\src\netif\ethernet.c
|
||||||
[old name] ethernetif.c [type] 1 [path] ..\Drivers\LwIP\src\netif\ethernetif.c
|
[old name] ethernetif.c [type] 1 [path] ..\Drivers\LwIP\src\netif\ethernetif.c
|
||||||
|
[old name] sys_arch.c [type] 1 [path] ..\Drivers\LwIP\port\sys_arch.c
|
||||||
|
[old name] SEGGER_RTT.c [type] 1 [path] ..\Drivers\SEGGER\RTT\SEGGER_RTT.c
|
||||||
[old name] config.c [type] 1 [path] ..\App\config.c
|
[old name] config.c [type] 1 [path] ..\App\config.c
|
||||||
[old name] flash_param.c [type] 1 [path] ..\App\flash_param.c
|
[old name] flash_param.c [type] 1 [path] ..\App\flash_param.c
|
||||||
|
[old name] route_msg.c [type] 1 [path] ..\App\route_msg.c
|
||||||
|
[old name] task_net_poll.c [type] 1 [path] ..\App\task_net_poll.c
|
||||||
[old name] tcp_client.c [type] 1 [path] ..\App\tcp_client.c
|
[old name] tcp_client.c [type] 1 [path] ..\App\tcp_client.c
|
||||||
[old name] tcp_server.c [type] 1 [path] ..\App\tcp_server.c
|
[old name] tcp_server.c [type] 1 [path] ..\App\tcp_server.c
|
||||||
[old name] uart_trans.c [type] 1 [path] ..\App\uart_trans.c
|
[old name] uart_trans.c [type] 1 [path] ..\App\uart_trans.c
|
||||||
[old name] SEGGER_RTT.c [type] 1 [path] ..\Middlewares\Third_Party\SEGGER_RTT\SEGGER_RTT.c
|
|
||||||
[old name] SEGGER_RTT_printf.c [type] 1 [path] ..\Middlewares\Third_Party\SEGGER_RTT\SEGGER_RTT_printf.c
|
|
||||||
|
|
||||||
[record region info]
|
[record region info]
|
||||||
[load region] LR_IROM1
|
[load region] LR_IROM1
|
||||||
[execution region] ER_IROM1, 0x08000000, 0x00010000, 0x0000D178 [type] 2 [ID] 3
|
[execution region] ER_IROM1, 0x08000000, 0x00040000, 0x000152E8 [type] 2 [ID] 3
|
||||||
[execution region] RW_IRAM1, 0x20000000, 0x00005000, 0x00004FF8 [type] 1 [ID] 2
|
[execution region] RW_IRAM1, 0x20000000, 0x0000C000, 0x0000B980 [type] 1 [ID] 2
|
||||||
---------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------------------------------------------------
|
||||||
FILE(s) | RAM (byte) | FLASH (byte) |
|
FILE(s) | RAM (byte) | FLASH (byte) |
|
||||||
---------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------------------------------------------------
|
||||||
ch390.o | 0 | 590 |
|
..\Drivers\LwIP\src\core\altcp.c(): | 0 | 0 |
|
||||||
ch390_interface.o | 0 | 680 |
|
..\Drivers\LwIP\src\api\api_lib.c(): | 0 | 2110 |
|
||||||
ch390_runtime.o | 91 | 1534 |
|
..\Drivers\LwIP\src\api\api_msg.c(): | 0 | 5997 |
|
||||||
config.o | 1248 | 4289 |
|
..\Drivers\CH390\CH390.c(): | 0 | 630 [+20] |
|
||||||
def.o | 0 | 8 |
|
..\Drivers\CH390\CH390_Interface.c(): | 0 | 708 |
|
||||||
dma.o | 0 | 124 |
|
../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.c(): | 1732 | 142 |
|
||||||
etharp.o | 241 | 1773 |
|
..\App\config.c(): | 254 | 4220 |
|
||||||
ethernet.o | 0 | 250 |
|
../Core/Src/debug_log.c(): | 12 | 290 |
|
||||||
ethernetif.o | 48 | 178 |
|
..\Drivers\LwIP\src\core\def.c(): | 0 | 8 |
|
||||||
flash_param.o | 0 | 246 |
|
../Core/Src/dma.c(): | 0 | 124 |
|
||||||
gpio.o | 0 | 240 |
|
..\Drivers\LwIP\src\core\ipv4\etharp.c(): | 241 | 2826 |
|
||||||
icmp.o | 0 | 452 |
|
..\Drivers\LwIP\src\netif\ethernet.c(): | 0 | 444 |
|
||||||
inet_chksum.o | 0 | 334 |
|
..\Drivers\LwIP\src\netif\ethernetif.c(): | 3132 | 1396 [+68] |
|
||||||
init.o | 0 | 26 |
|
../Middlewares/Third_Party/FreeRTOS/Source/event_groups.c(): | 0 | 0 |
|
||||||
ip.o | 24 | 0 |
|
..\App\flash_param.c(): | 1025 | 331 |
|
||||||
ip4.o | 2 | 780 |
|
../Core/Src/freertos.c(): | 88 | 1570 [+4] |
|
||||||
ip4_addr.o | 0 | 50 |
|
../Core/Src/gpio.c(): | 0 | 204 |
|
||||||
iwdg.o | 12 | 0 |
|
../Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/heap_4.c(): | 15392 | 528 |
|
||||||
main.o | 278 | 2937 |
|
..\Drivers\LwIP\src\core\ipv4\icmp.c(): | 0 | 712 |
|
||||||
mem.o | 4127 | 840 |
|
..\Drivers\LwIP\src\core\inet_chksum.c(): | 0 | 334 |
|
||||||
memp.o | 6496 | 472 |
|
..\Drivers\LwIP\src\core\init.c(): | 0 | 30 |
|
||||||
netif.o | 12 | 594 |
|
..\Drivers\LwIP\src\core\ip.c(): | 24 | 0 |
|
||||||
pbuf.o | 0 | 1118 |
|
..\Drivers\LwIP\src\core\ipv4\ip4.c(): | 2 | 896 |
|
||||||
raw.o | 4 | 252 |
|
..\Drivers\LwIP\src\core\ipv4\ip4_addr.c(): | 0 | 50 |
|
||||||
segger_rtt.o | 440 | 391 |
|
../Core/Src/iwdg.c(): | 12 | 44 |
|
||||||
segger_rtt_printf.o | 0 | 64 |
|
../Middlewares/Third_Party/FreeRTOS/Source/list.c(): | 0 | 138 |
|
||||||
spi.o | 88 | 216 |
|
../Core/Src/main.c(): | 0 | 382 |
|
||||||
startup_stm32f103xb.o | 1024 | 296 |
|
..\Drivers\LwIP\src\core\mem.c(): | 7203 | 1876 |
|
||||||
stm32f1xx_hal.o | 12 | 140 |
|
..\Drivers\LwIP\src\core\memp.c(): | 7244 | 851 |
|
||||||
stm32f1xx_hal_cortex.o | 0 | 198 |
|
..\Drivers\LwIP\src\api\netbuf.c(): | 0 | 246 |
|
||||||
stm32f1xx_hal_dma.o | 0 | 808 |
|
..\Drivers\LwIP\src\core\netif.c(): | 12 | 1090 |
|
||||||
stm32f1xx_hal_flash.o | 32 | 392 |
|
..\Drivers\LwIP\src\api\netifapi.c(): | 0 | 140 |
|
||||||
stm32f1xx_hal_flash_ex.o | 0 | 240 |
|
..\Drivers\LwIP\src\core\pbuf.c(): | 0 | 2654 |
|
||||||
stm32f1xx_hal_gpio.o | 0 | 516 |
|
../Middlewares/Third_Party/FreeRTOS/Source/portable/RVDS/ARM_CM3/port.c(): | 12 | 674 |
|
||||||
stm32f1xx_hal_iwdg.o | 0 | 12 |
|
../Middlewares/Third_Party/FreeRTOS/Source/queue.c(): | 64 | 2404 |
|
||||||
stm32f1xx_hal_msp.o | 0 | 60 |
|
..\Drivers\LwIP\src\core\raw.c(): | 4 | 517 |
|
||||||
stm32f1xx_hal_rcc.o | 0 | 1258 |
|
../Core/Src/retarget_rtt.c(): | 0 | 140 |
|
||||||
stm32f1xx_hal_spi.o | 0 | 1510 |
|
..\App\route_msg.c(): | 4224 | 496 |
|
||||||
stm32f1xx_hal_tim.o | 0 | 936 |
|
..\Drivers\SEGGER\RTT\SEGGER_RTT.c(): | 600 | 463 |
|
||||||
stm32f1xx_hal_tim_ex.o | 0 | 108 |
|
../Core/Src/spi.c(): | 88 | 200 |
|
||||||
stm32f1xx_hal_uart.o | 0 | 2300 |
|
startup_stm32f103xe.s(): | 2560 | 368 |
|
||||||
stm32f1xx_it.o | 0 | 490 |
|
../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal.c(): | 12 | 112 |
|
||||||
system_stm32f1xx.o | 4 | 30 |
|
../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_cortex.c(): | 0 | 158 |
|
||||||
tcp.o | 32 | 3699 |
|
../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_dma.c(): | 0 | 1236 |
|
||||||
tcp_client.o | 1120 | 1216 |
|
../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_flash.c(): | 32 | 392 |
|
||||||
tcp_in.o | 56 | 3720 |
|
../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_flash_ex.c(): | 0 | 240 |
|
||||||
tcp_out.o | 0 | 3862 |
|
../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_gpio.c(): | 0 | 530 |
|
||||||
tcp_server.o | 1104 | 962 |
|
../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_iwdg.c(): | 0 | 106 |
|
||||||
tim.o | 72 | 164 |
|
../Core/Src/stm32f1xx_hal_msp.c(): | 0 | 72 |
|
||||||
timeouts.o | 12 | 402 |
|
../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc.c(): | 0 | 1322 |
|
||||||
uart_trans.o | 2936 | 1268 |
|
../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_spi.c(): | 0 | 1152 |
|
||||||
usart.o | 624 | 816 |
|
../Core/Src/stm32f1xx_hal_timebase_tim.c(): | 0 | 128 |
|
||||||
---------------------------------------------------------------------------------
|
../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_uart.c(): | 0 | 2222 |
|
||||||
|
../Core/Src/stm32f1xx_it.c(): | 0 | 484 |
|
||||||
|
../Middlewares/Third_Party/FreeRTOS/Source/stream_buffer.c(): | 0 | 0 |
|
||||||
|
..\Drivers\LwIP\port\sys_arch.c(): | 0 | 378 |
|
||||||
|
../Core/Src/system_stm32f1xx.c(): | 4 | 30 |
|
||||||
|
..\App\task_net_poll.c(): | 0 | 792 |
|
||||||
|
../Middlewares/Third_Party/FreeRTOS/Source/tasks.c(): | 300 | 3062 |
|
||||||
|
..\Drivers\LwIP\src\core\tcp.c(): | 32 | 7121 |
|
||||||
|
..\App\tcp_client.c(): | 0 | 552 [+140] |
|
||||||
|
..\Drivers\LwIP\src\core\tcp_in.c(): | 56 | 5296 |
|
||||||
|
..\Drivers\LwIP\src\core\tcp_out.c(): | 0 | 7619 |
|
||||||
|
..\App\tcp_server.c(): | 0 | 416 [+64] |
|
||||||
|
..\Drivers\LwIP\src\api\tcpip.c(): | 16 | 784 |
|
||||||
|
..\Drivers\LwIP\src\core\timeouts.c(): | 12 | 656 |
|
||||||
|
../Middlewares/Third_Party/FreeRTOS/Source/timers.c(): | 300 | 992 |
|
||||||
|
..\App\uart_trans.c(): | 1576 | 1990 |
|
||||||
|
../Core/Src/usart.c(): | 624 | 816 |
|
||||||
|
-----------------------------------------------------------------------------------------------------------------------------------
|
||||||
[memory print mode]: 0
|
[memory print mode]: 0
|
||||||
LR_IROM1
|
LR_IROM1
|
||||||
RAM 1 [0x20000000 | 0x00005000 (20480)]
|
RAM 1 [0x20000000 | 0x0000C000 (49152)]
|
||||||
[zi start] 1 [zi end] 49
|
[zi start] 1 [zi end] 48
|
||||||
RW_IRAM1 [0x20000000]|¡ö¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ_| ( 19.9 KB / 20.0 KB ) 100.0%
|
RW_IRAM1 [0x20000000]|¡ö¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ¡õ__| ( 46.3 KB / 48.0 KB ) 96.6%
|
||||||
|
|
||||||
FLASH 1 [0x08000000 | 0x00010000 (65536)]
|
FLASH 1 [0x08000000 | 0x00040000 (262144)]
|
||||||
ER_IROM1 [0x08000000]|¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö__________| ( 52.3 KB / 64.0 KB ) 81.8%
|
ER_IROM1 [0x08000000]|¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö¡ö__________________________________| ( 85.0 KB / 256.0 KB ) 33.2% [+296]
|
||||||
|
|
||||||
[htm file path] D:\code\STM32Project\TCP2UART\MDK-ARM\TCP2UART\TCP2UART.htm
|
[htm file path] D:\code\STM32Project\TCP2UART\MDK-ARM\TCP2UART\TCP2UART.htm
|
||||||
Maximum Stack Usage = 968 bytes + Unknown(Functions without stacksize, Cycles, Untraceable Function Pointers)
|
Maximum Stack Usage = 1488 bytes + Unknown(Functions without stacksize, Cycles, Untraceable Function Pointers)
|
||||||
|
|
||||||
=============================================================================================================================
|
=============================================================================================================================
|
||||||
|
|
||||||
run time: 0.179 s
|
run time: 0.231 s
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ __initial_sp
|
|||||||
; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
|
; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
|
||||||
; </h>
|
; </h>
|
||||||
|
|
||||||
Heap_Size EQU 0x0
|
Heap_Size EQU 0x400
|
||||||
|
|
||||||
AREA HEAP, NOINIT, READWRITE, ALIGN=3
|
AREA HEAP, NOINIT, READWRITE, ALIGN=3
|
||||||
__heap_base
|
__heap_base
|
||||||
|
|||||||
@@ -290,19 +290,28 @@
|
|||||||
#error "Definition configUSE_16_BIT_TICKS must be zero to implement CMSIS-RTOS2 API."
|
#error "Definition configUSE_16_BIT_TICKS must be zero to implement CMSIS-RTOS2 API."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (configMAX_PRIORITIES != 56)
|
#if 0 && (configMAX_PRIORITIES != 56)
|
||||||
/*
|
/*
|
||||||
CMSIS-RTOS2 defines 56 different priorities (see osPriority_t) and portable CMSIS-RTOS2
|
CMSIS-RTOS2 defines 56 different priorities (see osPriority_t) and portable CMSIS-RTOS2
|
||||||
implementation should implement the same number of priorities.
|
implementation should implement the same number of priorities.
|
||||||
Set #define configMAX_PRIORITIES 56 to fix this error.
|
Set #define configMAX_PRIORITIES 56 to fix this error.
|
||||||
|
|
||||||
|
TCP2UART project note:
|
||||||
|
This firmware creates application tasks with native FreeRTOS APIs and intentionally
|
||||||
|
runs with configMAX_PRIORITIES = 7. Keep this wrapper-side check disabled during
|
||||||
|
phase-1 bring-up instead of forcing the whole project into the CMSIS priority model.
|
||||||
*/
|
*/
|
||||||
#error "Definition configMAX_PRIORITIES must equal 56 to implement Thread Management API."
|
#error "Definition configMAX_PRIORITIES must equal 56 to implement Thread Management API."
|
||||||
#endif
|
#endif
|
||||||
#if (configUSE_PORT_OPTIMISED_TASK_SELECTION != 0)
|
#if 0 && (configUSE_PORT_OPTIMISED_TASK_SELECTION != 0)
|
||||||
/*
|
/*
|
||||||
CMSIS-RTOS2 requires handling of 56 different priorities (see osPriority_t) while FreeRTOS port
|
CMSIS-RTOS2 requires handling of 56 different priorities (see osPriority_t) while FreeRTOS port
|
||||||
optimised selection for Cortex core only handles 32 different priorities.
|
optimised selection for Cortex core only handles 32 different priorities.
|
||||||
Set #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 to fix this error.
|
Set #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 to fix this error.
|
||||||
|
|
||||||
|
TCP2UART project note:
|
||||||
|
This check remains disabled together with the 56-priority requirement above because
|
||||||
|
the project does not rely on CMSIS thread-priority compatibility semantics.
|
||||||
*/
|
*/
|
||||||
#error "Definition configUSE_PORT_OPTIMISED_TASK_SELECTION must be zero to implement Thread Management API."
|
#error "Definition configUSE_PORT_OPTIMISED_TASK_SELECTION must be zero to implement Thread Management API."
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+8
-8
@@ -70,11 +70,11 @@ FREERTOS.configCHECK_FOR_STACK_OVERFLOW=2
|
|||||||
FREERTOS.configMAX_PRIORITIES=7
|
FREERTOS.configMAX_PRIORITIES=7
|
||||||
FREERTOS.configMINIMAL_STACK_SIZE=128
|
FREERTOS.configMINIMAL_STACK_SIZE=128
|
||||||
FREERTOS.configSUPPORT_DYNAMIC_ALLOCATION=1
|
FREERTOS.configSUPPORT_DYNAMIC_ALLOCATION=1
|
||||||
FREERTOS.configSUPPORT_STATIC_ALLOCATION=0
|
FREERTOS.configSUPPORT_STATIC_ALLOCATION=1
|
||||||
FREERTOS.configTICK_RATE_HZ=1000
|
FREERTOS.configTICK_RATE_HZ=1000
|
||||||
FREERTOS.configTOTAL_HEAP_SIZE=10240
|
FREERTOS.configTOTAL_HEAP_SIZE=15360
|
||||||
FREERTOS.configUSE_COUNTING_SEMAPHORES=1
|
FREERTOS.configUSE_COUNTING_SEMAPHORES=1
|
||||||
FREERTOS.configUSE_IDLE_HOOK=0
|
FREERTOS.configUSE_IDLE_HOOK=1
|
||||||
FREERTOS.configUSE_MALLOC_FAILED_HOOK=1
|
FREERTOS.configUSE_MALLOC_FAILED_HOOK=1
|
||||||
FREERTOS.configUSE_MUTEXES=1
|
FREERTOS.configUSE_MUTEXES=1
|
||||||
FREERTOS.configUSE_PREEMPTION=1
|
FREERTOS.configUSE_PREEMPTION=1
|
||||||
@@ -83,7 +83,7 @@ FREERTOS.configUSE_TICK_HOOK=0
|
|||||||
File.Version=6
|
File.Version=6
|
||||||
GPIO.groupedBy=Group By Peripherals
|
GPIO.groupedBy=Group By Peripherals
|
||||||
KeepUserPlacement=false
|
KeepUserPlacement=false
|
||||||
Mcu.CPN=STM32F103RCT6
|
Mcu.CPN=STM32F103RDT6
|
||||||
Mcu.Family=STM32F1
|
Mcu.Family=STM32F1
|
||||||
Mcu.IP0=DMA
|
Mcu.IP0=DMA
|
||||||
Mcu.IP1=FREERTOS
|
Mcu.IP1=FREERTOS
|
||||||
@@ -123,7 +123,7 @@ Mcu.Pin20=VP_TIM4_VS_ClockSourceINT
|
|||||||
Mcu.PinsNb=21
|
Mcu.PinsNb=21
|
||||||
Mcu.ThirdPartyNb=0
|
Mcu.ThirdPartyNb=0
|
||||||
Mcu.UserConstants=
|
Mcu.UserConstants=
|
||||||
Mcu.UserName=STM32F103RCTx
|
Mcu.UserName=STM32F103RDTx
|
||||||
MxCube.Version=6.16.1
|
MxCube.Version=6.16.1
|
||||||
MxDb.Version=DB.6.0.161
|
MxDb.Version=DB.6.0.161
|
||||||
NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||||
@@ -182,7 +182,7 @@ PC13-TAMPER-RTC.Signal=GPIO_Output
|
|||||||
PCC.Checker=false
|
PCC.Checker=false
|
||||||
PCC.Line=STM32F103
|
PCC.Line=STM32F103
|
||||||
PCC.MCU=STM32F103R(C-D-E)Tx
|
PCC.MCU=STM32F103R(C-D-E)Tx
|
||||||
PCC.PartNumber=STM32F103RCTx
|
PCC.PartNumber=STM32F103RDTx
|
||||||
PCC.Series=STM32F1
|
PCC.Series=STM32F1
|
||||||
PCC.Temperature=25
|
PCC.Temperature=25
|
||||||
PCC.Vdd=3.3
|
PCC.Vdd=3.3
|
||||||
@@ -200,12 +200,12 @@ ProjectManager.CoupleFile=true
|
|||||||
ProjectManager.CustomerFirmwarePackage=
|
ProjectManager.CustomerFirmwarePackage=
|
||||||
ProjectManager.DefaultFWLocation=true
|
ProjectManager.DefaultFWLocation=true
|
||||||
ProjectManager.DeletePrevious=true
|
ProjectManager.DeletePrevious=true
|
||||||
ProjectManager.DeviceId=STM32F103RCTx
|
ProjectManager.DeviceId=STM32F103RDTx
|
||||||
ProjectManager.FirmwarePackage=STM32Cube FW_F1 V1.8.7
|
ProjectManager.FirmwarePackage=STM32Cube FW_F1 V1.8.7
|
||||||
ProjectManager.FreePins=false
|
ProjectManager.FreePins=false
|
||||||
ProjectManager.FreePinsContext=
|
ProjectManager.FreePinsContext=
|
||||||
ProjectManager.HalAssertFull=false
|
ProjectManager.HalAssertFull=false
|
||||||
ProjectManager.HeapSize=0x200
|
ProjectManager.HeapSize=0x400
|
||||||
ProjectManager.KeepUserCode=true
|
ProjectManager.KeepUserCode=true
|
||||||
ProjectManager.LastFirmware=true
|
ProjectManager.LastFirmware=true
|
||||||
ProjectManager.LibraryCopy=0
|
ProjectManager.LibraryCopy=0
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
=================================================== keil-build-viewer v1.6 ==================================================
|
||||||
|
|
||||||
|
[User input]
|
||||||
|
[Current folder] D:\code\STM32Project\TCP2UART
|
||||||
|
[Encoding] 936
|
||||||
|
|
||||||
|
[ERROR] NO keil project found
|
||||||
|
[ERROR] Please check:
|
||||||
|
=============================================================================================================================
|
||||||
|
|
||||||
|
run time: 0.000 s
|
||||||
@@ -0,0 +1,208 @@
|
|||||||
|
# TCP2UART 调试交接清单
|
||||||
|
|
||||||
|
## 1. 文档目的
|
||||||
|
|
||||||
|
本清单用于把当前 `TCP2UART` 工程的调试状态、已验证结论、后续动作建议一次性交接给下一位 agent 或开发者。
|
||||||
|
|
||||||
|
这份文档本身就可以当作下一位 agent 的工作 prompt 使用。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 先读哪些文档
|
||||||
|
|
||||||
|
接手本工程后,推荐按以下顺序阅读:
|
||||||
|
|
||||||
|
1. `交接清单.md` —— 当前状态、下一步、禁止回退到哪些旧假设
|
||||||
|
2. `工程调试指南.md` —— 已固化的调试经验与真实工程边界
|
||||||
|
3. `项目技术实现.md` —— 架构、任务模型、协议模型
|
||||||
|
4. `项目需求说明.md` —— 用户需求与协议要求
|
||||||
|
5. `AT固件使用手册.md` —— AT 命令与配置面
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 当前工程状态(交接时刻)
|
||||||
|
|
||||||
|
### 3.1 当前平台与构建状态
|
||||||
|
|
||||||
|
1. 当前 Keil 工程目标仍是 `STM32F103RC`
|
||||||
|
2. 当前代码可以真实构建通过
|
||||||
|
3. 当前构建真值应查看:
|
||||||
|
- `MDK-ARM/build_capture.txt`
|
||||||
|
- `MDK-ARM/TCP2UART/TCP2UART.build_log.htm`
|
||||||
|
- `MDK-ARM/TCP2UART/TCP2UART.map`
|
||||||
|
4. 最近一次 Keil 构建示例:
|
||||||
|
- `Code=84560`
|
||||||
|
- `RW-data=432`
|
||||||
|
- `ZI-data=47056`
|
||||||
|
- `0 Error(s), 0 Warning(s)`
|
||||||
|
|
||||||
|
### 3.2 当前调试结论摘要
|
||||||
|
|
||||||
|
1. `DIAG_TASK_ISOLATION=1` 稳定
|
||||||
|
2. `DIAG_TASK_ISOLATION=0` 仍会卡死
|
||||||
|
3. 卡死边界已经从更早的启动阶段被推进到更靠后的 enabled `netconn_*` 路径
|
||||||
|
4. 在 `RCT6` 上,四个 TCP task 创建后 `FreeRTOS heap` 仅剩约 `944 bytes`
|
||||||
|
5. 这说明当前 `RCT6` 上的资源余量已经严重干扰调试判断
|
||||||
|
6. 因此当前推荐策略是:**先换到 pin2pin 的 `STM32F103RDT6`,再继续 full-task 调试**
|
||||||
|
|
||||||
|
### 3.3 已做过并有信息量的改动/观察
|
||||||
|
|
||||||
|
以下工作已经做过,不要在没有新理由的情况下重复一遍:
|
||||||
|
|
||||||
|
1. 清理与恢复 `DIAG_TASK_ISOLATION=0`
|
||||||
|
2. 用真实 Keil 日志替代 viewer 作为构建真值
|
||||||
|
3. staged creation:将四个 TCP task 延后到 `netif-ready` 后创建
|
||||||
|
4. `lwIP netif` 初始化、post-init、post-ready 关键 RTT 日志
|
||||||
|
5. CH390 TX bounded wait / timeout 观察
|
||||||
|
6. TCP task 栈从 `256` 提高到 `384 words`
|
||||||
|
7. TCP task 入口 `hwm` 日志
|
||||||
|
8. 对 `C1` 增加 one-shot first-connect defer discriminator
|
||||||
|
|
||||||
|
这些动作都让故障边界后移了,但仍未在 `RCT6` 上把问题彻底消灭。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 当前最可信的判断
|
||||||
|
|
||||||
|
当前最可信的判断不是“某一行代码单点必错”,而是:
|
||||||
|
|
||||||
|
1. `RCT6` 上的静态 RAM 占用与 FreeRTOS heap 余量都已经接近极限
|
||||||
|
2. disabled 的 task 可以持续打印,说明调度器与基础日志路径未整体死亡
|
||||||
|
3. enabled 的 `S1 / C1` 一旦进入真实 `netconn_*` 路径,就更容易触发新的运行期问题
|
||||||
|
4. 因此如果继续在 `RCT6` 上做更多 discriminator,很容易一直被资源边界噪声带偏
|
||||||
|
|
||||||
|
换句话说,**先把“内存极限平台”这个干扰项拿掉,再看逻辑问题还剩多少,是当前性价比最高的路线。**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 下一位 agent 现在应该做什么
|
||||||
|
|
||||||
|
### 5.1 第一目标
|
||||||
|
|
||||||
|
先完成 `STM32F103RCT6 -> STM32F103RDT6` 的工程切换,然后在**尽量不再改业务逻辑**的前提下复现当前版本。
|
||||||
|
|
||||||
|
### 5.2 为什么先这样做
|
||||||
|
|
||||||
|
因为下一位 agent 最先需要回答的,不是“立刻怎么修”,而是:
|
||||||
|
|
||||||
|
1. 换片后 full-task 模式是否还挂
|
||||||
|
2. 如果还挂,挂点是否后移
|
||||||
|
3. 换片后 `free/min heap` 是否显著改善
|
||||||
|
4. enabled `S1 / C1` 是否能进入更深的 `netconn_*` 路径
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 下一位 agent 的推荐工作步骤
|
||||||
|
|
||||||
|
### Step 1:切换目标器件到 `STM32F103RDT6`
|
||||||
|
|
||||||
|
建议动作:
|
||||||
|
|
||||||
|
1. 更新 Keil target 里的 device 选择
|
||||||
|
2. 对齐 Flash / RAM 容量描述
|
||||||
|
3. 确认 linker / scatter / startup 相关目标描述与新器件一致
|
||||||
|
4. 再次真实构建,确认 `0 Error(s), 0 Warning(s)`
|
||||||
|
|
||||||
|
### Step 2:保持当前代码基线,直接上板复测
|
||||||
|
|
||||||
|
要求:
|
||||||
|
|
||||||
|
1. 不要一换片就继续改业务逻辑
|
||||||
|
2. 使用当前代码基线直接验证
|
||||||
|
3. 仍以 `build_capture.txt` 和 RTT 为主证据
|
||||||
|
|
||||||
|
### Step 3:收集第一轮换片后的关键证据
|
||||||
|
|
||||||
|
至少记录:
|
||||||
|
|
||||||
|
1. `netif-ready` 后是否仍卡死
|
||||||
|
2. `free/min heap` 变化
|
||||||
|
3. enabled `S1 / C1` 的新 RTT 行为
|
||||||
|
4. `C1 first-connect defer` 是否仍然影响故障边界
|
||||||
|
5. LED 心跳和 IWDG 表现是否变化
|
||||||
|
|
||||||
|
### Step 4:根据换片结果分流
|
||||||
|
|
||||||
|
#### 情况 A:换片后明显稳定 / 不再挂
|
||||||
|
|
||||||
|
说明:
|
||||||
|
|
||||||
|
1. RAM 压力是主要阻碍项之一
|
||||||
|
2. 后续需要回头做“资源预算收敛”,而不是继续把当前临时参数直接当最终方案
|
||||||
|
|
||||||
|
#### 情况 B:换片后仍挂,但更晚 / 更深
|
||||||
|
|
||||||
|
说明:
|
||||||
|
|
||||||
|
1. 当前逻辑问题仍在
|
||||||
|
2. 但已经去掉了最主要的资源噪声
|
||||||
|
3. 这时再围绕 `S1 / C1` 的真实 `netconn_new / bind / connect / listen / accept` 做最小日志/判别,会更有信息量
|
||||||
|
|
||||||
|
#### 情况 C:换片后几乎同点位仍挂
|
||||||
|
|
||||||
|
说明:
|
||||||
|
|
||||||
|
1. 主问题不再是单纯 RAM
|
||||||
|
2. 应优先检查 enabled 路径的 API 使用、阻塞行为、线程间交互与资源释放
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 不要重复的方向
|
||||||
|
|
||||||
|
下一位 agent 接手后,除非有新证据,否则不要优先回到以下旧方向:
|
||||||
|
|
||||||
|
1. 单纯怀疑 startup/init 早期 bring-up
|
||||||
|
2. 把 viewer 当构建真值
|
||||||
|
3. 继续只靠加大 TCP task 栈来解释所有现象
|
||||||
|
4. 默认把 CH390 TX timeout 当成当前一号嫌疑
|
||||||
|
5. 在 `RCT6` 上继续大量增加日志、队列、栈或临时 buffer
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 关键文件
|
||||||
|
|
||||||
|
### 构建/目标
|
||||||
|
|
||||||
|
1. `MDK-ARM/TCP2UART.uvprojx`
|
||||||
|
2. `MDK-ARM/build_capture.txt`
|
||||||
|
3. `MDK-ARM/TCP2UART/TCP2UART.build_log.htm`
|
||||||
|
4. `MDK-ARM/TCP2UART/TCP2UART.map`
|
||||||
|
|
||||||
|
### 任务与运行期
|
||||||
|
|
||||||
|
1. `Core/Inc/FreeRTOSConfig.h`
|
||||||
|
2. `Core/Src/freertos.c`
|
||||||
|
3. `App/task_net_poll.c`
|
||||||
|
4. `App/tcp_server.c`
|
||||||
|
5. `App/tcp_client.c`
|
||||||
|
|
||||||
|
### 网络与驱动
|
||||||
|
|
||||||
|
1. `Drivers/LwIP/src/netif/ethernetif.c`
|
||||||
|
2. `Drivers/CH390/CH390.c`
|
||||||
|
3. `Drivers/CH390/CH390.h`
|
||||||
|
|
||||||
|
### 文档
|
||||||
|
|
||||||
|
1. `工程调试指南.md`
|
||||||
|
2. `项目技术实现.md`
|
||||||
|
3. `交接清单.md`
|
||||||
|
4. `CODING_PROMPT.md`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. 可直接给下一位 agent 的 Prompt
|
||||||
|
|
||||||
|
下面这段文字可以直接作为下一位 agent 的起始 prompt:
|
||||||
|
|
||||||
|
```text
|
||||||
|
请先阅读:`交接清单.md`、`工程调试指南.md`、`项目技术实现.md`。
|
||||||
|
|
||||||
|
当前项目是 STM32F103 + FreeRTOS + lwIP + CH390 的 TCP↔UART 透传工程。此前在 `STM32F103RCT6` 上调试时,`DIAG_TASK_ISOLATION=1` 稳定,`DIAG_TASK_ISOLATION=0` 仍会卡死,但故障边界已被多轮 discriminator 推进到 enabled 的 `netconn_*` 路径。当前最关键的资源事实是:在 `RCT6` 上 full-task 创建完四个 TCP 任务后,FreeRTOS heap 只剩约 944 bytes,静态 RAM 也已逼近物理上限,因此当前推荐先切换到 pin2pin 的 `STM32F103RDT6`,保持现有代码基线基本不变,先完成第一轮换片复测,再根据新器件上的 RTT、free/min heap 和 enabled `S1/C1` 行为决定下一步。
|
||||||
|
|
||||||
|
你的当前目标不是立刻修完所有问题,而是:
|
||||||
|
1. 完成 `RCT6 -> RDT6` 目标切换;
|
||||||
|
2. 用真实 Keil 日志确认构建通过;
|
||||||
|
3. 在新器件上复测当前代码,判断故障是否消失、后移或保持原状;
|
||||||
|
4. 仅在拿到新器件上的第一轮 RTT 后,再继续做最小化的下一步判别。
|
||||||
|
```
|
||||||
@@ -206,6 +206,93 @@ void vApplicationMallocFailedHook(void)
|
|||||||
2. TCP Server 是否在指定端口监听
|
2. TCP Server 是否在指定端口监听
|
||||||
3. TCP Client 是否成功连接远端
|
3. TCP Client 是否成功连接远端
|
||||||
|
|
||||||
|
### 6.5 P3.5:确认 ARP / ICMP 基础网络可达
|
||||||
|
|
||||||
|
在继续 TCP 联调前,建议先把 `ARP + ping(ICMP)` 跑通。对于当前 `CH390 + lwIP + FreeRTOS` 架构,这一步不是可选项,而是 TCP 可达之前必须成立的网络基线。
|
||||||
|
|
||||||
|
#### 6.5.1 推荐最小验证顺序
|
||||||
|
|
||||||
|
1. 先确认板卡 IP、掩码、MAC 与 PC 所在网段一致
|
||||||
|
2. 上电后先观察 RTT,确认 `ETH init: done` 已出现
|
||||||
|
3. 在 PC 侧执行一次 `ping <板卡IP>`,同时开启 Wireshark 抓包
|
||||||
|
4. 先看是否出现发往板卡 IP 的 ARP request,再看设备是否回 ARP reply
|
||||||
|
5. ARP 正常后,再看是否出现 ICMP echo request / echo reply 成对出现
|
||||||
|
|
||||||
|
#### 6.5.2 当前工程推荐观察点
|
||||||
|
|
||||||
|
如果网络基础链路有疑问,建议按以下分层观察,不要只看某一层:
|
||||||
|
|
||||||
|
1. **raw RX 层**:CH390 是否确实收到了以太网帧
|
||||||
|
2. **Ethernet demux 层**:`ethernet_input()` 是否识别到 `ETHTYPE_ARP` / `ETHTYPE_IP`
|
||||||
|
3. **协议处理层**:`etharp_input()` / `ip_input()` 是否真正进入
|
||||||
|
4. **协议发包层**:lwIP 是否已经生成待发送的 ARP reply / ICMP reply
|
||||||
|
5. **驱动发送层**:`low_level_output()` / CH390 TX 是否真正把帧送出
|
||||||
|
|
||||||
|
这次 bring-up 证明,`raw RX 正常` 并不等于 `lwIP 已真正处理该帧`。如果只看到底层收到了包,就直接假设协议栈一定会回复,通常会把排查方向带偏。
|
||||||
|
|
||||||
|
#### 6.5.3 这次 ARP / ICMP bring-up 的关键结论
|
||||||
|
|
||||||
|
本轮调试中,最终根因位于:
|
||||||
|
|
||||||
|
- `Drivers/LwIP/src/netif/ethernet.c`
|
||||||
|
|
||||||
|
问题本质是:
|
||||||
|
|
||||||
|
1. `ethernet_input()` 在 `ETHTYPE_ARP` 分支中,曾直接调用 `etharp_input(p, netif)`
|
||||||
|
2. 但 `etharp_input()` 要求 `p->payload` 从 **ARP 头** 开始,而不是从 Ethernet 头开始
|
||||||
|
3. 因此如果没有先执行:
|
||||||
|
|
||||||
|
```c
|
||||||
|
pbuf_remove_header(p, SIZEOF_ETH_HDR)
|
||||||
|
```
|
||||||
|
|
||||||
|
则 ARP 包虽然被收到了,但会在 `etharp_input()` 的早期校验中被静默丢弃,最终表现为:
|
||||||
|
|
||||||
|
1. Wireshark 能看到 PC 发来的 ARP request
|
||||||
|
2. 板子侧底层收包计数在增长
|
||||||
|
3. 但设备始终不回 ARP reply
|
||||||
|
4. ping 也自然不会成功
|
||||||
|
|
||||||
|
当前应保留的正确处理方式如下:
|
||||||
|
|
||||||
|
```c
|
||||||
|
case ETHTYPE_ARP:
|
||||||
|
if (netif->flags & NETIF_FLAG_ETHARP) {
|
||||||
|
if (pbuf_remove_header(p, SIZEOF_ETH_HDR)) {
|
||||||
|
pbuf_free(p);
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
etharp_input(p, netif);
|
||||||
|
} else {
|
||||||
|
pbuf_free(p);
|
||||||
|
}
|
||||||
|
return ERR_OK;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 6.5.4 为什么这类问题容易漏看
|
||||||
|
|
||||||
|
这类问题常见但隐蔽,原因通常有三点:
|
||||||
|
|
||||||
|
1. 根因非常小,外在表现却像“整个发送链路都坏了”
|
||||||
|
2. 多个低层信号可能同时正常,容易误导为 SPI / TX / CH390 初始化问题
|
||||||
|
3. `rx ok`、`ARP 帧计数在涨`、`链路已 up` 都不代表协议层一定接受了该帧
|
||||||
|
|
||||||
|
因此,后续遇到“收得到包但就是不回”的问题时,优先检查:
|
||||||
|
|
||||||
|
1. 传给上层协议处理函数时,`pbuf->payload` 是否已经对齐到正确协议头
|
||||||
|
2. glue-layer 是否和 lwIP 原生调用约定一致
|
||||||
|
3. 观察点是否已经覆盖到 `demux -> protocol handler -> linkoutput` 这一整条链
|
||||||
|
|
||||||
|
#### 6.5.5 建议保留的最小验收标准
|
||||||
|
|
||||||
|
在认定网络基线“已经打通”之前,至少应满足:
|
||||||
|
|
||||||
|
1. Keil 工程可稳定构建通过
|
||||||
|
2. 上电后可稳定看到网络初始化完成日志
|
||||||
|
3. Wireshark 中能看到设备对本机 ARP request 做出 reply
|
||||||
|
4. PC 对设备 `ping` 时,能看到 ICMP echo request / reply 成对出现
|
||||||
|
5. RTT 中无 `STACK OVERFLOW`、`MALLOC FAILED`、异常 trap 等故障信号
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7. MUX / NET / LINK[idx] 联调指导
|
## 7. MUX / NET / LINK[idx] 联调指导
|
||||||
@@ -256,6 +343,10 @@ void vApplicationMallocFailedHook(void)
|
|||||||
4. 不要在基础寄存器读写尚不可信时,直接调高层业务
|
4. 不要在基础寄存器读写尚不可信时,直接调高层业务
|
||||||
5. 不要在 ISR 中执行复杂 SPI 事务或调用阻塞 API
|
5. 不要在 ISR 中执行复杂 SPI 事务或调用阻塞 API
|
||||||
6. 不要忽视 `configCHECK_FOR_STACK_OVERFLOW` 报告
|
6. 不要忽视 `configCHECK_FOR_STACK_OVERFLOW` 报告
|
||||||
|
7. 不要把“底层已经收到 ARP 包”等同于“lwIP 一定已经正确处理 ARP 包”
|
||||||
|
8. 不要忽略 glue-layer 对 `pbuf->payload` 起始位置的约定,特别是 `Ethernet header -> ARP/IP header` 的切换
|
||||||
|
9. 不要在 ARP / ICMP 还没闭环前,就直接怀疑 TCP Server / TCP Client 逻辑
|
||||||
|
10. 不要在没有抓包和分层观测点的情况下,只凭单一日志就断言故障位于 TX 或 SPI 层
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -265,3 +356,114 @@ void vApplicationMallocFailedHook(void)
|
|||||||
2. `项目技术实现.md`
|
2. `项目技术实现.md`
|
||||||
3. `项目需求说明.md`
|
3. `项目需求说明.md`
|
||||||
4. `Keil工程配置说明.txt`
|
4. `Keil工程配置说明.txt`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. 近期调试经验固化(2026-04)
|
||||||
|
|
||||||
|
本节用于固化这一轮 `FreeRTOS + lwIP + CH390` 联调过程中已经验证过的经验,后续调试默认以本节为前提,不要反复回到已排除的旧假设。
|
||||||
|
|
||||||
|
### 11.1 构建结果的真值来源
|
||||||
|
|
||||||
|
当前工程的构建真值必须以 `Keil` 实际构建日志为准,而不是辅助 viewer。
|
||||||
|
|
||||||
|
推荐优先级如下:
|
||||||
|
|
||||||
|
1. `MDK-ARM/build_capture.txt`
|
||||||
|
2. `MDK-ARM/TCP2UART/TCP2UART.build_log.htm`
|
||||||
|
3. `MDK-ARM/TCP2UART/TCP2UART.map`
|
||||||
|
|
||||||
|
说明:
|
||||||
|
|
||||||
|
1. `keil-build-viewer.exe` 只能辅助观察内存占用或旧构建快照
|
||||||
|
2. viewer 未刷新时,不代表当前代码没有变化,往往只是最新构建没成功或 viewer 数据滞后
|
||||||
|
3. 后续任何“编译通过 / RAM 变化 / 目标器件切换”的判断,都必须引用以上三类 Keil 真实产物
|
||||||
|
|
||||||
|
### 11.2 近期已验证的事实
|
||||||
|
|
||||||
|
以下结论已经被本轮调试反复验证:
|
||||||
|
|
||||||
|
1. `DIAG_TASK_ISOLATION=1` 时,系统可以稳定运行
|
||||||
|
2. `DIAG_TASK_ISOLATION=0` 时,full-task 模式仍会卡死
|
||||||
|
3. 启动阶段 `lwip_netif_init()`、deferred `xTaskCreate()`、`netif-ready` 等关键日志已经真实跑通
|
||||||
|
4. 之前通过加日志、分阶段创建 TCP 任务、调整栈大小后,卡死边界会继续后移,但问题不会完全消失
|
||||||
|
5. 这说明当前问题不是单一固定点故障,而是“逻辑路径 + 极低资源余量”共同作用的结果
|
||||||
|
|
||||||
|
### 11.3 已排除或降级优先级的方向
|
||||||
|
|
||||||
|
以下方向目前不再应作为一号假设:
|
||||||
|
|
||||||
|
1. **startup/init 失败**
|
||||||
|
- 当前日志已能稳定走到 `netif-ready`
|
||||||
|
- 因此主要问题不再是最初的 bring-up 链路本身
|
||||||
|
2. **单纯 CH390 TX 无限等待是当前主因**
|
||||||
|
- 已为 TX 路径增加过 bounded wait / timeout 观察点
|
||||||
|
- 最新故障没有先落到 `[ETH] tx timeout` 分支
|
||||||
|
3. **只靠继续增大 TCP task 栈就能解决问题**
|
||||||
|
- `256 -> 384 words` 后,故障边界虽然继续后移,但系统仍会卡死
|
||||||
|
- 栈确实曾是问题的一部分,但不是唯一剩余问题
|
||||||
|
|
||||||
|
### 11.4 当前最重要的资源压力结论
|
||||||
|
|
||||||
|
当前 `STM32F103RCT6`(48KB SRAM)上的真实资源压力已经高到会直接干扰调试判断:
|
||||||
|
|
||||||
|
1. 真实构建中,`ZI-data` 已接近物理 RAM 上限(约 95%+)
|
||||||
|
2. 在 `DIAG_TASK_ISOLATION=0` 下,创建完四个 TCP 任务后,`xPortGetFreeHeapSize()` 只剩约 `944 bytes`
|
||||||
|
3. 这个余量不足以让后续 `netconn_*`、semaphore、mailbox、任务栈回旋空间保持清晰边界
|
||||||
|
4. 因此当前在 `RCT6` 上继续做 discriminator 时,结果会持续混入“资源边界噪声”
|
||||||
|
|
||||||
|
这也是为什么本轮调试后半段已经把重点从“继续在 RCT6 上做更多小修补”切换到“先换更大 RAM 的 pin2pin 器件再继续分析”。
|
||||||
|
|
||||||
|
### 11.5 当前推荐的硬件调试策略
|
||||||
|
|
||||||
|
当前推荐的下一阶段策略如下:
|
||||||
|
|
||||||
|
1. 先从 `STM32F103RCT6` 切换到 pin2pin 的 `STM32F103RDT6`
|
||||||
|
2. 在切换器件后,尽量保持当前代码基线不做大改
|
||||||
|
3. 先复测当前版本的 RTT 与运行边界,看故障是否:
|
||||||
|
- 消失
|
||||||
|
- 明显后移
|
||||||
|
- 仍然停在相同 enabled path
|
||||||
|
4. 再根据新器件上的表现,区分:
|
||||||
|
- 资源压力主导
|
||||||
|
- 逻辑 / 时序 / API 使用问题仍然存在
|
||||||
|
|
||||||
|
### 11.6 换片后第一轮调试目标
|
||||||
|
|
||||||
|
切换到 `RDT6` 后,第一轮调试不追求立刻修复,而是优先回答下面几个问题:
|
||||||
|
|
||||||
|
1. 当前 full-task 模式是否仍然卡死
|
||||||
|
2. `free/min heap` 是否明显高于 `RCT6` 版本
|
||||||
|
3. enabled 的 `S1 / C1` 是否能够继续进入更深的 `netconn_new / bind / connect / listen / accept` 路径
|
||||||
|
4. 之前为了定位问题而加入的 discriminator(例如 `C1 first-connect defer`)是否仍然影响故障边界
|
||||||
|
|
||||||
|
如果这些问题不先回答,后续继续改代码的结论可信度会很差。
|
||||||
|
|
||||||
|
### 11.7 当前建议保留的调试原则
|
||||||
|
|
||||||
|
后续 agent 或开发者继续接手本工程时,建议遵守以下原则:
|
||||||
|
|
||||||
|
1. 不要在 `RCT6` 上继续大量加日志、加栈、加 queue 深度后再试图解释现象
|
||||||
|
2. 不要把 viewer 当作当前构建真值
|
||||||
|
3. 不要忽略 `DIAG_TASK_ISOLATION=1 正常、=0 异常` 这个前提
|
||||||
|
4. 不要一次性修改 `C1/S1/CH390/lwIP` 多个方向,避免再次失去因果关系
|
||||||
|
5. 每次只做一个能明显改变故障边界的最小改动,并用 RTT + Keil build 结果交叉验证
|
||||||
|
|
||||||
|
### 11.8 固定 Client 端口重连策略(TIME_WAIT 取舍)
|
||||||
|
|
||||||
|
当前工程的 `Client` 链路保留固定 `LPORT` 配置语义,默认 `C1/C2` 均使用明确的本地源端口。
|
||||||
|
|
||||||
|
在 `lwIP + netconn` 路径下,如果仍沿用优雅 `netconn_close()`,则相同 `LPORT` 的快速重连会受到 TCP `TIME_WAIT` 影响,表现为一段时间内重复 `bind/connect` 失败。
|
||||||
|
|
||||||
|
结合本项目的约束,当前版本固化如下取舍:
|
||||||
|
|
||||||
|
1. 不取消 `Client` 固定 `LPORT` 语义
|
||||||
|
2. 不依赖扩大 PCB 池作为主修复手段
|
||||||
|
3. 不通过降低 `TCP_MSL` 改写全局 TCP 保守语义
|
||||||
|
4. 对 `Client` 主动断开后的释放路径采用 abortive close(RST),以立即释放 PCB 与本地端口
|
||||||
|
|
||||||
|
使用该策略时应明确接受以下副作用:
|
||||||
|
|
||||||
|
1. 对端可能看到 `RST` 或“连接被重置”
|
||||||
|
2. 连接尾部未完成发送的数据不会再走优雅关闭路径
|
||||||
|
3. 该策略仅用于固定 `Client` 端口快速重连场景,不应直接推广到所有 TCP 关闭路径
|
||||||
|
|||||||
@@ -48,105 +48,183 @@
|
|||||||
+--------------------------------------------------+
|
+--------------------------------------------------+
|
||||||
```
|
```
|
||||||
|
|
||||||
## 四、FreeRTOS 任务设计
|
## 四、FreeRTOS 任务设计(路径 A:netconn + 多 TCP 任务)
|
||||||
|
|
||||||
### 4.1 任务列表
|
### 4.1 架构路线
|
||||||
|
|
||||||
| 任务名 | 优先级 | 栈大小 | 周期 | 职责 |
|
本项目采用 **路径 A**:`NO_SYS=0 + netconn API + 每个 TCP 连接独立任务`。
|
||||||
|--------|--------|--------|------|------|
|
|
||||||
| `NetworkTask` | osPriorityHigh (4) | 512 words | 事件驱动 | CH390 事件消费 + lwIP 超时处理 |
|
|
||||||
| `UartTask` | osPriorityHigh (4) | 512 words | 事件驱动 | UART DMA/IDLE 接收 + MUX 帧提取 |
|
|
||||||
| `ConfigTask` | osPriorityNormal (3) | 256 words | 事件驱动 | AT 命令解析与响应 |
|
|
||||||
| `RouteTask` | osPriorityNormal (3) | 512 words | 事件驱动 | SRCID/DSTMASK 数据路由分发 |
|
|
||||||
| `DefaultTask` | osPriorityLow (1) | 128 words | 1000ms 周期 | LED 心跳 + IWDG 喂狗 |
|
|
||||||
|
|
||||||
### 4.2 任务间通信机制
|
核心决策:
|
||||||
|
1. lwIP 以 `NO_SYS=0` 模式运行,`tcpip_thread` 由 lwIP 自动创建
|
||||||
|
2. TCP 连接使用 `netconn` 阻塞 API(`netconn_accept` / `netconn_recv` / `netconn_write`)
|
||||||
|
3. 每个 TCP Server 和 Client 实例各占一个独立任务
|
||||||
|
4. 任务间通过 Queue 传递指针 + 元数据描述符,实现零拷贝
|
||||||
|
|
||||||
```text
|
### 4.2 任务列表(共 9 个任务 + 1 个 lwIP 自建)
|
||||||
UART ISR --[Semaphore]--> UartTask --[Queue]--> RouteTask --[Queue]--> NetworkTask
|
|
||||||
|
|
| 任务名 | 优先级 | 栈(words) | 模式 | 职责 |
|
||||||
ConfigTask <--[Queue]-- RouteTask <--[Queue]-- NetworkTask <--------+
|
|--------|--------|-----------|------|------|
|
||||||
|
|
| `tcpip_thread` | 6 (最高) | 512 | 阻塞 | lwIP 内核线程(自动创建) |
|
||||||
+--> UART TX (Direct DMA send)
|
| `NetPollTask` | 5 | 384 | 事件驱动 | `ethernetif_poll` + 链路检测 |
|
||||||
|
| `TcpSrvTask_S1` | 4 | 384 | 阻塞 | `netconn_accept` + S1 收发 |
|
||||||
|
| `TcpSrvTask_S2` | 4 | 384 | 阻塞 | `netconn_accept` + S2 收发 |
|
||||||
|
| `TcpCliTask_C1` | 4 | 256 | 阻塞 | `netconn_connect` + C1 收发 |
|
||||||
|
| `TcpCliTask_C2` | 4 | 256 | 阻塞 | `netconn_connect` + C2 收发 |
|
||||||
|
| `UartRxTask` | 4 | 384 | 事件驱动 | UART DMA/IDLE 接收 + MUX 帧提取 |
|
||||||
|
| `ConfigTask` | 2 | 256 | 阻塞 | AT 命令解析与响应 |
|
||||||
|
| `DefaultTask` | 1 | 128 | 周期 | LED 心跳 + IWDG 喂狗 |
|
||||||
|
|
||||||
|
说明:
|
||||||
|
- `tcpip_thread` 是 lwIP 自建的内核线程,处理所有协议栈内部事件
|
||||||
|
- 所有 `netconn_*` API 通过 `tcpip_thread` 消息机制实现线程安全
|
||||||
|
- `LWIP_TCPIP_CORE_LOCKING=1` 允许应用任务直接调用 `netconn_write` 而不经邮箱中转
|
||||||
|
- `tcpip_thread` 优先级最高(6),确保 TCP ACK 和超时处理不被延迟
|
||||||
|
|
||||||
|
### 4.3 零拷贝路由消息设计
|
||||||
|
|
||||||
|
```c
|
||||||
|
/* 路由消息描述符 - Queue 传递的是此结构的指针,不拷贝负载数据 */
|
||||||
|
typedef struct {
|
||||||
|
uint8_t src_id; /* 源端点 ID */
|
||||||
|
uint8_t dst_mask; /* 目标端点位图 */
|
||||||
|
uint16_t len; /* 数据长度 */
|
||||||
|
uint8_t conn_type; /* 连接标识:LINK_S1/S2/C1/C2 */
|
||||||
|
uint8_t *data; /* 指向预分配静态缓冲区 */
|
||||||
|
} route_msg_t;
|
||||||
```
|
```
|
||||||
|
|
||||||
具体通信对象:
|
静态缓冲池(预分配,避免动态分配):
|
||||||
|
|
||||||
|
```c
|
||||||
|
#define ROUTE_BUF_COUNT 4
|
||||||
|
#define ROUTE_BUF_SIZE 512
|
||||||
|
|
||||||
|
static uint8_t g_route_buf_pool[ROUTE_BUF_COUNT][ROUTE_BUF_SIZE];
|
||||||
|
static volatile uint8_t g_route_buf_used[ROUTE_BUF_COUNT];
|
||||||
|
```
|
||||||
|
|
||||||
|
- 发送方:从池中获取空闲缓冲区,拷贝数据,填充 `route_msg_t`,Queue 发送指针
|
||||||
|
- 接收方:从 Queue 取 `route_msg_t*`,处理数据后标记缓冲区为可用
|
||||||
|
- 无动态分配,无堆碎片
|
||||||
|
|
||||||
|
### 4.4 任务间通信机制
|
||||||
|
|
||||||
|
```text
|
||||||
|
UART ISR ──[TaskNotify]──> UartRxTask ──[Queue*]──> TcpSrvTask / TcpCliTask
|
||||||
|
│ ▲
|
||||||
|
├──[Queue*]──────────────>─┘
|
||||||
|
│
|
||||||
|
DSTMASK=0 └──[Queue]──> ConfigTask
|
||||||
|
|
||||||
|
TcpSrvTask / TcpCliTask ──[Queue*]──> UartRxTask (UART TX 方向)
|
||||||
|
|
||||||
|
EXTI0 ISR ──[BinarySem]──> NetPollTask ──> ethernetif_poll ──> tcpip_thread
|
||||||
|
```
|
||||||
|
|
||||||
|
通信对象:
|
||||||
|
|
||||||
| 对象 | 类型 | 生产者 | 消费者 | 用途 |
|
| 对象 | 类型 | 生产者 | 消费者 | 用途 |
|
||||||
|------|------|--------|--------|------|
|
|------|------|--------|--------|------|
|
||||||
| `xUartRxQueue` | Queue (64 items) | UartTask | RouteTask | UART 接收帧传递 |
|
| `xNetSemaphore` | Binary Semaphore | EXTI0 ISR | NetPollTask | CH390 中断通知 |
|
||||||
| `xTcpRxQueue` | Queue (32 items) | NetworkTask | RouteTask | TCP 接收数据传递 |
|
| `xUartRxNotify` | TaskNotification | UART IDLE ISR | UartRxTask | UART 接收通知 |
|
||||||
| `xConfigQueue` | Queue (16 items) | RouteTask | ConfigTask | AT 命令文本传递 |
|
| `xTcpRxQueue` | Queue (16, route_msg_t*) | TCP 任务 | UartRxTask | TCP→UART 数据 |
|
||||||
| `xCh390Semaphore` | Binary Semaphore | EXTI0 ISR | NetworkTask | CH390 中断通知 |
|
| `xUartTxQueue` | Queue (8, route_msg_t*) | UartRxTask | TCP 任务 | UART→TCP 数据 |
|
||||||
| `xSpiMutex` | Mutex | NetworkTask | 多任务 | SPI/CH390 访问保护 |
|
| `xConfigQueue` | Queue (8, char*) | UartRxTask | ConfigTask | AT 文本 |
|
||||||
| `xUart2TxStream` | StreamBuffer (1024) | RouteTask | UartTask | UART2 发送数据 |
|
|
||||||
| `xUart3TxStream` | StreamBuffer (1024) | RouteTask | UartTask | UART3 发送数据 |
|
|
||||||
|
|
||||||
### 4.3 NetworkTask 实现方向
|
说明:
|
||||||
|
- TCP→UART 方向:TCP 任务调用 `netconn_recv` 获取数据,构造 `route_msg_t` 指针投递到 `xTcpRxQueue`,UartRxTask 取出后写入 UART DMA
|
||||||
|
- UART→TCP 方向:UartRxTask 从 UART DMA 读取数据,构造 `route_msg_t` 指针投递到 `xUartTxQueue`,对应 TCP 任务取出后调用 `netconn_write` 发送
|
||||||
|
- 路由逻辑内联在 UartRxTask 和各 TCP 任务中,不设独立 RouteTask
|
||||||
|
|
||||||
|
### 4.5 NetPollTask 实现
|
||||||
|
|
||||||
```c
|
```c
|
||||||
void NetworkTask(void *argument)
|
void NetPollTask(void *argument)
|
||||||
{
|
{
|
||||||
/* 初始化 CH390 + lwIP netif */
|
/* 初始化 CH390 + lwIP netif */
|
||||||
/* 创建 TCP Server/Client 实例 */
|
ethernetif_init(&ch390_netif);
|
||||||
|
/* 等待链路就绪后启动 TCP 任务 */
|
||||||
|
/* ... */
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
/* 等待 CH390 中断信号量 */
|
xSemaphoreTake(xNetSemaphore, pdMS_TO_TICKS(2));
|
||||||
xSemaphoreTake(xCh390Semaphore, pdMS_TO_TICKS(10));
|
ethernetif_poll(&ch390_netif);
|
||||||
/* 处理 CH390 事件 */
|
ethernetif_check_link(&ch390_netif);
|
||||||
ethernetif_poll();
|
/* sys_check_timeouts() 由 tcpip_thread 自动执行,此处不需要调用 */
|
||||||
ethernetif_check_link();
|
|
||||||
/* lwIP 超时处理由 tcpip_thread 自动完成 */
|
|
||||||
/* TCP 数据收发 */
|
|
||||||
tcp_link_process();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4.4 UartTask 实现方向
|
### 4.6 TcpSrvTask 实现模板
|
||||||
|
|
||||||
```c
|
```c
|
||||||
void UartTask(void *argument)
|
void TcpSrvTask_S1(void *argument)
|
||||||
{
|
{
|
||||||
|
struct netconn *conn = netconn_new(NETCONN_TCP);
|
||||||
|
netconn_bind(conn, IP_ADDR_ANY, cfg->links[0].lport);
|
||||||
|
netconn_listen(conn);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
/* 等待 UART IDLE 中断通知 */
|
struct netconn *newconn;
|
||||||
ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(10));
|
if (netconn_accept(conn, &newconn) == ERR_OK) {
|
||||||
/* 处理 UART2/UART3 DMA 接收数据 */
|
/* 在本任务内处理唯一客户端 */
|
||||||
/* MUX=0: 直接投递到路由队列 */
|
tcp_server_worker(newconn, LINK_S1);
|
||||||
/* MUX=1: 提取 MUX 帧,分流控制帧与数据帧 */
|
netconn_close(newconn);
|
||||||
/* 检查 StreamBuffer,发送 UART TX 数据 */
|
netconn_delete(newconn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4.5 ConfigTask 实现方向
|
### 4.7 TcpCliTask 实现模板
|
||||||
|
|
||||||
|
```c
|
||||||
|
void TcpCliTask_C1(void *argument)
|
||||||
|
{
|
||||||
|
for (;;) {
|
||||||
|
struct netconn *conn = netconn_new(NETCONN_TCP);
|
||||||
|
ip_addr_t remote_ip;
|
||||||
|
IP_ADDR4(&remote_ip, cfg->links[2].rip[0], ...);
|
||||||
|
|
||||||
|
if (netconn_connect(conn, &remote_ip, cfg->links[2].rport) == ERR_OK) {
|
||||||
|
tcp_client_worker(conn, LINK_C1);
|
||||||
|
}
|
||||||
|
netconn_close(conn);
|
||||||
|
netconn_delete(conn);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(cfg->links[2].reconnect_interval));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.8 UartRxTask 实现
|
||||||
|
|
||||||
|
```c
|
||||||
|
void UartRxTask(void *argument)
|
||||||
|
{
|
||||||
|
for (;;) {
|
||||||
|
ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(10));
|
||||||
|
/* 处理 UART2/UART3 DMA 接收数据 */
|
||||||
|
/* MUX=0: 构造 route_msg_t 指针投递到 xUartTxQueue */
|
||||||
|
/* MUX=1: 提取 MUX 帧,DSTMASK=0 投 xConfigQueue,否则投 xUartTxQueue */
|
||||||
|
/* 从 xTcpRxQueue 取数据,写入 UART DMA 发送 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.9 ConfigTask 实现
|
||||||
|
|
||||||
```c
|
```c
|
||||||
void ConfigTask(void *argument)
|
void ConfigTask(void *argument)
|
||||||
{
|
{
|
||||||
for (;;) {
|
for (;;) {
|
||||||
/* 从配置队列接收 AT 命令文本 */
|
char *cmd;
|
||||||
xQueueReceive(xConfigQueue, &cmd, portMAX_DELAY);
|
xQueueReceive(xConfigQueue, &cmd, portMAX_DELAY);
|
||||||
/* 解析并执行 AT 命令 */
|
|
||||||
config_process_at_cmd(cmd);
|
config_process_at_cmd(cmd);
|
||||||
/* 通过 UART1 发送响应 */
|
/* 通过 UART1 发送响应 */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4.6 RouteTask 实现方向
|
|
||||||
|
|
||||||
```c
|
|
||||||
void RouteTask(void *argument)
|
|
||||||
{
|
|
||||||
for (;;) {
|
|
||||||
/* 从 UART 队列和 TCP 队列读取数据帧 */
|
|
||||||
/* 根据 SRCID/DSTMASK 决定路由目标 */
|
|
||||||
/* 控制帧 (DSTMASK=0x00) -> ConfigTask */
|
|
||||||
/* 数据帧 -> TCP 实例或 UART TX */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 五、最终协议实现模型
|
## 五、最终协议实现模型
|
||||||
|
|
||||||
### 5.1 MUX 帧承载层
|
### 5.1 MUX 帧承载层
|
||||||
@@ -276,13 +354,24 @@ EN,LPORT,RIP,RPORT,UART
|
|||||||
3. 在 `MUX=1` 时执行 MUX 帧收发
|
3. 在 `MUX=1` 时执行 MUX 帧收发
|
||||||
4. 将控制帧与业务数据帧分流
|
4. 将控制帧与业务数据帧分流
|
||||||
|
|
||||||
### 7.3 TCP Server / Client 模块
|
### 7.3 TCP Server / Client 模块(需重写)
|
||||||
|
|
||||||
最终职责:
|
原 `tcp_server.c` / `tcp_client.c` 基于 lwIP RAW API 回调模式,需重写为 netconn 阻塞模式:
|
||||||
|
|
||||||
1. 不再从外部协议角度区分不同字段模型
|
1. 删除所有 `tcp_pcb` / `tcp_recv` / `tcp_accept` 回调代码
|
||||||
2. 统一受 `LINK[idx]` 配置驱动
|
2. 改用 `netconn_new` / `netconn_bind` / `netconn_listen` / `netconn_accept`(Server)
|
||||||
3. 由调度层决定实例与 UART 的数据交换路径
|
3. 改用 `netconn_new` / `netconn_connect`(Client)
|
||||||
|
4. 收发改为 `netconn_recv` / `netconn_write` 阻塞调用
|
||||||
|
5. 内部 ring buffer 可取消(netconn 内部已有 pbuf 缓冲)
|
||||||
|
6. 每个 TCP 任务内直接处理路由,通过 Queue 指针传递数据
|
||||||
|
|
||||||
|
补充约束(当前实现口径):
|
||||||
|
|
||||||
|
1. `Client` 链路保留固定 `LPORT` 配置语义,以满足产品侧对固定源端口的依赖
|
||||||
|
2. 在 `lwIP + netconn` 模型下,若 `Client` 继续使用优雅 `netconn_close()`,相同本地端口的快速重连会受 `TIME_WAIT` 影响
|
||||||
|
3. 因此当前工程对 `Client` 会话结束后的释放路径采用 abortive close(`tcp_abort` / RST)以立即释放 PCB 与本地端口
|
||||||
|
4. 该策略只针对 `Client` 固定端口重连路径,不扩展到 `Server` listener 或一般被动关闭场景
|
||||||
|
5. 该策略的已知代价是:对端可能看到 `RST`,且尾部未完成发送的数据不会再走优雅 `FIN/ACK` 收尾
|
||||||
|
|
||||||
### 7.4 FreeRTOS 初始化 `freertos.c`
|
### 7.4 FreeRTOS 初始化 `freertos.c`
|
||||||
|
|
||||||
@@ -309,36 +398,67 @@ CubeMX 生成的 FreeRTOS 初始化文件,职责:
|
|||||||
| `configUSE_MALLOC_FAILED_HOOK` | 1 | 内存分配失败钩子 |
|
| `configUSE_MALLOC_FAILED_HOOK` | 1 | 内存分配失败钩子 |
|
||||||
| `configSUPPORT_DYNAMIC_ALLOCATION` | 1 | 动态内存分配 |
|
| `configSUPPORT_DYNAMIC_ALLOCATION` | 1 | 动态内存分配 |
|
||||||
|
|
||||||
## 八、lwIP 配置方向
|
## 八、lwIP 配置(NO_SYS=0 + netconn)
|
||||||
|
|
||||||
### 8.1 lwIP 线程模型
|
### 8.1 lwIP 线程模型
|
||||||
|
|
||||||
由于采用 `NO_SYS=0`,lwIP 将运行以下线程:
|
由于采用 `NO_SYS=0`,lwIP 将运行以下线程:
|
||||||
|
|
||||||
1. `tcpip_thread`:lwIP 核心线程,处理所有协议栈内部事件
|
1. `tcpip_thread`(优先级 6,栈 512 words):lwIP 核心线程,处理所有协议栈内部事件
|
||||||
2. 应用任务通过 `netconn` / `socket` API 与 lwIP 交互
|
2. 应用任务通过 `netconn` API 与 lwIP 交互,由 `tcpip_thread` 消息机制保证线程安全
|
||||||
|
3. `LWIP_TCPIP_CORE_LOCKING=1`:允许应用任务在持有核心锁时直接调用 `netconn_write`,无需通过邮箱中转
|
||||||
|
|
||||||
### 8.2 lwIP 内存配置建议
|
### 8.2 lwIP 关键配置项(lwipopts.h)
|
||||||
|
|
||||||
| 配置项 | 建议值 | 说明 |
|
| 配置项 | 值 | 说明 |
|
||||||
|--------|--------|------|
|
|--------|-----|------|
|
||||||
|
| `NO_SYS` | 0 | 启用 OS 抽象 |
|
||||||
|
| `LWIP_NETCONN` | 1 | 启用 netconn API |
|
||||||
|
| `LWIP_SOCKET` | 0 | 不使用 socket API,节省 RAM |
|
||||||
|
| `LWIP_TCPIP_CORE_LOCKING` | 1 | 允许直接发送,减少延时 |
|
||||||
| `MEM_SIZE` | 8192 | lwIP 堆大小 |
|
| `MEM_SIZE` | 8192 | lwIP 堆大小 |
|
||||||
| `MEMP_NUM_NETCONN` | 6 | netconn 连接数 |
|
| `PBUF_POOL_SIZE` | 10 | pbuf 池数量 |
|
||||||
| `MEMP_NUM_TCP_PCB` | 6 | TCP 控制块数 |
|
| `MEMP_NUM_NETCONN` | 8 | 2监听 + 4连接 + 2余量 |
|
||||||
| `PBUF_POOL_SIZE` | 8 | pbuf 池大小 |
|
| `MEMP_NUM_NETBUF` | 8 | netconn 缓冲 |
|
||||||
| `PBUF_POOL_BUFSIZE` | 1524 | pbuf 缓冲大小 |
|
| `MEMP_NUM_TCP_PCB` | 4 | TCP 控制块 |
|
||||||
| `TCP_WND` | 2048 | TCP 窗口大小 |
|
| `MEMP_NUM_TCP_PCB_LISTEN` | 2 | TCP 监听 |
|
||||||
| `TCP_MSS` | 1460 | TCP 最大段大小 |
|
| `MEMP_NUM_TCP_SEG` | 24 | TCP 段 |
|
||||||
|
| `MEMP_NUM_TCPIP_MSG_API` | 8 | API 消息池 |
|
||||||
|
| `MEMP_NUM_TCPIP_MSG_INPKT` | 8 | 入包消息池 |
|
||||||
|
| `TCP_MSS` | 536 | 保守 MSS |
|
||||||
|
| `TCP_SND_BUF` | 8×MSS=4288 | 发送缓冲 |
|
||||||
|
| `TCP_WND` | 8×MSS=4288 | 接收窗口 |
|
||||||
|
| `TCPIP_THREAD_STACKSIZE` | 512 | tcpip_thread 栈 |
|
||||||
|
| `TCPIP_THREAD_PRIO` | 6 (最高) | tcpip_thread 优先级 |
|
||||||
|
| `LWIP_DHCP` | 0 | 不使用 DHCP |
|
||||||
|
| `LWIP_UDP` | 0 | 不使用 UDP |
|
||||||
|
|
||||||
### 8.3 sys_arch 移植层
|
### 8.3 sys_arch 移植层
|
||||||
|
|
||||||
`Drivers/LwIP/port/sys_arch.c` 提供 lwIP 到 FreeRTOS 的适配:
|
`Drivers/LwIP/port/sys_arch.c` 需实现 lwIP 到 FreeRTOS 的适配:
|
||||||
|
|
||||||
1. `sys_thread_new`:创建 lwIP 线程
|
1. `sys_thread_new`:创建 lwIP 线程(即 `tcpip_thread`)
|
||||||
2. `sys_mbox_*`:消息邮箱(基于 FreeRTOS Queue)
|
2. `sys_mbox_*`:消息邮箱(基于 FreeRTOS Queue,容量 `TCPIP_MBOX_SIZE=8`)
|
||||||
3. `sys_sem_*`:信号量(基于 FreeRTOS Semaphore)
|
3. `sys_sem_*`:信号量(基于 FreeRTOS Semaphore)
|
||||||
4. `sys_mutex_*`:互斥锁(基于 FreeRTOS Mutex)
|
4. `sys_mutex_*`:互斥锁(基于 FreeRTOS Mutex)
|
||||||
5. `sys_arch_protect / unprotect`:临界区保护
|
5. `sys_arch_protect / unprotect`:临界区保护(基于 `vPortEnterCritical / vPortExitCritical`)
|
||||||
|
|
||||||
|
### 8.4 lwIP 初始化流程
|
||||||
|
|
||||||
|
```c
|
||||||
|
/* 在 MX_FREERTOS_Init 或 NetPollTask 中调用 */
|
||||||
|
void lwip_init_task(void)
|
||||||
|
{
|
||||||
|
/* tcpip_thread 在 lwip_init() 或第一个 sys_thread_new 时自动启动 */
|
||||||
|
tcpip_init(NULL, NULL);
|
||||||
|
|
||||||
|
/* 等待 tcpip_thread 就绪 */
|
||||||
|
/* 添加网络接口 */
|
||||||
|
netif_add(&ch390_netif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, &tcpip_input);
|
||||||
|
netif_set_default(&ch390_netif);
|
||||||
|
netif_set_up(&ch390_netif);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## 九、中断与 HAL 时间基准
|
## 九、中断与 HAL 时间基准
|
||||||
|
|
||||||
@@ -365,34 +485,65 @@ FreeRTOS 下 `SysTick` 被 FreeRTOS 占用,HAL 时间基准改用 `TIM4`:
|
|||||||
|
|
||||||
FreeRTOS 可管理的中断优先级必须 >= `configMAX_SYSCALL_INTERRUPT_PRIORITY`(本工程为 5)。
|
FreeRTOS 可管理的中断优先级必须 >= `configMAX_SYSCALL_INTERRUPT_PRIORITY`(本工程为 5)。
|
||||||
|
|
||||||
## 十、内存预算
|
## 十、内存预算(路径 A 精确估算)
|
||||||
|
|
||||||
以 `STM32F103RCT6` 为目标(48KB SRAM):
|
以 `STM32F103RCT6` 为目标(48KB SRAM):
|
||||||
|
|
||||||
### 10.1 RAM 预算
|
### 10.1 RAM 预算
|
||||||
|
|
||||||
| 项目 | 建议值 | 说明 |
|
| 项目 | 大小 | 说明 |
|
||||||
|------|--------|------|
|
|------|------|------|
|
||||||
| 启动栈 (MSP) | 2 KB | startup_stm32f103xe.s 中定义 |
|
| 启动栈 (MSP) | 2,048 B | `startup_stm32f103xe.s` 定义 0x800 |
|
||||||
| FreeRTOS 堆 | 10 KB | heap_4.c 管理 |
|
| FreeRTOS 堆 (heap_4) | 10,240 B | `configTOTAL_HEAP_SIZE` |
|
||||||
| 任务栈合计 | ~6 KB | 5 个任务 |
|
| 任务栈 (9 任务) | 13,312 B | 3,328 words × 4 (见上表) |
|
||||||
| lwIP 堆 | 8 KB | MEM_SIZE |
|
| lwIP 堆 (MEM_SIZE) | 8,192 B | |
|
||||||
| UART 缓冲 | 4 KB | RX/TX DMA 缓冲 |
|
| PBUF 池 (10 个) | ~6,000 B | 10 × ~600B |
|
||||||
| Queue/StreamBuffer | 4 KB | 任务间通信 |
|
| MEMP 池 | ~4,000 B | netconn/netbuf/tcpip_msg/pcb/seg |
|
||||||
| 参数/状态 | 2 KB | 配置结构 |
|
| UART DMA+Ring 缓冲 | 2,304 B | 2 通道 × (256+256+512+384)/2 |
|
||||||
| 空闲栈 | 1 KB | 系统预留 |
|
| 路由缓冲池 (4×512B) | 2,048 B | 零拷贝指针传递 |
|
||||||
| **合计** | ~37 KB | 预留约 11 KB 余量 |
|
| 配置结构 | 1,024 B | |
|
||||||
|
| **合计** | **~49,168 B** | |
|
||||||
|
| **余量 (RCT6 48KB)** | **~-928 B** | ⚠️ 超出,需优化或换 RDT6 |
|
||||||
|
| **余量 (RDT6 64KB)** | **~15,264 B** | ✅ 充裕 |
|
||||||
|
|
||||||
### 10.2 Flash 预算
|
### 10.2 优化空间(RCT6 下)
|
||||||
|
|
||||||
|
若坚持使用 RCT6,可通过以下措施压缩到 48KB 以内:
|
||||||
|
|
||||||
|
| 优化项 | 节省 |
|
||||||
|
|--------|------|
|
||||||
|
| 取消 TCP 任务的 ring buffer(netconn 内部有 pbuf 缓冲) | -2,048 B |
|
||||||
|
| `configTOTAL_HEAP_SIZE` 降至 8KB | -2,048 B |
|
||||||
|
| `MEM_SIZE` 降至 6KB | -2,048 B |
|
||||||
|
| TcpCliTask 栈降至 192 words × 2 | -512 B |
|
||||||
|
| **优化后合计** | **~42,504 B** |
|
||||||
|
| **RCT6 余量** | **~5,464 B** |
|
||||||
|
|
||||||
|
### 10.3 备选 MCU
|
||||||
|
|
||||||
|
当 RAM 最终不够用时,切换为 `STM32F103RDT6`(pin-to-pin 替代):
|
||||||
|
|
||||||
|
| 项目 | RCT6 | RDT6 |
|
||||||
|
|------|------|------|
|
||||||
|
| Flash | 256 KB | 384 KB |
|
||||||
|
| SRAM | 48 KB | 64 KB |
|
||||||
|
| 引脚 | LQFP64 | LQFP64(完全兼容) |
|
||||||
|
| 启动文件 | `startup_stm32f103xe.s` | `startup_stm32f103xe.s` |
|
||||||
|
| 宏定义 | `STM32F103xE` | `STM32F103xE` |
|
||||||
|
| Flash 算法 | `STM32F10x_HD` | `STM32F10x_HD`(相同) |
|
||||||
|
| SRAM 大小 | `0xC000` | `0x10000` |
|
||||||
|
| Flash 大小 | `0x40000` | `0x60000` |
|
||||||
|
|
||||||
|
### 10.4 Flash 预算
|
||||||
|
|
||||||
| 项目 | 估计值 | 说明 |
|
| 项目 | 估计值 | 说明 |
|
||||||
|------|--------|------|
|
|------|--------|------|
|
||||||
| FreeRTOS 内核 | ~8 KB | 含 CMSIS-RTOS V2 |
|
| FreeRTOS 内核 | ~8 KB | 含 CMSIS-RTOS V2 |
|
||||||
| HAL 驱动 | ~20 KB | GPIO/UART/SPI/DMA/IWDG/TIM |
|
| HAL 驱动 | ~20 KB | GPIO/UART/SPI/DMA/IWDG/TIM |
|
||||||
| lwIP 协议栈 | ~40 KB | core + api + ipv4 + netif |
|
| lwIP 协议栈 | ~50 KB | core + api + ipv4 + netif + sys_arch |
|
||||||
| CH390 驱动 | ~4 KB | |
|
| CH390 驱动 | ~4 KB | |
|
||||||
| 应用代码 | ~20 KB | config/uart_trans/tcp/route |
|
| 应用代码 | ~20 KB | config/uart_trans/tcp_server/tcp_client |
|
||||||
| **合计** | ~92 KB | 预留约 164 KB 余量 |
|
| **合计** | ~102 KB | RCT6 预留 154 KB,RDT6 预留 282 KB |
|
||||||
|
|
||||||
## 十一、硬件资源
|
## 十一、硬件资源
|
||||||
|
|
||||||
@@ -451,3 +602,45 @@ FreeRTOS 可管理的中断优先级必须 >= `configMAX_SYSCALL_INTERRUPT_PRIOR
|
|||||||
2. 控制帧只使用 `DSTMASK=0x00`
|
2. 控制帧只使用 `DSTMASK=0x00`
|
||||||
3. MUX 帧格式固定为 `SYNC | LEN_H | LEN_L | SRCID | DSTMASK | PAYLOAD | TAIL`
|
3. MUX 帧格式固定为 `SYNC | LEN_H | LEN_L | SRCID | DSTMASK | PAYLOAD | TAIL`
|
||||||
4. AT 手册、需求说明、技术实现三份文档不得再出现历史展开式字段
|
4. AT 手册、需求说明、技术实现三份文档不得再出现历史展开式字段
|
||||||
|
|
||||||
|
## 十四、路径 A 实现清单
|
||||||
|
|
||||||
|
### 14.1 必须重写的模块
|
||||||
|
|
||||||
|
| 模块 | 原实现 | 目标实现 | 说明 |
|
||||||
|
|------|--------|----------|------|
|
||||||
|
| `tcp_server.c/.h` | lwIP RAW API 回调 | netconn 阻塞任务 | `tcp_new` → `netconn_new`,回调 → 阻塞循环 |
|
||||||
|
| `tcp_client.c/.h` | lwIP RAW API 回调 | netconn 阻塞任务 | 同上 |
|
||||||
|
| `sys_arch.c/.h` | NO_SYS=1 空壳 | FreeRTOS 移植层 | `sys_mbox`、`sys_sem`、`sys_mutex`、`sys_thread` |
|
||||||
|
| `lwipopts.h` | NO_SYS=1 | NO_SYS=0 + netconn | 已更新 |
|
||||||
|
| `main.c` | while(1) 轮询 | FreeRTOS 任务创建 | `App_Poll()` → 各任务函数 |
|
||||||
|
| `stm32f1xx_it.c` | 裸机 ISR | FreeRTOS ISR | `xxFromISR` API |
|
||||||
|
|
||||||
|
### 14.2 可复用(需适配)的模块
|
||||||
|
|
||||||
|
| 模块 | 适配内容 |
|
||||||
|
|------|----------|
|
||||||
|
| `uart_trans.c/.h` | 添加 `xTaskNotifyFromISR` 替代 poll 模式 |
|
||||||
|
| `config.c/.h` | 添加 `xQueueReceive` 替代 `config_poll()` |
|
||||||
|
| `flash_param.c/.h` | 无需修改 |
|
||||||
|
| `CH390` 驱动 | `ethernetif_poll` 改为 NetPollTask 调用,SPI 加 Mutex 保护 |
|
||||||
|
| `ethernetif.c` | 添加 `netif_add` 的 `tcpip_input` 回调 |
|
||||||
|
|
||||||
|
### 14.3 无需修改的模块
|
||||||
|
|
||||||
|
| 模块 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `FreeRTOSConfig.h` | 已更新(任务优先级宏、堆大小) |
|
||||||
|
| `startup_stm32f103xe.s` | 已适配 RCT6 |
|
||||||
|
| `TCP2UART.ioc` | 已适配 RCT6 + FreeRTOS + TIM4 |
|
||||||
|
| `MDK-ARM/TCP2UART.uvprojx` | 已适配 RCT6 + xE 宏 |
|
||||||
|
| MUX 帧编解码 | 协议逻辑与 RTOS 无关 |
|
||||||
|
|
||||||
|
### 14.4 新增模块
|
||||||
|
|
||||||
|
| 模块 | 职责 |
|
||||||
|
|------|------|
|
||||||
|
| `route_msg.c/.h` | 零拷贝路由消息池管理 |
|
||||||
|
| `task_tcp_server.c/.h` | netconn Server 任务模板 |
|
||||||
|
| `task_tcp_client.c/.h` | netconn Client 任务模板 |
|
||||||
|
| `task_net_poll.c/.h` | CH390 poll + link check 任务 |
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
### 2.1 硬件边界
|
### 2.1 硬件边界
|
||||||
|
|
||||||
- 主控:`STM32F103RCT6`(256KB Flash / 48KB SRAM)
|
- 主控:`STM32F103RCT6`(256KB Flash / 48KB SRAM)
|
||||||
|
- 备选主控:`STM32F103RDT6`(384KB Flash / 64KB SRAM),pin-to-pin 兼容,当 RAM 不够时直接替换
|
||||||
- 以太网芯片:`CH390D`
|
- 以太网芯片:`CH390D`
|
||||||
- 网卡数量:`1`
|
- 网卡数量:`1`
|
||||||
- 配置口:`UART1`
|
- 配置口:`UART1`
|
||||||
@@ -30,10 +31,11 @@
|
|||||||
### 2.2 软件边界
|
### 2.2 软件边界
|
||||||
|
|
||||||
- 执行模型:`FreeRTOS`
|
- 执行模型:`FreeRTOS`
|
||||||
- 网络协议栈:`lwIP + NO_SYS=0`(支持 socket/netconn 线程安全 API)
|
- 网络协议栈:`lwIP NO_SYS=0 + netconn API`(线程安全,每连接独立任务)
|
||||||
- 调试输出:`SEGGER RTT`
|
- 调试输出:`SEGGER RTT`
|
||||||
- 采用 `FreeRTOS` 任务调度
|
- 采用 `FreeRTOS` 任务调度
|
||||||
- 采用 `lwIP socket/netconn` 或 `RAW API` 实现多路 TCP 并发
|
- TCP 连接使用 `netconn` 阻塞 API(`netconn_accept` / `netconn_recv` / `netconn_write`)
|
||||||
|
- 每条 TCP 连路(S1/S2/C1/C2)独立一个任务
|
||||||
- 不包含 DHCP 协议支持
|
- 不包含 DHCP 协议支持
|
||||||
|
|
||||||
## 三、最终协议需求
|
## 三、最终协议需求
|
||||||
@@ -152,22 +154,26 @@ EN,LPORT,RIP,RPORT,UART
|
|||||||
|
|
||||||
| 任务 | 优先级 | 职责 |
|
| 任务 | 优先级 | 职责 |
|
||||||
|------|--------|------|
|
|------|--------|------|
|
||||||
| NetworkTask | 高 | CH390 事件轮询 + lwIP tcpip 处理 |
|
| tcpip_thread | 6 (最高) | lwIP 内核线程(自动创建) |
|
||||||
| UartTask | 高 | UART DMA/IDLE 接收 + MUX 帧处理 |
|
| NetPollTask | 5 | CH390 事件轮询 + 链路检测 |
|
||||||
| ConfigTask | 中 | AT 命令解析与响应 |
|
| TcpSrvTask_S1 | 4 | S1 netconn_accept + 收发 |
|
||||||
| RouteTask | 中 | SRCID/DSTMASK 数据路由 |
|
| TcpSrvTask_S2 | 4 | S2 netconn_accept + 收发 |
|
||||||
| DefaultTask | 低 | LED 心跳 + 看门狗 |
|
| TcpCliTask_C1 | 4 | C1 netconn_connect + 收发 |
|
||||||
|
| TcpCliTask_C2 | 4 | C2 netconn_connect + 收发 |
|
||||||
|
| UartRxTask | 4 | UART DMA/IDLE 接收 + MUX 帧提取 + 路由 |
|
||||||
|
| ConfigTask | 2 | AT 命令解析与响应 |
|
||||||
|
| DefaultTask | 1 | LED 心跳 + 看门狗 |
|
||||||
|
|
||||||
### 6.2 任务间通信
|
### 6.2 任务间通信
|
||||||
|
|
||||||
- 使用 `Queue` 传递 UART 接收数据帧
|
- 使用 `Queue` 传递指针 + 元数据描述符(零拷贝路由消息)
|
||||||
- 使用 `Semaphore` 同步 CH390 中断事件
|
- 使用 `Binary Semaphore` 同步 CH390 中断事件
|
||||||
- 使用 `Mutex` 保护 SPI/CH390 共享访问
|
- 使用 `TaskNotification` 通知 UART IDLE 事件
|
||||||
- 使用 `StreamBuffer` 传递 TCP 数据到 UART 方向
|
- 预分配静态缓冲池,避免动态分配
|
||||||
|
|
||||||
## 七、非功能需求
|
## 七、非功能需求
|
||||||
|
|
||||||
1. 满足 `STM32F103RCT6` 的 `256KB Flash / 48KB SRAM` 约束
|
1. 满足 `STM32F103RCT6` 的 `256KB Flash / 48KB SRAM` 约束,若 RAM 不足可切换 `STM32F103RDT6`(pin-to-pin,64KB SRAM)
|
||||||
2. 工程可在 `MDK-ARM` 下构建
|
2. 工程可在 `MDK-ARM` 下构建
|
||||||
3. 调试输出统一使用 `SEGGER RTT`
|
3. 调试输出统一使用 `SEGGER RTT`
|
||||||
4. 不引入 DHCP、DNS、UDP 等当前非目标协议
|
4. 不引入 DHCP、DNS、UDP 等当前非目标协议
|
||||||
|
|||||||
Reference in New Issue
Block a user