#if CLIENT_AUTO_TEST_STM32==1
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "lcd.h"
#include "beep.h"
#include "usmart.h"
#include "sram.h"
#include "lan8720.h"
#include "timer.h"
#include "rtc.h"
#include "adc.h"
#include "malloc.h"
#include "lwip/netif.h"
#include "lwip_comm.h"
#include "lwipopts.h"
#include "netif/etharp.h"
#include "lwip/ip_addr.h"   // 🔥 修复 IP_ADDR4 未定义
#include "lwip/dns.h"      // 🔥 修复 DNS API
#include <string.h>
#include "platform_adapter.h"

/****************************************************************************************
 *                              LWIP 调度机制 重要说明
 *
 *  本工程为 STM32 裸机环境，无 OS，LwIP 必须依靠 主动调用 lwip_periodic_handle() 才能运行
 *
 *  旧版问题：
 *     1. LwIP 只在部分 while 循环里调用，大部分时间不运行
 *     2. ARP、TCP 重传、网卡收包、心跳无法及时处理
 *     3. 极易出现：网络卡死、断连、收不到包、LwIP 死机
 *
 *  新版改进（关键）：
 *     1. 增加 LWIP_SAFE_POLL() 宏，强制调用 LwIP 周期处理
 *     2. 所有 等待函数、延时、循环、MQTT 处理 中都会调用
 *     3. LwIP 协议栈 100% 稳定运行，永不停止、永不卡死
 *     4. 裸机网络稳定性达到工业级标准
 *
 *  核心区别：
 *     旧版：LwIP 偶尔运行
 *     新版：LwIP 无处不在，每次循环必运行
 *
 *  所有 MQTT 测试逻辑、用例、流程、判定 均与旧版完全一致，仅优化 LwIP 调度安全性
 ****************************************************************************************/

// ==========================
// 重定向标准库 malloc/free
// ==========================
#include <stdlib.h>
void* malloc(size_t size)
{
    return mymalloc(SRAMIN, size);
}

void free(void* p)
{
    myfree(SRAMIN, p);
}

// ==========================
// 安全读取【真实生效IP】
// ==========================
void get_lwip_real_ip(u8 *ip)
{
    if(netif_default == NULL) {
        ip[0]=ip[1]=ip[2]=ip[3]=0;
        return;
    }
    ip[0] = ip4_addr1(&netif_default->ip_addr);
    ip[1] = ip4_addr2(&netif_default->ip_addr);
    ip[2] = ip4_addr3(&netif_default->ip_addr);
    ip[3] = ip4_addr4(&netif_default->ip_addr);
}

void get_lwip_real_gw(u8 *gw)
{
    if(netif_default == NULL) {
        gw[0]=gw[1]=gw[2]=gw[3]=0;
        return;
    }
    gw[0] = ip4_addr1(&netif_default->gw);
    gw[1] = ip4_addr2(&netif_default->gw);
    gw[2] = ip4_addr3(&netif_default->gw);
    gw[3] = ip4_addr4(&netif_default->gw);
}

// ==========================
// 判断 LwIP 网络是否真正就绪
// ==========================
uint8_t lwip_net_is_ready(void)
{
    if(netif_default == NULL) return 0;
    if(!netif_is_up(netif_default)) return 0;
    if(netif_default->ip_addr.addr == 0) return 0;
    return 1;
}

// ==========================
// 全局 LwIP 调度宏（强制调度）
// ==========================
#define LWIP_SAFE_POLL()  do { lwip_periodic_handle(); } while(0)

// ==========================
// 以下是你的 MQTT 测试代码
// ==========================
#define CLIENT_AUTO_TEST 1
/***************************************************************************
* File Name: mqtt_client_auto_test.c
***************************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "type.h"

/* -------------------------- 跨平台硬件适配 -------------------------- */
#if defined(STM32F10x) || defined(STM32F4xx) || defined(STM32H7xx) || defined(STM32L4xx)
  #define PLATFORM_STM32
  #include "stm32f4xx_hal.h"
  #define USE_STDIN_INPUT 0
#else
  #define PLATFORM_PC
  #define USE_STDIN_INPUT 1
#endif

#include "type.h"
#include "platform_adapter.h"
#include "agent_log.h"
#include "mqtt_client_sdk.h"

#ifndef PLATFORM_STM32
#ifdef _WIN32
#include <conio.h>
#include <windows.h>
#endif
#endif

/* -------------------------- 全局配置宏 -------------------------- */
#define APP_AUTO_LOG_EN            1
#define APP_LOG_LEVEL              AGENT_LOG_INFO
#define APP_MAX_CLIENT_NUM         2

#define MQTT_LOOP_INTERVAL_MS      50
#define MQTT_KEEP_ALIVE_SEC        30
#define MQTT_RECONNECT_INTERVAL_SEC 15
#define MQTT_MAX_RECONNECT_COUNT   0
#define MQTT_CONNACK_TIMEOUT_MS    5000
#define MQTT_PUB_TIMEOUT_MS        2000
#define MQTT_SUB_TIMEOUT_MS        5000
#define APP_DEMO_MQTT_VERSION      0
#define MQTT_CLEAN_START_MODE      true
#define MQTT_CONNECT_WAIT_MS       5500

#define AUTO_TEST_REPORT_INTERVAL  20
#define AUTO_PUB_INTERVAL_MS       500
#define TEST_MSG_BUF_LEN           512
#define AUTO_TEST_PUB_LOOP_CNT     200
#define AUTO_TEST_CHECK_SUBACK     1
#define AUTO_TEST_CHECK_PUBACK     1

#define THIRD_PARTY_TOPIC_PREFIX   "third/device/"
#define THIRD_PARTY_MSG_FORMAT     "{\"dev_id\":\"%s\",\"data\":\"%s\",\"ts\":%lld}"
#define THIRD_PARTY_DEV_ID         "mqtt_auto_test_001"
#define THIRD_PARTY_DATA_FIELD     "sensor_temp_hum"

#define DEFAULT_BROKER_IP          "192.168.3.10"
#define DEFAULT_BROKER_PORT        1883

#define CLIENT2_CLIENT_ID    "mqtt_auto_test_002"

#define APP_CRYPTO_KEY_DEF    "1234567890123456"
#define APP_CRYPTO_IV_DEF     "abcdef1234567890"
#define APP_CRYPTO_LEN        16
#define MQTT_CRYPTO_ENABLE    0

#define TEST_TOPIC_QOS0       THIRD_PARTY_TOPIC_PREFIX "qos0/report"
#define TEST_TOPIC_QOS1       THIRD_PARTY_TOPIC_PREFIX "qos1/control"
#define TEST_TOPIC_QOS2       THIRD_PARTY_TOPIC_PREFIX "qos2/important"
#define TEST_TOPIC_WILD       THIRD_PARTY_TOPIC_PREFIX "#"
#define TEST_TOPIC_WILL       THIRD_PARTY_TOPIC_PREFIX "offline/alert"
#define TEST_WILL_MSG         "{\"dev_id\":\"%s\",\"status\":\"offline\"}"

