AI辅助下的嵌入式UI系统设计与实践(二)[代码阅读理解]

目录

问题1

1.1(线程与定时器的本质区别)

[1.2 按键线程延迟50ms的影响](#1.2 按键线程延迟50ms的影响)

问题2

问题3

问题4

代码解读


问题1

按键扫描线程为什么不使用定时器?实际项目为什么选择了线程?按键线程延迟50ms会有什么影响?

1.1(线程与定时器的本质区别)

定时器是基于系统时钟中断,在中断上下文中执行回调函数,执行时间受限,不能有阻塞操作

线程是在任务上下文中执行,可以包含阻塞操作,执行时间更灵活

实际项目选择线程的原因

1、按键扫描的特点

一是需要持续监控按键状态变化,二是需要处理按键的按下和释放事件 ,包含状态机逻辑(空闲态、防抖态、保持按下态)

2、 线程的优势

  1. 逻辑完整性 :按键扫描的状态机逻辑需要连续执行,线程可以完整实现整个状态机流程

  2. 响应及时性 :线程可以在按键状态变化时立即处理,而定时器受定时周期限制

  3. 灵活性 :线程可以根据需要调整扫描间隔,适应不同的硬件特性

  4. 独立性 :按键处理逻辑独立于其他系统任务,不会影响主任务的执行

  5. 资源隔离 :线程有自己的栈空间,不会与其他任务共享栈资源 2.3 定时器的局限性

总结:

1、定时器回调函数执行时间有限制,不能执行复杂的状态机逻辑

2、定时器回调在中断上下文,不能使用可能引起阻塞的函数

3、多个定时器可能产生时间冲突,影响系统稳定性

1.2 按键线程延迟50ms的影响

  1. 扫描间隔的设计考虑

50ms 是一个平衡值,兼顾了响应速度和系统资源消耗,太短的间隔会增加CPU负担,太长的间隔会影响按键响应速度潜在负面影响。理论上,按键按下后最多需要50ms才能被检测到,对于非常快速的连续按键操作,可能会有轻微延迟。

  • 用户体验 :50ms的延迟在大多数场景下对用户体验影响不大,但在需要极高响应速度的场景下可能不够理想

总结:

1、人类感知的反应时间通常在100-200ms之间

2、50ms的扫描间隔远低于人类感知阈值,因此在实际使用中不会被用户察觉

3、对于机械按键来说,50ms的扫描间隔已经足够捕捉按键状态变化

问题2

当前屏幕,上一个屏幕,下一个屏幕是怎么在多个线程间进行通信的?多线程同步使用互斥锁,互斥锁在此代码中保护了哪些共享变量?你觉得哪些变量需要保护?

  1. 标志位机制
  • 使用 g_screen_switch_flag 作为线程间的信号,通知LVGL主线程执行屏幕切换

  • 这种"标志位+定时器"的模式避免了线程间的直接阻塞等待,提高了系统响应速度

  1. 状态分离
  • g_current_screen :当前实际显示的屏幕

  • g_target_screen :即将要显示的目标屏幕

  • 这种分离确保了即使在切换过程中,系统也能正确响应新的切换请求

  1. 互斥锁保护
  • 所有对共享变量的访问都通过互斥锁保护,确保线程安全

  • 特别是在计算下一个/上一个屏幕时,需要原子操作以避免数据竞争

  1. 优先级设计
  • 按键线程优先级设置为15,低于LVGL主线程(通常为更高优先级)

  • 确保UI更新的及时性,同时保证按键事件能够被及时处理

问题3

目前所有lvgl操作,包括屏幕切换及屏幕数据更新均在一个线程中进行?有什么好处?是否有更好的方案?

代码中所有LVGL操作(包括屏幕切换和数据更新)确实都在一个线程中进行,具体是在update_device_data定时器回调中执行。

集中在一个线程的好处

1.线程安全:

LVGL本身不是线程安全的,所有LVGL操作集中在一个线程中避免了多线程访问冲突,无需复杂的线程同步机制,降低了系统复杂度

2.性能优化:

减少了线程上下文切换的开销,避免了多线程竞争导致的性能下降

3.逻辑清晰:

所有UI相关操作集中管理,便于代码维护,避免了UI操作分散在多个线程的混乱情况

4.资源管理:

统一的内存分配和释放,减少内存泄漏风险,集中处理UI更新,便于控制更新频率

可能的改进方案

1.双线程方案:

UI线程:负责LVGL操作和屏幕更新

数据采集线程:负责从设备获取数据,通过队列或共享内存传递给UI线程

优点:数据采集和UI更新分离,提高系统响应速度

缺点:增加了线程同步的复杂度

2.多核心优化:

在多核系统上,将数据处理和UI更新分配到不同核心

利用现代处理器的多核心优势,提高系统整体性能

3.事件驱动方案:

使用事件队列代替定时器轮询

只有在数据变化时才触发UI更新,减少不必要的计算

问题4

全局数据初始化,首次初始化设备数据,避免频繁清零导致指针失效,为什么频繁清0会导致指针失效?

频繁清零导致指针失效的原因

  1. 指针覆盖 :
  • 当 g_main_info 中包含指针成员时, memset 会将这些指针清零

  • 清零后的指针变成野指针,再次访问会导致内存访问错误

  1. 动态内存管理 :
  • 如果 g_main_info 中的指针指向动态分配的内存,频繁清零会导致内存泄漏

  • 因为清零前没有释放已分配的内存,清零后无法再访问这些内存

  1. 数据一致性 :
  • 频繁清零会破坏数据的一致性,特别是在多线程环境下

  • 可能导致部分数据被清零,部分数据仍在使用,造成数据错乱

  1. 性能影响 :
  • 频繁的 memset 操作会增加CPU负担,特别是对于大型结构体

解决方案

  • 首次初始化 :只在首次使用时清零,之后不再清零

  • 选择性更新 :只更新需要变化的字段,而不是整个结构体

  • 内存管理 :对动态分配的内存进行正确的释放和重新分配

代码解读

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "lvgl.h"
#include "custom.h"
#include "ui_objects.h"
#include "aic_ui.h"
#include <inttypes.h>
#include <string.h>
#include <getopt.h>
#include <rtthread.h>
#include "rtdevice.h"
#include <rtdef.h>
#include "aic_core.h"
#include "aic_hal_gpio.h"
#include "../../../../../application/rt-thread/bl_hmi_ctl_app/driver/main_logic_proc.h"
#include "../../../../../application/rt-thread/bl_hmi_ctl_app/driver/sys_config.h"

/************************** 全局宏定义(集中管理,便于维护)**************************/
// 业务常量-模块与页面映射
#define MODULE_POWER_SCREEN 1
#define MODULE_WIFI_SCREEN 2
#define MODULE_SWITCH_SCREEN 3
#define MODULE_LOCATOR_SCREEN 4 // 精确定位
#define MODULE_TRAFFIC_LIGHT_SCREEN 5
#define MODULE_LOCATOR_SCREEN_VAGUE 7 // 区域定位
#define MAX_AVAILABLE_SCREENS 5

// 硬件参数-按键配置
#define KEY_UP_PIN "PE.13"    // 上键引脚
#define KEY_DOWN_PIN "PE.14"  // 下键引脚
#define KEY_DEBOUNCE_TICK 100 // 按键防抖时间(ms)
#define KEY_SCAN_INTERVAL 50  // 按键扫描间隔(ms)

// LVGL配置-定时器/动画
#define DATA_UPDATE_MS 500           // 数据更新频率(ms),LVGL操作主定时器
#define SCREEN_SWITCH_ANIM_MS 100    // 屏幕切换动画时间(ms),提升视觉体验
#define RESTORE_TIMER_MS 15000       // 按键后恢复自动轮询时间(ms)
#define DEFAULT_SCREEN_INTERVAL 4000 // 默认屏幕自动轮询间隔(ms)

// 业务配置-定位器/卡片
#define CARD_ID_LEN 5              // 卡号最大长度,防止越界
#define CARD_MAX_NUM 30            // 定位器最大显示卡片数
#define CARD_LINE_BREAK 9          // 区域定位卡片8个换行
#define CARD_PRECISE_LINE_BREAK 10 // 精确定位卡片10个换行

// 缓冲区配置-通用
#define IP_BUF_SIZE 31         // IP最大长度(255.255.255.255=15)+预留
#define HID_BUF_SIZE 16        // HID缓冲区大小
#define NUM_STR_SIZE 32        // 数字格式化字符串大小
#define CARD_SHOW_STR_SIZE 255 // 卡片拼接字符串大小

// 颜色宏定义
#define COLOR_CONNECT_GREEN lv_color_hex(0x00ff00)
#define COLOR_CONNECT_RED lv_color_hex(0xff0000)
#define COLOR_CONNECT_YELLOW lv_color_hex(0xffed2e)

// 供电类型适配(预留毫伏级注释,便于底层数据适配)
#define VOLTAGE_UNIT "V" // 若底层为毫伏,改为"mV"并去掉除1000逻辑

/************************** 多线程同步-互斥锁定义 **************************/
static rt_mutex_t g_ui_mutex = RT_NULL;
#define UI_MUTEX_TAKE() rt_mutex_take(g_ui_mutex, RT_WAITING_FOREVER)
#define UI_MUTEX_RELEASE() rt_mutex_release(g_ui_mutex)

/************************** 全局变量-业务核心(带互斥锁保护)**************************/
// 可用页面映射表
static rt_uint8_t g_available_screen_map[MAX_AVAILABLE_SCREENS] = {0};
static rt_uint8_t g_available_screen_count = 0;
// 屏幕管理-核心(按键/定时器仅修改标志位,LVGL线程处理实际切换)
static rt_uint8_t g_current_screen = 0;
static rt_uint8_t g_target_screen = 0;            // 目标屏幕标志位
static rt_bool_t g_screen_switch_flag = RT_FALSE; // 屏幕切换请求标志
static rt_bool_t g_auto_rotate_en = RT_TRUE;      // 自动轮询使能标志
// LVGL定时器句柄(仅做创建/销毁,无有效性判断,兼容低版本)
static lv_timer_t *g_screen_timer = NULL;
static lv_timer_t *g_restore_timer = NULL;
static lv_timer_t *g_data_update_timer = NULL;
// 设备数据-全局
extern sys_config_t g_sys_config;
static main_info_t g_main_info;
static rt_bool_t g_data_print_enable = RT_FALSE;
// 按键结构体(独立状态,防抖保护)
typedef struct
{
    rt_base_t pin;
    rt_uint8_t state;
    rt_uint32_t press_tick;
    rt_bool_t is_pressed;
    const char *name; // 改为const,避免字符串修改
} my_key_t;
static my_key_t g_key_up = {RT_NULL, 0, 0, RT_FALSE, "key_up"};
static my_key_t g_key_down = {RT_NULL, 0, 0, RT_FALSE, "key_down"};

/************************** 静态函数声明(按功能分类,便于维护)**************************/
// 屏幕管理
static void screen_switch_proc(void);
static rt_uint8_t get_next_available_screen(void);
static rt_uint8_t get_prev_available_screen(void);
// 按键处理
static void key_scan_process(my_key_t *key);
static void key_scan_thread_entry(void *param);
static void key_up_handler(void);
static void key_down_handler(void);
// 定时器回调(仅修改标志位,无LVGL操作)
static void screen_timer_cb(lv_timer_t *timer);
static void restore_timer_cb(lv_timer_t *timer);
static void update_device_data(lv_timer_t *timer);
// 数据更新-各模块(纯LVGL操作,运行在LVGL主线程)
static void update_power_data(void);
static void update_wifi_data(void);
static void update_switch_data(void);
static void update_locator_data_vague(void);   // 区域定位(screen3)
static void update_locator_data_precise(void); // 精确定位(screen7)
static void update_traffic_data(void);
// 辅助函数
static void print_main_info(void);
static rt_uint8_t get_screen_map_index(rt_uint8_t screen_idx);
static rt_uint8_t get_screen_from_map(rt_uint8_t map_idx);
static rt_uint8_t get_screen_display_page(rt_uint8_t screen_idx);
static const char *get_port_status_str(rt_uint8_t state);
static void update_port_label(lv_obj_t *label, rt_uint8_t state);

/************************** 外部接口-页面显示页码(供UI调用)**************************/
rt_uint8_t get_screen_display_page(rt_uint8_t screen_idx)
{
    UI_MUTEX_TAKE();
    rt_uint8_t map_idx = get_screen_map_index(screen_idx);
    rt_uint8_t ret = 0;
    if (map_idx < g_available_screen_count)
    {
        ret = (map_idx + 1);
    }
    UI_MUTEX_RELEASE();
    return ret;
}

/************************** 核心函数-屏幕切换处理(纯LVGL操作,LVGL线程执行)**************************/
static void screen_switch_proc(void)
{
    UI_MUTEX_TAKE();
    // 1. 校验目标屏幕有效性
    if (g_target_screen < 1 || g_target_screen > 7 ||
        get_screen_map_index(g_target_screen) >= g_available_screen_count)
    {
        rt_kprintf("[UI] Invalid target screen: %d\n", g_target_screen);
        g_screen_switch_flag = RT_FALSE;
        UI_MUTEX_RELEASE();
        return;
    }
    // 2. 若目标屏幕与当前一致,直接返回
    if (g_target_screen == g_current_screen)
    {
        g_screen_switch_flag = RT_FALSE;
        UI_MUTEX_RELEASE();
        return;
    }
    // rt_kprintf("[UI] Switch screen: %d -> %d\n", g_current_screen, g_target_screen);

    // 3. 安全删除旧屏幕(LVGL内部线程安全,立即删除避免野指针)
    lv_obj_t *act_scr = lv_scr_act();
    if (act_scr && !lv_obj_is_valid(act_scr))
    {
        act_scr = NULL;
        rt_kprintf("[UI] Old screen obj invalid, force clear\n");
    }

    // 4. 根据模块类型动态创建目标屏幕(核心:定位器双界面逻辑)
    lv_obj_t *new_screen = NULL;
    switch (g_target_screen)
    {
    case MODULE_POWER_SCREEN:
        screen_1_create(&ui_manager);
        new_screen = screen_1_get(&ui_manager)->obj;
        break;
    case MODULE_WIFI_SCREEN:
        screen_2_create(&ui_manager);
        new_screen = screen_2_get(&ui_manager)->obj;
        break;
    case MODULE_SWITCH_SCREEN:
        screen_5_create(&ui_manager);
        new_screen = screen_5_get(&ui_manager)->obj;
        break;
    case MODULE_LOCATOR_SCREEN:
        // 根据定位器类型创建 0 screen(区域)/1 screen7(精准)
        screen_7_create(&ui_manager);
        new_screen = screen_7_get(&ui_manager)->obj;
        break;
    case MODULE_TRAFFIC_LIGHT_SCREEN:
        screen_4_create(&ui_manager);
        new_screen = screen_4_get(&ui_manager)->obj;
        break;
    case MODULE_LOCATOR_SCREEN_VAGUE:
        screen_3_create(&ui_manager);
        new_screen = screen_3_get(&ui_manager)->obj;
        break;

    default:
        break;
    }

    // 5. 加载新屏幕并更新当前屏幕
    if (new_screen)
    {
        lv_scr_load_anim(new_screen, LV_SCR_LOAD_ANIM_FADE_ON, SCREEN_SWITCH_ANIM_MS, 0, RT_TRUE);
        g_current_screen = g_target_screen; // 仅创建成功后更新
    }
    else
    {
        rt_kprintf("[UI] Failed to create screen %d\n", g_target_screen);
    }
    // 6. 清除切换标志
    g_screen_switch_flag = RT_FALSE;
    UI_MUTEX_RELEASE();
}

/************************** 按键处理-状态机+防抖(无LVGL操作,纯标志位修改)**************************/
static void key_scan_process(my_key_t *key)
{
    if (!key || key->pin < 0)
        return;

    rt_uint8_t current_level = rt_pin_read(key->pin);
    switch (key->state)
    {
    case 0: // 空闲态
        if (current_level == PIN_LOW && !key->is_pressed)
        {
            key->state = 1;
            key->press_tick = rt_tick_get();
        }
        break;
    case 1: // 防抖态
        if (rt_tick_get() - key->press_tick >= KEY_DEBOUNCE_TICK)
        {
            if (current_level == PIN_LOW)
            {
                key->state = 2;
                key->is_pressed = RT_TRUE;
                // 触发按键回调(仅修改标志位)
                if (rt_strcmp(key->name, "key_up") == RT_EOK)
                    key_up_handler();
                else if (rt_strcmp(key->name, "key_down") == RT_EOK)
                    key_down_handler();
            }
            else
            {
                key->state = 0; // 抖动脉冲,放弃
            }
        }
        break;
    case 2: // 保持按下态
        if (current_level == PIN_HIGH)
        {
            key->state = 0;
            key->is_pressed = RT_FALSE;
        }
        break;
    default:
        key->state = 0;
        break;
    }
}

static void key_up_handler(void)
{
    UI_MUTEX_TAKE();
    g_auto_rotate_en = RT_FALSE;                   // 暂停自动轮询
    g_target_screen = get_prev_available_screen(); // 设置上一页
    g_screen_switch_flag = RT_TRUE;                // 触发切换请求
    // 重置恢复定时器(恢复自动轮询)
    if (g_restore_timer)
        lv_timer_reset(g_restore_timer);
    UI_MUTEX_RELEASE();
    rt_kprintf("[KEY] Key up pressed, target screen: %d\n", g_target_screen);
}

static void key_down_handler(void)
{
    UI_MUTEX_TAKE();
    g_auto_rotate_en = RT_FALSE;
    g_target_screen = get_next_available_screen();
    g_screen_switch_flag = RT_TRUE;
    if (g_restore_timer)
        lv_timer_reset(g_restore_timer);
    UI_MUTEX_RELEASE();
    rt_kprintf("[KEY] Key down pressed, target screen: %d\n", g_target_screen);
}

static void key_scan_thread_entry(void *param)
{
    // 初始化按键引脚
    g_key_up.pin = rt_pin_get(KEY_UP_PIN);
    g_key_down.pin = rt_pin_get(KEY_DOWN_PIN);
    if (g_key_up.pin < 0 || g_key_down.pin < 0)
    {
        rt_kprintf("[KEY] Failed to get key pins (up: %ld, down: %ld)\n", g_key_up.pin, g_key_down.pin);
        return;
    }
    // 设置上拉输入
    rt_pin_mode(g_key_up.pin, PIN_MODE_INPUT_PULLUP);
    rt_pin_mode(g_key_down.pin, PIN_MODE_INPUT_PULLUP);
    rt_kprintf("[KEY] Key scan thread init success (pins: %s, %s)\n", KEY_UP_PIN, KEY_DOWN_PIN);

    // 无限扫描
    while (1)
    {
        key_scan_process(&g_key_up);
        key_scan_process(&g_key_down);
        rt_thread_mdelay(KEY_SCAN_INTERVAL);
    }
}

/************************** 定时器回调-仅修改标志位(无LVGL操作,兼容低版本)**************************/
static void screen_timer_cb(lv_timer_t *timer)
{
    UI_MUTEX_TAKE();
    // 仅自动轮询使能时,执行自动切换
    if (g_auto_rotate_en && g_available_screen_count > 0)
    {
        g_target_screen = get_next_available_screen();
        g_screen_switch_flag = RT_TRUE;
    }
    UI_MUTEX_RELEASE();
}

static void restore_timer_cb(lv_timer_t *timer)
{
    UI_MUTEX_TAKE();
    g_auto_rotate_en = RT_TRUE; // 恢复自动轮询
    // rt_kprintf("[TIMER] Restore auto screen rotate\n");
    UI_MUTEX_RELEASE();
}

/************************** 核心LVGL定时器-设备数据更新(所有LVGL操作入口)**************************/
static void update_device_data(lv_timer_t *timer)
{
    UI_MUTEX_TAKE();
    // 1. 首次初始化设备数据,避免频繁清零导致指针失效
    static rt_bool_t g_main_info_inited = RT_FALSE;
    if (!g_main_info_inited)
    {
        memset(&g_main_info, 0, sizeof(main_info_t));
        g_main_info_inited = RT_TRUE;
        rt_kprintf("[DATA] Global device info init success\n");
    }
    UI_MUTEX_RELEASE();

    // 2. 处理屏幕切换请求(核心:所有LVGL操作在此执行)
    if (g_screen_switch_flag)
    {
        screen_switch_proc();
    }

    // 3. 调试数据打印(使能时)
    if (g_data_print_enable)
    {
        print_main_info();
    }

    // 4. 校验当前屏幕有效性
    UI_MUTEX_TAKE();
    rt_uint8_t curr_screen = g_current_screen;
    UI_MUTEX_RELEASE();
    if (curr_screen == 0 || get_screen_map_index(curr_screen) >= g_available_screen_count)
    {
        return;
    }
    // 5. 按需获取设备数据并更新UI(当前屏幕仅更新对应模块,节省资源)
    switch (curr_screen)
    {
    case MODULE_POWER_SCREEN:
        get_battery_info(&g_main_info.m_battery_info);
        update_power_data();
        break;
    case MODULE_WIFI_SCREEN:
        get_io_info(&g_main_info.m_io_info);
        update_wifi_data();
        break;
    case MODULE_SWITCH_SCREEN:
        get_io_info(&g_main_info.m_io_info);
        update_switch_data();
        break;
    case MODULE_LOCATOR_SCREEN:
        get_locator_info(&g_main_info.m_locator_info);
        update_locator_data_precise();
        break;
    case MODULE_TRAFFIC_LIGHT_SCREEN:
        get_traffic_info(&g_main_info.m_traffic_light_info);
        update_traffic_data();
        break;
    case MODULE_LOCATOR_SCREEN_VAGUE:
        get_locator_info(&g_main_info.m_locator_info);
        update_locator_data_vague();
        break;

    default:
        break;
    }
}

/************************** 设备数据打印-调试用(RT-Thread线程安全)**************************/
static void print_main_info(void)
{
    rt_kprintf("==================== DEVICE DATA ====================\n");
    // 定位器信息
    rt_kprintf("Locator Type: %s\n", g_main_info.m_locator_info.locator_type == 0 ? "Precise" : "Vague");
    // for (rt_uint8_t i = 0; i < locator_info.card_info.current_card_num; i++)
    // {
    //     for (rt_uint8_t j = 0; j < CARD_ID_LEN; j++)
    //         rt_kprintf("%c", locator_info.card_info.card_id[i][j]);
    //     rt_kprintf("|");
    // }
    rt_kprintf("\n");
    rt_kprintf("Locator State: %s\n", g_main_info.m_locator_info.is_dev_online ? "Online" : "Offline");
    rt_kprintf("Antenna Dir: %d (0=Init,1=Left,2=Right)\n", g_main_info.m_locator_info.antenna_direction);
    rt_kprintf("Card Total: %d, Current: %d\n",
               g_main_info.m_locator_info.card_info.total_card_num,
               g_main_info.m_locator_info.card_info.current_card_num);
    // 电池信息
    rt_kprintf("Battery SOC: %d%%, Power Type: %s\n",
               g_main_info.m_battery_info.soc,
               g_main_info.m_battery_info.power_type ? "Battery" : "AC");
    rt_kprintf("Battery CH0: %d%s, %d.%02dA | CH1: %d%s, %d.%02dA\n",
               g_main_info.m_battery_info.voltage[0], VOLTAGE_UNIT,
               g_main_info.m_battery_info.current[0] / 100, g_main_info.m_battery_info.current[0] % 100,
               g_main_info.m_battery_info.voltage[1], VOLTAGE_UNIT,
               g_main_info.m_battery_info.current[1] / 100, g_main_info.m_battery_info.current[1] % 100);
    rt_kprintf("Battery HID: 0x%08lX\n", g_main_info.m_battery_info.hid);
    // 红绿灯信息
    rt_kprintf("Traffic Light State: %s, Count: %d\n",
               g_main_info.m_traffic_light_info.online_state ? "Online" : "Offline",
               g_main_info.m_traffic_light_info.traffic_num);
    for (rt_uint8_t i = 0; i < g_main_info.m_traffic_light_info.traffic_num; i++)
    {
        rt_kprintf("Traffic %d HID: 0x%08" PRIx32 "\n", i + 1, g_main_info.m_traffic_light_info.hid[i]);
    }
    rt_kprintf("=====================================================\n\n");
}

/************************** 各模块UI数据更新(纯LVGL操作,双层空指针校验)**************************/
static void update_power_data(void)
{
    screen_1_t *scr = screen_1_get(&ui_manager);
    if (!scr || !scr->obj)
        return;

    // 更新页码
    if (scr->page_1)
    {
        rt_uint8_t page = get_screen_display_page(MODULE_POWER_SCREEN);
        UI_MUTEX_TAKE();
        lv_label_set_text_fmt(scr->page_1, "第%d/%d页", page, g_available_screen_count);
        UI_MUTEX_RELEASE();
    }

    // 电池HID/状态核心逻辑
    if (scr->Battery_Hid)
    {
        UI_MUTEX_TAKE();
        rt_uint32_t bat_hid = g_main_info.m_battery_info.hid;
        rt_uint8_t bat_soc = g_main_info.m_battery_info.soc;
        rt_int32_t vol0 = g_main_info.m_battery_info.voltage[0];
        rt_int32_t cur0 = g_main_info.m_battery_info.current[0];
        rt_int32_t vol1 = g_main_info.m_battery_info.voltage[1];
        rt_int32_t cur1 = g_main_info.m_battery_info.current[1];
        rt_uint8_t power_type = g_main_info.m_battery_info.power_type;
        UI_MUTEX_RELEASE();

        if (bat_hid == 0)
        { // 离线状态
            lv_obj_set_style_text_color(scr->Battery_Hid, COLOR_CONNECT_RED, LV_PART_MAIN);
            if (scr->Power_Mode)
                lv_obj_set_style_text_color(scr->Power_Mode, COLOR_CONNECT_YELLOW, LV_PART_MAIN);
            if (scr->Battery_Hid)
                lv_label_set_text(scr->Battery_Hid, "离线");
            if (scr->Power_Mode)
                lv_label_set_text(scr->Power_Mode, "未知");
            if (scr->vol_1)
                lv_label_set_text(scr->vol_1, "0" VOLTAGE_UNIT);
            if (scr->cur_1)
                lv_label_set_text(scr->cur_1, "0.00A");
            if (scr->battery_1)
                lv_label_set_text(scr->battery_1, "0%");
            if (scr->vol_2)
                lv_label_set_text(scr->vol_2, "0" VOLTAGE_UNIT);
            if (scr->cur_2)
                lv_label_set_text(scr->cur_2, "0.00A");
            if (scr->battery_2)
                lv_label_set_text(scr->battery_2, "0%");
        }
        else
        { // 在线状态
            lv_obj_set_style_text_color(scr->Battery_Hid, COLOR_CONNECT_YELLOW, LV_PART_MAIN);
            // 更新CH0
            if (scr->vol_1)
                lv_label_set_text_fmt(scr->vol_1, "%ld" VOLTAGE_UNIT, vol0);
            if (scr->cur_1)
                lv_label_set_text_fmt(scr->cur_1, "%ld.%02ldA", cur0 / 100, cur0 % 100);
            if (scr->battery_1)
                lv_label_set_text_fmt(scr->battery_1, "%d%%", bat_soc);
            // 更新CH1
            if (scr->vol_2)
                lv_label_set_text_fmt(scr->vol_2, "%ld" VOLTAGE_UNIT, vol1);
            if (scr->cur_2)
                lv_label_set_text_fmt(scr->cur_2, "%ld.%02ldA", cur1 / 100, cur1 % 100);
            if (scr->battery_2)
                lv_label_set_text_fmt(scr->battery_2, "%d%%", bat_soc);
            // 供电类型
            if (scr->Power_Mode)
            {
                lv_label_set_text(scr->Power_Mode, power_type == 0 ? "交流供电" : "电池供电");
            }
            // HID/IP显示
            if (g_sys_config.power_type == CAN_POWER)
            {
                lv_label_set_text_fmt(scr->Battery_Hid, "0x%08lX", bat_hid);
            }
            else
            {
                rt_uint8_t *ip = (rt_uint8_t *)&bat_hid;
                lv_label_set_text_fmt(scr->Battery_Hid, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
            }
        }
    }
}

static void update_wifi_data(void)
{
    screen_2_t *scr = screen_2_get(&ui_manager);
    if (!scr || !scr->obj)
        return;

    // 更新页码
    if (scr->page_2)
    {
        rt_uint8_t page = get_screen_display_page(MODULE_WIFI_SCREEN);
        UI_MUTEX_TAKE();
        lv_label_set_text_fmt(scr->page_2, "第%d/%d页", page, g_available_screen_count);
        UI_MUTEX_RELEASE();
    }

    // WiFi状态更新
    if (scr->work_status)
    {
        UI_MUTEX_TAKE();
        rt_uint8_t wifi_state = g_main_info.m_io_info.wifi7_state;
        UI_MUTEX_RELEASE();
        const char *state_str = NULL;

        if (wifi_state == 1)
        { // 正常
            state_str = "正常";
            lv_obj_set_style_text_color(scr->work_status, COLOR_CONNECT_GREEN, LV_PART_MAIN);
            // IP显示(复用宏定义,避免越界)
            if (scr->ip_addr)
            {
                char ip_str[IP_BUF_SIZE] = {0};
                snprintf(ip_str, sizeof(ip_str), "%d.%d.%d.%d",
                         g_sys_config.wifi_module_ip[0], g_sys_config.wifi_module_ip[1],
                         g_sys_config.wifi_module_ip[2], g_sys_config.wifi_module_ip[3]);
                lv_label_set_text(scr->ip_addr, ip_str);
            }
        }
        else
        { // 异常/默认
            state_str = "异常";
            lv_obj_set_style_text_color(scr->work_status, COLOR_CONNECT_RED, LV_PART_MAIN);
            if (scr->ip_addr)
                lv_label_set_text(scr->ip_addr, "");
        }
        lv_label_set_text(scr->work_status, state_str);
    }
}

// 网口状态辅助函数
static const char *get_port_status_str(rt_uint8_t state)
{
    return (state == 1) ? "在线" : "离线";
}

static void update_port_label(lv_obj_t *label, rt_uint8_t state)
{
    if (!label)
        return;
    if (state == 1)
    {
        lv_obj_set_style_text_color(label, COLOR_CONNECT_GREEN, LV_PART_MAIN);
    }
    else if (state == 0)
    {
        lv_obj_set_style_text_color(label, COLOR_CONNECT_RED, LV_PART_MAIN);
    }
    else
    {
        lv_obj_set_style_text_color(label, COLOR_CONNECT_YELLOW, LV_PART_MAIN);
    }
    lv_label_set_text(label, get_port_status_str(state));
}

static void update_switch_data(void)
{
    screen_5_t *scr = screen_5_get(&ui_manager);
    if (!scr || !scr->obj)
        return;

    // 更新网口状态
    UI_MUTEX_TAKE();
    io_info_t io_info = g_main_info.m_io_info;
    UI_MUTEX_RELEASE();
    update_port_label(scr->Eport_1, io_info.ep1_100m_state);
    update_port_label(scr->Eport_2, io_info.ep2_100m_state);
    update_port_label(scr->Oport1_100, io_info.op1_100m_state);
    update_port_label(scr->Oport2_100, io_info.op2_100m_state);
    update_port_label(scr->Gport1_1000, io_info.op1_1000m_state);
    update_port_label(scr->Gport2_1000, io_info.op2_1000m_state);

    // 更新页码
    if (scr->page_5)
    {
        rt_uint8_t page = get_screen_display_page(MODULE_SWITCH_SCREEN);
        UI_MUTEX_TAKE();
        lv_label_set_text_fmt(scr->page_5, "第%d/%d页", page, g_available_screen_count);
        UI_MUTEX_RELEASE();
    }
}

// 区域定位(screen3)-数据更新
static void update_locator_data_vague(void)
{
    screen_3_t *scr = screen_3_get(&ui_manager);
    if (!scr || !scr->obj)
        return;

    // 统一加互斥锁读取所有定位器数据,避免多线程数据错乱
    UI_MUTEX_TAKE();
    locator_info_t loc_info = g_main_info.m_locator_info;
    UI_MUTEX_RELEASE();

    // 服务器连接状态
    if (scr->server_connect_status)
    {
        lv_color_t color = COLOR_CONNECT_YELLOW;
        const char *state_str = "";
        if (loc_info.server_link_state.len > 0)
        {
            color = loc_info.server_link_state.state == 1 ? COLOR_CONNECT_GREEN : COLOR_CONNECT_RED;
            state_str = loc_info.server_link_state.state == 1 ? "在线" : "离线";
        }
        lv_obj_set_style_text_color(scr->server_connect_status, color, LV_PART_MAIN);
        lv_label_set_text(scr->server_connect_status, state_str);
    }

    // IP/HID显示
    if (scr->position_ip)
    {
        char ip_str[IP_BUF_SIZE] = {0};
        if (loc_info.local_ip.len > 0 && loc_info.local_ip.len < IP_BUF_SIZE)
        {
            memcpy(ip_str, loc_info.local_ip.ip, loc_info.local_ip.len);
        }
        lv_label_set_text(scr->position_ip, strlen(ip_str) > 0 ? ip_str : "");
    }
    if (scr->position_hid)
    {
        char hid_str[HID_BUF_SIZE] = {0};
        if (loc_info.local_hid.len > 0 && loc_info.local_hid.len < HID_BUF_SIZE)
        {
            memcpy(hid_str, loc_info.local_hid.hid, loc_info.local_hid.len);
        }
        lv_label_set_text(scr->position_hid, strlen(hid_str) > 0 ? hid_str : "");
    }

    // 卡片信息显示(核心修复:匹配实际卡号长度+正确取值)
    if (scr->identify_cardID && scr->label_25)
    {
        // 设备离线:清空显示
        if (loc_info.is_dev_online != 1)
        {
            lv_label_set_text(scr->label_25, "");
            lv_label_set_text(scr->identify_cardID, "");
            return;
        }

        // 加互斥锁读取卡片信息,避免数据错乱
        UI_MUTEX_TAKE();
        locator_card_info_t card_info = loc_info.card_info;
        UI_MUTEX_RELEASE();

        char card_show_str[CARD_SHOW_STR_SIZE] = {0};
        // 核心修正1:取current_card_num(当前显示数),且限制≤MAX_CARD_NUM
        rt_uint8_t valid_card_num = 0;
        if (card_info.current_card_num > 0)
        {
            valid_card_num = card_info.current_card_num;
        }

        if (valid_card_num == 0)
        {
            strcpy(card_show_str, "无");
        }
        else
        {
            // 显示卡片总数
            char num_str[NUM_STR_SIZE] = {0};
            snprintf(num_str, sizeof(num_str), "(%d个)", card_info.total_card_num);
            lv_label_set_text(scr->label_25, num_str);

            // 拼接卡号:按8个/行,每个卡号后3个空格,行末换行
            char line_buf[256] = {0};  // 单行缓冲区
            rt_uint8_t line_count = 0; // 行内卡号计数

            for (rt_uint8_t i = 0; i < valid_card_num; i++)
            {
                // 核心修正2:仅读取5位有效卡号(匹配实际日志),并强制加终止符
                char single_card[6] = {0};                    // 5位卡号 + '\0'
                memcpy(single_card, card_info.card_id[i], 5); // 固定读取5位,舍弃多余乱码
                single_card[5] = '\0';                        // 强制终止,避免乱码

                // 拼接当前卡号到行缓冲区
                strcat(line_buf, single_card);
                line_count++;

                // 格式控制:
                // 1. 行内未到8个,且不是最后一个卡号 → 加3个空格
                if (line_count < CARD_LINE_BREAK && i < valid_card_num - 1)
                {
                    strcat(line_buf, "   ");
                }
                // 2. 行内满8个,且不是最后一个卡号 → 换行+重置行缓冲区
                else if (line_count == CARD_LINE_BREAK && i < valid_card_num - 1)
                {
                    strcat(card_show_str, line_buf);
                    strcat(card_show_str, "\n");
                    memset(line_buf, 0, sizeof(line_buf));
                    line_count = 0;
                }
            }

            // 拼接最后一行剩余的卡号
            if (strlen(line_buf) > 0)
            {
                strcat(card_show_str, line_buf);
            }
        }

        // 设置最终显示的卡号字符串
        lv_label_set_text(scr->identify_cardID, card_show_str);
    }

    // 页码显示
    if (scr->page_3)
    {
        rt_uint8_t page = get_screen_display_page(MODULE_LOCATOR_SCREEN_VAGUE);
        UI_MUTEX_TAKE();
        lv_label_set_text_fmt(scr->page_3, "第%d/%d页", page, g_available_screen_count);
        UI_MUTEX_RELEASE();
    }
}
// 精确定位(screen7)-数据更新
static void update_locator_data_precise(void)
{
    screen_7_t *scr = screen_7_get(&ui_manager);
    if (!scr || !scr->obj)
        return;

    UI_MUTEX_TAKE();
    locator_info_t loc_info = g_main_info.m_locator_info;
    UI_MUTEX_RELEASE();

    // 服务器状态
    if (scr->server_status)
    {
        lv_color_t color = COLOR_CONNECT_YELLOW;
        const char *state_str = "";
        if (loc_info.server_link_state.len > 0)
        {
            color = loc_info.server_link_state.state == 1 ? COLOR_CONNECT_GREEN : COLOR_CONNECT_RED;
            state_str = loc_info.server_link_state.state == 1 ? "在线" : "离线";
        }
        lv_obj_set_style_text_color(scr->server_status, color, LV_PART_MAIN);
        lv_label_set_text(scr->server_status, state_str);
    }

    // 读卡器/天线方向(精确定位专属)
    if (scr->head_status)
    {
        lv_color_t color = COLOR_CONNECT_YELLOW;
        const char *state_str = "";
        if (loc_info.card_module_state.len > 0)
        {
            color = loc_info.card_module_state.state == 1 ? COLOR_CONNECT_GREEN : COLOR_CONNECT_RED;
            state_str = loc_info.card_module_state.state == 1 ? "在线" : "离线";
        }
        lv_obj_set_style_text_color(scr->head_status, color, LV_PART_MAIN);
        lv_label_set_text(scr->head_status, state_str);
    }
// 天线方向
#if 0
    if (scr->antenna_orient)
    {
        const char *dir_str = "";
        if (loc_info.antenna_direction == 1)
            dir_str = "--→";
        else if (loc_info.antenna_direction == 2)
            dir_str = "←--";
        lv_label_set_text(scr->antenna_orient, dir_str);
    }
#endif

    if (scr->image_left && scr->image_right)
    {
        // 根据antenna_direction控制箭头显示/隐藏
        switch (loc_info.antenna_direction)
        {
        case 2:                                                      // 显示右箭头,隐藏左箭头
            lv_obj_clear_flag(scr->image_right, LV_OBJ_FLAG_HIDDEN); // 清除隐藏标志=显示
            lv_obj_add_flag(scr->image_left, LV_OBJ_FLAG_HIDDEN);    // 添加隐藏标志=隐藏
            break;
        case 1:                                                     // 显示左箭头,隐藏右箭头
            lv_obj_clear_flag(scr->image_left, LV_OBJ_FLAG_HIDDEN); // 清除隐藏标志=显示
            lv_obj_add_flag(scr->image_right, LV_OBJ_FLAG_HIDDEN);  // 添加隐藏标志=隐藏
            break;
        default: // 其他情况,都隐藏
            lv_obj_add_flag(scr->image_left, LV_OBJ_FLAG_HIDDEN);
            lv_obj_add_flag(scr->image_right, LV_OBJ_FLAG_HIDDEN);
            break;
        }
    }

    // IP/HID显示
    if (scr->position_ip)
    {
        char ip_str[IP_BUF_SIZE] = {0};
        if (loc_info.local_ip.len > 0 && loc_info.local_ip.len < IP_BUF_SIZE)
        {
            memcpy(ip_str, loc_info.local_ip.ip, loc_info.local_ip.len);
        }
        lv_label_set_text(scr->position_ip, strlen(ip_str) > 0 ? ip_str : "");
    }
    if (scr->position_hid)
    {
        char hid_str[HID_BUF_SIZE] = {0};
        if (loc_info.local_hid.len > 0 && loc_info.local_hid.len < HID_BUF_SIZE)
        {
            memcpy(hid_str, loc_info.local_hid.hid, loc_info.local_hid.len);
        }
        lv_label_set_text(scr->position_hid, strlen(hid_str) > 0 ? hid_str : "");
    }

    // 卡片信息显示(带越界日志)
    if (scr->label_2 && scr->card_num)
    {
        if (loc_info.is_dev_online == 1)
        {
            locator_card_info_t *card_info = &loc_info.card_info;
            char card_show_str[CARD_SHOW_STR_SIZE] = {0};

            if (card_info->total_card_num == 0 || card_info->current_card_num == 0 ||
                card_info->current_card_num > card_info->total_card_num)
            {
                strcpy(card_show_str, "无");
            }
            else if (card_info->card_id == NULL)
            {
                strcpy(card_show_str, "无");
            }
            else
            {
                char num_str[NUM_STR_SIZE] = {0};
                snprintf(num_str, sizeof(num_str), "(%d个)", card_info->total_card_num);
                lv_label_set_text(scr->card_num, num_str);

                rt_uint8_t spliced = 0;
                size_t remain_len = sizeof(card_show_str) - 1;
                for (rt_uint8_t i = 0; i < card_info->total_card_num && remain_len > 0; i++)
                {
                    if (spliced > 30)
                        break;
                    char single_card[CARD_ID_LEN + 1] = {0};
                    if (card_info->card_id[i] != NULL)
                    {
                        // 修改:显式转换为const char* 消除指针符号警告
                        size_t card_len = strlen((const char *)card_info->card_id[i]);
                        // 取"卡片ID长度"和"CARD_ID_LEN"的较小值,防止single_card溢出
                        size_t copy_len = card_len > CARD_ID_LEN ? CARD_ID_LEN : card_len;
                        memcpy(single_card, card_info->card_id[i], copy_len);
                    }
                    spliced++;

                    if (remain_len > strlen(single_card))
                    {
                        strncat(card_show_str, single_card, remain_len);
                        remain_len -= strlen(single_card);
                    }
                    else
                    {
                        break;
                    }

                    if (i < card_info->total_card_num - 1 && remain_len >= 3)
                    {
                        strncat(card_show_str, " ", 3);
                        remain_len -= 3;
                    }

                    if ((spliced % CARD_PRECISE_LINE_BREAK == 0) && spliced != card_info->total_card_num && remain_len >= 1)
                    {
                        strncat(card_show_str, "\n", 1);
                        remain_len -= 1;
                    }
                }
            }
            lv_label_set_text(scr->label_2, card_show_str);
        }
        else
        {
            lv_label_set_text(scr->label_2, "");
            lv_label_set_text(scr->card_num, "");
        }
    }
    // 更新页码
    if (scr->page_3)
    {
        rt_uint8_t page = get_screen_display_page(MODULE_LOCATOR_SCREEN);
        UI_MUTEX_TAKE();
        lv_label_set_text_fmt(scr->page_3, "第%d/%d页", page, g_available_screen_count);
        UI_MUTEX_RELEASE();
    }
}

// 红绿灯模块-数据更新
static void update_traffic_data(void)
{
    screen_4_t *scr = screen_4_get(&ui_manager);
    if (!scr || !scr->obj)
        return;

    // 更新页码
    if (scr->page_4)
    {
        rt_uint8_t page = get_screen_display_page(MODULE_TRAFFIC_LIGHT_SCREEN);
        UI_MUTEX_TAKE();
        lv_label_set_text_fmt(scr->page_4, "第%d/%d页", page, g_available_screen_count);
        UI_MUTEX_RELEASE();
    }

    UI_MUTEX_TAKE();
    traffic_light_info_t tl_info = g_main_info.m_traffic_light_info;
    UI_MUTEX_RELEASE();

    // 红绿灯整体状态
    if (scr->work_status_led)
    {
        const char *state_str = tl_info.online_state ? "在线" : "离线";
        lv_color_t color = tl_info.online_state ? COLOR_CONNECT_GREEN : COLOR_CONNECT_RED;
        lv_obj_set_style_text_color(scr->work_status_led, color, LV_PART_MAIN);
        lv_label_set_text(scr->work_status_led, state_str);
    }

    // HID映射表(结构化管理,便于扩展)
    typedef struct
    {
        lv_obj_t *hid_label;
        rt_uint8_t idx;
    } tl_hid_map_t;
    const tl_hid_map_t hid_map[] = {
        {scr->led_hid1, 0}, {scr->led_hid2, 1}, {scr->led_hid3, 2}, {scr->led_hid4, 3}};
    rt_uint8_t map_count = sizeof(hid_map) / sizeof(hid_map[0]);

    // 先清空所有HID标签
    for (rt_uint8_t i = 0; i < map_count; i++)
    {
        if (hid_map[i].hid_label)
            lv_label_set_text(hid_map[i].hid_label, "");
    }

    // 在线时更新HID
    if (tl_info.online_state == 1)
    {
        rt_uint8_t valid_count = (tl_info.traffic_num > map_count) ? map_count : tl_info.traffic_num;
        if (valid_count == 0)
            return;

        for (rt_uint8_t i = 0; i < valid_count; i++)
        {
            if (!hid_map[i].hid_label)
                continue;
            if (hid_map[i].idx >= sizeof(tl_info.hid) / sizeof(rt_uint32_t))
                continue;
            rt_uint32_t hid = tl_info.hid[hid_map[i].idx];
            if (hid != 0)
            {
                lv_label_set_text_fmt(hid_map[i].hid_label, "0x%08" PRIx32, hid);
            }
            else
            {
                lv_label_set_text(hid_map[i].hid_label, "未配置"); // 友好提示
            }
        }
    }
    else
    {
        // 离线时标注所有HID为离线
        for (rt_uint8_t i = 0; i < map_count; i++)
        {
            if (hid_map[i].hid_label)
            {
                lv_label_set_text(hid_map[i].hid_label, "");
            }
        }
    }
}

/************************** 屏幕管理辅助函数(带互斥锁保护)**************************/
static rt_uint8_t get_screen_map_index(rt_uint8_t screen_idx)
{
    for (rt_uint8_t i = 0; i < g_available_screen_count; i++)
    {
        if (g_available_screen_map[i] == screen_idx)
        {
            return i;
        }
    }
    return g_available_screen_count;
}

static rt_uint8_t get_screen_from_map(rt_uint8_t map_idx)
{
    if (map_idx >= g_available_screen_count)
    {
        return 0;
    }
    return g_available_screen_map[map_idx];
}

static rt_uint8_t get_next_available_screen(void)
{
    UI_MUTEX_TAKE();
    rt_uint8_t ret = g_current_screen;
    if (g_available_screen_count == 0)
    {
        UI_MUTEX_RELEASE();
        return ret;
    }
    rt_uint8_t curr_idx = get_screen_map_index(g_current_screen);
    rt_uint8_t next_idx = (curr_idx + 1) % g_available_screen_count;
    ret = get_screen_from_map(next_idx);
    UI_MUTEX_RELEASE();
    return ret;
}

static rt_uint8_t get_prev_available_screen(void)
{
    UI_MUTEX_TAKE();
    rt_uint8_t ret = g_current_screen;
    if (g_available_screen_count == 0)
    {
        UI_MUTEX_RELEASE();
        return ret;
    }
    rt_uint8_t curr_idx = get_screen_map_index(g_current_screen);
    rt_uint8_t prev_idx = (curr_idx == 0) ? (g_available_screen_count - 1) : (curr_idx - 1);
    ret = get_screen_from_map(prev_idx);
    UI_MUTEX_RELEASE();
    return ret;
}

/************************** 可用页面映射表初始化(核心入口)**************************/
void init_available_screen_map(void)
{
    UI_MUTEX_TAKE();
    memset(g_available_screen_map, 0, sizeof(g_available_screen_map));
    g_available_screen_count = 0;

    // 根据系统配置添加可用页面
    if (g_sys_config.power_module == RT_TRUE)
    {
        g_available_screen_map[g_available_screen_count++] = MODULE_POWER_SCREEN;
    }
    if (g_sys_config.wifi_module == RT_TRUE)
    {
        g_available_screen_map[g_available_screen_count++] = MODULE_WIFI_SCREEN;
    }
    if (g_sys_config.network_switch_module == RT_TRUE)
    {
        g_available_screen_map[g_available_screen_count++] = MODULE_SWITCH_SCREEN;
    }
    if (g_sys_config.locator_module == RT_TRUE)
    {
        rt_uint8_t locator_type = get_sys_config_locator_type();
        if (locator_type == 0) // 0表示精确定位
        {
            g_available_screen_map[g_available_screen_count++] = MODULE_LOCATOR_SCREEN;
        }
        else
        {
            g_available_screen_map[g_available_screen_count++] = MODULE_LOCATOR_SCREEN_VAGUE;
        }
    }
    if (g_sys_config.traffic_light_module == RT_TRUE)
    {
        g_available_screen_map[g_available_screen_count++] = MODULE_TRAFFIC_LIGHT_SCREEN;
    }

    // 打印映射表信息
    rt_kprintf("[UI] Available screen count: %d\n", g_available_screen_count);
    for (rt_uint8_t i = 0; i < g_available_screen_count; i++)
    {
        rt_kprintf("[UI] Map %d -> Screen %d\n", i, g_available_screen_map[i]);
    }

    // 初始化当前/目标屏幕为第一个可用页面,并主动创建+加载第一个页面
    if (g_available_screen_count > 0)
    {
        g_current_screen = g_available_screen_map[0];
        g_target_screen = g_current_screen;
        rt_kprintf("[UI] Init first screen: %d\n", g_current_screen);

        // 核心:主动创建第一个页面的UI对象
        lv_obj_t *first_screen_obj = NULL;
        switch (g_current_screen)
        {
        case MODULE_POWER_SCREEN:
            screen_1_create(&ui_manager);
            first_screen_obj = screen_1_get(&ui_manager)->obj;
            break;
        case MODULE_WIFI_SCREEN:
            screen_2_create(&ui_manager);
            first_screen_obj = screen_2_get(&ui_manager)->obj;
            break;
        case MODULE_SWITCH_SCREEN:
            screen_5_create(&ui_manager);
            first_screen_obj = screen_5_get(&ui_manager)->obj;
            break;
        case MODULE_LOCATOR_SCREEN: // 精确定位
            screen_7_create(&ui_manager);
            first_screen_obj = screen_7_get(&ui_manager)->obj;
            break;
        case MODULE_LOCATOR_SCREEN_VAGUE: // 区域定位
            screen_3_create(&ui_manager);
            first_screen_obj = screen_3_get(&ui_manager)->obj;
            break;
        case MODULE_TRAFFIC_LIGHT_SCREEN:
            screen_4_create(&ui_manager);
            first_screen_obj = screen_4_get(&ui_manager)->obj;
            break;
        default:
            rt_kprintf("[UI] Unknown first screen type: %d\n", g_current_screen);
            break;
        }

        // 加载第一个页面到LVGL(确保首次显示)
        if (first_screen_obj && lv_obj_is_valid(first_screen_obj))
        {
            lv_scr_load(first_screen_obj);
            rt_kprintf("[UI] Load first screen success (obj: %p)\n", first_screen_obj);
        }
        else
        {
            rt_kprintf("[UI] First screen obj invalid: %p\n", first_screen_obj);
        }

        // 保留切换标志,兼容后续定时器/按键逻辑
        g_screen_switch_flag = RT_TRUE;
    }
    UI_MUTEX_RELEASE();
}

/************************** 模块初始化/销毁(全局入口,资源统一管理)**************************/
void custom_init(void)
{
    // 1. 创建UI互斥锁(多线程同步核心)
    g_ui_mutex = rt_mutex_create("ui_mutex", RT_IPC_FLAG_PRIO);
    if (g_ui_mutex == RT_NULL)
    {
        rt_kprintf("[ERROR] Create UI mutex failed!\n");
        return;
    }
    rt_kprintf("[UI] Create UI mutex success\n");

    // 2. 初始化可用页面映射表
    init_available_screen_map();

    // 3. 创建LVGL定时器(均为无限循环,避免反复创建)
    // 3.1 屏幕自动轮询定时器
    rt_uint16_t screen_interval = get_sys_config_screen_fresh_interval() * 1000;
    if (screen_interval == 0)
    {
        screen_interval = DEFAULT_SCREEN_INTERVAL;
        rt_kprintf("[TIMER] Screen interval 0, use default %dms\n", DEFAULT_SCREEN_INTERVAL);
    }
    g_screen_timer = lv_timer_create(screen_timer_cb, screen_interval, NULL);
    // 3.2 恢复自动轮询定时器
    g_restore_timer = lv_timer_create(restore_timer_cb, RESTORE_TIMER_MS, NULL);
    // 3.3 数据更新主定时器(所有LVGL操作入口)
    g_data_update_timer = lv_timer_create(update_device_data, DATA_UPDATE_MS, NULL);
    rt_kprintf("[TIMER] Create timers (screen: %dms, restore: %dms, data: %dms)\n",
               screen_interval, RESTORE_TIMER_MS, DATA_UPDATE_MS);

    // 4. 创建按键扫描线程(栈1024字节,足够使用,节省内存)
    rt_thread_t key_thread = rt_thread_create("key_scan",
                                              key_scan_thread_entry,
                                              RT_NULL,
                                              1024,
                                              15,
                                              20);
    if (key_thread)
    {
        rt_thread_startup(key_thread);
        rt_kprintf("[UI] Create key scan thread success (stack: 1024)\n");
    }
    else
    {
        rt_kprintf("[ERROR] Create key scan thread failed!\n");
    }

    rt_kprintf("[UI] Custom module init complete!\n");
}

void custom_deinit(void)
{
    UI_MUTEX_TAKE();
    // 1. 销毁所有LVGL定时器
    if (g_screen_timer)
    {
        lv_timer_del(g_screen_timer);
        g_screen_timer = NULL;
    }
    if (g_restore_timer)
    {
        lv_timer_del(g_restore_timer);
        g_restore_timer = NULL;
    }
    if (g_data_update_timer)
    {
        lv_timer_del(g_data_update_timer);
        g_data_update_timer = NULL;
    }
    UI_MUTEX_RELEASE();

    // 2. 销毁按键扫描线程
    rt_thread_t key_thread = rt_thread_find("key_scan");
    if (key_thread)
    {
        rt_thread_delete(key_thread);
        rt_kprintf("[UI] Delete key scan thread success\n");
    }

    // 3. 销毁UI互斥锁
    if (g_ui_mutex)
    {
        rt_mutex_delete(g_ui_mutex);
        g_ui_mutex = RT_NULL;
        rt_kprintf("[UI] Delete UI mutex success\n");
    }

    rt_kprintf("[UI] Custom module deinit complete!\n");
}

/************************** MSH调试命令(RT-Thread规范,带分号)**************************/
static void lvgl_test(rt_int32_t argc, char *argv[])
{
    if (argc == 1 || argc > 2)
    {
        rt_kprintf("Please input correct command!\r\n");
        goto __usage;
    }

    if (rt_strcmp(argv[1], "--help") == RT_EOK)
    {
        goto __usage;
    }
    else if (rt_strcmp(argv[1], "--debug_on") == RT_EOK)
    {
        g_data_print_enable = RT_TRUE;
        rt_kprintf("[DEBUG] Data print enable\n");
    }
    else if (rt_strcmp(argv[1], "--debug_off") == RT_EOK)
    {
        g_data_print_enable = RT_FALSE;
        rt_kprintf("[DEBUG] Data print disable\n");
    }
    else
    {
        rt_kprintf("Unknown command: %s\r\n", argv[1]);
        goto __usage;
    }
    return;

__usage:
    rt_kprintf("Usage:\r\n");
    rt_kprintf("  lvgl --help      - Show help info\r\n");
    rt_kprintf("  lvgl --debug_on  - Enable device data print\r\n");
    rt_kprintf("  lvgl --debug_off - Disable device data print\r\n");
}
// 修正:添加分号,解决语法错误
MSH_CMD_EXPORT_ALIAS(lvgl_test, lvgl, LVGL debug and data print command);
相关推荐
比昨天多敲两行2 小时前
C++ 多态
开发语言·c++
是娇娇公主~2 小时前
C++ 多态机制与虚函数实现原理
c语言·c++
m0_569881472 小时前
跨语言调用C++接口
开发语言·c++·算法
2501_924952693 小时前
C++中的过滤器模式
开发语言·c++·算法
zhixingheyi_tian3 小时前
gdb 之 attach
c++
2401_873204653 小时前
C++中的组合模式实战
开发语言·c++·算法
2401_831824963 小时前
高性能压缩库实现
开发语言·c++·算法
2401_874732533 小时前
C++中的策略模式进阶
开发语言·c++·算法
steins_甲乙3 小时前
C# 通过共享内存与 C++ 宿主协同捕获软件窗口
开发语言·c++·c#·内存共享