Files
STM32F4-Base/Drivers/BSP/CH395F/ch395f_test.c
2026-07-19 15:27:49 +08:00

645 lines
22 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 模å<C2A1>—å<E28094><C3A5>称:CH395F Driver Test Suite
* 模å<C2A1>—功能:CH395F 驱动å<C2A8>„功能模å<C2A1>—çš„æµè¯•å…¥å<C2A5>£ï¼Œåˆ†é˜¶æ®µç»„织æµè¯•用ä¾
* é€ç”¨å¹³å<C2B3>°ï¼šSTM32F4 系列(CH395F 以太网芯片)
* 作者:王建� * 创建日期�026-07-19
* 修改记录� * 2026-07-19 Phase 1/2/3 implemented
*/
/* 头æ‡ä»¶åŒ…å<E280A6>«åŒº */
#include <string.h>
#include <stdio.h>
#include "ch395f_test.h"
#include "ch395f.h"
#include "net_socket.h"
#define DBG_TAG "[CH395T]"
#include "dbg_log.h"
test_stats_t g_test_stats;
/*
* Phase 2 é…<C3A9>置默认ï¿? */
#ifndef PHASE2_REMOTE_IP
#define PHASE2_REMOTE_IP "192.168.1.2"
#endif
#ifndef PHASE2_REMOTE_PORT
#define PHASE2_REMOTE_PORT 8081
#endif
#ifndef PHASE2_LOCAL_PORT
#define PHASE2_LOCAL_PORT 50000
#endif
#ifndef PHASE2_LOOP_COUNT
#define PHASE2_LOOP_COUNT 3
#endif
#ifndef PHASE2_TIMEOUT_MS
#define PHASE2_TIMEOUT_MS 10000
#endif
/*
* Phase 3 é…<C3A9>置默认ï¿? */
#ifndef PHASE3_REMOTE_IP
#define PHASE3_REMOTE_IP "192.168.1.2"
#endif
#ifndef PHASE3_REMOTE_PORT
#define PHASE3_REMOTE_PORT 8082
#endif
#ifndef PHASE3_LOCAL_PORT
#define PHASE3_LOCAL_PORT 60000
#endif
#ifndef PHASE3_ECHO_COUNT
#define PHASE3_ECHO_COUNT 30
#endif
#ifndef PHASE3_TIMEOUT_MS
#define PHASE3_TIMEOUT_MS 30000
#endif
/*
* 函数功能:æ<C5A1>¢ï¿?TCP Server 多连接模å¼<C3A5>的数æ<C2B0>® Socket é…<C3A9>ç½®
* å…¥å<C2A5>£å<C2A3>数:port - TCP æº<C3A6>端å<C2AF>£å<C2A3>·
* ï¿?ï¿?值:ï¿? * é™<C3A9>定æ<C5A1>¡ä»¶ï¼šCH395F å<><C3A5>议栈已åˆ<C3A5>å§ï¿? * 函数说明:é‡<C3A9>æ°è®¾ç½®æ•°ï¿?Socket çš„å<E2809E><C3A5>议类åžåŒæº<C3A6>端ï¿? */
static void restore_data_sockets(uint16_t port) {
int i = 0;
for (i = NET_TCP_SERVER_DATA_SOCK_START; i < NET_MAX_SOCKETS; i++) {
ch395f_set_proto_type((uint8_t)i, CH395F_PROTO_TYPE_TCP);
ch395f_set_sour_port((uint8_t)i, port);
}
DBG_INFO("data socks restored (port %d)", port);
}
/*
* ============================ Phase 1 ============================
* 函数功能:寄存器读写 + 中断一致性基础测试
* å…¥å<C2A5>£å<C2A3>数:无
* ï¿?ï¿?值:ï¿? * é™<C3A9>定æ<C5A1>¡ä»¶ï¼šCH395F 芯片正常应答
* 函数说明:包�GET_VERSION / GET_CMD_STATUS / GET_IP_INF �9 � */
void ch395f_phase1_tests(void) {
uint8_t i = 0;
int ver = 0;
DBG_INFO("=== CH395F Phase 1 Tests ===");
/* Test 1: GET_VERSION */
ver = ch395f_get_version();
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();
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];
ch395f_get_ip_inf(ip_info);
DBG_INFO("GET_IP_INF:");
DBG_INFO(" IP: %d.%d.%d.%d", ip_info[0], ip_info[1], ip_info[2], ip_info[3]);
DBG_INFO(" GW: %d.%d.%d.%d", ip_info[4], ip_info[5], ip_info[6], ip_info[7]);
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]);
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();
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();
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);
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);
TEST_CHECK(1, "SET_ARP(period=10*100ms, cnt=5): OK");
/* Test 8: SET_TTL */
ch395f_set_ttl(0, 64);
TEST_CHECK(1, "SET_TTL(sock=0, ttl=64): OK");
/* Test 9: CLEAR_RECV_BUF + SOCK_INT poll */
ch395f_clear_recv_buf(0);
TEST_CHECK(1, "CLEAR_RECV_BUF(sock=0): OK");
for (i = 0; i < 8; i++) {
uint8_t si = ch395f_get_sock_int_status(i);
TEST_CHECK(si == 0x00, "SOCK_INT(%d): 0x%02X", i, si);
}
TEST_REPORT("Phase 1");
}
/*
* ============================ Phase 2 ============================
* 函数功能:TCP Client æ”¶å<C2B6> + 关闭é‡<C3A9>连 ×3 ï¿? * å…¥å<C2A5>£å<C2A3>数:无
* ï¿?ï¿?值:ï¿? * é™<C3A9>定æ<C5A1>¡ä»¶ï¼šPC 端已å<C2B2>¯åЍ TCP Server(默ï¿?192.168.1.2:8081ï¿? * 函数说明:æ¯<C3A6>轮连接â†å<E28099>é€<C3A9>â†æŽ¥æ”¶â†å…³é—­ï¼Œè¿žç»­ 3 ï¿? */
void ch395f_phase2_tests(void) {
uint8_t sock = 0;
uint8_t sock_int = 0;
uint8_t rx_buf[300] = {0};
int i = 0;
uint32_t tick = 0;
uint16_t int_st = 0;
int iter_pass = 0;
DBG_INFO("=== CH395F Phase 2 Tests (TCP Client - Direct Driver) ===");
/* è§£æž<C3A6>ç®æ ‡ IP */
uint8_t ip_arr[4];
{
uint32_t a[4];
sscanf(PHASE2_REMOTE_IP, "%lu.%lu.%lu.%lu", &a[0], &a[1], &a[2], &a[3]);
ip_arr[0] = (uint8_t)a[0];
ip_arr[1] = (uint8_t)a[1];
ip_arr[2] = (uint8_t)a[2];
ip_arr[3] = (uint8_t)a[3];
}
DBG_INFO("Target: %s:%d", PHASE2_REMOTE_IP, PHASE2_REMOTE_PORT);
sock = (uint8_t)(NET_MAX_SOCKETS - 1);
/* 一次性é…<C3A9>ï¿?*/
ch395f_set_proto_type(sock, CH395F_PROTO_TYPE_TCP);
ch395f_set_send_buf(sock, 28, 2);
ch395f_set_recv_buf(sock, 30, 2);
ch395f_set_des_ip(sock, ip_arr);
ch395f_set_des_port(sock, PHASE2_REMOTE_PORT);
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);
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();
while (HAL_GetTick() - tick < PHASE2_TIMEOUT_MS) {
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_CONNECT) break;
}
HAL_Delay(10);
}
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);
/* å<>é€<C3A9>æµè¯•æ•°ï¿?*/
{
uint8_t test_buf[64] = {0};
const char *msg = "HelloFromCH395F_TCP_Client! This is a 64-byte test message.";
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);
ch395f_write_send_buf(sock, test_buf, 64);
}
/* Echo 循环:收数æ<C2B0>® ï¿?åžå<C5BE> */
{
int got_echo = 0;
tick = HAL_GetTick();
while (HAL_GetTick() - tick < 10000) {
uint16_t rlen = ch395f_get_recv_len(sock);
if (rlen > 0) {
uint16_t read_len = (rlen > sizeof(rx_buf)) ? (uint16_t)sizeof(rx_buf) : rlen;
memset(rx_buf, 0, sizeof(rx_buf));
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"); 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);
{
uint8_t st[2];
uint32_t wait = HAL_GetTick();
while (HAL_GetTick() - wait < 5000) {
ch395f_get_socket_status(sock, st);
if (st[0] == CH395F_SOCKET_CLOSED) break;
HAL_Delay(50);
}
DBG_INFO("closed: sock=0x%02X tcp=0x%02X", st[0], st[1]);
}
HAL_Delay(200);
}
restore_data_sockets(8080);
TEST_REPORT("Phase 2");
}
/*
* ============================ Phase 3 ============================
* 函数功能:UDP Server Echo + PING + 大包测试
* å…¥å<C2A5>£å<C2A3>数:无
* ï¿?ï¿?值:ï¿? * é™<C3A9>定æ<C5A1>¡ä»¶ï¼šPC 端已å<C2B2>¯åЍ UDP Client(默ï¿?192.168.1.2:8082ï¿? * 函数说明:包ï¿?20 次回显�? ï¿?PINGï¿?0 次大包收ï¿? */
void ch395f_phase3_tests(void) {
uint8_t sock = 0;
uint8_t rx_buf[300] = {0};
uint32_t tick = 0;
int i = 0;
int echo_ok = 0;
DBG_INFO("=== CH395F Phase 3 Tests (UDP) ===");
sock = (uint8_t)(NET_MAX_SOCKETS - 1);
/* UDP Server 模å¼<C3A5>:DesIP=0xFFFFFFFF ï¿?接å<C2A5>—ä»»æ„<C3A6>æ<EFBFBD>¥æº<C3A6> */
ch395f_set_proto_type(sock, CH395F_PROTO_TYPE_UDP);
ch395f_set_send_buf(sock, 28, 2);
ch395f_set_recv_buf(sock, 30, 2);
ch395f_set_sour_port(sock, PHASE3_LOCAL_PORT);
{
uint8_t zero_ip[4] = {0xFF, 0xFF, 0xFF, 0xFF};
ch395f_set_des_ip(sock, zero_ip);
}
ch395f_set_des_port(sock, 0);
TEST_CHECK(ch395f_open_socket(sock) == CH395F_ERR_SUCCESS,
"UDP socket %d opened (port=%d)", sock, PHASE3_LOCAL_PORT);
HAL_Delay(200);
/* Echo 循环:收ï¿?ï¿?è§£æž<C3A6>æ<EFBFBD>¥æº<C3A6> ï¿?回显 */
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);
if (rlen > 8) {
memset(rx_buf, 0, sizeof(rx_buf));
ch395f_read_recv_buf(sock, rx_buf, rlen);
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];
uint8_t *payload = &rx_buf[8];
DBG_INFO("UDP #%d: %dB from %d.%d.%d.%d:%d [%.32s]",
i + 1, payload_len,
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);
{
uint32_t swait = HAL_GetTick();
while (HAL_GetTick() - swait < 2000) {
uint16_t gs = ch395f_get_glob_int_status_all();
if (gs & (1U << (sock + 4))) {
if (ch395f_get_sock_int_status(sock) & CH395F_SINT_STAT_SENBUF_FREE)
break;
}
HAL_Delay(10);
}
}
echo_ok = 1;
break;
}
HAL_Delay(50);
}
TEST_CHECK(echo_ok, "UDP echo #%d/%d", i + 1, PHASE3_ECHO_COUNT);
if (!echo_ok) break;
}
ch395f_close_socket(sock);
TEST_CHECK(1, "UDP socket closed");
restore_data_sockets(8080);
TEST_REPORT("Phase 3");
}
/*
* ============================ Phase 4 ============================
* NET �TCP Echo:在主循环中调用,用 net_recv + net_send 回显
*/
#ifdef ENABLE_PHASE4_TESTS
static char s_phase4_buf[2048];
#endif
/*
* 函数功能:NET �TCP Echo 测试
* å…¥å<C2A5>£å<C2A3>数:无
* ï¿?ï¿?值:ï¿? * é™<C3A9>定æ<C5A1>¡ä»¶ï¼šnet_init 已完ï¿? * 函数说明:在 netTask 中è¿<C3A8>行,轮询 Socket 1~7 åžæ˜¾æŽ¥æ”¶æ•°æ<C2B0>®
*/
void ch395f_phase4_tests(void) {
#ifdef ENABLE_PHASE4_TESTS
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) {
continue;
}
int n = net_recv(i, s_phase4_buf, sizeof(s_phase4_buf), NET_MSG_DONTWAIT);
if (n > 0) {
net_send(i, s_phase4_buf, n, 0);
}
}
#endif
}
/*
* ============================ Phase 5 ============================
* NET ï¿?UDP Echo:netTask 中è¿<C3A8>行,ï¿?net_recvfrom + net_sendto 回显
*/
#ifndef PHASE5_LOCAL_PORT
#define PHASE5_LOCAL_PORT 60000
#endif
#ifdef ENABLE_PHASE5_TESTS
static int s_phase5_sock = -1;
static char s_phase5_buf[2048];
static uint32_t s_phase5_count = 0;
#endif
/*
* 函数功能:NET ï¿?UDP Echo åˆ<C3A5>å§ï¿? * å…¥å<C2A5>£å<C2A3>数:无
* ï¿?ï¿?值:ï¿? * é™<C3A9>定æ<C5A1>¡ä»¶ï¼šnet_init 已完ï¿? * 函数说明:创ï¿?UDP Socket 并绑定本地端ï¿? */
void ch395f_phase5_init(void) {
#ifdef ENABLE_PHASE5_TESTS
struct net_sockaddr_in addr;
s_phase5_sock = net_socket(NET_AF_INET, NET_SOCK_DGRAM, 0);
if (s_phase5_sock < 0) {
DBG_ERROR("Phase5: net_socket failed");
return;
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = NET_AF_INET;
addr.sin_port = net_htons(PHASE5_LOCAL_PORT);
if (net_bind(s_phase5_sock, (struct net_sockaddr *)&addr, sizeof(addr)) < 0) {
DBG_ERROR("Phase5: net_bind failed");
net_close(s_phase5_sock);
s_phase5_sock = -1;
return;
}
s_phase5_count = 0;
DBG_INFO("Phase5: UDP socket %d bound to port %d", s_phase5_sock, PHASE5_LOCAL_PORT);
#endif
}
/*
* 函数功能:NET �UDP Echo 测试
* å…¥å<C2A5>£å<C2A3>数:无
* ï¿?ï¿?值:ï¿? * é™<C3A9>定æ<C5A1>¡ä»¶ï¼šch395f_phase5_init å·²æˆ<C3A6>功调ï¿? * 函数说明:在 netTask 中è¿<C3A8>è¡Œï¼Œåžæ˜¾ UDP 接收数æ<C2B0>®
*/
void ch395f_phase5_tests(void) {
#ifdef ENABLE_PHASE5_TESTS
if (s_phase5_sock < 0) return;
struct net_sockaddr_in src;
int addrlen = sizeof(src);
int n = net_recvfrom(s_phase5_sock, s_phase5_buf, sizeof(s_phase5_buf),
NET_MSG_DONTWAIT,
(struct net_sockaddr *)&src, &addrlen);
if (n > 0) {
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 é…<C3A9>置默认ï¿? */
#ifndef PHASE6_ANNOUNCE_PORT
#define PHASE6_ANNOUNCE_PORT 60001
#endif
#ifndef PHASE6_ANNOUNCE_SOCK
#define PHASE6_ANNOUNCE_SOCK 6
#endif
/*
* ============================ Phase 6 ============================
* 函数功能:DHCP 自动获å<C2B7> IP 测试
* å…¥å<C2A5>£å<C2A3>数:无
* ï¿?ï¿?值:ï¿? * é™<C3A9>定æ<C5A1>¡ä»¶ï¼šå±€åŸŸç½å†…å­˜ï¿?DHCP Server
* 函数说明:å<C5A1>¯ï¿?DHCP ï¿?轮询等待 IP ï¿?打å<E2809C>°ç»“æžœ ï¿?广播宣告 ï¿?HELLO 回显
*/
void ch395f_phase6_tests(void) {
#ifdef ENABLE_PHASE6_TESTS
uint8_t status = 0;
uint8_t ip_info[20] = {0};
uint32_t tick = 0;
DBG_INFO("=== CH395F Phase 6 Tests (DHCP) ===");
/* 1. å<>¯ç”¨ DHCP */
ch395f_set_dhcp(1);
TEST_CHECK(1, "DHCP enabled, waiting for IP...");
/* 2. 轮询等待 DHCP 完æˆ<C3A6> */
HAL_Delay(500);
tick = HAL_GetTick();
while (HAL_GetTick() - tick < 30000) {
uint16_t gint = ch395f_get_glob_int_status_all();
if (gint & CH395F_GINT_STAT_DHCP) {
DBG_INFO("DHCP interrupt");
}
status = ch395f_get_dhcp_status();
if (status == 0x00) {
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) {
goto phase6_end;
}
/* 3. 读å<C2BB>获å<C2B7>ï¿?IP */
ch395f_get_ip_inf(ip_info);
DBG_INFO(" IP: %d.%d.%d.%d", ip_info[0], ip_info[1], ip_info[2], ip_info[3]);
DBG_INFO(" GW: %d.%d.%d.%d", ip_info[4], ip_info[5], ip_info[6], ip_info[7]);
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]);
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 确认 */
{
#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] = {0};
/* UDP Server 模å¼<C3A5>:本地端ï¿?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) {
/* å<>é€<C3A9>广æ­å®£åŠï¼ˆå®£åŠç«¯å<C2AF>£ = 60001,æ<C592>¥æº<C3A6>端ï¿?= 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(æ‰å†Œè¦<C3A8>æ±ï¼šæ¯<C3A6>次 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");
/* é‡<C3A9>ç½® Server 模å¼<C3A5>,等ï¿?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) {
/* 读å<C2BB>全局中æ­ï¼ˆåˆ·ï¿?socket 中æ­çжæ€<C3A6>) */
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:
TEST_REPORT("Phase 6");
#endif
}
/*
* ============================ Phase 7 ============================
* Select/Poll I/O 多路å¤<C3A5>用æµè¯• ï¿?net_select() + net_recv/send echo
*/
#include "net_select.h"
#ifdef ENABLE_PHASE7_TESTS
static char s_phase7_buf[2048];
#endif
/*
* 函数功能:Select/Poll I/O 多路å¤<C3A5>用æµè¯•
* å…¥å<C2A5>£å<C2A3>数:无
* ï¿?ï¿?值:ï¿? * é™<C3A9>定æ<C5A1>¡ä»¶ï¼šnet_init 已完æˆ<C3A6>,多连ï¿?TCP Server å·²å<C2B2>¯ï¿? * 函数说明:在 netTask 中è¿<C3A8>行,验è¯<C3A8> select/poll 正确返回读写事件
*/
void ch395f_phase7_tests(void) {
#ifdef ENABLE_PHASE7_TESTS
static uint32_t s_phase7_count = 0;
net_fd_set readfds;
net_timeval tv;
FD_ZERO
NET_FD_ZERO(&readfds);
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) {
NET_FD_SET(i, &readfds);
}
}
tv.tv_sec = 0;
tv.tv_usec = 50000;
int n = net_select(NET_MAX_SOCKETS, &readfds, NULL, NULL, &tv);
if (n <= 0) return;
for (int i = 0; i < NET_MAX_SOCKETS; i++) {
if (!NET_FD_ISSET(i, &readfds)) continue;
int len = net_recv(i, s_phase7_buf, sizeof(s_phase7_buf), NET_MSG_DONTWAIT);
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);
}
}
#endif
}