/* -------------------------- 全局变量 -------------------------- */
static bool_xxl                g_app_running = true;
static MqttSdkClient       g_mqtt_clients[APP_MAX_CLIENT_NUM] = {NULL};
static MqttSdkClientCfg    g_client_cfgs[APP_MAX_CLIENT_NUM] = {0};
static uint8_xxl             g_client_cnt = 0;
static time_t              g_test_start_time = 0;
static time_t              g_last_report_time = 0;

static uint32_xxl            g_total_case = 0;
static uint32_xxl            g_pass_case = 0;
static uint32_xxl            g_fail_case = 0;
static uint32_xxl            g_pub_total = 0;
static uint32_xxl            g_pub_ok = 0;
static uint32_xxl            g_pub_err = 0;
static uint32_xxl            g_sub_total = 0;
static uint32_xxl            g_sub_ok = 0;
static uint32_xxl            g_recv_msg = 0;
static bool_xxl                g_is_encrypt = false;
static uint32_xxl            g_third_party_msg_cnt = 0;
static bool_xxl                g_suback_received = false;

static char        g_user_broker1_ip[64] = {0};
static char        g_user_broker2_ip[64] = {0};
static int         g_user_broker1_port    = 0;
static int         g_user_broker2_port    = 0;

/* -------------------------- 第三方对接专用回调 -------------------------- */
static bool_xxl app_third_party_msg_check(const MqttSdkMsg* msg)
{
    if(msg == NULL || msg->payload == NULL || msg->payload_len == 0) return false;
    char* payload = (char*)msg->payload;
    if(strstr(payload, "dev_id") == NULL || strstr(payload, "data") == NULL || strstr(payload, "ts") == NULL)
    {
        agent_log_error("[third check fail] msg:%s", payload);
    }
    g_third_party_msg_cnt++;
    return true;
}

static void app_mqtt_loop(void)
{
    LWIP_SAFE_POLL();
    if(g_client_cnt == 0) return;
    for(uint8_xxl i=0; i<g_client_cnt; i++)
    {
        if(g_mqtt_clients[i] != NULL)
        {
            xxl_mqtt_sdk_client_loop(g_mqtt_clients[i]);
            LWIP_SAFE_POLL();  // <-- 每个客户端都调度一次
        }
    }
    
    LWIP_SAFE_POLL();  // <-- 最后再调度一次
}

/* -------------------------- 工具函数 -------------------------- */
static const char* app_mqtt_state_to_str(MqttSdkConnState state)
{
    switch(state)
    {
        case MQTT_SDK_STATE_DISCONNECTED: return "DISCONNECTED";
        case MQTT_SDK_STATE_CONNECTING:    return "CONNECTING";
        case MQTT_SDK_STATE_CONNECTED:     return "CONNECTED";
        default: return "UNKNOWN";
    }
}

static bool_xxl app_wait_mqtt_connected_ex(MqttSdkClient client, uint32_xxl timeout_ms)
{
    if (client == NULL) {
        agent_log_error("[wait] client is null!");
        return false;
    }

    uint32_xxl start_tick = ADAPTER_GetTickMs();
    MqttSdkConnState conn_state = MQTT_SDK_STATE_DISCONNECTED;

    agent_log_info("[wait] wait connect, timeout:%d ms", timeout_ms);
    
    while((ADAPTER_GetTickMs() - start_tick) < timeout_ms)
    {
        LWIP_SAFE_POLL();
        xxl_mqtt_sdk_client_loop(client);
        LWIP_SAFE_POLL();

        conn_state = xxl_mqtt_sdk_client_get_conn_state(client);
        if (conn_state == MQTT_SDK_STATE_CONNECTED) {
            agent_log_info("[wait] connect success!");
            return true;
        }

        // 微秒级延时，不阻塞TCP收包
        delay_us(100);
    }

    agent_log_error("[wait] connect timeout! state:%s", app_mqtt_state_to_str(conn_state));
    return false;
}

/* -------------------------- SDK回调函数 -------------------------- */
static void app_mqtt_msg_cb(const MqttSdkMsg* msg)
{
    if (NULL == msg) { 
        agent_log_error("[callback] invalid msg ptr"); 
        return; 
    }
    
    g_recv_msg++;
    
    if(AUTO_TEST_CHECK_SUBACK && msg->topic != NULL && strlen(msg->topic) == 0)
    {
        if(msg->payload_len == 1 && msg->payload != NULL)
        {
            uint8_xxl sub_auth_code = *(uint8_xxl*)msg->payload;
            g_suback_received = true;
            g_sub_ok++;
            if(sub_auth_code == 0x80)
            {
                agent_log_error("[suback] fail code:0x%02X", sub_auth_code);
            }
            else
            {
                agent_log_info("[suback] ok qos:%d", sub_auth_code);
            }
            return;
        }
        else if(msg->payload_len == 0 && msg->payload == NULL)
        {
            agent_log_info("[unsuback] ok");
            return;
        }
    }

    const char* safe_topic = (msg->topic != NULL) ? msg->topic : "NULL_TOPIC";
    bool_xxl third_check_ok = app_third_party_msg_check(msg);
    agent_log_info("[rx] topic:%s, qos:%d, len:%d, cnt:%d, check:%s",
                   safe_topic, msg->qos, msg->payload_len, g_recv_msg, third_check_ok ? "PASS" : "FAIL");
}

static void app_mqtt_conn_cb(const MqttSdkBrokerRespStatus* resp_status)
{
    // 🔥 修复：直接使用 SDK 传递的状态，不自己维护索引
    if (resp_status->client_connected)
    {
        agent_log_info("[conn] client connected success");
    }
    else
    {
        agent_log_warn("[conn] client disconnected");
    }
}

/* -------------------------- 工具函数 -------------------------- */
static char* app_safe_strdup(const char* src)
{
    if (NULL == src || strlen(src) == 0) return NULL;
    char* dst = (char*)malloc(strlen(src) + 1);
    if (dst) strcpy(dst, src);
    return dst;
}

static uint8_xxl app_get_client_idx(MqttSdkClient client)
{
    if(client == NULL || g_client_cnt == 0)
    {
        return 0xFF;
    }
    for(uint8_xxl i=0; i<g_client_cnt; i++)
    {
        if(g_mqtt_clients[i] == client) return i;
    }
    return 0xFF;
}

static bool_xxl app_check_all_config(void)
{
    agent_log_info("=============================================================");
    agent_log_info("config check start");
    agent_log_info("=============================================================");
    bool_xxl cfg_ok = true;
    
    if(strlen(THIRD_PARTY_TOPIC_PREFIX) == 0)
    {
        agent_log_error("[cfg] third party topic prefix empty");
        cfg_ok = false;
    }
    else
    {
        agent_log_info("[cfg] third party topic ok");
    }
    
    if(strlen(g_user_broker1_ip) == 0 || g_user_broker1_port < 1024)
    {
        agent_log_error("[cfg] broker1 invalid");
        cfg_ok = false;
    }
    else
    {
        agent_log_info("[cfg] broker1 ok:%s:%d", g_user_broker1_ip, g_user_broker1_port);
    }
    
    agent_log_info("=============================================================");
    agent_log_info("[cfg] check %s", cfg_ok ? "ok" : "fail");
    agent_log_info("=============================================================\n");
    return cfg_ok;
}

