/*
 * 模块名称：CH395F Driver Test Suite
 * 模块功能：CH395F 驱动各功能模块的测试入口，分阶段组织测试用例
 * 适用平台：STM32F4 系列（CH395F 以太网芯片）
 * 作者：王建�? * 创建日期�?026-07-19
 * 修改记录�? *     2026-07-19  Phase 1/2/3 implemented
 */

/* 头文件包含区 */
#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 配置默认�? */
#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 配置默认�? */
#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

/*
 * 函数功能：恢�?TCP Server 多连接模式的数据 Socket 配置
 * 入口参数：port - TCP 源端口号
 * �?�?值：�? * 限定条件：CH395F 协议栈已初始�? * 函数说明：重新设置数�?Socket 的协议类型和源端�? */
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 ============================
 * 函数功能：寄存器读写 + 中断一致性基础测试
 * 入口参数：无
 * �?�?值：�? * 限定条件：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 收发 + 关闭重连 ×3 �? * 入口参数：无
 * �?�?值：�? * 限定条件：PC 端已启动 TCP Server（默�?192.168.1.2:8081�? * 函数说明：每轮连接→发送→接收→关闭，连续 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) ===");

    /* 解析目标 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);

    /* 一次性配�?*/
    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);

        /* 发送测试数�?*/
        {
            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 循环：收数据 �?回发 */
        {
            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 + 大包测试
 * 入口参数：无
 * �?�?值：�? * 限定条件：PC 端已启动 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 模式：DesIP=0xFFFFFFFF �?接受任意来源 */
    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 循环：收�?�?解析来源 �?回显 */
    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 测试
 * 入口参数：无
 * �?�?值：�? * 限定条件：net_init 已完�? * 函数说明：在 netTask 中运行，轮询 Socket 1~7 回显接收数据
 */
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_sock(sk, s_phase4_buf, sizeof(s_phase4_buf), NET_MSG_DONTWAIT);
        if (n > 0) {
            net_send_sock(sk, s_phase4_buf, n);
        }
    }
#endif
}

/*
 * ============================ Phase 5 ============================
 * NET �?UDP Echo：netTask 中运行，�?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 初始�? * 入口参数：无
 * �?�?值：�? * 限定条件：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_sock(net_get_sock(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 测试
 * 入口参数：无
 * �?�?值：�? * 限定条件：ch395f_phase5_init 已成功调�? * 函数说明：在 netTask 中运行，回显 UDP 接收数据
 */
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 配置默认�? */
#ifndef PHASE6_ANNOUNCE_PORT
#define PHASE6_ANNOUNCE_PORT    60001
#endif
#ifndef PHASE6_ANNOUNCE_SOCK
#define PHASE6_ANNOUNCE_SOCK    6
#endif

/*
 * ============================ Phase 6 ============================
 * 函数功能：DHCP 自动获取 IP 测试
 * 入口参数：无
 * �?�?值：�? * 限定条件：局域网内存�?DHCP Server
 * 函数说明：启�?DHCP �?轮询等待 IP �?打印结果 �?广播宣告 �?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 完成 */
    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. 读取获取�?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 模式：本地端�?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:
    TEST_REPORT("Phase 6");
#endif
}

/*
 * ============================ Phase 7 ============================
 * Select/Poll I/O 多路复用测试 �?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 多路复用测试
 * 入口参数：无
 * �?�?值：�? * 限定条件：net_init 已完成，多连�?TCP Server 已启�? * 函数说明：在 netTask 中运行，验证 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++) {
        net_sock_t *sk = net_get_sock(i);
        if (!sk || !NET_FD_ISSET(i, &readfds)) continue;

        int len = net_recv_sock(sk, s_phase7_buf, sizeof(s_phase7_buf), NET_MSG_DONTWAIT);
        if (len > 0) {
            net_send_sock(sk, s_phase7_buf, len);
            s_phase7_count++;
            TEST_CHECK(1, "Phase7: select echo #%lu (sock=%d, %d bytes)", s_phase7_count, i, len);
        }
    }
#endif
}

