freeRTOS支持
This commit is contained in:
@@ -1313,7 +1313,7 @@ uint16_t ch395f_get_glob_int_status_all(void)
|
||||
|
||||
/*
|
||||
* 函数功能:获取 Socket 中断状态
|
||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||
* 返回值:Socket 中断状态字节 uint8_t
|
||||
* 限定条件:芯片已初始化
|
||||
*/
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
test_stats_t g_test_stats;
|
||||
|
||||
/*
|
||||
* Phase 2 配置默认值
|
||||
*/
|
||||
@@ -49,7 +51,7 @@
|
||||
#define PHASE3_LOCAL_PORT 60000
|
||||
#endif
|
||||
#ifndef PHASE3_ECHO_COUNT
|
||||
#define PHASE3_ECHO_COUNT 20
|
||||
#define PHASE3_ECHO_COUNT 30
|
||||
#endif
|
||||
#ifndef PHASE3_TIMEOUT_MS
|
||||
#define PHASE3_TIMEOUT_MS 30000
|
||||
@@ -82,14 +84,14 @@ void ch395f_phase1_tests(void)
|
||||
|
||||
/* Test 1: GET_VERSION */
|
||||
ver = ch395f_get_version();
|
||||
DBG_INFO("GET_VERSION: 0x%02X (ver=%d)", ver, ver & 0x3F);
|
||||
TEST_CHECK(ver > 0, "GET_VERSION: 0x%02X (ver=%d)", ver, ver & 0x3F);
|
||||
|
||||
/* Test 2: GET_CMD_STATUS */
|
||||
uint8_t cmd_st = ch395f_get_cmd_status();
|
||||
DBG_INFO("GET_CMD_STATUS: 0x%02X (%s)",
|
||||
cmd_st,
|
||||
cmd_st == CH395F_ERR_SUCCESS ? "SUCCESS" :
|
||||
cmd_st == CH395F_ERR_BUSY ? "BUSY" : "OTHER");
|
||||
TEST_CHECK(cmd_st == CH395F_ERR_SUCCESS,
|
||||
"GET_CMD_STATUS: 0x%02X (%s)", cmd_st,
|
||||
cmd_st == CH395F_ERR_SUCCESS ? "SUCCESS" :
|
||||
cmd_st == CH395F_ERR_BUSY ? "BUSY" : "OTHER");
|
||||
|
||||
/* Test 3: GET_IP_INF */
|
||||
uint8_t ip_info[20];
|
||||
@@ -100,43 +102,50 @@ void ch395f_phase1_tests(void)
|
||||
DBG_INFO(" MASK: %d.%d.%d.%d", ip_info[8], ip_info[9], ip_info[10], ip_info[11]);
|
||||
DBG_INFO(" DNS1: %d.%d.%d.%d", ip_info[12], ip_info[13], ip_info[14], ip_info[15]);
|
||||
DBG_INFO(" DNS2: %d.%d.%d.%d", ip_info[16], ip_info[17], ip_info[18], ip_info[19]);
|
||||
DBG_INFO(" IP match: %s", (ip_info[0]==192 && ip_info[1]==168 && ip_info[2]==1 && ip_info[3]==100) ? "YES" : "NO");
|
||||
DBG_INFO(" GW match: %s", (ip_info[4]==192 && ip_info[5]==168 && ip_info[6]==1 && ip_info[7]==1) ? "YES" : "NO");
|
||||
DBG_INFO(" MASK match: %s", (ip_info[8]==255 && ip_info[9]==255 && ip_info[10]==255 && ip_info[11]==0) ? "YES" : "NO");
|
||||
TEST_CHECK(ip_info[0]==192 && ip_info[1]==168 && ip_info[2]==1 && ip_info[3]==100,
|
||||
"IP match");
|
||||
TEST_CHECK(ip_info[4]==192 && ip_info[5]==168 && ip_info[6]==1 && ip_info[7]==1,
|
||||
"GW match");
|
||||
TEST_CHECK(ip_info[8]==255 && ip_info[9]==255 && ip_info[10]==255 && ip_info[11]==0,
|
||||
"MASK match");
|
||||
|
||||
/* Test 4: GINT_STATUS_ALL (2-byte version) */
|
||||
uint16_t gint_all = ch395f_get_glob_int_status_all();
|
||||
DBG_INFO("GINT_STATUS_ALL: 0x%04X (lo=0x%02X hi=0x%02X)", gint_all, gint_all & 0xFF, (gint_all >> 8) & 0xFF);
|
||||
TEST_CHECK((gint_all & 0xFF) == 0x04 || (gint_all & 0xFF) == 0x00,
|
||||
"GINT_STATUS_ALL: 0x%04X (lo=0x%02X hi=0x%02X)",
|
||||
gint_all, gint_all & 0xFF, (gint_all >> 8) & 0xFF);
|
||||
|
||||
/* Test 5: GINT_STATUS (1-byte version) — read-clear check */
|
||||
uint8_t gint_1b = ch395f_get_glob_int_status();
|
||||
DBG_INFO("GINT_STATUS_1byte (after clear): 0x%02X (expect 0x00 after read-clear)", gint_1b);
|
||||
TEST_CHECK(gint_1b == 0x00,
|
||||
"GINT_STATUS_1byte: 0x%02X (expect 0x00 after read-clear)", gint_1b);
|
||||
|
||||
/* Test 6: SOCK_STATUS(0) */
|
||||
{
|
||||
uint8_t st[2];
|
||||
ch395f_get_socket_status(0, st);
|
||||
DBG_INFO("SOCK_STATUS(0): sock=0x%02X(OPEN), tcp=0x%02X(LISTEN)", st[0], st[1]);
|
||||
TEST_CHECK(st[0] == 0x05 && st[1] == 0x01,
|
||||
"SOCK_STATUS(0): sock=0x%02X(LISTEN), tcp=0x%02X(LISTEN)", st[0], st[1]);
|
||||
}
|
||||
|
||||
/* Test 7: SET_ARP */
|
||||
ch395f_set_arp(10, 5);
|
||||
DBG_INFO("SET_ARP(period=10*100ms, cnt=5): OK");
|
||||
TEST_CHECK(1, "SET_ARP(period=10*100ms, cnt=5): OK");
|
||||
|
||||
/* Test 8: SET_TTL */
|
||||
ch395f_set_ttl(0, 64);
|
||||
DBG_INFO("SET_TTL(sock=0, ttl=64): OK");
|
||||
TEST_CHECK(1, "SET_TTL(sock=0, ttl=64): OK");
|
||||
|
||||
/* Test 9: CLEAR_RECV_BUF + SOCK_INT poll */
|
||||
ch395f_clear_recv_buf(0);
|
||||
DBG_INFO("CLEAR_RECV_BUF(sock=0): OK");
|
||||
TEST_CHECK(1, "CLEAR_RECV_BUF(sock=0): OK");
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
uint8_t si = ch395f_get_sock_int_status(i);
|
||||
DBG_INFO("SOCK_INT(%d): 0x%02X", i, si);
|
||||
TEST_CHECK(si == 0x00, "SOCK_INT(%d): 0x%02X", i, si);
|
||||
}
|
||||
|
||||
DBG_INFO("=== Phase 1 Tests Complete ===");
|
||||
TEST_REPORT("Phase 1");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -146,12 +155,12 @@ void ch395f_phase1_tests(void)
|
||||
void ch395f_phase2_tests(void)
|
||||
{
|
||||
uint8_t sock;
|
||||
uint8_t status;
|
||||
uint8_t sock_int;
|
||||
uint8_t rx_buf[300];
|
||||
int i;
|
||||
uint32_t tick;
|
||||
uint16_t int_st;
|
||||
int iter_pass;
|
||||
|
||||
DBG_INFO("=== CH395F Phase 2 Tests (TCP Client - Direct Driver) ===");
|
||||
|
||||
@@ -179,13 +188,12 @@ void ch395f_phase2_tests(void)
|
||||
for (i = 0; i < PHASE2_LOOP_COUNT; i++)
|
||||
{
|
||||
DBG_INFO("--- Iteration %d/%d ---", i + 1, PHASE2_LOOP_COUNT);
|
||||
iter_pass = 1;
|
||||
|
||||
ch395f_set_sour_port(sock, PHASE2_LOCAL_PORT + i);
|
||||
|
||||
status = ch395f_open_socket(sock);
|
||||
if (status != CH395F_ERR_SUCCESS) { DBG_ERROR("open failed"); goto phase2_end; }
|
||||
status = ch395f_tcp_connect(sock);
|
||||
if (status != CH395F_ERR_SUCCESS) { DBG_ERROR("connect failed"); ch395f_close_socket(sock); goto phase2_end; }
|
||||
if (ch395f_open_socket(sock) != CH395F_ERR_SUCCESS) { TEST_CHECK(0, "open socket"); iter_pass = 0; goto phase2_iter_done; }
|
||||
if (ch395f_tcp_connect(sock) != CH395F_ERR_SUCCESS) { TEST_CHECK(0, "tcp connect"); iter_pass = 0; ch395f_close_socket(sock); goto phase2_iter_done; }
|
||||
|
||||
/* 等待 CONNECT */
|
||||
tick = HAL_GetTick();
|
||||
@@ -195,11 +203,11 @@ void ch395f_phase2_tests(void)
|
||||
if (int_st & (1U << (sock + 4)))
|
||||
{
|
||||
sock_int = ch395f_get_sock_int_status(sock);
|
||||
if (sock_int & CH395F_SINT_STAT_CONNECT) { DBG_INFO("CONNECT"); break; }
|
||||
if (sock_int & CH395F_SINT_STAT_CONNECT) break;
|
||||
}
|
||||
HAL_Delay(10);
|
||||
}
|
||||
if (HAL_GetTick() - tick >= PHASE2_TIMEOUT_MS) { DBG_ERROR("connect timeout"); ch395f_close_socket(sock); goto phase2_end; }
|
||||
if (HAL_GetTick() - tick >= PHASE2_TIMEOUT_MS) { TEST_CHECK(0, "connect timeout"); iter_pass = 0; ch395f_close_socket(sock); goto phase2_iter_done; }
|
||||
|
||||
HAL_Delay(100);
|
||||
|
||||
@@ -210,13 +218,12 @@ void ch395f_phase2_tests(void)
|
||||
int p, mlen = (int)strlen(msg);
|
||||
memcpy(test_buf, msg, mlen);
|
||||
for (p = mlen; p < 64; p++) test_buf[p] = (uint8_t)('0' + (p - mlen) % 10);
|
||||
DBG_INFO("Sending test data (64 bytes)");
|
||||
ch395f_write_send_buf(sock, test_buf, 64);
|
||||
}
|
||||
|
||||
/* Echo 循环 */
|
||||
for (;;)
|
||||
/* Echo 循环:收数据 → 回发 */
|
||||
{
|
||||
int got_echo = 0;
|
||||
tick = HAL_GetTick();
|
||||
while (HAL_GetTick() - tick < 10000)
|
||||
{
|
||||
@@ -228,20 +235,24 @@ void ch395f_phase2_tests(void)
|
||||
ch395f_read_recv_buf(sock, rx_buf, read_len);
|
||||
DBG_INFO("recv: %d bytes [%.30s]", read_len, (char *)rx_buf);
|
||||
ch395f_write_send_buf(sock, rx_buf, read_len);
|
||||
got_echo = 1;
|
||||
break;
|
||||
}
|
||||
int_st = ch395f_get_glob_int_status_all();
|
||||
if (int_st & (1U << (sock + 4)))
|
||||
{
|
||||
sock_int = ch395f_get_sock_int_status(sock);
|
||||
if (sock_int & CH395F_SINT_STAT_DISCONNECT) { DBG_INFO("DISCONNECT"); goto phase2_iter_done; }
|
||||
if (sock_int & CH395F_SINT_STAT_SOCK_TIMEOUT) { DBG_INFO("SOCK_TIMEOUT"); goto phase2_iter_done; }
|
||||
if (sock_int & CH395F_SINT_STAT_DISCONNECT) { DBG_INFO("DISCONNECT"); break; }
|
||||
if (sock_int & CH395F_SINT_STAT_SOCK_TIMEOUT) { DBG_INFO("SOCK_TIMEOUT"); break; }
|
||||
}
|
||||
HAL_Delay(50);
|
||||
}
|
||||
if (!got_echo) { TEST_CHECK(0, "echo recv (iter %d)", i + 1); iter_pass = 0; }
|
||||
}
|
||||
|
||||
phase2_iter_done:
|
||||
if (iter_pass) TEST_CHECK(1, "Iteration %d PASS", i + 1);
|
||||
|
||||
/* 关闭 socket */
|
||||
ch395f_close_socket(sock);
|
||||
{
|
||||
@@ -258,9 +269,8 @@ phase2_iter_done:
|
||||
HAL_Delay(200);
|
||||
}
|
||||
|
||||
phase2_end:
|
||||
restore_data_sockets(8080);
|
||||
DBG_INFO("=== Phase 2 Tests Complete ===");
|
||||
TEST_REPORT("Phase 2");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -271,8 +281,9 @@ void ch395f_phase3_tests(void)
|
||||
{
|
||||
uint8_t sock;
|
||||
uint8_t rx_buf[300];
|
||||
uint32_t tick, echo_start;
|
||||
uint32_t tick;
|
||||
int i;
|
||||
int echo_ok;
|
||||
|
||||
DBG_INFO("=== CH395F Phase 3 Tests (UDP) ===");
|
||||
|
||||
@@ -289,20 +300,16 @@ void ch395f_phase3_tests(void)
|
||||
}
|
||||
ch395f_set_des_port(sock, 0);
|
||||
|
||||
if (ch395f_open_socket(sock) != CH395F_ERR_SUCCESS)
|
||||
{
|
||||
DBG_ERROR("UDP open failed");
|
||||
goto phase3_end;
|
||||
}
|
||||
DBG_INFO("UDP socket %d opened (server, port=%d, accept any)", sock, PHASE3_LOCAL_PORT);
|
||||
TEST_CHECK(ch395f_open_socket(sock) == CH395F_ERR_SUCCESS,
|
||||
"UDP socket %d opened (port=%d)", sock, PHASE3_LOCAL_PORT);
|
||||
|
||||
HAL_Delay(200);
|
||||
|
||||
/* Echo 循环:收到 → 解析来源 → 回显,最多 PHASE3_ECHO_COUNT 轮 */
|
||||
echo_start = HAL_GetTick();
|
||||
/* Echo 循环:收到 → 解析来源 → 回显 */
|
||||
for (i = 0; i < PHASE3_ECHO_COUNT; i++)
|
||||
{
|
||||
tick = HAL_GetTick();
|
||||
echo_ok = 0;
|
||||
while (HAL_GetTick() - tick < PHASE3_TIMEOUT_MS)
|
||||
{
|
||||
uint16_t rlen = ch395f_get_recv_len(sock);
|
||||
@@ -311,7 +318,6 @@ void ch395f_phase3_tests(void)
|
||||
memset(rx_buf, 0, sizeof(rx_buf));
|
||||
ch395f_read_recv_buf(sock, rx_buf, rlen);
|
||||
|
||||
/* 8 字节头: [0-1]reserved [2-3]src_port(LE) [4-7]src_ip [8+]payload */
|
||||
uint16_t payload_len = rlen - 8;
|
||||
uint16_t src_port = (uint16_t)rx_buf[2] | ((uint16_t)rx_buf[3] << 8);
|
||||
uint8_t *src_ip = &rx_buf[4];
|
||||
@@ -322,12 +328,10 @@ void ch395f_phase3_tests(void)
|
||||
src_ip[0], src_ip[1], src_ip[2], src_ip[3], src_port,
|
||||
payload_len > 0 ? (char *)payload : "");
|
||||
|
||||
/* 回显到发送方 */
|
||||
ch395f_set_des_ip(sock, src_ip);
|
||||
ch395f_set_des_port(sock, src_port);
|
||||
ch395f_write_send_buf(sock, payload, payload_len);
|
||||
|
||||
/* 等 SENDBUF_FREE 再收下一个(CH395F 要求写前必须空闲) */
|
||||
{
|
||||
uint32_t swait = HAL_GetTick();
|
||||
while (HAL_GetTick() - swait < 2000)
|
||||
@@ -341,29 +345,20 @@ void ch395f_phase3_tests(void)
|
||||
HAL_Delay(10);
|
||||
}
|
||||
}
|
||||
echo_ok = 1;
|
||||
break;
|
||||
}
|
||||
HAL_Delay(50);
|
||||
}
|
||||
|
||||
if (HAL_GetTick() - tick >= PHASE3_TIMEOUT_MS)
|
||||
{
|
||||
DBG_INFO("UDP recv timeout (%ds)", PHASE3_TIMEOUT_MS / 1000);
|
||||
break;
|
||||
}
|
||||
TEST_CHECK(echo_ok, "UDP echo #%d/%d", i + 1, PHASE3_ECHO_COUNT);
|
||||
if (!echo_ok) break;
|
||||
}
|
||||
|
||||
if (i >= PHASE3_ECHO_COUNT)
|
||||
DBG_INFO("Max echoes reached (%d)", PHASE3_ECHO_COUNT);
|
||||
else
|
||||
DBG_INFO("Elapsed: %lums", HAL_GetTick() - echo_start);
|
||||
|
||||
ch395f_close_socket(sock);
|
||||
DBG_INFO("UDP socket closed");
|
||||
TEST_CHECK(1, "UDP socket closed");
|
||||
|
||||
phase3_end:
|
||||
restore_data_sockets(8080);
|
||||
DBG_INFO("=== Phase 3 Tests Complete ===");
|
||||
TEST_REPORT("Phase 3");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -371,14 +366,14 @@ phase3_end:
|
||||
* NET 层 TCP Echo:在主循环中调用,用 net_recv + net_send 回显
|
||||
*/
|
||||
|
||||
#ifdef ENABLE_PHASE4_TESTS
|
||||
static char s_phase4_buf[2048];
|
||||
#endif
|
||||
|
||||
void ch395f_phase4_tests(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
#ifdef ENABLE_PHASE4_TESTS
|
||||
for (i = NET_TCP_SERVER_DATA_SOCK_START; i < NET_MAX_SOCKETS; i++)
|
||||
for (int i = NET_TCP_SERVER_DATA_SOCK_START; i < NET_MAX_SOCKETS; i++)
|
||||
{
|
||||
net_sock_t *sk = net_get_sock(i);
|
||||
if (sk == NULL || !sk->in_use || sk->state != NET_SOCK_STATE_ESTABLISHED)
|
||||
@@ -392,15 +387,12 @@ void ch395f_phase4_tests(void)
|
||||
net_send(i, s_phase4_buf, n, 0);
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void)i;
|
||||
(void)s_phase4_buf;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* ============================ Phase 5 ============================
|
||||
* NET 层 UDP Echo:主循环中运行,用 net_recvfrom + net_sendto 回显
|
||||
* NET 层 UDP Echo:netTask 中运行,用 net_recvfrom + net_sendto 回显
|
||||
*/
|
||||
|
||||
#ifndef PHASE5_LOCAL_PORT
|
||||
@@ -408,8 +400,9 @@ void ch395f_phase4_tests(void)
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_PHASE5_TESTS
|
||||
static int s_phase5_sock = -1;
|
||||
static char s_phase5_buf[2048];
|
||||
static int s_phase5_sock = -1;
|
||||
static char s_phase5_buf[2048];
|
||||
static uint32_t s_phase5_count = 0;
|
||||
#endif
|
||||
|
||||
void ch395f_phase5_init(void)
|
||||
@@ -436,6 +429,7 @@ void ch395f_phase5_init(void)
|
||||
return;
|
||||
}
|
||||
|
||||
s_phase5_count = 0;
|
||||
DBG_INFO("Phase5: UDP socket %d bound to port %d", s_phase5_sock, PHASE5_LOCAL_PORT);
|
||||
#endif
|
||||
}
|
||||
@@ -455,10 +449,22 @@ void ch395f_phase5_tests(void)
|
||||
{
|
||||
net_sendto(s_phase5_sock, s_phase5_buf, n, 0,
|
||||
(struct net_sockaddr *)&src, sizeof(src));
|
||||
s_phase5_count++;
|
||||
TEST_CHECK(1, "Phase5: UDP echo #%lu (%d bytes)", s_phase5_count, n);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Phase 6 配置默认值
|
||||
*/
|
||||
#ifndef PHASE6_ANNOUNCE_PORT
|
||||
#define PHASE6_ANNOUNCE_PORT 60001
|
||||
#endif
|
||||
#ifndef PHASE6_ANNOUNCE_SOCK
|
||||
#define PHASE6_ANNOUNCE_SOCK 6
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ============================ Phase 6 ============================
|
||||
* DHCP 自动获取 IP 测试
|
||||
@@ -475,7 +481,7 @@ void ch395f_phase6_tests(void)
|
||||
|
||||
/* 1. 启用 DHCP */
|
||||
ch395f_set_dhcp(1);
|
||||
DBG_INFO("DHCP enabled, waiting for IP...");
|
||||
TEST_CHECK(1, "DHCP enabled, waiting for IP...");
|
||||
|
||||
/* 2. 轮询等待 DHCP 完成 */
|
||||
HAL_Delay(500);
|
||||
@@ -491,17 +497,18 @@ void ch395f_phase6_tests(void)
|
||||
status = ch395f_get_dhcp_status();
|
||||
if (status == 0x00)
|
||||
{
|
||||
DBG_INFO("DHCP: SUCCESS");
|
||||
TEST_CHECK(1, "DHCP: SUCCESS");
|
||||
break;
|
||||
}
|
||||
|
||||
HAL_Delay(500);
|
||||
}
|
||||
|
||||
TEST_CHECK(HAL_GetTick() - tick < 30000,
|
||||
"DHCP completed within 30s (status=0x%02X)", status);
|
||||
|
||||
if (HAL_GetTick() - tick >= 30000)
|
||||
{
|
||||
status = ch395f_get_dhcp_status();
|
||||
DBG_ERROR("DHCP timeout (status=0x%02X)", status);
|
||||
goto phase6_end;
|
||||
}
|
||||
|
||||
@@ -512,13 +519,97 @@ void ch395f_phase6_tests(void)
|
||||
DBG_INFO(" MASK: %d.%d.%d.%d", ip_info[8], ip_info[9], ip_info[10], ip_info[11]);
|
||||
DBG_INFO(" DNS1: %d.%d.%d.%d", ip_info[12], ip_info[13], ip_info[14], ip_info[15]);
|
||||
|
||||
if (ip_info[0] == 0 && ip_info[1] == 0 && ip_info[2] == 0 && ip_info[3] == 0)
|
||||
TEST_CHECK(ip_info[0] != 0 || ip_info[1] != 0 || ip_info[2] != 0 || ip_info[3] != 0,
|
||||
"IP = %d.%d.%d.%d (non-zero)", ip_info[0], ip_info[1], ip_info[2], ip_info[3]);
|
||||
|
||||
/* 4. 广播宣告 + 等待 PC HELLO 确认 */
|
||||
{
|
||||
DBG_ERROR("DHCP: got 0.0.0.0 (failed)");
|
||||
#define PHASE6_HELLO_PORT 60000
|
||||
uint8_t anno_sock = PHASE6_ANNOUNCE_SOCK;
|
||||
uint8_t bcast_ip[4] = {0xFF, 0xFF, 0xFF, 0xFF};
|
||||
uint8_t rx_buf[64];
|
||||
|
||||
/* UDP Server 模式:本地端口 60000(接收 HELLO),DesIP=0xFFFFFFFF */
|
||||
ch395f_set_proto_type(anno_sock, CH395F_PROTO_TYPE_UDP);
|
||||
ch395f_set_send_buf(anno_sock, 24, 2);
|
||||
ch395f_set_recv_buf(anno_sock, 26, 2);
|
||||
ch395f_set_sour_port(anno_sock, PHASE6_HELLO_PORT);
|
||||
ch395f_set_des_ip(anno_sock, bcast_ip);
|
||||
ch395f_set_des_port(anno_sock, 0);
|
||||
|
||||
if (ch395f_open_socket(anno_sock) == CH395F_ERR_SUCCESS)
|
||||
{
|
||||
/* 发送广播宣告(宣告端口 = 60001,来源端口 = 60000) */
|
||||
ch395f_set_des_ip(anno_sock, bcast_ip);
|
||||
ch395f_set_des_port(anno_sock, PHASE6_ANNOUNCE_PORT);
|
||||
ch395f_write_send_buf(anno_sock, ip_info, 4);
|
||||
|
||||
/* 等待 SENDBUF_FREE(手册要求:每次 write_send_buf 后必须等待) */
|
||||
{
|
||||
uint32_t swait = HAL_GetTick();
|
||||
while (HAL_GetTick() - swait < 2000)
|
||||
{
|
||||
uint16_t gs = ch395f_get_glob_int_status_all();
|
||||
if (gs & (1U << (anno_sock + 4)))
|
||||
{
|
||||
if (ch395f_get_sock_int_status(anno_sock) & CH395F_SINT_STAT_SENBUF_FREE)
|
||||
break;
|
||||
}
|
||||
HAL_Delay(10);
|
||||
}
|
||||
}
|
||||
DBG_INFO("DHCP announcement: IP=%d.%d.%d.%d (port %d->%d)",
|
||||
ip_info[0], ip_info[1], ip_info[2], ip_info[3],
|
||||
PHASE6_HELLO_PORT, PHASE6_ANNOUNCE_PORT);
|
||||
TEST_CHECK(1, "DHCP announcement sent");
|
||||
|
||||
/* 重置 Server 模式,等待 PC 发送 HELLO */
|
||||
ch395f_set_des_ip(anno_sock, bcast_ip);
|
||||
ch395f_set_des_port(anno_sock, 0);
|
||||
|
||||
uint32_t wait = HAL_GetTick();
|
||||
uint8_t hello_ok = 0;
|
||||
while (HAL_GetTick() - wait < 5000)
|
||||
{
|
||||
/* 读取全局中断(刷新 socket 中断状态) */
|
||||
ch395f_get_glob_int_status_all();
|
||||
uint16_t rlen = ch395f_get_recv_len(anno_sock);
|
||||
if (rlen > 8)
|
||||
{
|
||||
memset(rx_buf, 0, sizeof(rx_buf));
|
||||
ch395f_read_recv_buf(anno_sock, rx_buf, rlen);
|
||||
uint16_t payload_len = rlen - 8;
|
||||
uint8_t *payload = &rx_buf[8];
|
||||
|
||||
if (payload_len == 5 && memcmp(payload, "HELLO", 5) == 0)
|
||||
{
|
||||
uint8_t *src_ip = &rx_buf[4];
|
||||
uint16_t src_port = (uint16_t)rx_buf[2] | ((uint16_t)rx_buf[3] << 8);
|
||||
ch395f_set_des_ip(anno_sock, src_ip);
|
||||
ch395f_set_des_port(anno_sock, src_port);
|
||||
ch395f_write_send_buf(anno_sock, payload, payload_len);
|
||||
HAL_Delay(100);
|
||||
DBG_INFO("HELLO response sent to %d.%d.%d.%d:%d",
|
||||
src_ip[0], src_ip[1], src_ip[2], src_ip[3], src_port);
|
||||
TEST_CHECK(1, "HELLO echo OK");
|
||||
hello_ok = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
HAL_Delay(50);
|
||||
}
|
||||
TEST_CHECK(hello_ok, "HELLO echo within 5s");
|
||||
|
||||
ch395f_close_socket(anno_sock);
|
||||
}
|
||||
else
|
||||
{
|
||||
TEST_CHECK(0, "DHCP announcement: open socket failed");
|
||||
}
|
||||
}
|
||||
|
||||
phase6_end:
|
||||
DBG_INFO("=== Phase 6 Tests Complete ===");
|
||||
TEST_REPORT("Phase 6");
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -536,14 +627,13 @@ static char s_phase7_buf[2048];
|
||||
void ch395f_phase7_tests(void)
|
||||
{
|
||||
#ifdef ENABLE_PHASE7_TESTS
|
||||
int i;
|
||||
static uint32_t s_phase7_count = 0;
|
||||
net_fd_set readfds;
|
||||
net_timeval tv;
|
||||
|
||||
NET_FD_ZERO(&readfds);
|
||||
|
||||
/* 把 ESTABLISHED 状态的 TCP 数据 socket 加入监听集合 */
|
||||
for (i = NET_TCP_SERVER_DATA_SOCK_START; i < NET_MAX_SOCKETS; i++)
|
||||
for (int i = NET_TCP_SERVER_DATA_SOCK_START; i < NET_MAX_SOCKETS; i++)
|
||||
{
|
||||
net_sock_t *sk = net_get_sock(i);
|
||||
if (sk && sk->in_use && sk->state == NET_SOCK_STATE_ESTABLISHED)
|
||||
@@ -552,15 +642,13 @@ void ch395f_phase7_tests(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* 50ms 超时,避免阻塞主循环 */
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 50000;
|
||||
|
||||
int n = net_select(NET_MAX_SOCKETS, &readfds, NULL, NULL, &tv);
|
||||
if (n <= 0) return;
|
||||
|
||||
/* 处理就绪的 socket */
|
||||
for (i = 0; i < NET_MAX_SOCKETS; i++)
|
||||
for (int i = 0; i < NET_MAX_SOCKETS; i++)
|
||||
{
|
||||
if (!NET_FD_ISSET(i, &readfds)) continue;
|
||||
|
||||
@@ -568,9 +656,9 @@ void ch395f_phase7_tests(void)
|
||||
if (len > 0)
|
||||
{
|
||||
net_send(i, s_phase7_buf, len, 0);
|
||||
s_phase7_count++;
|
||||
TEST_CHECK(1, "Phase7: select echo #%lu (sock=%d, %d bytes)", s_phase7_count, i, len);
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void)0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -6,6 +6,19 @@
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-07-19
|
||||
* 修改记录:
|
||||
*
|
||||
* === 通过标准速查 ===
|
||||
*
|
||||
* Phase | 通过条件 | 失败特征
|
||||
* ---------|-----------------------------------|--------------------------------
|
||||
* Phase 1 | 9 项全部打印 OK/SUCCESS/YES/0x00 | 任何一项显示 FAIL、ERROR、MISMATCH
|
||||
* Phase 2 | 3 轮 "PASS" 打印 | 任何一轮打印 "FAIL" 或超时
|
||||
* Phase 3 | 20/20 回显 + PING 5/5 + 大包 10/10 | 任何回显超时或丢包
|
||||
* Phase 4 | PC 脚本显示 10/10 sent/received | 断连、数据错乱
|
||||
* Phase 5 | PC 脚本显示 10/10 sent/received | 断连、数据错乱
|
||||
* Phase 6 | 日志打印 IP/GW/MASK 非零 IP | DHCP timeout 或 0.0.0.0
|
||||
* Phase 7 | PC 脚本显示 10/10 sent/received | 断连、数据错乱
|
||||
* Phase 8 | 70/70 成功率 100% | 任何连接失败或丢包
|
||||
*/
|
||||
|
||||
#ifndef __CH395F_TEST_H
|
||||
@@ -15,6 +28,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* 阶段使能开关(取消注释即启用对应阶段)
|
||||
* 注意:Phase 6 (DHCP) 会改变 IP,建议独立运行
|
||||
@@ -22,58 +37,97 @@ extern "C" {
|
||||
//#define ENABLE_PHASE1_TESTS /* 寄存器读写 + 中断一致性 */
|
||||
//#define ENABLE_PHASE2_TESTS /* TCP Client 收发 + 关闭重连 */
|
||||
//#define ENABLE_PHASE3_TESTS /* UDP Server Echo */
|
||||
//#define ENABLE_PHASE4_TESTS /* NET 层 TCP Echo(需主循环调用) */
|
||||
//#define ENABLE_PHASE5_TESTS /* NET 层 UDP Echo(需主循环调用) */
|
||||
#define ENABLE_PHASE4_TESTS /* NET 层 TCP Echo(netTask 中运行) */
|
||||
//#define ENABLE_PHASE5_TESTS /* NET 层 UDP Echo(netTask 中运行) */
|
||||
//#define ENABLE_PHASE6_TESTS /* DHCP 自动获取 IP(会改 IP!) */
|
||||
//#define ENABLE_PHASE7_TESTS /* Select/Poll I/O 多路复用 */
|
||||
//#define ENABLE_PHASE7_TESTS /* Select/Poll I/O 多路复用(netTask 中运行) */
|
||||
|
||||
/* 测试统计 */
|
||||
typedef struct {
|
||||
uint16_t total;
|
||||
uint16_t passed;
|
||||
uint16_t failed;
|
||||
} test_stats_t;
|
||||
|
||||
extern test_stats_t g_test_stats;
|
||||
|
||||
#define TEST_CHECK(cond, fmt, ...) do { \
|
||||
g_test_stats.total++; \
|
||||
if (cond) { \
|
||||
g_test_stats.passed++; \
|
||||
DBG_INFO("[PASS] " fmt, ##__VA_ARGS__); \
|
||||
} else { \
|
||||
g_test_stats.failed++; \
|
||||
DBG_ERROR("[FAIL] " fmt, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define TEST_REPORT(name) do { \
|
||||
DBG_INFO("=== %s: %d/%d PASSED (failed=%d) ===", \
|
||||
name, g_test_stats.passed, g_test_stats.total, g_test_stats.failed); \
|
||||
} while(0)
|
||||
|
||||
/*
|
||||
* Phase 1: 底层寄存器测试(版本、IP、中断、ARP/TTL 等)
|
||||
* 非破坏性,net_init() 后即可运行
|
||||
* Phase 1: 底层寄存器测试
|
||||
* 通过: 9 项全部打印 OK/SUCCESS/YES/0x00
|
||||
* 失败: 任何一项 FAIL/ERROR/MISMATCH
|
||||
*/
|
||||
void ch395f_phase1_tests(void);
|
||||
|
||||
/*
|
||||
* Phase 2: TCP Client 功能测试(3 轮收发 + 关闭重连)
|
||||
* 需 PC 端先运行:
|
||||
* Phase 2: TCP Client 收发 + 关闭重连 ×3 轮
|
||||
* 通过: 日志打印 3 轮 "PASS"
|
||||
* 失败: 任何一轮打印 "FAIL" 或超时
|
||||
* PC 端预启动:
|
||||
* python test/ch395f_socket_test.py tcp_server --port 8081
|
||||
*/
|
||||
void ch395f_phase2_tests(void);
|
||||
|
||||
/*
|
||||
* Phase 3: UDP Server Echo 测试(HELLO 探针 + PING + 大包)
|
||||
* 需 PC 端先运行:
|
||||
* python test/ch395f_socket_test.py udp_client --ip 192.168.1.100 --port 60000 --timeout 30
|
||||
* Phase 3: UDP Server Echo + PING + 大包
|
||||
* 通过: 20/20 回显 + PING 5/5 + 大包 10/10
|
||||
* 失败: 任何回显超时或丢包
|
||||
* PC 端:
|
||||
* ping 192.168.1.100
|
||||
* python test/ch395f_socket_test.py udp_client --ip 192.168.1.100 --port 60000
|
||||
*/
|
||||
void ch395f_phase3_tests(void);
|
||||
|
||||
/*
|
||||
* Phase 4: NET 层 TCP Echo(主循环中运行)
|
||||
* 需 PC 端运行(主循环进入后):
|
||||
* Phase 4: NET 层 TCP Echo(netTask 中运行)
|
||||
* 通过: PC 脚本 10/10 sent/received
|
||||
* 失败: 断连或数据错乱
|
||||
* PC 端:
|
||||
* python test/ch395f_socket_test.py tcp_client --ip 192.168.1.100 --port 8080
|
||||
*/
|
||||
void ch395f_phase4_tests(void);
|
||||
|
||||
/*
|
||||
* Phase 5: NET 层 UDP Echo(主循环中运行)
|
||||
* 需 PC 端运行(主循环进入后):
|
||||
* python test/ch395f_socket_test.py udp_client --ip 192.168.1.100 --port 60000 --timeout 30
|
||||
* 限定条件:需在 USER CODE BEGIN 2 中调用 ch395f_phase5_init() 创建 Socket,
|
||||
* USER CODE BEGIN 3 中调用 ch395f_phase5_tests() 做 echo
|
||||
* Phase 5: NET 层 UDP Echo(netTask 中运行)
|
||||
* 通过: PC 脚本 10/10 sent/received
|
||||
* 失败: 断连或数据错乱
|
||||
* 注:init 在 USER CODE BEGIN 2 中调用,echo 在 netTask 中运行
|
||||
* PC 端:
|
||||
* python test/ch395f_socket_test.py udp_client --ip 192.168.1.100 --port 60000
|
||||
*/
|
||||
void ch395f_phase5_init(void);
|
||||
void ch395f_phase5_tests(void);
|
||||
|
||||
/*
|
||||
* Phase 6: DHCP 测试
|
||||
* 自动获取 IP,打印结果。需独立运行(会改变 IP)
|
||||
* Phase 6: DHCP 自动获取 IP
|
||||
* 通过: DHCP SUCCESS + IP 非零 + 广播宣告 + HELLO 回显
|
||||
* 失败: DHCP timeout 或宣告/HELLO 失败
|
||||
* 注意: 会改变 IP,需独立运行
|
||||
* PC 端:管理员权限
|
||||
* python test/ch395f_socket_test.py dhcp_server --dhcp-iface 192.168.1.2 --ip 192.168.1.100
|
||||
*/
|
||||
void ch395f_phase6_tests(void);
|
||||
|
||||
/*
|
||||
* Phase 7: Select/Poll 测试(主循环中运行)
|
||||
* 使用 net_select() 检测可读 socket,net_recv/net_send 回显
|
||||
* 需 PC 端运行:
|
||||
* Phase 7: Select/Poll 测试(netTask 中运行)
|
||||
* 通过: PC 脚本 10/10 sent/received
|
||||
* 失败: 断连或数据错乱
|
||||
* PC 端:
|
||||
* python test/ch395f_socket_test.py tcp_client --ip 192.168.1.100 --port 8080
|
||||
*/
|
||||
void ch395f_phase7_tests(void);
|
||||
|
||||
@@ -160,6 +160,24 @@ int net_poll(void)
|
||||
break;
|
||||
}
|
||||
|
||||
/* 诊断:每 3 秒打印一次全局中断状态位和 Socket 状态
|
||||
* 注意:不要在此处读取 per-socket 中断状态(ch395f_get_sock_int_status
|
||||
* 会清除中断标志),避免破坏后续正常处理流程 */
|
||||
static uint32_t s_last_diag = 0;
|
||||
uint32_t now_diag = HAL_GetTick();
|
||||
if ((now_diag - s_last_diag >= 3000) || s_last_diag == 0)
|
||||
{
|
||||
s_last_diag = now_diag;
|
||||
uint16_t cur_int = ch395f_get_glob_int_status_all();
|
||||
DBG_INFO("GINT=0x%04X", cur_int);
|
||||
for (int di = 0; di < NET_MAX_SOCKETS; di++)
|
||||
{
|
||||
DBG_INFO(" s%d: in_use=%d state=%d rl=%d",
|
||||
di, g_net_socks[di].in_use, g_net_socks[di].state,
|
||||
g_net_socks[di].state == NET_SOCK_STATE_ESTABLISHED ? ch395f_get_recv_len((uint8_t)di) : 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (int_status & CH395F_GINT_STAT_PHY_CHANGE)
|
||||
{
|
||||
uint8_t phy = ch395f_get_phy_status();
|
||||
@@ -396,7 +414,23 @@ int net_listen(int sockfd, int backlog)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 配置 CH395F Socket */
|
||||
/* 多连接模式:先为数据 Socket 设置协议类型、源端口和独立缓冲区块
|
||||
* 必须在监听话筒 Socket OPEN+LISTEN 之前配置,确保 CH395F 的
|
||||
* 自动分配机制能扫描到所有可用 Socket
|
||||
* CH395F 根据源端口匹配、协议类型 TCP、状态 CLOSED 查找可用 Socket */
|
||||
for (int ds = NET_TCP_SERVER_DATA_SOCK_START; ds < NET_MAX_SOCKETS; ds++)
|
||||
{
|
||||
uint8_t base = (uint8_t)(ds * 4);
|
||||
ch395f_set_send_buf((uint8_t)ds, base, 2);
|
||||
ch395f_set_recv_buf((uint8_t)ds, base + 2, 2);
|
||||
/* 按 CH395F 手册 9.2.6 节顺序:先设源端口,再设协议类型 */
|
||||
ch395f_set_sour_port((uint8_t)ds, sock->local_port);
|
||||
ch395f_set_proto_type((uint8_t)ds, CH395F_PROTO_TYPE_TCP);
|
||||
}
|
||||
|
||||
/* 最后配置监听 Socket 并启动监听 */
|
||||
ch395f_set_send_buf((uint8_t)sockfd, 0, 2);
|
||||
ch395f_set_recv_buf((uint8_t)sockfd, 2, 2);
|
||||
ch395f_set_proto_type(sockfd, CH395F_PROTO_TYPE_TCP);
|
||||
ch395f_set_sour_port(sockfd, sock->local_port);
|
||||
status = ch395f_open_socket(sockfd);
|
||||
@@ -410,20 +444,6 @@ int net_listen(int sockfd, int backlog)
|
||||
/* 启动 TCP 监听 */
|
||||
ch395f_tcp_listen(sockfd);
|
||||
|
||||
/* 多连接模式:为数据 Socket 设置协议类型和源端口(不 OPEN)
|
||||
* Socket 4-7 默认无收发缓冲,需在此分配
|
||||
* CH395F 根据这些信息在客户端连接时自动分配空闲 Socket */
|
||||
for (int ds = NET_TCP_SERVER_DATA_SOCK_START; ds < NET_MAX_SOCKETS; ds++)
|
||||
{
|
||||
if (ds >= 4)
|
||||
{
|
||||
ch395f_set_send_buf((uint8_t)ds, 28, 2);
|
||||
ch395f_set_recv_buf((uint8_t)ds, 30, 2);
|
||||
}
|
||||
ch395f_set_proto_type((uint8_t)ds, CH395F_PROTO_TYPE_TCP);
|
||||
ch395f_set_sour_port((uint8_t)ds, sock->local_port);
|
||||
}
|
||||
|
||||
sock->state = NET_SOCK_STATE_LISTENING;
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user