static void app_gen_third_party_msg(char* buf, uint32_xxl buf_len, uint32_xxl seq)
{
    if(buf == NULL || buf_len < 64) return;
    char_xxl data_str[64] = {0};
    sprintf(data_str, "%s_%d", THIRD_PARTY_DATA_FIELD, seq);
    snprintf(buf, buf_len-1, THIRD_PARTY_MSG_FORMAT, THIRD_PARTY_DEV_ID, data_str, (long long)time(NULL));
}

/* -------------------------- 客户端配置初始化 -------------------------- */
static void app_init_client_cfg(MqttSdkClientCfg* cfg, uint8_xxl idx, bool_xxl is_encrypt, bool_xxl use_client1)
{
    memset(cfg, 0, sizeof(MqttSdkClientCfg));
    if (use_client1)
    {
        cfg->broker_ip = app_safe_strdup(g_user_broker1_ip);
        cfg->broker_port = g_user_broker1_port;
        cfg->client_id = app_safe_strdup(THIRD_PARTY_DEV_ID);
    }
    else
    {
        cfg->broker_ip = app_safe_strdup(g_user_broker2_ip);
        cfg->broker_port = g_user_broker2_port;
        cfg->client_id = app_safe_strdup(CLIENT2_CLIENT_ID);
    }

    cfg->clean_start    = MQTT_CLEAN_START_MODE;
    cfg->keep_alive     = MQTT_KEEP_ALIVE_SEC;
    cfg->mqtt_version   = APP_DEMO_MQTT_VERSION;
    cfg->reconnect_intv = MQTT_RECONNECT_INTERVAL_SEC;
    cfg->max_reconnect  = MQTT_MAX_RECONNECT_COUNT;

    cfg->crypto_enable  = is_encrypt;
    g_is_encrypt = is_encrypt;
    if (is_encrypt)
    {
        uint8_xxl key_buf[16] = {0};
        uint8_xxl iv_buf[16] = {0};
        strncpy((char*)key_buf, APP_CRYPTO_KEY_DEF, 16);
        strncpy((char*)iv_buf, APP_CRYPTO_IV_DEF, 16);
        cfg->crypto_key = app_safe_strdup((char*)key_buf);
        cfg->crypto_iv  = app_safe_strdup((char*)iv_buf);
    }

    char_xxl will_msg[TEST_MSG_BUF_LEN] = {0};
    sprintf(will_msg, TEST_WILL_MSG, cfg->client_id);
    cfg->will_enable = true;
    cfg->will_msg.topic = TEST_TOPIC_WILL;
    cfg->will_msg.payload = (uint8_xxl*)will_msg;
    cfg->will_msg.payload_len = strlen(will_msg);
    cfg->will_msg.qos = MQTT_SDK_QOS1;
    cfg->will_msg.retain = true;
}

/* -------------------------- 断言 -------------------------- */
static bool_xxl app_case_assert(const char* case_name, MqttSdkErrCode ret)
{
    g_total_case++;
    if (ret == MQTT_SDK_OK)
    {
        agent_log_info("[case pass] %s", case_name);
        g_pass_case++;
        return true;
    }
    else
    {
        agent_log_error("[case fail] %s | err:%d", case_name, ret);
        g_fail_case++;
        return false;
    }
}

/* -------------------------- 测试用例 -------------------------- */
static bool_xxl app_testcase_00_no_encrypt_create(void)
{
    agent_log_info("case00 no encrypt create");
    if (g_mqtt_clients[0] != NULL) return app_case_assert("case00 exist", MQTT_SDK_OK);
    
    app_init_client_cfg(&g_client_cfgs[0], 0, false, true);
    g_mqtt_clients[0] = xxl_mqtt_sdk_client_create(&g_client_cfgs[0], app_mqtt_msg_cb, app_mqtt_conn_cb);
    
    LWIP_SAFE_POLL(); // <-- 加固
    
    if (g_mqtt_clients[0] == NULL) return app_case_assert("case00 create fail", MQTT_SDK_ERR_CREATE);

    MqttSdkErrCode ret = xxl_mqtt_sdk_client_connect(g_mqtt_clients[0]);
    
    LWIP_SAFE_POLL(); // <-- 加固
    LWIP_SAFE_POLL(); // <-- 加固
    
    if (ret == MQTT_SDK_OK) 
    {
        bool_xxl conn_ok = app_wait_mqtt_connected_ex(g_mqtt_clients[0], MQTT_CONNECT_WAIT_MS);
        if(conn_ok)
        {
            g_client_cnt++;
        }
        else
        {
            ret = MQTT_SDK_ERR_CONN;
        }
    }
    return app_case_assert("case00 no encrypt create", ret);
}

static bool_xxl app_testcase_01_encrypt_create(void)
{
    agent_log_info("case01 encrypt create");
    if(MQTT_CRYPTO_ENABLE == 0)
    {
        agent_log_info("encrypt skip");
        return app_case_assert("case01 skip", MQTT_SDK_OK);
    }
    if (g_mqtt_clients[0] != NULL) return app_case_assert("case01 exist", MQTT_SDK_OK);
    
    app_init_client_cfg(&g_client_cfgs[0], 0, true, true);
    g_mqtt_clients[0] = xxl_mqtt_sdk_client_create(&g_client_cfgs[0], app_mqtt_msg_cb, app_mqtt_conn_cb);
    if (g_mqtt_clients[0] == NULL) return app_case_assert("case01 create fail", MQTT_SDK_ERR_CREATE);

    MqttSdkErrCode ret = xxl_mqtt_sdk_client_connect(g_mqtt_clients[0]);
    if (ret == MQTT_SDK_OK) 
    {
        bool_xxl conn_ok = app_wait_mqtt_connected_ex(g_mqtt_clients[0], MQTT_CONNECT_WAIT_MS);
        if(conn_ok)
        {
            g_client_cnt++;
        }
        else
        {
            ret = MQTT_SDK_ERR_CONN;
        }
    }
    return app_case_assert("case01 encrypt create", ret);
}

