Files
zhengxinandCursor 851e347cf5 初始提交卡包 USB 工程
纳入固件源码、屏幕组件、nand_xfer 工具和文档。忽略本机构建产物、sdkconfig,以及含本机路径的依赖锁。

Co-authored-by: Cursor <[email protected]>
2026-10-13 21:54:50 +08:00

540 lines
21 KiB
C

/*
* Copyright 2026 NXP
* NXP Proprietary. This software is owned or controlled by NXP and may only be used strictly in
* accordance with the applicable license terms. By expressly accepting such terms or by downloading, installing,
* activating and/or otherwise using the software, you are agreeing that you have read, and that you agree to
* comply with and are bound by, such license terms. If you do not agree to be bound by the applicable license
* terms, then you may not retain, install, activate or otherwise use the software.
*/
#include "lvgl.h"
#include "gui_guider.h"
#include "widgets_init.h"
#include <stdlib.h>
#include <string.h>
#include "ui.h"
#include "ui_nav.h"
#include "UI_DISPATCH/ui_dispatch.h"
#include "esp_log.h"
static const char *TAG_UI_CLOCK = "ui_clock";
static lv_obj_t *ui_Screen_Calendar = NULL;
// 提前声明日历指针,解决编译错误
static lv_obj_t *g_auto_calendar = NULL;
// 日历屏幕的手势事件回调
static void calendar_scr_event_handler(lv_event_t * e) {
lv_event_code_t code = lv_event_get_code(e);
if (code == LV_EVENT_GESTURE) {
lv_dir_t dir = lv_indev_get_gesture_dir(lv_indev_get_act());
// 检测右滑 (返回)
if (dir == LV_DIR_RIGHT) {
if (guider_ui.screen_component != NULL) {
ui_nav_calendar_back_to_component();
ui_Screen_Calendar = NULL;
g_auto_calendar = NULL;
}
}
}
}
__attribute__((unused)) void kb_event_cb (lv_event_t *e) {
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t *kb = lv_event_get_target(e);
if(code == LV_EVENT_READY || code == LV_EVENT_CANCEL) {
lv_obj_add_flag(kb, LV_OBJ_FLAG_HIDDEN);
}
}
__attribute__((unused)) void ta_event_cb (lv_event_t *e) {
#if LV_USE_KEYBOARD
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t * ta = lv_event_get_target(e);
lv_obj_t * kb = lv_event_get_user_data(e);
if(code == LV_EVENT_FOCUSED) {
if(lv_indev_get_type(lv_indev_active()) != LV_INDEV_TYPE_KEYPAD) {
lv_keyboard_set_textarea(kb, ta);
lv_obj_remove_flag(kb, LV_OBJ_FLAG_HIDDEN);
}
} else if(code == LV_EVENT_READY) {
lv_obj_add_flag(kb, LV_OBJ_FLAG_HIDDEN);
lv_obj_remove_state(ta, LV_STATE_FOCUSED);
lv_indev_reset(NULL, ta);
} else if(code == LV_EVENT_DEFOCUSED) {
lv_keyboard_set_textarea(kb, NULL);
lv_obj_add_flag(kb, LV_OBJ_FLAG_HIDDEN);
}
#endif
}
void clock_count(int *hour, int *min, int *sec)
{
(*sec)++;
if (*sec >= 60) {
*sec = 0;
(*min)++;
if (*min >= 60) {
*min = 0;
(*hour)++;
if (*hour >= 24) {
*hour = 0;
}
}
}
}
void digital_clock_count(int * hour, int * minute, int * seconds, char * meridiem)
{
(*seconds)++;
if(*seconds == 60) {
*seconds = 0;
(*minute)++;
}
if(*minute == 60) {
*minute = 0;
if(*hour < 12) {
(*hour)++;
}
else {
(*hour)++;
(*hour) = (*hour) % 12;
}
}
if(*hour == 12 && *seconds == 0 && *minute == 0) {
if((lv_strcmp(meridiem, "PM") == 0)) {
lv_strcpy(meridiem, "AM");
}
else {
lv_strcpy(meridiem, "PM");
}
}
}
extern int screen_time_digital_clock_now_hour_value;
extern int screen_time_digital_clock_now_min_value;
extern int screen_time_digital_clock_now_sec_value;
void screen_time_digital_clock_now_timer(lv_timer_t *timer)
{
(void)timer;
const int prev_hour = screen_time_digital_clock_now_hour_value;
const int prev_min = screen_time_digital_clock_now_min_value;
const int prev_sec = screen_time_digital_clock_now_sec_value;
static bool s_weather_slot_labels_timer_inited = false;
if (!ui_dispatch_digital_clock_monotonic_tick()) {
clock_count(&screen_time_digital_clock_now_hour_value, &screen_time_digital_clock_now_min_value, &screen_time_digital_clock_now_sec_value);
ui_dispatch_clock_calendar_try_roll_at_midnight(prev_hour, prev_min, prev_sec,
screen_time_digital_clock_now_hour_value,
screen_time_digital_clock_now_min_value,
screen_time_digital_clock_now_sec_value);
}
ESP_LOGI(TAG_UI_CLOCK, "UI time: %02d:%02d:%02d",
screen_time_digital_clock_now_hour_value,
screen_time_digital_clock_now_min_value,
screen_time_digital_clock_now_sec_value);
if (lv_obj_is_valid(guider_ui.screen_time_digital_clock_now))
{
lv_label_set_text_fmt(guider_ui.screen_time_digital_clock_now, "%d:%02d",
screen_time_digital_clock_now_hour_value,
screen_time_digital_clock_now_min_value);
if (!s_weather_slot_labels_timer_inited || screen_time_digital_clock_now_hour_value != prev_hour) {
s_weather_slot_labels_timer_inited = true;
ui_dispatch_refresh_home_weather_slot_hour_labels();
}
}
}
//-------------------------------------万年历组件------------------------------------------//
// // 全局变量
// static int g_last_update_day = -1;
// static int g_current_shown_year = 2026; // 当前显示年份
// static int g_current_shown_month = 1; // 当前显示月份
// // 时间模拟系统
// typedef struct {
// time_t base_time; // 基础时间(模拟的"真实世界"时间)
// time_t last_update; // 最后更新时间戳
// uint32_t tick_count; // 系统启动后的tick数
// } time_simulator_t;
// static time_simulator_t g_time_sim = {0};
// // 初始化时间模拟系统
// void smart_calendar_init_time_simulator(void)
// {
// ESP_LOGI(CAL_TAG, "初始化时间模拟系统");
// // 1. 设置时区
// setenv("TZ", "CST-8", 1);
// tzset();
// // 2. 设置一个合理的起始时间
// struct tm start_tm = {
// .tm_year = 126, // 2026 - 1900
// .tm_mon = 0, // 1月
// .tm_mday = 13, // 今天设置为1月13日
// .tm_hour = 20,
// .tm_min = 00,
// .tm_sec = 0
// };
// g_time_sim.base_time = mktime(&start_tm);
// g_time_sim.last_update = xTaskGetTickCount();
// // 3. 设置系统时间
// struct timeval tv = {
// .tv_sec = g_time_sim.base_time,
// .tv_usec = 0
// };
// settimeofday(&tv, NULL);
// ESP_LOGI(CAL_TAG, "时间模拟系统初始化: %s", ctime(&g_time_sim.base_time));
// }
// // 更新时间模拟器(定期调用)
// void smart_calendar_update_time_simulator(void)
// {
// uint32_t current_tick = xTaskGetTickCount();
// uint32_t elapsed_ticks = current_tick - g_time_sim.last_update;
// // 将ticks转换为秒(1000 ticks = 1秒)
// time_t elapsed_seconds = elapsed_ticks * portTICK_PERIOD_MS / 1000;
// if (elapsed_seconds > 0) {
// g_time_sim.base_time += elapsed_seconds;
// g_time_sim.last_update = current_tick;
// // 更新系统时间
// struct timeval tv = {
// .tv_sec = g_time_sim.base_time,
// .tv_usec = 0
// };
// settimeofday(&tv, NULL);
// // 每10分钟记录一次(可选)
// static time_t last_log = 0;
// if (g_time_sim.base_time - last_log > 600) {
// struct tm tm_info;
// localtime_r(&g_time_sim.base_time, &tm_info);
// ESP_LOGI(CAL_TAG, "模拟时间更新: %04d-%02d-%02d %02d:%02d:%02d",
// tm_info.tm_year + 1900, tm_info.tm_mon + 1, tm_info.tm_mday,
// tm_info.tm_hour, tm_info.tm_min, tm_info.tm_sec);
// last_log = g_time_sim.base_time;
// }
// }
// }
// // 获取当前日期
// void smart_calendar_get_current_date(int *year, int *month, int *day)
// {
// // 更新时间模拟器
// smart_calendar_update_time_simulator();
// time_t now = g_time_sim.base_time;
// struct tm timeinfo;
// localtime_r(&now, &timeinfo);
// *year = timeinfo.tm_year + 1900;
// *month = timeinfo.tm_mon + 1;
// *day = timeinfo.tm_mday;
// }
// // 定时器回调函数:检查并更新日期
// static void check_date_update_callback(lv_timer_t *timer)
// {
// if (g_auto_calendar == NULL) return;
// int year, month, day;
// smart_calendar_get_current_date(&year, &month, &day);
// // 检查日期是否变化
// if (day != g_last_update_day) {
// // 更新今天日期
// lv_calendar_set_today_date(g_auto_calendar, year, month, day);
// // 如果显示的是当前月份,刷新显示
// if (g_current_shown_year == year && g_current_shown_month == month) {
// lv_obj_invalidate(g_auto_calendar);
// }
// g_last_update_day = day;
// ESP_LOGI(CAL_TAG, "日历今天日期已更新: %d-%02d-%02d", year, month, day);
// if (month != g_current_shown_month || year != g_current_shown_year) {
// // 判断是否应该自动切换
// int month_diff = (year - g_current_shown_year) * 12 + (month - g_current_shown_month);
// if (abs(month_diff) > 1) { // 如果相差超过1个月,自动切换
// g_current_shown_year = year;
// g_current_shown_month = month;
// lv_calendar_set_showed_date(g_auto_calendar, year, month);
// ESP_LOGI(CAL_TAG, "自动切换到: %d年%02d月", year, month);
// }
// }
// }
// }
// // 每日强制更新回调
// static lv_calendar_date_t g_click_highlight[1];
// static void daily_force_update_callback(lv_timer_t *timer)
// {
// if (g_auto_calendar != NULL) {
// int year, month, day;
// smart_calendar_get_current_date(&year, &month, &day);
// lv_calendar_set_today_date(g_auto_calendar, year, month, day);
// lv_obj_invalidate(g_auto_calendar);
// ESP_LOGI(CAL_TAG, "每日强制更新: %d-%02d-%02d", year, month, day);
// }
// }
// static lv_calendar_date_t selected_date = {2026, 1, 13};
// // 点击事件回调函数
// static lv_calendar_date_t g_click_highlight[1];
// static void calendar_event_handler(lv_event_t * e) {
// // 简化事件处理,只保留必要的操作,减少CPU占用
// lv_event_code_t code = lv_event_get_code(e);
// lv_obj_t * obj_calendar = g_auto_calendar;
// if (obj_calendar == NULL) return;
// // 只处理值变化事件
// if(code == LV_EVENT_VALUE_CHANGED) {
// lv_calendar_date_t clicked_date;
// // 获取点击的日期
// if(lv_calendar_get_pressed_date(obj_calendar, &clicked_date)) {
// // 简化校验,只检查基本范围
// if(clicked_date.year < 2000 || clicked_date.year > 2030) return;
// if(clicked_date.month < 1 || clicked_date.month > 12) return;
// if(clicked_date.day < 1 || clicked_date.day > 31) return;
// // 更新选中日期和高亮点
// g_click_highlight[0] = clicked_date;
// // 设置高亮 - 减少不必要的赋值操作
// lv_calendar_set_highlighted_dates(obj_calendar, g_click_highlight, 1);
// // 移除手动刷新,LVGL会自动处理刷新
// // lv_obj_invalidate(obj_calendar);
// }
// }
// }
// // 创建带自动更新的日历
// void smart_calendar_create_auto_update_calendar(void)
// {
// ESP_LOGI(CAL_TAG, "创建带自动更新的日历");
// ui_Screen_Calendar = lv_obj_create(NULL);
// lv_obj_set_style_bg_color(ui_Screen_Calendar, lv_color_black(), 0);
// // 获取当前日期
// int current_year, current_month, current_day;
// smart_calendar_get_current_date(&current_year, &current_month, &current_day);
// // 创建万年历
// g_auto_calendar = lv_calendar_create(ui_Screen_Calendar);
// lv_obj_set_size(g_auto_calendar, 400, 360);
// lv_obj_center(g_auto_calendar);
// // 保持日历的可点击标志,确保年月选择区域能够正常响应点击事件
// // 透明拦截图层会拦截日历主体部分的点击事件
// lv_obj_add_flag(g_auto_calendar, LV_OBJ_FLAG_CLICKABLE);
// // 在日历上面添加一层透明的可点击图层,只覆盖日历主体部分,留出顶部年月选择区域
// // 计算顶部年月选择区域高度(总高度360的1/7约为51px)
// int calendar_height = 360;
// int year_month_height = calendar_height / 7;
// int glass_height = calendar_height - year_month_height;
// // 创建透明拦截图层
// lv_obj_t *calendar_glass = lv_obj_create(ui_Screen_Calendar);
// lv_obj_set_size(calendar_glass, 400, glass_height);
// lv_obj_add_event_cb(ui_Screen_Calendar, calendar_scr_event_handler, LV_EVENT_GESTURE, NULL);
// lv_screen_load_anim(ui_Screen_Calendar, LV_SCR_LOAD_ANIM_MOVE_LEFT, 300, 0, false);
// // 定位图层到日历主体部分(顶部留出year_month_height空间)
// lv_obj_align_to(calendar_glass, g_auto_calendar, LV_ALIGN_TOP_MID, 0, year_month_height);
// // 设置图层为完全透明,去除边框
// lv_obj_set_style_bg_color(calendar_glass, lv_color_hex(0x000000), LV_PART_MAIN);
// lv_obj_set_style_bg_opa(calendar_glass, LV_OPA_TRANSP, LV_PART_MAIN);
// // 去除边框
// lv_obj_set_style_border_width(calendar_glass, 0, LV_PART_MAIN);
// lv_obj_set_style_border_opa(calendar_glass, LV_OPA_TRANSP, LV_PART_MAIN);
// // 设置图层为可点击,拦截所有点击事件
// lv_obj_add_flag(calendar_glass, LV_OBJ_FLAG_CLICKABLE);
// // 添加一个空的事件处理器,确保点击事件被拦截
// lv_obj_add_event_cb(calendar_glass, NULL, LV_EVENT_ALL, NULL);
// // 设置今天和显示日期
// lv_calendar_set_today_date(g_auto_calendar, current_year, current_month, current_day);
// lv_calendar_set_showed_date(g_auto_calendar, current_year, current_month);
// // 记录最后更新日期
// g_last_update_day = current_day;
// // 设置星期名称
// static const char *chinese_weekdays[7] = { "日", "一", "二", "三", "四", "五", "六" };
// lv_calendar_set_day_names(g_auto_calendar, chinese_weekdays);
// // 设置高亮日期
// static lv_calendar_date_t highlighted_days[3];
// highlighted_days[0].year = current_year;
// highlighted_days[0].month = current_month;
// highlighted_days[0].day = 1;
// highlighted_days[1].year = current_year;
// highlighted_days[1].month = current_month;
// highlighted_days[1].day = 19;
// highlighted_days[2].year = current_year;
// highlighted_days[2].month = current_month;
// highlighted_days[2].day = 26;
// lv_calendar_set_highlighted_dates(g_auto_calendar, highlighted_days, 3);
// // ========== 设置日历样式 ==========
// // 1. 设置屏幕背景颜色
// lv_obj_set_style_bg_color(lv_screen_active(), lv_color_hex(0x000000), 0);
// // 2. 设置日历主体背景(黑色)
// lv_obj_set_style_bg_color(g_auto_calendar, lv_color_hex(0x000000), LV_PART_MAIN);
// // 3. 设置日历主体文字颜色(白色)
// lv_obj_set_style_text_color(g_auto_calendar, lv_color_hex(0xffffff), LV_PART_MAIN);
// // 4. 设置边框样式
// lv_obj_set_style_border_color(g_auto_calendar, lv_color_hex(0x00eeff), LV_PART_MAIN);
// lv_obj_set_style_border_width(g_auto_calendar, 2, LV_PART_MAIN);
// lv_obj_set_style_border_opa(g_auto_calendar, LV_OPA_100, LV_PART_MAIN);
// // 5. 设置阴影
// // lv_obj_set_style_shadow_color(g_auto_calendar, lv_color_hex(0x00eeff), LV_PART_MAIN);
// // lv_obj_set_style_shadow_width(g_auto_calendar, 10, LV_PART_MAIN);
// // lv_obj_set_style_shadow_spread(g_auto_calendar, 2, LV_PART_MAIN);
// // ========== 设置日期单元格样式 ==========
// // 6. 设置默认日期单元格样式
// lv_obj_set_style_bg_color(g_auto_calendar, lv_color_hex(0x1A1A1A), LV_PART_ITEMS);
// lv_obj_set_style_text_color(g_auto_calendar, lv_color_hex(0xCCCCCC), LV_PART_ITEMS);
// lv_obj_set_style_pad_all(g_auto_calendar, 8, LV_PART_ITEMS);
// lv_obj_set_style_radius(g_auto_calendar, 12, LV_PART_ITEMS);
// // 7. 设置今天日期的样式
// lv_obj_set_style_bg_color(g_auto_calendar, lv_color_hex(0xFF4081), LV_PART_ITEMS | LV_STATE_CHECKED);
// lv_obj_set_style_bg_opa(g_auto_calendar, LV_OPA_100, LV_PART_ITEMS | LV_STATE_CHECKED);
// lv_obj_set_style_text_color(g_auto_calendar, lv_color_white(), LV_PART_ITEMS | LV_STATE_CHECKED);
// lv_obj_set_style_border_width(g_auto_calendar, 2, LV_PART_ITEMS | LV_STATE_CHECKED);
// lv_obj_set_style_border_color(g_auto_calendar, lv_color_hex(0xC2185B), LV_PART_ITEMS | LV_STATE_CHECKED);
// // 8. 设置高亮日期的样式
// lv_obj_set_style_bg_color(g_auto_calendar, lv_color_hex(0x2196F3), LV_PART_ITEMS | LV_STATE_FOCUSED);
// lv_obj_set_style_bg_opa(g_auto_calendar, LV_OPA_50, LV_PART_ITEMS | LV_STATE_FOCUSED);
// lv_obj_set_style_text_color(g_auto_calendar, lv_color_white(), LV_PART_ITEMS | LV_STATE_FOCUSED);
// // 10. 设置非本月日期的样式
// lv_obj_set_style_text_color(g_auto_calendar, lv_color_hex(0x666666), LV_PART_ITEMS | LV_STATE_DISABLED);
// lv_obj_set_style_bg_opa(g_auto_calendar, LV_OPA_0, LV_PART_ITEMS | LV_STATE_DISABLED);
// // 11. 设置星期名称样式
// lv_obj_set_style_text_color(g_auto_calendar, lv_color_hex(0x00eeff), LV_PART_ITEMS | LV_STATE_DISABLED);
// lv_obj_set_style_text_font(g_auto_calendar, &lv_font_MiSans_VF_25, LV_PART_ITEMS | LV_STATE_DISABLED);
// lv_obj_set_style_pad_top(g_auto_calendar, 10, LV_PART_ITEMS | LV_STATE_DISABLED);
// lv_obj_set_style_pad_bottom(g_auto_calendar, 10, LV_PART_ITEMS | LV_STATE_DISABLED);
// // ========== 设置日历头部样式 ==========
// // 12. 设置年份/月份显示样式
// lv_obj_set_style_text_color(g_auto_calendar, lv_color_hex(0x00eeff), LV_PART_ITEMS | LV_STATE_FOCUSED);
// lv_obj_set_style_text_font(g_auto_calendar, &lv_font_MiSans_VF_25, LV_PART_ITEMS | LV_STATE_FOCUSED);
// lv_obj_set_style_pad_bottom(g_auto_calendar, 15, LV_PART_ITEMS | LV_STATE_FOCUSED);
// // 13. 设置网格间距
// lv_obj_set_style_pad_row(g_auto_calendar, 6, LV_PART_MAIN);
// lv_obj_set_style_pad_column(g_auto_calendar, 6, LV_PART_MAIN);
// // ========== 强制应用样式 ==========
// // 14. 强制刷新样式
// lv_obj_refresh_style(g_auto_calendar, LV_PART_ITEMS, LV_STYLE_PROP_ANY);
// lv_obj_refresh_style(g_auto_calendar, LV_PART_MAIN, LV_STYLE_PROP_ANY);
// // 15. 强制重绘
// // lv_obj_invalidate(g_auto_calendar);
// // ========== 设置下拉列表和中文模式 ==========
// // 设置下拉列表
// #if LV_USE_CALENDAR_HEADER_DROPDOWN
// lv_obj_t * header = lv_calendar_header_dropdown_create(g_auto_calendar);
// // 设置下拉列表样式
// lv_obj_set_style_text_color(header, lv_color_hex(0xffffff), 0);
// lv_obj_set_style_bg_color(header, lv_color_hex(0x333333), 0);
// lv_obj_set_style_text_font(header, &lv_font_source_han_sans_sc_14_cjk, 0);
// #elif LV_USE_CALENDAR_HEADER_ARROW
// lv_calendar_header_arrow_create(g_auto_calendar);
// #endif
// // 设置中文模式
// lv_calendar_set_chinese_mode(g_auto_calendar, true);
// // 设置整个日历的中文字体
// lv_obj_set_style_text_font(g_auto_calendar, &lv_font_MiSans_VF_25, LV_PART_MAIN);
// // 取消点击事件,只保留日历观看功能,减少CPU压力// 移除事件监听,确保日历不处理任何点击事件
// //lv_obj_add_event_cb(g_auto_calendar, calendar_event_handler, LV_EVENT_VALUE_CHANGED, NULL);
// // 关闭日历的所有事件监听,彻底杜绝重绘
// lv_obj_remove_event_cb(g_auto_calendar, calendar_event_handler);
// // 关闭日历的可点击标志,进一步减少CPU占用
// lv_obj_clear_flag(g_auto_calendar, LV_OBJ_FLAG_CLICKABLE);
// ESP_LOGI(CAL_TAG, "自动更新日历创建完成,当前日期: %d-%02d-%02d",
// current_year, current_month, current_day);
// }
// // 创建自动更新定时器
// void smart_calendar_create_auto_update_timer(void)
// {
// ESP_LOGI(CAL_TAG, "创建自动更新定时器");
// // 每分钟检查一次日期变化
// lv_timer_create(check_date_update_callback, 60000, NULL);
// // 每天0点强制更新一次(24小时)
// lv_timer_create(daily_force_update_callback, 86400000, NULL);
// ESP_LOGI(CAL_TAG, "自动更新定时器已创建");
// }
// 主循环中的时间更新(每秒更新)
void smart_calendar_time_update_loop(void)
{
static uint32_t last_time_update = 0;
uint32_t current_tick = xTaskGetTickCount();
if (current_tick - last_time_update > 1000) // 每秒更新一次
{
smart_calendar_update_time_simulator();
last_time_update = current_tick;
}
}