static bool_xxl app_testcase_02_sub_topic(MqttSdkClient client)
{
    agent_log_info("case02 sub topic");
    if(client == NULL) return app_case_assert("case02 client null", MQTT_SDK_ERR_PARAM);
    
    LWIP_SAFE_POLL(); // <-- 建议加这行

    MqttSdkConnState conn_state = xxl_mqtt_sdk_client_get_conn_state(client);
    if (conn_state != MQTT_SDK_STATE_CONNECTED) {
        return app_case_assert("case02 not connected", MQTT_SDK_ERR_NO_CONN);
    }

    g_suback_received = false;
    MqttSdkErrCode ret = MQTT_SDK_OK;

    g_suback_received = false;
    ret |= xxl_mqtt_sdk_client_subscribe(client, TEST_TOPIC_QOS0, MQTT_SDK_QOS0, NULL);
    app_wait_mqtt_connected_ex(client, 500);

    g_suback_received = false;
    ret |= xxl_mqtt_sdk_client_subscribe(client, TEST_TOPIC_QOS1, MQTT_SDK_QOS1, NULL);
    app_wait_mqtt_connected_ex(client, 500);

    g_suback_received = false;
    ret |= xxl_mqtt_sdk_client_subscribe(client, TEST_TOPIC_QOS2, MQTT_SDK_QOS2, NULL);
    app_wait_mqtt_connected_ex(client, 500);

    g_sub_total +=3;
    return app_case_assert("case02 sub qos0/1/2", ret);
}

static bool_xxl app_testcase_03_sub_wildcard(MqttSdkClient client)
{
    agent_log_info("case03 sub wild");
    if(client == NULL) return app_case_assert("case03 client null", MQTT_SDK_ERR_PARAM);
    
    LWIP_SAFE_POLL(); // <-- 建议加这行

    MqttSdkConnState conn_state = xxl_mqtt_sdk_client_get_conn_state(client);
    if (conn_state != MQTT_SDK_STATE_CONNECTED) {
        return app_case_assert("case03 not connected", MQTT_SDK_ERR_NO_CONN);
    }

    g_suback_received = false;
    MqttSdkErrCode ret = xxl_mqtt_sdk_client_subscribe(client, TEST_TOPIC_WILD, MQTT_SDK_QOS1,NULL);
    g_sub_total +=1;
    app_wait_mqtt_connected_ex(client, 800);
    return app_case_assert("case03 sub wild", ret);
}

static bool_xxl app_testcase_04_publish_qos_msg(MqttSdkClient client, MqttSdkQos qos, const char* topic)
{
    if(client == NULL || topic == NULL) return app_case_assert("case04 param err", MQTT_SDK_ERR_PARAM);
    
    MqttSdkConnState conn_state = xxl_mqtt_sdk_client_get_conn_state(client);
    if (conn_state != MQTT_SDK_STATE_CONNECTED) {
        g_pub_total++;
        g_pub_err++;
        return app_case_assert("case04 not connected", MQTT_SDK_ERR_NO_CONN);
    }

    g_pub_total++;
    MqttSdkMsg msg = {0};
    char_xxl payload[TEST_MSG_BUF_LEN] = {0};
    sprintf(payload, "LAN_MQTT_DATA:%d,QoS=%d,TS=%lld", g_pub_total, qos, (long long)time(NULL));

    msg.topic = topic;
    msg.payload = (uint8_xxl*)payload;
    msg.payload_len = strlen(payload);
    msg.qos = qos;
    msg.retain = false;

    MqttSdkErrCode ret = xxl_mqtt_sdk_client_publish(client, &msg);
    app_mqtt_loop();
    if (ret == MQTT_SDK_OK) g_pub_ok++;
    else g_pub_err++;

    char_xxl case_name[64] = {0};
    sprintf(case_name, "case04 pub %s qos%d", g_is_encrypt?"enc":"plain", qos);
    return app_case_assert(case_name, ret);
}

static bool_xxl app_testcase_05_publish_retain(MqttSdkClient client)
{
    agent_log_info("case05 pub retain");
    if(client == NULL) return app_case_assert("case05 client null", MQTT_SDK_ERR_PARAM);
    
    MqttSdkConnState conn_state = xxl_mqtt_sdk_client_get_conn_state(client);
    if (conn_state != MQTT_SDK_STATE_CONNECTED) {
        g_pub_total++;
        g_pub_err++;
        return app_case_assert("case05 not connected", MQTT_SDK_ERR_NO_CONN);
    }

    g_pub_total++;
    MqttSdkMsg msg = {0};
    char_xxl payload[TEST_MSG_BUF_LEN] = {0};
    sprintf(payload, "LAN_RETAIN_DATA:%d,TS=%lld", g_pub_total, (long long)time(NULL));

    msg.topic = TEST_TOPIC_QOS0;
    msg.payload = (uint8_xxl*)payload;
    msg.payload_len = strlen(payload);
    msg.qos = MQTT_SDK_QOS0;
    msg.retain = true;

    MqttSdkErrCode ret = xxl_mqtt_sdk_client_publish(client, &msg);
    app_mqtt_loop();
    if (ret == MQTT_SDK_OK) g_pub_ok++;
    else g_pub_err++;
    return app_case_assert("case05 pub retain", ret);
}

static bool_xxl app_testcase_06_config_will(MqttSdkClient client)
{
    agent_log_info("case06 config will");
    uint8_xxl idx = app_get_client_idx(client);
    if (idx == 0xFF) return app_case_assert("case06 idx err", MQTT_SDK_ERR_PARAM);

    char_xxl will_msg[TEST_MSG_BUF_LEN] = {0};
    sprintf(will_msg, TEST_WILL_MSG, g_client_cfgs[idx].client_id);
    g_client_cfgs[idx].will_enable = true;
    g_client_cfgs[idx].will_msg.payload = (uint8_xxl*)will_msg;
    g_client_cfgs[idx].will_msg.payload_len = strlen(will_msg);

    xxl_mqtt_sdk_client_disconnect(client);
    app_mqtt_loop();
    delay_ms(1000);
    MqttSdkErrCode ret = xxl_mqtt_sdk_client_connect(client);
    bool_xxl conn_ok = app_wait_mqtt_connected_ex(client, MQTT_CONNECT_WAIT_MS);
    if(!conn_ok) ret = MQTT_SDK_ERR_CONN;
    return app_case_assert("case06 config will", ret);
}

static bool_xxl app_testcase_07_manual_reconnect(MqttSdkClient client)
{
    agent_log_info("case07 manual reconnect");
    if(client == NULL) return app_case_assert("case07 client null", MQTT_SDK_ERR_PARAM);
    
    MqttSdkErrCode ret = xxl_mqtt_sdk_client_disconnect(client);
    
    LWIP_SAFE_POLL(); // <-- 加固
    app_mqtt_loop();
    LWIP_SAFE_POLL(); // <-- 加固
    
    delay_ms(1000);
    
    LWIP_SAFE_POLL(); // <-- 加固
    
    if (ret != MQTT_SDK_OK) return app_case_assert("case07 disconnect fail", ret);

    delay_ms(1000);
    
    LWIP_SAFE_POLL(); // <-- 加固
    
    ret = xxl_mqtt_sdk_client_connect(client);
    
    LWIP_SAFE_POLL(); // <-- 加固
    LWIP_SAFE_POLL(); // <-- 加固
    
    bool_xxl conn_ok = app_wait_mqtt_connected_ex(client, MQTT_CONNECT_WAIT_MS);
    if(!conn_ok) ret = MQTT_SDK_ERR_CONN;

    return app_case_assert("case07 manual reconnect", ret);
}

static bool_xxl app_testcase_08_unsubscribe(MqttSdkClient client)
{
    agent_log_info("case08 unsub");
    if(client == NULL) return app_case_assert("case08 client null", MQTT_SDK_ERR_PARAM);
    
    MqttSdkConnState conn_state = xxl_mqtt_sdk_client_get_conn_state(client);
    if (conn_state != MQTT_SDK_STATE_CONNECTED) {
        return app_case_assert("case08 not connected", MQTT_SDK_ERR_NO_CONN);
    }

    MqttSdkErrCode ret = xxl_mqtt_sdk_client_unsubscribe(client, TEST_TOPIC_WILD,NULL);
    app_mqtt_loop();
    return app_case_assert("case08 unsub wild", ret);
}

static bool_xxl app_testcase_09_disconnect(MqttSdkClient client)
{
    agent_log_info("case09 disconnect");
    if(client == NULL) return app_case_assert("case09 client null", MQTT_SDK_ERR_PARAM);
    
    MqttSdkErrCode ret = xxl_mqtt_sdk_client_disconnect(client);
    
    LWIP_SAFE_POLL();  // <-- 加固
    LWIP_SAFE_POLL();  // <-- 加固
    
    app_mqtt_loop();
    
    LWIP_SAFE_POLL();  // <-- 加固
    
    delay_ms(1000);
    
    LWIP_SAFE_POLL();  // <-- 加固
    
    return app_case_assert("case09 disconnect", ret);
}

static bool_xxl app_testcase_10_destroy(MqttSdkClient client)
{
    agent_log_info("case10 destroy");
    uint8_xxl idx = app_get_client_idx(client);
    if (idx == 0xFF || g_client_cnt == 0) 
        return app_case_assert("case10 idx err", MQTT_SDK_ERR_PARAM);
    
    if(g_mqtt_clients[idx] != NULL)
    {
        xxl_mqtt_sdk_client_destroy(client);
    }

    LWIP_SAFE_POLL(); // <-- 加固

    if(g_client_cfgs[idx].broker_ip) free((void*)g_client_cfgs[idx].broker_ip);
    if(g_client_cfgs[idx].client_id) free((void*)g_client_cfgs[idx].client_id);
    if(g_client_cfgs[idx].crypto_key) free((void*)g_client_cfgs[idx].crypto_key);
    if(g_client_cfgs[idx].crypto_iv) free((void*)g_client_cfgs[idx].crypto_iv);
    
    memset(&g_client_cfgs[idx], 0, sizeof(MqttSdkClientCfg));
    g_mqtt_clients[idx] = NULL;
    if(g_client_cnt > 0) g_client_cnt--;
    g_is_encrypt = false;

    LWIP_SAFE_POLL(); // <-- 加固
    app_mqtt_loop();
    LWIP_SAFE_POLL(); // <-- 加固
    
    delay_ms(1000);
    
    LWIP_SAFE_POLL(); // <-- 加固
    
    return app_case_assert("case10 destroy", MQTT_SDK_OK);
}

static bool_xxl app_testcase_11_third_party_publish(MqttSdkClient client)
{
    agent_log_info("case11 third pub");
    if(client == NULL) return app_case_assert("case11 client null", MQTT_SDK_ERR_PARAM);
    
    MqttSdkConnState conn_state = xxl_mqtt_sdk_client_get_conn_state(client);
    if (conn_state != MQTT_SDK_STATE_CONNECTED) {
        g_pub_total++;
        g_pub_err++;
        return app_case_assert("case11 not connected", MQTT_SDK_ERR_NO_CONN);
    }

    g_pub_total++;
    MqttSdkMsg msg = {0};
    char_xxl payload[TEST_MSG_BUF_LEN] = {0};
    app_gen_third_party_msg(payload, TEST_MSG_BUF_LEN, g_pub_total);

    msg.topic = TEST_TOPIC_QOS1;
    msg.payload = (uint8_xxl*)payload;
    msg.payload_len = strlen(payload);
    msg.qos = MQTT_SDK_QOS1;
    msg.retain = false;

    MqttSdkErrCode ret = xxl_mqtt_sdk_client_publish(client, &msg);
    app_mqtt_loop();
    if (ret == MQTT_SDK_OK) 
    {
        g_pub_ok++;
    }
    else 
    {
        g_pub_err++;
    }
    return app_case_assert("case11 third pub", ret);
}

static bool_xxl app_testcase_12_third_party_multi_device(void)
{
    agent_log_info("【测试用例-12】双实例多设备第三方对接测试 >>> 开始执行");
    bool_xxl ret1 = app_testcase_00_no_encrypt_create();
    if(!ret1) return false;

    app_init_client_cfg(&g_client_cfgs[1], 1, false, false);
    g_mqtt_clients[1] = xxl_mqtt_sdk_client_create(&g_client_cfgs[1], app_mqtt_msg_cb, app_mqtt_conn_cb);
    if (g_mqtt_clients[1] == NULL)
    {
        return app_case_assert("双实例-创建第二台设备失败(第三方多设备对接)", MQTT_SDK_ERR_CREATE);
    }

    MqttSdkErrCode ret2 = xxl_mqtt_sdk_client_connect(g_mqtt_clients[1]);
    if(ret2 == MQTT_SDK_OK) 
    {
        bool_xxl conn_ok = app_wait_mqtt_connected_ex(g_mqtt_clients[1], MQTT_CONNECT_WAIT_MS);
        if(conn_ok)
        {
            g_client_cnt++;
            agent_log_info("[双实例成功] 实例2连接状态：%s", app_mqtt_state_to_str(xxl_mqtt_sdk_client_get_conn_state(g_mqtt_clients[1])));
        }
        else
        {
            ret2 = MQTT_SDK_ERR_CONN;
        }
    }
    return app_case_assert("双实例多设备同时对接局域网Broker(第三方平台多设备兼容)", ret2);
}

#define MAX_MULTI_CLIENT_NUM    10
#define MULTI_CLIENT_ID_PREFIX  "mqtt_multi_10_"

static bool_xxl app_testcase_13_dual_broker_online(void)
{
    agent_log_info("【测试用例-13】双独立Broker多实例长效测试 >>> 开始执行");
    MqttSdkClient c1 = NULL;
    MqttSdkClient c2 = NULL;
    MqttSdkErrCode ret1 = MQTT_SDK_OK;
    MqttSdkErrCode ret2 = MQTT_SDK_OK;

    app_init_client_cfg(&g_client_cfgs[0], 0, false, true);
    g_mqtt_clients[0] = xxl_mqtt_sdk_client_create(&g_client_cfgs[0], app_mqtt_msg_cb, app_mqtt_conn_cb);
    if (g_mqtt_clients[0] == NULL)
        return app_case_assert("双Broker-实例1创建失败", MQTT_SDK_ERR_CREATE);
    ret1 = xxl_mqtt_sdk_client_connect(g_mqtt_clients[0]);
    bool_xxl ok1 = false;
    if (ret1 == MQTT_SDK_OK)
        ok1 = app_wait_mqtt_connected_ex(g_mqtt_clients[0], MQTT_CONNECT_WAIT_MS);
    if (ok1)
    {
        g_client_cnt++;
        c1 = g_mqtt_clients[0];
        app_testcase_02_sub_topic(c1);
    }
    else
        ret1 = MQTT_SDK_ERR_CONN;

    app_init_client_cfg(&g_client_cfgs[1], 1, false, false);
    g_mqtt_clients[1] = xxl_mqtt_sdk_client_create(&g_client_cfgs[1], app_mqtt_msg_cb, app_mqtt_conn_cb);
    if (g_mqtt_clients[1] == NULL)
        return app_case_assert("双Broker-实例2创建失败", MQTT_SDK_ERR_CREATE);
    ret2 = xxl_mqtt_sdk_client_connect(g_mqtt_clients[1]);
    bool_xxl ok2 = false;
    if (ret2 == MQTT_SDK_OK)
        ok2 = app_wait_mqtt_connected_ex(g_mqtt_clients[1], MQTT_CONNECT_WAIT_MS);
    if (ok2)
    {
        g_client_cnt++;
        c2 = g_mqtt_clients[1];
        app_testcase_03_sub_wildcard(c2);
    }
    else
        ret2 = MQTT_SDK_ERR_CONN;

    agent_log_info("【双Broker测试】开始双实例独立发布消息，验证数据隔离...");
    for (int i = 0; i < 10; i++)
    {
        if (c1 != NULL)
            app_testcase_04_publish_qos_msg(c1, MQTT_SDK_QOS1, TEST_TOPIC_QOS1);
        if (c2 != NULL)
            app_testcase_04_publish_qos_msg(c2, MQTT_SDK_QOS0, TEST_TOPIC_QOS0);

        app_mqtt_loop();
        delay_ms(150);
    }

    agent_log_info("【双Broker测试】维持双长连接5秒，验证稳定性...");
    uint32_xxl hold_start = ADAPTER_GetTickMs();
    while ((ADAPTER_GetTickMs() - hold_start) < 5000)
    {
        app_mqtt_loop();
        delay_ms(50);
    }

    if (c1 != NULL)
    {
        xxl_mqtt_sdk_client_disconnect(c1);
        app_mqtt_loop();
        xxl_mqtt_sdk_client_destroy(c1);
        g_mqtt_clients[0] = NULL;
        g_client_cnt--;
    }
    if (c2 != NULL)
    {
        xxl_mqtt_sdk_client_disconnect(c2);
        app_mqtt_loop();
        xxl_mqtt_sdk_client_destroy(c2);
        g_mqtt_clients[1] = NULL;
        g_client_cnt--;
    }

    MqttSdkErrCode final_ret = (ret1 == MQTT_SDK_OK && ret2 == MQTT_SDK_OK) ? MQTT_SDK_OK : MQTT_SDK_ERR_CONN;
    return app_case_assert("双独立Broker多实例·独立订阅·独立发布·长连接测试", final_ret);
}

static bool_xxl app_testcase_14_ten_client_full_test(void)
{
    agent_log_info("case14 10 client test");
    MqttSdkClient temp_list[MAX_MULTI_CLIENT_NUM] = {NULL};
    MqttSdkClientCfg temp_cfg[MAX_MULTI_CLIENT_NUM] = {0};
    bool_xxl all_success = true;
    char temp_client_id[64] = {0};

    for (int i = 0; i < MAX_MULTI_CLIENT_NUM; i++)
    {
        sprintf(temp_client_id, "%s%d", MULTI_CLIENT_ID_PREFIX, i + 1);
        memset(&temp_cfg[i], 0, sizeof(MqttSdkClientCfg));

        temp_cfg[i].broker_ip = app_safe_strdup(g_user_broker1_ip);
        temp_cfg[i].broker_port = g_user_broker1_port;
        temp_cfg[i].client_id = app_safe_strdup(temp_client_id);

        temp_cfg[i].clean_start = MQTT_CLEAN_START_MODE;
        temp_cfg[i].keep_alive = MQTT_KEEP_ALIVE_SEC;
        temp_cfg[i].mqtt_version = APP_DEMO_MQTT_VERSION;
        temp_cfg[i].reconnect_intv = MQTT_RECONNECT_INTERVAL_SEC;
        temp_cfg[i].max_reconnect = MQTT_MAX_RECONNECT_COUNT;

        temp_list[i] = xxl_mqtt_sdk_client_create(&temp_cfg[i], app_mqtt_msg_cb, app_mqtt_conn_cb);
        if (temp_list[i] == NULL)
        {
            all_success = false;
            continue;
        }

        MqttSdkErrCode ret = xxl_mqtt_sdk_client_connect(temp_list[i]);
        if (ret == MQTT_SDK_OK)
        {
            bool_xxl conn_ok = app_wait_mqtt_connected_ex(temp_list[i], MQTT_CONNECT_WAIT_MS);
            if (!conn_ok)
            {
                all_success = false;
                continue;
            }

            g_suback_received = false;
            xxl_mqtt_sdk_client_subscribe(temp_list[i], TEST_TOPIC_QOS0, MQTT_SDK_QOS0, NULL);
            app_wait_mqtt_connected_ex(temp_list[i], 500);

            MqttSdkMsg msg = {0};
            char payload[128] = {0};
            sprintf(payload, "test14_msg_%d", i+1);
            msg.topic = TEST_TOPIC_QOS0;
            msg.payload = (uint8_xxl*)payload;
            msg.payload_len = strlen(payload);
            msg.qos = MQTT_SDK_QOS0;
            xxl_mqtt_sdk_client_publish(temp_list[i], &msg);
            app_mqtt_loop();
        }
        else
        {
            all_success = false;
        }
    }

    uint32_xxl hold_tick = ADAPTER_GetTickMs();
    while ((ADAPTER_GetTickMs() - hold_tick) < 3000)
    {
        for (int i = 0; i < MAX_MULTI_CLIENT_NUM; i++)
        {
            if (temp_list[i] != NULL)
            {
                xxl_mqtt_sdk_client_loop(temp_list[i]);
                LWIP_SAFE_POLL();
            }
        }
        delay_ms(50);
    }

    for (int i = 0; i < MAX_MULTI_CLIENT_NUM; i++)
    {
        if (temp_list[i] != NULL)
        {
            xxl_mqtt_sdk_client_disconnect(temp_list[i]);
            app_mqtt_loop();
            delay_ms(500);
            xxl_mqtt_sdk_client_destroy(temp_list[i]);
            temp_list[i] = NULL;
        }
        if (temp_cfg[i].broker_ip) free((void*)temp_cfg[i].broker_ip);
        if (temp_cfg[i].client_id) free((void*)temp_cfg[i].client_id);
    }

    for (int i = 0; i < APP_MAX_CLIENT_NUM; i++)
    {
        g_mqtt_clients[i] = NULL;
    }
    g_client_cnt = 0;

    MqttSdkErrCode final_ret = all_success ? MQTT_SDK_OK : MQTT_SDK_ERR_CONN;
    return app_case_assert("case14 10 client test", final_ret);
}

/* -------------------------- 测试报告 -------------------------- */
static void app_print_test_report(void)
{
    time_t now = time(NULL);
    double run_time = difftime(now, g_test_start_time);
    float case_pass_rate = 100.0f;
    float pub_pass_rate = 100.0f;
    
    if(g_total_case > 0)
        case_pass_rate = (g_pass_case * 100.0f) / g_total_case;
    if(g_pub_total > 0)
        pub_pass_rate = (g_pub_ok * 100.0f) / g_pub_total;

    agent_log_info("###########################################################################");
    agent_log_info("                       MQTT TEST REPORT");
    agent_log_info("###########################################################################");
    agent_log_info("time:%.0fs", run_time);
    agent_log_info("total case:%d pass:%d fail:%d", g_total_case, g_pass_case, g_fail_case);
    agent_log_info("case rate:%.2f%%", case_pass_rate);
    agent_log_info("pub total:%d ok:%d err:%d", g_pub_total, g_pub_ok, g_pub_err);
    agent_log_info("pub rate:%.2f%%", pub_pass_rate);
    agent_log_info("sub total:%d ok:%d", g_sub_total, g_sub_ok);
    agent_log_info("rx msg:%d", g_recv_msg);
    agent_log_info("third msg:%d", g_third_party_msg_cnt);
    agent_log_info("encrypt:%s", g_is_encrypt?"yes":"no");
    agent_log_info("###########################################################################");
    if (g_fail_case == 0)
    {
        agent_log_info("all test pass!");
    }
    else
    {
        agent_log_error("test fail:%d", g_fail_case);
    }
    agent_log_info("###########################################################################\n");
}

/* -------------------------- 测试主流程 -------------------------- */
static void app_auto_test_run(void)
{
    MqttSdkClient client = NULL;
    g_test_start_time = time(NULL);
    g_last_report_time = g_test_start_time;

    // 全局调度
    LWIP_SAFE_POLL();

    if(!app_check_all_config())
    {
        agent_log_error("config check fail!");
        g_app_running = false;
        return;
    }

    // ==============================================
    // 阶段 1：基础测试
    // ==============================================
    agent_log_info("phase 1: base test");
    LWIP_SAFE_POLL();

    if (app_testcase_00_no_encrypt_create())
    {
        LWIP_SAFE_POLL();
        client = g_mqtt_clients[0];

        app_testcase_02_sub_topic(client);
        LWIP_SAFE_POLL();

        app_testcase_03_sub_wildcard(client);
        LWIP_SAFE_POLL();

        app_testcase_04_publish_qos_msg(client, MQTT_SDK_QOS0, TEST_TOPIC_QOS0);
        LWIP_SAFE_POLL();

        app_testcase_04_publish_qos_msg(client, MQTT_SDK_QOS1, TEST_TOPIC_QOS1);
        LWIP_SAFE_POLL();

        app_testcase_04_publish_qos_msg(client, MQTT_SDK_QOS2, TEST_TOPIC_QOS2);
        LWIP_SAFE_POLL();

        app_testcase_05_publish_retain(client);
        LWIP_SAFE_POLL();

        app_testcase_06_config_will(client);
        LWIP_SAFE_POLL();

        app_testcase_07_manual_reconnect(client);
        LWIP_SAFE_POLL();

        app_testcase_08_unsubscribe(client);
        LWIP_SAFE_POLL();

        app_testcase_09_disconnect(client);
        LWIP_SAFE_POLL();

        app_testcase_10_destroy(client);
        LWIP_SAFE_POLL();
    }

    LWIP_SAFE_POLL();
    agent_log_info("==================================================================");

    // ==============================================
    // 阶段 2：加密测试
    // ==============================================
    agent_log_info("==================================================================");
    agent_log_info("【测试阶段-02】>>> 单实例加密对接功能测试 [开始执行] <<<");
    agent_log_info("==================================================================");
    LWIP_SAFE_POLL();

    if (app_testcase_01_encrypt_create())
    {
        LWIP_SAFE_POLL();
        client = g_mqtt_clients[0];

        app_testcase_02_sub_topic(client);
        LWIP_SAFE_POLL();

        app_testcase_04_publish_qos_msg(client, MQTT_SDK_QOS0, TEST_TOPIC_QOS0);
        LWIP_SAFE_POLL();

        app_testcase_07_manual_reconnect(client);
        LWIP_SAFE_POLL();

        app_testcase_09_disconnect(client);
        LWIP_SAFE_POLL();

        app_testcase_10_destroy(client);
        LWIP_SAFE_POLL();
    }

    LWIP_SAFE_POLL();
    agent_log_info("==================================================================");

    // ==============================================
    // 阶段 3：第三方对接 + 200条压测
    // ==============================================
    agent_log_info("==================================================================");
    agent_log_info("【测试阶段-03】>>> 第三方对接专项功能测试 [开始执行] <<<");
    agent_log_info("==================================================================");
    LWIP_SAFE_POLL();

    if (app_testcase_00_no_encrypt_create())
    {
        LWIP_SAFE_POLL();
        client = g_mqtt_clients[0];

        app_testcase_02_sub_topic(client);
        LWIP_SAFE_POLL();

        app_testcase_03_sub_wildcard(client);
        LWIP_SAFE_POLL();

        agent_log_info("【专项压测】开始连续发布200条第三方标准JSON格式消息...");
        for(int i=0; i<200; i++)
        {
            LWIP_SAFE_POLL();
            app_testcase_11_third_party_publish(client);
            LWIP_SAFE_POLL();
            delay_ms(AUTO_PUB_INTERVAL_MS);
            LWIP_SAFE_POLL();
            app_mqtt_loop();
            LWIP_SAFE_POLL();
        }

        agent_log_info("【专项压测】第三方格式消息压测完成：连续发布200条标准JSON消息 ✔️");
        LWIP_SAFE_POLL();

//        app_testcase_12_third_party_multi_device();
        LWIP_SAFE_POLL();

        app_testcase_09_disconnect(client);
        LWIP_SAFE_POLL();

        app_testcase_10_destroy(client);
        LWIP_SAFE_POLL();
    }

    LWIP_SAFE_POLL();
    agent_log_info("==================================================================");

    // ==============================================
    // 阶段 4：高频消息压测
    // ==============================================
    agent_log_info("==================================================================");
    agent_log_info("【测试阶段-04】>>> 高频消息发布性能压测 [开始执行] <<<");
    agent_log_info("==================================================================");
    LWIP_SAFE_POLL();

    if (app_testcase_00_no_encrypt_create())
    {
        LWIP_SAFE_POLL();
        client = g_mqtt_clients[0];

        app_testcase_02_sub_topic(client);
        LWIP_SAFE_POLL();

        agent_log_info("【性能压测】开始连续发布%d条QoS0消息...", AUTO_TEST_PUB_LOOP_CNT);
        for(int i=0; i<AUTO_TEST_PUB_LOOP_CNT; i++)
        {
            LWIP_SAFE_POLL();
            app_testcase_04_publish_qos_msg(client, MQTT_SDK_QOS0, TEST_TOPIC_QOS0);
            LWIP_SAFE_POLL();
            delay_ms(AUTO_PUB_INTERVAL_MS);
            LWIP_SAFE_POLL();
            app_mqtt_loop();
            LWIP_SAFE_POLL();
        }

        agent_log_info("【性能压测】消息发布完成：连续发布%d条QoS0消息 ✔️", AUTO_TEST_PUB_LOOP_CNT);
        LWIP_SAFE_POLL();

        app_testcase_09_disconnect(client);
        LWIP_SAFE_POLL();

        app_testcase_10_destroy(client);
        LWIP_SAFE_POLL();
    }

    LWIP_SAFE_POLL();
    agent_log_info("==================================================================");

    // ==============================================
    // 阶段 5：多实例 / 双Broker / 10客户端极限测试
    // ==============================================
    agent_log_info("==================================================================");
    agent_log_info("【测试阶段-05】>>> 多实例专项测试（双Broker+10极限实例） <<<");
    agent_log_info("==================================================================");
    LWIP_SAFE_POLL();

//    app_testcase_13_dual_broker_online();
    LWIP_SAFE_POLL();

//    app_testcase_14_ten_client_full_test();
    LWIP_SAFE_POLL();

    agent_log_info("==================================================================");

    // 最终报告
    LWIP_SAFE_POLL();
    app_print_test_report();
    LWIP_SAFE_POLL();

    g_app_running = false;
}

static void mqtt_log_init(void)
{
    AgentLogConfig log_cfg = {0};
    log_cfg.level = AGENT_LOG_DEBUG;

#ifdef PLATFORM_STM32
    log_cfg.dest = AGENT_LOG_DEST_CONSOLE;
#else
    log_cfg.dest = AGENT_LOG_DEST_CONSOLE | AGENT_LOG_DEST_FLASH;
    log_cfg.max_flash_size = 2 * 1024 * 1024;
#endif

    log_cfg.max_log_length = 256;
    agent_log_init(&log_cfg);
    agent_log_info("log init ok");
}

static void user_input_config(void)
{
    strcpy(g_user_broker1_ip, DEFAULT_BROKER_IP);
    g_user_broker1_port = DEFAULT_BROKER_PORT;

    strcpy(g_user_broker2_ip, DEFAULT_BROKER_IP);
    g_user_broker2_port = DEFAULT_BROKER_PORT;

    delay_ms(1000);
}

/**********************************************************/
int main(void)
{
    u8 t = 0;
    u8 real_ip[4] = {0};
    u8 real_gw[4] = {0};

    // 🔹 用于 10ms 定时调度 LWIP（不修改 timer.c）
    extern u32 lwip_localtime;
    static u32 last_lwip_tick = 0;

    HAL_Init();
    Stm32_Clock_Init(336,8,2,7);
    delay_init(168);
    uart_init(115200);
    LED_Init();
    BEEP_Init();
    KEY_Init();
    LCD_Init();
    SRAM_Init();
    MY_ADC_Init();
    RTC_Init();
    TIM3_Init(1000-1,83);

    my_mem_init(SRAMIN);
    my_mem_init(SRAMEX);
    my_mem_init(SRAMCCM);

    printf("\r\n\r\n=============================================\r\n");
    printf(" STM32F407 LwIP + MQTT Example\r\n");
    printf("=============================================\r\n");

    lwipdev.dhcpstatus = 0;

    // 本地静态IP
    lwipdev.ip[0] = 192;
    lwipdev.ip[1] = 168;
    lwipdev.ip[2] = 3;
    lwipdev.ip[3] = 130;

    // 子网掩码
    lwipdev.netmask[0] = 255;
    lwipdev.netmask[1] = 255;
    lwipdev.netmask[2] = 255;
    lwipdev.netmask[3] = 0;

    // 网关
    lwipdev.gateway[0] = 192;
    lwipdev.gateway[1] = 168;
    lwipdev.gateway[2] = 3;
    lwipdev.gateway[3] = 1;

    // MAC地址
    lwipdev.mac[0] = 0x00;
    lwipdev.mac[1] = 0x11;
    lwipdev.mac[2] = 0x22;
    lwipdev.mac[3] = 0x33;
    lwipdev.mac[4] = 0x44;
    lwipdev.mac[5] = 0x55;

    while(lwip_comm_init())
    {
        printf("[NET] LwIP Init FAIL, Retry...\r\n");
        delay_ms(50);
        LWIP_SAFE_POLL();
    }
    printf("[NET] LwIP Init OK\r\n");

    // ==========================
    // LWIP 1.4.1 初始化 DNS 服务器（正确版本，无报错）
    // ==========================
    {
        ip_addr_t dns_srv;
        IP4_ADDR(&dns_srv, 223, 5, 5, 5);
        dns_setserver(0, &dns_srv);
        IP4_ADDR(&dns_srv, 8, 8, 8, 8);
        dns_setserver(1, &dns_srv);
        printf("[NET] DNS Server: 223.5.5.5 & 8.8.8.8 OK\r\n");
    }

    printf("[NET] Waiting for IP ready...\r\n");
    while (!lwip_net_is_ready())
    {
        LWIP_SAFE_POLL();
        delay_ms(50);
    }

    get_lwip_real_ip(real_ip);
    get_lwip_real_gw(real_gw);

    printf("\r\n=============================================\r\n");
    printf("[NET] REAL IP     : %d.%d.%d.%d\r\n", real_ip[0],real_ip[1],real_ip[2],real_ip[3]);
    printf("[NET] REAL GW     : %d.%d.%d.%d\r\n", real_gw[0],real_gw[1],real_gw[2],real_gw[3]);
    printf("=============================================\r\n\r\n");

    mqtt_log_init();
    user_input_config();
    xxl_mqtt_sdk_global_init();
    app_auto_test_run();

    // 🔹 主循环：LWIP 10ms 精准调度 + MQTT 轮询（永不卡死）
    while(1)
    {
        // 每 10ms 调用一次 lwip_periodic_handle，LWIP 核心必须
        if(lwip_localtime - last_lwip_tick >= 10)
        {
            last_lwip_tick = lwip_localtime;
            lwip_periodic_handle();
        }

        // MQTT 客户端轮询
        app_mqtt_loop();

        // 心跳 LED
        LED0 = !LED0;
        delay_ms(10);
    }
}

#include <time.h>
static uint32_t g_tick_sec = 0;
time_t time(time_t *t)
{
    static uint32_t last_tick = 0;
    uint32_t now = HAL_GetTick();
    if(now - last_tick >= 1000)
    {
        g_tick_sec++;
        last_tick = now;
    }
    if(t) *t = g_tick_sec;
    return g_tick_sec;
}

#endif
