diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e73a61..65007ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,10 @@ add_executable(DTU-HMI src/Drv/pages/AppInfo/model.c src/Drv/pages/AppInfo/presenter.c src/Drv/pages/AppInfo/view.c + src/Drv/pages/YC/page.c + src/Drv/pages/YC/model.c + src/Drv/pages/YC/presenter.c + src/Drv/pages/YC/view.c src/Drv/lcd/lcd.c src/Drv/lcd/lcd_draw.c src/Drv/lcd/lcd_text.c diff --git a/include/types.h b/include/types.h index 6bfe0a5..e05481a 100644 --- a/include/types.h +++ b/include/types.h @@ -2,21 +2,46 @@ #define __TYPES__H__ #include - -#define uint8_t unsigned char -#define uint16_t unsigned short -#define uint32_t unsigned int -#define uint64_t unsigned long long -#define int8_t char -#define int16_t short -#define int32_t int -#define int64_t long long - -#define ptr_size_t unsigned long long +#include typedef int (*FUNCPTR) ( ); +enum _MEA_TYPE_ +{ + EN_MEA_RLY, + EN_MEA_RLY2, + EN_MEA_RLY3, + EN_MEA_ANA, + EN_MEA_ANA2, + EN_MEA_ANA3, + EN_MEA_AC, + EN_MEA_DC, + EN_MEA_SYN, + EN_MEA_POWER, + EN_MEA_DD, + EN_MEA_JLYC, + EN_MEA_GEAR, + EN_MEA_TQ, + EN_MEA_INPUT1, + EN_MEA_INPUT2, + EN_MEA_INPUT3, + EN_INPUT_RLY_ALL, + EN_INPUT_RLY_FAULT, + EN_INPUT_RLY_OTHER, + EN_INPUT_BS_ALL, + EN_INPUT_BS_FAULT, + EN_INPUT_BS_OTHER, + EN_MEA_ADJ, + EN_MEA_YX, + EN_OUTPUT_TRIP, + EN_OUTPUT_SIGN, + EN_MEA_LS, + EN_MEA_SCRLY +}; + + + // 调试模式断言 #ifdef DEBUG #define ASSERT(expr) \ diff --git a/src/Drv/lcd/lcd_text.c b/src/Drv/lcd/lcd_text.c index 71b26cf..d6eca36 100644 --- a/src/Drv/lcd/lcd_text.c +++ b/src/Drv/lcd/lcd_text.c @@ -128,7 +128,7 @@ static int8_t Lcd_Pub_UTF8(uint16_t x, uint16_t y, uint32_t unicode) * - 与历史行为兼容,保留 -1/-2 两种错误码语义。 * - 内部会在渲染前做边界预判,并在底层写像素失败时转化为越界错误返回。 * ------------------------------------------------------------------------- */ -int8_t Lcd_ShowStr(uint16_t x, uint16_t y, uint8_t *pcString) +int8_t Lcd_ShowStr(uint16_t x, uint16_t y, const uint8_t *pcString) { const textConfig *cfg = &text_cfg; uint16_t bakx = x; diff --git a/src/Drv/lcd/lcd_text.h b/src/Drv/lcd/lcd_text.h index 4703e0a..71a3a12 100644 --- a/src/Drv/lcd/lcd_text.h +++ b/src/Drv/lcd/lcd_text.h @@ -16,7 +16,7 @@ typedef struct { extern textConfig text_cfg; -int8_t Lcd_ShowStr(uint16_t x, uint16_t y, uint8_t *pcString); +int8_t Lcd_ShowStr(uint16_t x, uint16_t y, const uint8_t *pcString); int8_t Lcd_ShowTest(uint16_t x, uint16_t y, uint8_t *pcString); #endif diff --git a/src/Drv/menu/app/menu.c b/src/Drv/menu/app/menu.c index 5de124f..24e5d1d 100644 --- a/src/Drv/menu/app/menu.c +++ b/src/Drv/menu/app/menu.c @@ -32,7 +32,7 @@ void MenuProc_See_AppInfo(void) void MenuProc_See_YC(void) { - MenuPage_TriggerCurrentAction(); + (void)PageManager_Navigate(PAGE_ID_YC); } void MenuProc_Set_Value(void) { MenuPage_TriggerCurrentAction(); } diff --git a/src/Drv/pages/AppInfo/def.h b/src/Drv/pages/AppInfo/def.h deleted file mode 100644 index 513be67..0000000 --- a/src/Drv/pages/AppInfo/def.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef APPINFO_def_H -#define APPINFO_def_H - -#define CN_HEIGHT 12 -#define CN_ROWSPACE 2 -#define APPINFO_WITDTH 7 - - -#endif \ No newline at end of file diff --git a/src/Drv/pages/AppInfo/page.h b/src/Drv/pages/AppInfo/page.h index 53c5a45..8483307 100644 --- a/src/Drv/pages/AppInfo/page.h +++ b/src/Drv/pages/AppInfo/page.h @@ -4,6 +4,5 @@ #include "Drv/pages/page.h" page_t *AppInfoPage_GetInstance(void); -void AppInfoPage_TriggerCurrentAction(void); #endif \ No newline at end of file diff --git a/src/Drv/pages/AppInfo/view.c b/src/Drv/pages/AppInfo/view.c index 895f36f..d6e45f0 100644 --- a/src/Drv/pages/AppInfo/view.c +++ b/src/Drv/pages/AppInfo/view.c @@ -2,64 +2,12 @@ #include "Drv/pages/AppInfo/view.h" #include -/* MSVC 对含多字节/中文格式串的静态分析可能误报 C4474/C4996。 - * 本文件内的格式化输出均为受控 buffer,并用于显示文本渲染。 */ -#if defined(_MSC_VER) -#pragma warning(disable : 4474) -#pragma warning(disable : 4996) -#endif + static const PageRenderPort *s_port = NULL; -/* ------------------------------------------------------------------------- -* 函数名: MenuView_DrawMeitou -* 功能: -* 绘制菜单标题装饰线(“眉头”样式):中间横线 + 左右两端斜线。 -* -* 参数: -* view - 菜单视图对象,提供底层渲染端口 -* yStart - 装饰线基准 Y 坐标(横线所在行) -* width - 线宽参数(传递给 line_h/line) -* -* 边界处理: -* - 本函数不做空指针判定,调用方需保证 view 与 s_port 有效。 -* - 坐标范围合法性由上层布局计算保证。 -* -* 说明: -* - 颜色统一使用字体前景色(get_color_font),确保装饰与文字风格一致。 -* - 绘制顺序: -* 1) 中间横线(x:16~144) -* 2) 左斜线(8, yStart-8 -> 16, yStart) -* 3) 右斜线(144, yStart -> 152, yStart-8) -* - 该函数用于视觉分隔与层次强调,不改变菜单状态数据。 -* -* 返回值: -* - 无 -* ------------------------------------------------------------------------- */ -static void AppInfoView_DrawMeitou(uint16_t yStart, uint16_t width) -{ - uint8_t fontColor = s_port->get_color_font(); - s_port->line_h(16, 144, yStart, width, fontColor); - s_port->line(8, yStart - 8, 16, yStart, width, fontColor); - s_port->line(144, yStart, 152, yStart - 8, width, fontColor); -} -void AppInfoView_ShowInfoPage(uint16_t wPageNum, uint16_t wPageMax ) -{ - /* show_str 期望的是 '\0' 结尾的 UTF-8 字符串 */ - char pbyTips[64]; - uint16_t y = s_port->get_size_y() - 16; - /* 格式化字符串(用于 LCD 文本显示) */ -#if defined(_MSC_VER) - (void)sprintf_s(pbyTips, sizeof(pbyTips), "第%4u 页 , 共%4u 页", - (unsigned)wPageNum, (unsigned)wPageMax); -#else - (void)snprintf(pbyTips, sizeof(pbyTips), "第%4u 页 , 共%4u 页", - (unsigned)wPageNum, (unsigned)wPageMax); -#endif - s_port->show_str(6, y, (uint8_t *)pbyTips); -} void AppInfoView_ShowTerminalInfo(void) { @@ -85,9 +33,8 @@ void AppInfoView_ShowTopName(uint8_t *name) s_port->fill_rect(0, 0, s_port->get_size_x() - 1, s_port->get_size_y() - 1, s_port->get_color_back()); /* 显示顶部名称,居中显示 */ s_port->show_str((s_port->get_size_x() - wLen) / 2, 3, name); - - AppInfoView_DrawMeitou(18, 2); - AppInfoView_ShowInfoPage(10, 1); + s_port->draw_meitou(18, 2); + s_port->show_info_page(10, 1); AppInfoView_ShowTerminalInfo(); } void AppInfoView_Init(appinfo_view_t *view) diff --git a/src/Drv/pages/AppInfo/view.h b/src/Drv/pages/AppInfo/view.h index 9e94a11..9f3cea1 100644 --- a/src/Drv/pages/AppInfo/view.h +++ b/src/Drv/pages/AppInfo/view.h @@ -2,7 +2,6 @@ #define APPINFO_VIEW_H #include "types.h" -#include "Drv/pages/AppInfo/def.h" #include "Drv/pages/global/renderer_lcd.h" typedef struct appinfo_view_t appinfo_view_t; diff --git a/src/Drv/pages/YC/model.c b/src/Drv/pages/YC/model.c new file mode 100644 index 0000000..624cd93 --- /dev/null +++ b/src/Drv/pages/YC/model.c @@ -0,0 +1,367 @@ +#include "Drv/pages/YC/model.h" +#include "../global/global_state.h" +#include + +#ifndef CN_PHASE_NAME_LEN +#define CN_PHASE_NAME_LEN (4) +#endif + +/* YC 页面编译接入阶段的兼容常量(后续可替换为真实业务定义) */ +#ifndef CN_RGB_YELLOW +#define CN_RGB_YELLOW (0x00FFFF00u) +#define CN_RGB_GREEN (0x0000FF00u) +#define CN_RGB_RED (0x00FF0000u) +#define CN_RGB_WHITE (0x00FFFFFFu) +#endif + +enum +{ + EN_UNIT01_A = 1, EN_UNIT01_B, EN_UNIT01_C, + EN_UNIT02_A, EN_UNIT02_B, EN_UNIT02_C, + EN_UNIT01_0, EN_VOL1_A, EN_VOL1_B, EN_VOL1_C, + EN_VOL2_A, EN_VOL2_B, EN_VOL2_C, EN_VOL1_0, + EN_VOL2_0, EN_VOL1_FR, EN_UNIT01_DC +}; + +// 定义单位类型常量 +enum _UNIT_TYPE_ +{ + EN_UNIT_NULL=0, // 0 " " + EN_UNIT_A, // 1 "A" + EN_UNIT_V, // 2 "V" + EN_UNIT_S, // 3 "S" + EN_UNIT_HZ, // 4 "Hz" + EN_UNIT_HZPS, // 5 "Hz/s" + EN_UNIT_DGREE, // 6 "°" + EN_UNIT_OHM, // 7 "Ω" + EN_UNIT_KM, // 8 "kM" + EN_UNIT_M, // 9 "M" + EN_UNIT_VPS, // 0AH "V/S" + EN_UNIT_KV, // 0BH "kV" + EN_UNIT_W, // 0CH "W" + EN_UNIT_VAR, // 0DH "VAR" + EN_UNIT_MVA, // 0EH "MVA" + EN_UNIT_0F, // 0FH " " + EN_UNIT_PERCENT, // 10H "%" + EN_UNIT_MW, // 11H "MW" + EN_UNIT_MV, // 12H "mV" + EN_UNIT_MA, // 13H "mA" + EN_UNIT_KOHM, // 14 "kΩ" + EN_UNIT_VA, // 15H "VA" + EN_UNIT_AKA, // 16H "A(kA)" + EN_UNIT_KA, // 17H "kA" + EN_UNIT_KVPS, // 18H "KV/S" + EN_UNIT_MVAR, // 19H "MVAR" + EN_UNIT_KW, // 1AH "KW" + EN_UNIT_KVAR, // 1BH "KVAR" + EN_UNIT_KVA, // 1CH "KVA" + EN_UNIT_KWH, // 1DH "kWh" + EN_UNIT_KVARH, // 1EH "kVarh" + EN_UNIT_IE, // 1AH "Ie" + EN_UNIT_1B, // 1BH "无" + EN_UNIT_1C, // 1CH "无" + EN_UNIT_1D, // 1DH "无" + EN_UNIT_1E, // 1EH "无" + EN_UNIT_1F, // 1FH "无" + EN_UNIT_20, // 20H "无" + EN_UNIT_PERUN, // 21H "%Un" + +}; + +//================================================================================ +// 遥测量交流通道 +//================================================================================ +enum _YCMEA_INDEX_TYPE_ +{ + EN_YCMEA_ORI_START = 0, + EN_YCMEA_I_START = EN_YCMEA_ORI_START, + EN_YCMEA_IA01 = EN_YCMEA_I_START, // 遥测A相电流01 + EN_YCMEA_IB01, // 遥测B相电流01 + EN_YCMEA_IC01, // 遥测C相电流01 + EN_YCMEA_IA02, // 遥测A相电流01 + EN_YCMEA_IB02, // 遥测B相电流01 + EN_YCMEA_IC02, + //------------------add by lc 为了功率计算能通过定值设置选择电压---------------- + EN_YCMEA_I_END, // 遥测电流模拟量通道 END,本条不能修改 2 + //================================================================================ + // 遥测量电压通道 + //================================================================================ + EN_YCMEA_U_START = EN_YCMEA_I_END-1, // 遥测量电压通道 START,本条不能修改 1 + //---------------------------------------------- + //------------------add by lc 为了功率计算能通过定值设置选择电压---------------- + // 以下部分添加格式必须是:UA、UB、UC、UAB、UBC、UCA + + EN_YCMEA_UA1, // 遥测A相电压1 2 + EN_YCMEA_UB1, // 遥测B相电压1 + EN_YCMEA_UC1, // 遥测C相电压1 + + EN_YCMEA_UA2, // 遥测A相电压2 + EN_YCMEA_UB2, // 遥测B相电压2 + EN_YCMEA_UC2, // 遥测C相电压2 + + EN_YCMEA_UAB1, + EN_YCMEA_UBC1, + EN_YCMEA_UCA1, + + EN_YCMEA_UAB2, + EN_YCMEA_UBC2, + EN_YCMEA_UCA2, + + //------------------add by lc 为了功率计算能通过定值设置选择电压---------------- + EN_YCMEA_U_END, // 遥测电压模拟量通道 END,本条不能修改 + //================================================================================ + // 遥测量电压通道 + //================================================================================ + EN_YCMEA_3I0_START = EN_YCMEA_U_END-1, // 遥测量零序通道 START,本条不能修改 + //---------------------------------------------- + //------------------add by lc 为了功率计算能通过定值设置选择电压---------------- + EN_YCMEA_3I01, // 3I01 + EN_YCMEA_3I0_END, + EN_YCMEA_3U0_START = EN_YCMEA_3I0_END-1, + EN_YCMEA_3U01, // 3U01 + EN_YCMEA_3U02, // 3U02 +//---------------------------------------------- + EN_YCMEA_3U0_END, +//================================================================================ +// 频率测量通道 +//================================================================================ + EN_YCMEA_FR_START = EN_YCMEA_3U0_END-1, + EN_YCMEA_FR1, +//---------------------------------------------- + EN_YCMEA_ANA_END, // 遥测交流模拟量通道 END,本条不能修改 +//================================================================================ +// 遥测量直流通道 +//================================================================================ + EN_YCMEA_DC_START = EN_YCMEA_ANA_END-1, // 遥测量直流通道 START,本条不能修改 +//---------------------------------------------- + EN_YCMEA_DC_01, // 直流01 + EN_YCMEA_DC_02, // 直流02 + + +//---------------------------------------------- + EN_YCMEA_DC_END, // 遥测量直流通道 END,本条不能修改 +//================================================================================ +// 遥测量电度通道 +//================================================================================ + EN_YCMEA_P_START = EN_YCMEA_DC_END-1, // 遥测量电度通道 START,本条不能修改 +//---------------------------------------------- + EN_YCMEA_PA_1, // A相有功功率1 + EN_YCMEA_PB_1, // B相有功功率1 + EN_YCMEA_PC_1, // C相有功功率1 + EN_YCMEA_P_1, // 有功功率1 + EN_YCMEA_Q_1, // 无功功率1 + EN_YCMEA_S_1, // 视在功率1 + EN_YCMEA_COS_1, // 功率因素1 +//---------------------------------------------- + EN_YCMEA_P_END, // 遥测量电度通道 END,本条不能修改 + +//================================================================================ +// 遥测量档位通道 +//================================================================================ + EN_YCMEA_DW_START = EN_YCMEA_P_END-1, // 遥测量档位通道 START,本条不能修改 +//---------------------------------------------- + + //EN_YCMEA_DW_1, // 档位1 + +//---------------------------------------------- + EN_YCMEA_DW_END, // 遥测量档位通道 END,本条不能修改 + EN_YCMEA_END=EN_YCMEA_DW_END // 遥测量通道 END,本条不能修改 +}; + +// BIT位定义 +#define DB0 (0x01) +#define DB1 (0x02) +#define DB2 (0x04) +#define DB3 (0x08) +#define DB4 (0x10) +#define DB5 (0x20) +#define DB6 (0x40) +#define DB7 (0x80) +#define DB8 (0x100) +#define DB9 (0x200) +#define DB10 (0x400) +#define DB11 (0x800) +#define DB12 (0x1000) +#define DB13 (0x2000) +#define DB14 (0x4000) +#define DB15 (0x8000) +#define DB16 (0x10000) +#define DB17 (0x20000) +#define DB18 (0x40000) +#define DB19 (0x80000) +#define DB20 (0x100000) +#define DB21 (0x200000) +#define DB22 (0x400000) +#define DB23 (0x800000) +#define DB24 (0x1000000) +#define DB25 (0x2000000) +#define DB26 (0x4000000) +#define DB27 (0x8000000) +#define DB28 (0x10000000) +#define DB29 (0x20000000) +#define DB30 (0x40000000) +#define DB31 (0x80000000) + +//============================================================================ +//上送CPU定义 +//============================================================================ +enum _ANA_CPU_ { // 字节高三位分别表示 + EN_CPU0 = 32, // bit5 + EN_CPU1 = 64, // bit6 + EN_CPU2 = 128 // bit7 +}; +//============================================================================ +//模拟量常量表类型定义(应用于交流量常量表,及) +//============================================================================ +enum _ANA_TYP_ { // 模拟量类型定义 + EN_ANA_TYP_NULL = 0, // 未定义 + EN_ANA_TYP_I, // 电流 + EN_ANA_TYP_I0, // 电流 + EN_ANA_TYP_U, // 电压 + EN_ANA_TYP_Ux, + EN_ANA_TYP_U0, // 电压 + EN_ANA_TYP_U_S, // 站用变电压 + + EN_ANA_TYP_P, // 有功功率 + EN_ANA_TYP_Q, // 无功功率 + EN_ANA_TYP_S, // 视在功率 + EN_ANA_TYP_COS, // 功率因素 + EN_ANA_TYP_DC_U, // 直流电压 + EN_ANA_TYP_DC_I, // 直流电流 + EN_ANA_TYP_GEAR, // 档位 + EN_ANA_TYP_FR, // 频率 + EN_ANA_TYP_T, // 温度 + EN_ANA_TYP_DU, // 直流 + EN_ANA_TYP_MC, // 脉冲 + EN_ANA_TYP_AMP, + EN_ANA_TYP_ST, // 设备态 + EN_ANA_TYP_IMP // 阻抗 +}; + +#define CN_COE_YCMEA_I1A (1) // 遥测电流通道系数 1A -> +#define CN_COE_YCMEA_I1A_0 +#define CN_COE_YCMEA_VOL (1) // 遥测电流通道系数 1V -> +// 条件成立常用标志 +#define CN_FLAG_TRUE (0x5A) // 条件成立标志 +#define CN_FLAG_FALSE (0xA5) // 条件不成立标志 +#define CN_REC_ACTION (0x55) // 记录动作标志 +#define CN_REC_RETURN (0xAA) // 记录返回标志 +#define CN_REC_RETURN_YX (0x5500+CN_REC_RETURN) // 记录返回标志(表示不清除保护遥信) + +// 遥测量常量信息表数据结构 +typedef struct +{ + uint16_t wIndex; // 模拟量虚端子号 + uint8_t byPinName[32]; // 模拟量虚端子名称 + uint8_t byUnit; // 二次模拟量单位索引号,字符串单位常量表中偏移地址 + uint8_t byKiloUnit; // 一次模拟量单位索引号,字符串单位常量表中偏移地址 + uint8_t byCpu; // 数据由哪一 CPU 上送 + uint16_t wChanType; // 模拟量向量类型 + uint8_t byName[8]; // 模拟量描述字符串 + uint8_t byPhaseName[CN_PHASE_NAME_LEN]; // 模拟量相别 + uint8_t byWidth; // 数据长度 (包含小数点长度) + uint8_t byDotBit; // 小数位数; + uint32_t dwRGB; // 显示颜色 + uint16_t wCode; // 103 规约测量值代码 + uint32_t dwChanCoe; // 通道系数 + uint16_t wCapacity; // 遥测量的量程 + uint32_t dwXuYcDflt; // 虚遥测的默认值 + uint16_t wSamPinNO; // 遥测采样通道序号(仅原始采样通道及测频通道有效) + uint16_t wYcAdjFlg; // 遥测关联调节系数标志,TRUE-带调节系数,否则 - 不带调节系数 + uint16_t wHarmFlg; // 谐波计算标志,TRUE-需要计算谐波,否则 - 不需要计算谐波 + uint16_t wParIndex1; // 关联的遥测参数号,线电压关联相量虚端子,无关联为 0xAAAA + uint16_t wParIndex2; // 关联的遥测参数号,线电压关联相量虚端子,无关联为 0xAAAA + uint32_t dwCommAttr; // 通讯传输属性,DB0 置位:103 上送,DB1 置位:调试规约上送,DB2 置位:打印规约,DB3 置位:显示上送,DB4~DB31:未定义 + uint32_t dwResePara; // 保留参数 (按照 bit 位使用) + +}tagYcIndexTab; + +const tagYcIndexTab g_tYcIndexTab[] = +{ + //================================================================================ + // 遥测量交流通道 + //================================================================================ + // wIndex byPinName byUnit byKiloUnit byCpu wChanType byName byPhase byWidth byDotBit dwRGB wCode wChanCoe wCapacity wXuYcDflt wSamPinNO wYcAdjFlg wHarmFlg wParIndex1 wParIndex2 dwCommAttr dwResePara + {EN_YCMEA_IA01, "EN_YCMEA_IA01", EN_UNIT_A, EN_UNIT_KA, EN_CPU0, EN_ANA_TYP_I, "Ia1", "A", 7, 3, CN_RGB_YELLOW, 92, CN_COE_YCMEA_I1A, 6, 1000, EN_UNIT01_A, CN_FLAG_TRUE, CN_FLAG_TRUE, 0xAAAA, 0xAAAA, 0xFFFF, 0 }, // A相测量电流 + {EN_YCMEA_IB01, "EN_YCMEA_IB01", EN_UNIT_A, EN_UNIT_KA, EN_CPU0, EN_ANA_TYP_I, "Ib1", "B", 7, 3, CN_RGB_GREEN, 93, CN_COE_YCMEA_I1A, 6, 1000, EN_UNIT01_B, CN_FLAG_TRUE, CN_FLAG_TRUE, 0xAAAA, 0xAAAA, 0xFFFF, 0 }, // B相测量电流 + {EN_YCMEA_IC01, "EN_YCMEA_IC01", EN_UNIT_A, EN_UNIT_KA, EN_CPU0, EN_ANA_TYP_I, "Ic1", "C", 7, 3, CN_RGB_RED, 94, CN_COE_YCMEA_I1A, 6, 1000, EN_UNIT01_C, CN_FLAG_TRUE, CN_FLAG_TRUE, 0xAAAA, 0xAAAA, 0xFFFF, 0 }, // C相测量电流 + {EN_YCMEA_IA02, "EN_YCMEA_IA02", EN_UNIT_A, EN_UNIT_KA, EN_CPU0, EN_ANA_TYP_I, "Ia2", "A", 7, 3, CN_RGB_YELLOW, 95, CN_COE_YCMEA_I1A, 6, 1000, EN_UNIT02_A, CN_FLAG_TRUE, CN_FLAG_TRUE, 0xAAAA, 0xAAAA, 0xFFFF, 0 }, // A相测量电流 + {EN_YCMEA_IB02, "EN_YCMEA_IB02", EN_UNIT_A, EN_UNIT_KA, EN_CPU0, EN_ANA_TYP_I, "Ib2", "B", 7, 3, CN_RGB_GREEN, 96, CN_COE_YCMEA_I1A, 6, 1000, EN_UNIT02_B, CN_FLAG_TRUE, CN_FLAG_TRUE, 0xAAAA, 0xAAAA, 0xFFFF, 0 }, // B相测量电流 + {EN_YCMEA_IC02, "EN_YCMEA_IC02", EN_UNIT_A, EN_UNIT_KA, EN_CPU0, EN_ANA_TYP_I, "Ic2", "C", 7, 3, CN_RGB_RED, 97, CN_COE_YCMEA_I1A, 6, 1000, EN_UNIT02_C, CN_FLAG_TRUE, CN_FLAG_TRUE, 0xAAAA, 0xAAAA, 0xFFFF, 0 }, // C相测量电流 + {EN_YCMEA_UA1, "EN_YCMEA_UA1", EN_UNIT_V, EN_UNIT_KV, EN_CPU0, EN_ANA_TYP_U, "Ua1", "A", 6, 2, CN_RGB_YELLOW, 98, CN_COE_YCMEA_VOL, 120, 6000, EN_VOL1_A, CN_FLAG_TRUE, CN_FLAG_TRUE, 0xAAAA, 0xAAAA, 0xFFFF, DB5}, + {EN_YCMEA_UB1, "EN_YCMEA_UB1", EN_UNIT_V, EN_UNIT_KV, EN_CPU0, EN_ANA_TYP_U, "Ub1", "B", 6, 2, CN_RGB_GREEN, 99, CN_COE_YCMEA_VOL, 120, 6000, EN_VOL1_B, CN_FLAG_TRUE, CN_FLAG_TRUE, 0xAAAA, 0xAAAA, 0xFFFF, DB5}, + {EN_YCMEA_UC1, "EN_YCMEA_UC1", EN_UNIT_V, EN_UNIT_KV, EN_CPU0, EN_ANA_TYP_U, "Uc1", "C", 6, 2, CN_RGB_RED, 100, CN_COE_YCMEA_VOL, 120, 6000, EN_VOL1_C, CN_FLAG_TRUE, CN_FLAG_TRUE, 0xAAAA, 0xAAAA, 0xFFFF, DB5}, + {EN_YCMEA_UA2, "EN_YCMEA_UA2", EN_UNIT_V, EN_UNIT_KV, EN_CPU0, EN_ANA_TYP_U, "Ua2", "A", 6, 2, CN_RGB_YELLOW, 101, CN_COE_YCMEA_VOL, 120, 6000, EN_VOL2_A, CN_FLAG_TRUE, CN_FLAG_TRUE, 0xAAAA, 0xAAAA, 0xFFFF, DB5}, + {EN_YCMEA_UB2, "EN_YCMEA_UB2", EN_UNIT_V, EN_UNIT_KV, EN_CPU0, EN_ANA_TYP_U, "Ub2", "B", 6, 2, CN_RGB_GREEN, 102, CN_COE_YCMEA_VOL, 120, 6000, EN_VOL2_B, CN_FLAG_TRUE, CN_FLAG_TRUE, 0xAAAA, 0xAAAA, 0xFFFF, DB5}, + {EN_YCMEA_UC2, "EN_YCMEA_UC2", EN_UNIT_V, EN_UNIT_KV, EN_CPU0, EN_ANA_TYP_U, "Uc2", "C", 6, 2, CN_RGB_RED, 103, CN_COE_YCMEA_VOL, 120, 6000, EN_VOL2_C, CN_FLAG_TRUE, CN_FLAG_TRUE, 0xAAAA, 0xAAAA, 0xFFFF, DB5}, + {EN_YCMEA_UAB1, "EN_YCMEA_UAB1", EN_UNIT_V, EN_UNIT_KV, EN_CPU0, EN_ANA_TYP_U, "Uab1", "A", 6, 2, CN_RGB_YELLOW, 104, CN_COE_YCMEA_VOL, 120, 10000, 0xAAAA, 0xAAAA, CN_FLAG_TRUE, EN_VOL1_A, EN_VOL1_B, 0xFFFF, 0 }, // AB相电压 1 + {EN_YCMEA_UBC1, "EN_YCMEA_UBC1", EN_UNIT_V, EN_UNIT_KV, EN_CPU0, EN_ANA_TYP_U, "Ubc1", "B", 6, 2, CN_RGB_GREEN, 105, CN_COE_YCMEA_VOL, 120, 10000, 0xAAAA, 0xAAAA, CN_FLAG_TRUE, EN_VOL1_B, EN_VOL1_C, 0xFFFF, 0 }, // BC相电压 1 + {EN_YCMEA_UCA1, "EN_YCMEA_UCA1", EN_UNIT_V, EN_UNIT_KV, EN_CPU0, EN_ANA_TYP_U, "Uca1", "C", 6, 2, CN_RGB_RED, 106, CN_COE_YCMEA_VOL, 120, 10000, 0xAAAA, 0xAAAA, CN_FLAG_TRUE, EN_VOL1_C, EN_VOL1_A, 0xFFFF, 0 }, // CA相电压 1 + {EN_YCMEA_UAB2, "EN_YCMEA_UAB2", EN_UNIT_V, EN_UNIT_KV, EN_CPU0, EN_ANA_TYP_U, "Uab2", "A", 6, 2, CN_RGB_YELLOW, 107, CN_COE_YCMEA_VOL, 120, 10000, 0xAAAA, 0xAAAA, CN_FLAG_TRUE, EN_VOL2_A, EN_VOL2_B, 0xFFFF, 0 }, // AB相电压 1 + {EN_YCMEA_UBC2, "EN_YCMEA_UBC2", EN_UNIT_V, EN_UNIT_KV, EN_CPU0, EN_ANA_TYP_U, "Ubc2", "B", 6, 2, CN_RGB_GREEN, 108, CN_COE_YCMEA_VOL, 120, 10000, 0xAAAA, 0xAAAA, CN_FLAG_TRUE, EN_VOL2_B, EN_VOL2_C, 0xFFFF, 0 }, // BC相电压 1 + {EN_YCMEA_UCA2, "EN_YCMEA_UCA2", EN_UNIT_V, EN_UNIT_KV, EN_CPU0, EN_ANA_TYP_U, "Uca2", "C", 6, 2, CN_RGB_RED, 109, CN_COE_YCMEA_VOL, 120, 10000, 0xAAAA, 0xAAAA, CN_FLAG_TRUE, EN_VOL2_C, EN_VOL2_A, 0xFFFF, 0 }, // CA相电压 1 + {EN_YCMEA_3I01, "EN_YCMEA_3I01", EN_UNIT_A, EN_UNIT_KA, EN_CPU0, EN_ANA_TYP_I0, "Io1", "0", 7, 3, CN_RGB_WHITE, 110, CN_COE_YCMEA_I1A, 6, 1000, EN_UNIT01_0, CN_FLAG_TRUE, CN_FLAG_TRUE, 0xAAAA, 0xAAAA, 0xFFFF, 0 }, // 零序电流 + {EN_YCMEA_3U01, "EN_YCMEA_3U01", EN_UNIT_V, EN_UNIT_KV, EN_CPU0, EN_ANA_TYP_U0, "Uo1", "0", 6, 2, CN_RGB_WHITE, 111, CN_COE_YCMEA_VOL, 120, 10000, EN_VOL1_0, CN_FLAG_TRUE, CN_FLAG_TRUE, 0xAAAA, 0xAAAA, 0xFFFF, 0 }, // 零序电压 + {EN_YCMEA_3U02, "EN_YCMEA_3U02", EN_UNIT_V, EN_UNIT_KV, EN_CPU0, EN_ANA_TYP_U, "Uo2", "0", 6, 2, CN_RGB_WHITE, 112, CN_COE_YCMEA_VOL, 120, 10000, EN_VOL2_0, CN_FLAG_TRUE, CN_FLAG_TRUE, 0xAAAA, 0xAAAA, 0xFFFF, 0 }, // 零序电压 + {EN_YCMEA_FR1, "EN_YCMEA_FR1", EN_UNIT_HZ, EN_UNIT_HZ, EN_CPU0, EN_ANA_TYP_FR, "Fr1", "0", 5, 2, CN_RGB_YELLOW, 113, 1, 20, 4999, EN_VOL1_FR, 0xAAAA, 0xAAAA, 0xAAAA, 0xAAAA, 0xFFFF, DB0}, + //====================================================================================== + // 遥测量直流通道 + //====================================================================================== + {EN_YCMEA_DC_01, "EN_YCMEA_DC_01", EN_UNIT_NULL, EN_UNIT_NULL, EN_CPU0, EN_ANA_TYP_DU, "ZL01", "0", 6, 2, CN_RGB_WHITE, 114, 1, 512, 6000, EN_UNIT01_DC, CN_FLAG_TRUE, 0xAAAA, 0xAAAA, 0xAAAA, 0xFFFF, 0 }, // 直流量1 + {EN_YCMEA_DC_02, "EN_YCMEA_DC_02", EN_UNIT_NULL, EN_UNIT_NULL, EN_CPU0, EN_ANA_TYP_DU, "ZL02", "0", 6, 2, CN_RGB_WHITE, 115, 2, 512, 6000, 0xAAAA, CN_FLAG_TRUE, 0xAAAA, 0xAAAA, 0xAAAA, 0xFFFF, 0 }, // 直流量2 + //====================================================================================== + // 遥测量电度通道 + //====================================================================================== + {EN_YCMEA_PA_1, "EN_YCMEA_PA_1", EN_UNIT_W, EN_UNIT_W, EN_CPU0, EN_ANA_TYP_P, "Pa1", "A", 8, 3, CN_RGB_YELLOW, 116, CN_COE_YCMEA_VOL * CN_COE_YCMEA_I1A, 866, 60000, 0xAAAA, CN_FLAG_TRUE, 0xAAAA, 0xAAAA, 0xAAAA, 0xFFFF, DB5}, // PA + {EN_YCMEA_PB_1, "EN_YCMEA_PB_1", EN_UNIT_W, EN_UNIT_W, EN_CPU0, EN_ANA_TYP_P, "Pb1", "B", 8, 3, CN_RGB_GREEN, 117, CN_COE_YCMEA_VOL * CN_COE_YCMEA_I1A, 866, 60000, 0xAAAA, CN_FLAG_TRUE, 0xAAAA, 0xAAAA, 0xAAAA, 0xFFFF, DB5}, // PB + {EN_YCMEA_PC_1, "EN_YCMEA_PC_1", EN_UNIT_W, EN_UNIT_W, EN_CPU0, EN_ANA_TYP_P, "Pc1", "C", 8, 3, CN_RGB_RED, 118, CN_COE_YCMEA_VOL * CN_COE_YCMEA_I1A, 866, 60000, 0xAAAA, CN_FLAG_TRUE, 0xAAAA, 0xAAAA, 0xAAAA, 0xFFFF, DB5}, // PC + {EN_YCMEA_P_1, "EN_YCMEA_P_1", EN_UNIT_W, EN_UNIT_W, EN_CPU0, EN_ANA_TYP_P, "P1", "0", 8, 3, CN_RGB_YELLOW, 119, CN_COE_YCMEA_VOL * CN_COE_YCMEA_I1A, 866, 180000, 0xAAAA, CN_FLAG_TRUE, 0xAAAA, 0xAAAA, 0xAAAA, 0xFFFF, 0 }, // P + {EN_YCMEA_Q_1, "EN_YCMEA_Q_1", EN_UNIT_VAR, EN_UNIT_VAR, EN_CPU0, EN_ANA_TYP_Q, "Q1", "0", 8, 3, CN_RGB_GREEN, 120, CN_COE_YCMEA_VOL * CN_COE_YCMEA_I1A, 866, 180000, 0xAAAA, CN_FLAG_TRUE, 0xAAAA, 0xAAAA, 0xAAAA, 0xFFFF, 0 }, // Q + {EN_YCMEA_S_1, "EN_YCMEA_S_1", EN_UNIT_VA, EN_UNIT_VA, EN_CPU0, EN_ANA_TYP_S, "S1", "0", 8, 3, CN_RGB_YELLOW, 121, CN_COE_YCMEA_VOL * CN_COE_YCMEA_I1A, 866, 180000, 0xAAAA, CN_FLAG_TRUE, 0xAAAA, 0xAAAA, 0xAAAA, 0xFFFF, 0 }, // S + {EN_YCMEA_COS_1, "EN_YCMEA_COS_1", EN_UNIT_NULL, EN_UNIT_NULL, EN_CPU0, EN_ANA_TYP_COS, "COS1", "0", 7, 3, CN_RGB_GREEN, 122, 1, 1, 1000, 0xAAAA, 0xAAAA, 0xAAAA, 0xAAAA, 0xAAAA, 0xFFFF, 0 }, // COS +}; + +uint16_t Get_RealData_Num(uint16_t wTabType) +{ + uint16_t wNum = 0; + + if (wTabType == EN_MEA_AC) + { + uint16_t wLoopMax = EN_YCMEA_ANA_END; + for(uint16_t index = 0; index < wLoopMax; index++) + { + if( (g_tYcIndexTab[index].dwCommAttr & DB3) == DB3 ) + { + wNum++; + } + } + } + else if (wTabType == EN_MEA_DC) + { + uint16_t wLoopMax = EN_YCMEA_DC_END; + for(uint16_t index = EN_YCMEA_DC_START; index < wLoopMax; index++) + { + if( (g_tYcIndexTab[index].dwCommAttr & DB3) == DB3 ) + { + wNum++; + } + } + } + return wNum; +} + +#define CN_NUM_OF_PAGE_ANADBG ( 9 ) //每页显示的交流量/遥信量等的个数 + +void Model_Init(model_t *model) +{ + if (model == NULL) + { + return; + } + + memset(model, 0, sizeof(*model)); + /* 默认顶栏标题,与菜单「实时数据」条目一致 */ + model->topName = GlobalModel_GetMenuActionName(); + model->wGroup = (Get_RealData_Num(GlobalModel_GetMenuActionAttrib()) + CN_NUM_OF_PAGE_ANADBG - 1) / CN_NUM_OF_PAGE_ANADBG; + model->wPage = 1; +} diff --git a/src/Drv/pages/YC/model.h b/src/Drv/pages/YC/model.h new file mode 100644 index 0000000..e393597 --- /dev/null +++ b/src/Drv/pages/YC/model.h @@ -0,0 +1,16 @@ +#ifndef YC_MODEL_H +#define YC_MODEL_H + +#include "types.h" + +typedef struct model_t model_t; + +typedef struct model_t { + const uint8_t *topName; + uint16_t wGroup; + uint16_t wPage; +} model_t; + +void Model_Init(model_t *model); + +#endif \ No newline at end of file diff --git a/src/Drv/pages/YC/page.c b/src/Drv/pages/YC/page.c new file mode 100644 index 0000000..c01cbc7 --- /dev/null +++ b/src/Drv/pages/YC/page.c @@ -0,0 +1,218 @@ +#include +#include + +#include "Drv/pages/YC/page.h" +#include "Drv/pages/YC/model.h" +#include "Drv/pages/YC/presenter.h" +#include "Drv/pages/YC/view.h" +#include "Drv/pages/global/renderer_lcd.h" + +/* ------------------------------------------------------------------------- + * 模块内静态对象说明: + * s_model - AppInfo页 Model 实例(AppInfo数据与运行时结构) + * s_view - AppInfo页 View 实例(布局与渲染能力) + * s_presenter - AppInfo页 Presenter 实例(输入处理与状态驱动) + * s_page - 页面管理器可注册的 page_t 描述对象 + * + * 说明: + * - 以上对象均为文件内静态单例,生命周期覆盖进程运行期。 + * - 通过 AppInfoPage_GetInstance() 暴露 s_page 给 PageManager 注册。 + * ------------------------------------------------------------------------- */ +static model_t s_model; +static view_t s_view; +static presenter_t s_presenter; +static page_t s_page; +static const PageRenderPort *s_port = NULL; +/* ------------------------------------------------------------------------- + * 函数名: AppInfoPage_OnExit + * 功能: + * 页面退出回调占位点;当前版本无额外退出动作。 + * + * 参数: + * page - 当前页面对象指针(本实现未直接使用) + * + * 边界处理: + * - 使用 (void)page 防止未使用参数告警。 + * + * 说明: + * - 预留给后续扩展(如停止定时任务、冻结动画、保存瞬时 UI 状态等)。 + * + * 返回值: + * - 无 + * ------------------------------------------------------------------------- */ +static void Page_OnExit(page_t *page) +{ + s_port->clear_screen(); + (void)page; +} + +/* ------------------------------------------------------------------------- + * 函数名: AppInfoPage_OnDestroy + * 功能: + * 页面销毁回调:清空菜单页内部三层对象(Model/View/Presenter)状态。 + * + * 参数: + * page - 当前页面对象指针(本实现未直接使用) + * + * 边界处理: + * - 使用 memset 全量清零静态对象,避免残留状态影响后续重建。 + * + * 说明: + * - 与 is_cached 策略配合:当页面被标记为非缓存并弹栈销毁时,该函数用于复位。 + * - page_t 元信息不在此函数复位,由页面生命周期创建阶段重新赋值。 + * + * 返回值: + * - 无 + * ------------------------------------------------------------------------- */ +static void Page_OnDestroy(page_t *page) +{ + (void)page; + memset(&s_model, 0, sizeof(s_model)); + memset(&s_view, 0, sizeof(s_view)); + memset(&s_presenter, 0, sizeof(s_presenter)); +} + +/* ------------------------------------------------------------------------- + * 函数名: AppInfoPage_OnEvent + * 功能: + * 页面事件回调:校验输入事件后,将按键转交 Presenter 处理。 + * + * 参数: + * page - 当前页面对象指针(本实现未直接使用) + * event - 输入事件指针 + * + * 边界处理: + * - event 为 NULL 时返回 EVENT_UNHANDLED。 + * - 仅处理 PAGE_EVENT_KEY 事件类型,其它类型返回 EVENT_UNHANDLED。 + * - keyVal 为 0 视为无效按键,返回 EVENT_UNHANDLED。 + * + * 说明: + * - 事件有效时调用 Presenter 对外输入接口执行业务流转。 + * - 返回 EVENT_HANDLED,表示该事件已被菜单页消费,不再交给上层页面逻辑。 + * + * 返回值: + * - EVENT_HANDLED : 事件已处理 + * - EVENT_UNHANDLED : 事件无效或不属于本页处理范围 + * ------------------------------------------------------------------------- */ +static event_result_t Page_OnEvent(page_t *page, input_event_t *event) +{ + (void)page; + if ((event == NULL) || (event->type != PAGE_EVENT_KEY) || (event->keyVal == 0)) + { + return EVENT_UNHANDLED; + } + + s_presenter.handle_input(&s_presenter, event->keyVal); + return EVENT_HANDLED; +} + +/* ------------------------------------------------------------------------- + * 函数名: AppInfoPage_OnLoop + * 功能: + * 页面循环回调:周期性驱动 Presenter 执行刷新逻辑。 + * + * 参数: + * page - 当前页面对象指针(本实现未直接使用) + * + * 边界处理: + * - 使用 (void)page 防止未使用参数告警。 + * + * 说明: + * - 实际刷新策略(全量/增量)由 Presenter 内部状态控制。 + * - 该函数通常由 PageManager_Loop() 在主循环节拍中调用。 + * + * 返回值: + * - 无 + * ------------------------------------------------------------------------- */ +static void Page_OnLoop(page_t *page) +{ + (void)page; + s_presenter.refresh(&s_presenter); +} + +/* ------------------------------------------------------------------------- + * 函数名: AppInfoPage_OnCreate + * 功能: + * 页面创建回调:按 Model -> View -> Presenter 顺序完成菜单页运行时装配, + * 并初始化 page_t 描述对象字段。 + * + * 参数: + * page - 当前页面对象指针(由 PageManager 传入) + * + * 边界处理: + * - 先清零 s_menuPage,再统一重建其元信息与回调绑定,避免脏状态遗留。 + * - 假定 page 非空且来自 PageManager 生命周期调用链。 + * + * 说明: + * - 初始化顺序固定: + * 1) MenuModel_Init(&s_model) + * 2) MenuView_Init(&s_view) + * 3) MenuPresenter_Init(&s_presenter, &s_model, &s_view) + * - 将 model/presenter/view 回填到 page 与 s_menuPage,便于调试与统一访问。 + * - s_menuPage 作为静态页面实例,对外由 MenuPage_GetInstance() 返回。 + * + * 返回值: + * - 无 + * ------------------------------------------------------------------------- */ +static void Page_OnCreate(page_t *page) +{ + /* 1) model init */ + Model_Init(&s_model); + + /* 2) view init */ + View_Init(&s_view); + + /* 3) presenter setup + runtime build */ + Presenter_Init(&s_presenter, &s_model, &s_view); + + + page->model = &s_model; + page->presenter = &s_presenter; + page->view = &s_view; + + s_page.presenter = &s_presenter; + s_page.view = &s_view; + s_page.model = &s_model; + s_port = PageRenderer_Lcd(); +} + +/* ------------------------------------------------------------------------- + * 函数名: YCPage_OnEnter + * 功能: + * 页面进入回调:将菜单渲染标记为“首帧全量刷新”,并立即触发一次刷新。 + * + * 参数: + * page - 当前页面对象指针(本实现未直接使用) + * + * 边界处理: + * - 本函数不依赖 page 内容,统一转为 (void)page 消除未使用告警。 + * + * 说明: + * - 通过 refresh(..., 1) 告知 Presenter 下一次刷新走首帧路径。 + * - 进入页面后立即刷新,确保界面可见状态与内部状态同步。 + * + * 返回值: + * - 无 + * ------------------------------------------------------------------------- */ + static void Page_OnEnter(page_t *page) + { + (void)page; + /* 首帧全量刷新 */ + LOG("YCPage_OnEnter\n"); + s_presenter.refresh(&s_presenter); + } + +page_t *YCPage_GetInstance(void) +{ + /* 确保在注册到 PageManager 前,页面生命周期回调已就绪 */ + memset(&s_page, 0, sizeof(s_page)); + s_page.page_id = PAGE_ID_YC; + s_page.is_cached = 1; + s_page.on_create = Page_OnCreate; + s_page.on_enter = Page_OnEnter; + s_page.on_exit = Page_OnExit; + s_page.on_destroy = Page_OnDestroy; + s_page.on_event = Page_OnEvent; + s_page.on_loop = Page_OnLoop; + return &s_page; +} diff --git a/src/Drv/pages/YC/page.h b/src/Drv/pages/YC/page.h new file mode 100644 index 0000000..fe915b1 --- /dev/null +++ b/src/Drv/pages/YC/page.h @@ -0,0 +1,8 @@ +#ifndef YC_PAGE_H +#define YC_PAGE_H + +#include "Drv/pages/page.h" + +page_t *YCPage_GetInstance(void); + +#endif \ No newline at end of file diff --git a/src/Drv/pages/YC/presenter.c b/src/Drv/pages/YC/presenter.c new file mode 100644 index 0000000..da58f8d --- /dev/null +++ b/src/Drv/pages/YC/presenter.c @@ -0,0 +1,91 @@ +#include "Drv/pages/YC/presenter.h" +#include "Drv/pages/page_manager.h" +#include "Drv/key.h" +#include + +static void Presenter_HandleInput(presenter_t *presenter, uint8_t keyVal) +{ + switch (keyVal) + { + case KEY_ESC: + (void)PageManager_Pop(); + break; + default: break; + } +} + +/* ------------------------------------------------------------------------- + * 函数名:MenuPresenter_Refresh + * 功能: + * Presenter 层的对外刷新接口,根据是否为首帧渲染选择不同的刷新策略。 + * 本函数作为 menu_presenter_t::refresh 回调被调用,负责协调 View 层完成界面更新。 + * + * 参数: + * presenter - 菜单 Presenter 实例指针,内部持有 menuCtrl 上下文和 view 接口引用 + * isFirstFrame - 是否为首帧标志: + * 1 - 首帧渲染:需要完整初始化并刷新整个菜单界面 + * 0 - 非首帧渲染:根据当前状态差异进行增量或局部刷新 + * + * 刷新策略: + * 首帧模式 (isFirstFrame == 1): + * - 调用 View 层的 full_refresh() 接口,完整重绘整个菜单界面。 + * - 此时 menuCtrl 中的导航路径、选中项等状态已完成初始化,可安全进行全量渲染。 + * - MODE_NONE 表示不进行特殊模式过滤(如调试模式、特定层级过滤等)。 + * + * 非首帧模式 (isFirstFrame == 0): + * - 调用 MenuPresenter_RenderByState() 进行智能状态对比刷新: + * 1) 比较 pt0Level 与 ptRoute[0],判断顶层上下文是否切换 + * 2) 比较 ptCurBak 与 ptCurrent,判断选中项是否变化 + * 3) 根据层级关系和父节点关联选择最优渲染策略: + * - 同层同父:局部反显更新(旧选中恢复 + 新选中高亮) + * - 新层级 >= 旧层级:补绘受影响层级 + * - 回退到更高层:整页刷新保证一致性 + * - 此策略可避免不必要的重绘,提升界面响应性能。 + * + * 调用关系: + * - 被 MenuPresenter_HandleInput() 在导航状态变化后调用(isFirstFrame = 0) + * - 被外部初始化完成后首次调用(isFirstFrame = 1) + * - 通过 presenter->refresh 函数指针绑定,符合 Presenter 的接口抽象。 + * + * 边界处理: + * - 本函数假设 presenter 指针有效,不做空指针校验(由调用方保证)。 + * - view 接口的 full_refresh() 和内部渲染逻辑负责具体的绘制安全校验。 + * ------------------------------------------------------------------------- */ + static void Presenter_Refresh(presenter_t *presenter) + { + presenter->view->show_top_name(presenter->model->topName); + presenter->view->show_info_page(presenter->model->wPage, presenter->model->wGroup); + } +/* ------------------------------------------------------------------------- + * 函数名: MenuPresenter_Init + * 功能: + * 初始化菜单 Presenter 实例,完成依赖绑定、对外接口挂接以及初始导航状态装配。 + * + * 参数: + * presenter - 待初始化的 Presenter 实例 + * model - 菜单 Model 实例,提供菜单树与运行时数据 + * view - 菜单 View 实例,提供刷新与绘制能力 + * + * 边界处理: + * - 若 `presenter`、`model` 或 `view` 任一为空,则直接返回。 + * + * 说明: + + * + * 返回值: + * - 无 + * ------------------------------------------------------------------------- */ + void Presenter_Init(presenter_t *presenter, model_t *model, view_t *view) + { + ASSERT((presenter == NULL) || (model == NULL) || (view == NULL)); + if ((presenter == NULL) || (model == NULL) || (view == NULL)) + { + return; + } + + memset(presenter, 0, sizeof(*presenter)); + presenter->model = model; + presenter->view = view; + presenter->handle_input = Presenter_HandleInput; + presenter->refresh = Presenter_Refresh; + } \ No newline at end of file diff --git a/src/Drv/pages/YC/presenter.h b/src/Drv/pages/YC/presenter.h new file mode 100644 index 0000000..aa05ac0 --- /dev/null +++ b/src/Drv/pages/YC/presenter.h @@ -0,0 +1,17 @@ +#ifndef YC_PRESENTER_H +#define YC_PRESENTER_H + +#include "Drv/pages/YC/model.h" +#include "Drv/pages/YC/view.h" + +typedef struct presenter_t presenter_t; + +typedef struct presenter_t { + model_t *model; + view_t *view; + void (*handle_input)(presenter_t *presenter, uint8_t keyVal); + void (*refresh)(presenter_t *presenter); +} presenter_t; + +void Presenter_Init(presenter_t *presenter, model_t *model, view_t *view); +#endif \ No newline at end of file diff --git a/src/Drv/pages/YC/view.c b/src/Drv/pages/YC/view.c new file mode 100644 index 0000000..80d6b9a --- /dev/null +++ b/src/Drv/pages/YC/view.c @@ -0,0 +1,45 @@ +#include "Drv/pages/YC/view.h" +#include + + + +static const PageRenderPort *s_port = NULL; + + +static void YCView_ShowInfoPage(uint16_t wPageNum, uint16_t wPageMax) +{ + s_port->show_info_page(wPageNum, wPageMax); +} + +static void YCView_ShowTerminalInfo(void) +{ + uint8_t *context[] = { + "终端类型 : F30", + "终端型号 : F30", + "软件版本 : SV0.010", + "硬件版本 : HW0.010", + "软件校验 : 4454", + "程序日期 : 2024.08.27" + }; + s_port->show_str(32, 26, "馈线自动化终端"); + for(uint8_t index = 0; index < 6; index++ ) + { + s_port->show_str(6, 26 + (index + 1) * (s_port->get_ascii_height() + s_port->get_row_space()), context[index]); + } +} + +static void YCView_ShowTopName(const uint8_t *name) +{ + uint16_t wLen = s_port->get_utf8_len(name) * s_port->get_ascii_width(); + s_port->fill_rect(0, 0, s_port->get_size_x() - 1, s_port->get_size_y() - 1, s_port->get_color_back()); + /* 显示顶部名称,居中显示 */ + s_port->show_str((s_port->get_size_x() - wLen) / 2, 3, name); + s_port->draw_meitou(18, 2); +} + +void View_Init(view_t *view) +{ + s_port = PageRenderer_Lcd(); + view->show_top_name = YCView_ShowTopName; + view->show_info_page = YCView_ShowInfoPage; +} \ No newline at end of file diff --git a/src/Drv/pages/YC/view.h b/src/Drv/pages/YC/view.h new file mode 100644 index 0000000..c173789 --- /dev/null +++ b/src/Drv/pages/YC/view.h @@ -0,0 +1,14 @@ +#ifndef YC_VIEW_H +#define YC_VIEW_H + +#include "types.h" +#include "Drv/pages/global/renderer_lcd.h" + +typedef struct view_t { + void (*show_top_name)(const uint8_t *name); + void (*show_info_page)(uint16_t wPageNum, uint16_t wPageMax); +} view_t; + +void View_Init(view_t *view); + +#endif \ No newline at end of file diff --git a/src/Drv/pages/global/global_state.c b/src/Drv/pages/global/global_state.c index b0c494b..56aa337 100644 --- a/src/Drv/pages/global/global_state.c +++ b/src/Drv/pages/global/global_state.c @@ -4,6 +4,31 @@ static GlobalModel s_globalModel; +/* ------------------------------------------------------------------------- + * 函数名:GlobalModel_CopyText + * 功能: + * 安全地将源字符串拷贝到目标缓冲区,确保不会发生缓冲区溢出。 + * + * 参数: + * dst - 目标缓冲区指针(输出),用于存放拷贝的字符串 + * dstSize - 目标缓冲区的大小(字节) + * src - 源字符串指针(输入),需要被拷贝的字符串 + * + * 边界处理: + * - 若 dst 为 NULL 或 dstSize 为 0,函数直接返回,不做任何操作。 + * - 若 src 为 NULL,则将目标缓冲区置为空字符串 (dst[0] = '\0')。 + * - 拷贝时最多保留 dstSize-1 个字符,确保最后一个字节用于存放字符串结束符 '\0'。 + * - 若在拷贝过程中遇到源字符串的结束符 '\0',则提前终止拷贝。 + * + * 说明: + * - 本函数是一个安全的字符串拷贝工具,专门用于全局模型中菜单名称和提示文本的拷贝。 + * - 通过限制拷贝长度为 dstSize-1 并强制在末尾添加 '\0',确保目标缓冲区永远不会越界。 + * - 当源字符串长度大于等于目标缓冲区大小时,会截断源字符串,但保证结果仍是有效的 C 字符串。 + * - 该函数为静态函数,仅在当前文件内部使用。 + * + * 返回值: + * - 无 + * ------------------------------------------------------------------------- */ static void GlobalModel_CopyText(uint8_t *dst, uint16_t dstSize, const uint8_t *src) { uint16_t i; @@ -29,32 +54,141 @@ static void GlobalModel_CopyText(uint8_t *dst, uint16_t dstSize, const uint8_t * dst[dstSize - 1] = '\0'; } +/* ------------------------------------------------------------------------- + * 函数名:GlobalModel_Init + * 功能: + * 初始化全局模型实例,将所有成员变量设置为零值。 + * + * 参数: + * 无 + * + * 边界处理: + * - 本函数不处理任何异常情况,直接对静态全局变量进行清零操作。 + * + * 说明: + * - 本函数用于在系统启动或需要重置全局状态时调用。 + * - 通过 memset 将 s_globalModel 的所有字节设置为 0,包括: + * 1) activeYcType(当前遥测类型) + * 2) activeMenuPara(当前菜单参数) + * 3) activeActionId(当前菜单动作 ID) + * 4) activeMenuName(当前菜单名称数组) + * 5) activeMenuTip(当前菜单提示文本数组) + * - 初始化后,全局模型处于空状态,需要调用其他设置函数来配置有效值。 + * + * 返回值: + * - 无 + * ------------------------------------------------------------------------- */ void GlobalModel_Init(void) { memset(&s_globalModel, 0, sizeof(s_globalModel)); } +/* ------------------------------------------------------------------------- + * 函数名:GlobalModel_Instance + * 功能: + * 获取全局模型单例实例的指针,用于访问和修改全局状态数据。 + * + * 参数: + * 无 + * + * 边界处理: + * - 本函数不做任何校验,始终返回静态变量 s_globalModel 的地址。 + * - 调用方应确保在调用此函数前已先调用 GlobalModel_Init() 进行初始化。 + * + * 说明: + * - 本函数采用单例模式,提供对全局模型实例的访问接口。 + * - 返回的是静态变量 s_globalModel 的指针,该变量在整个程序生命周期内只有一份副本。 + * - 调用方可以通过返回的指针直接访问和修改全局状态成员,如 activeYcType、activeActionId 等。 + * - 由于返回的是原始指针,调用方在操作时应注意线程安全和数据一致性。 + * + * 返回值: + * - 指向 GlobalModel 结构体的指针 + * ------------------------------------------------------------------------- */ GlobalModel *GlobalModel_Instance(void) { return &s_globalModel; } +/* ------------------------------------------------------------------------- + * 函数名:GlobalModel_SetActiveYcType + * 功能: + * 设置当前活跃的遥测类型,用于标识系统正在处理哪种类型的遥测量。 + * + * 参数: + * ycType - 遥测类型值,通常为枚举类型或预定义的类型常量 + * + * 边界处理: + * - 本函数不做参数合法性校验,调用方应保证 ycType 为有效值。 + * + * 说明: + * - 该函数用于设置全局模型中的 activeYcType 字段。 + * - 遥测类型用于区分不同类型的交流量(如电压、电流、功率等)。 + * - 设置后,系统其他模块可通过 GetActiveYcType() 查询当前类型。 + * + * 返回值: + * - 无 + * ------------------------------------------------------------------------- */ void GlobalModel_SetActiveYcType(uint16_t ycType) { s_globalModel.activeYcType = ycType; } +/* ------------------------------------------------------------------------- + * 函数名:GlobalModel_GetActiveYcType + * 功能: + * 获取当前活跃的遥测类型。 + * + * 参数: + * 无 + * + * 边界处理: + * - 本函数不做任何校验,直接返回静态变量的值。 + * - 若系统未初始化或类型未被设置,可能返回 0(默认值)。 + * + * 说明: + * - 该函数用于查询全局模型中的 activeYcType 字段。 + * - 返回值表示当前系统正在处理或最后设置的遥测类型。 + * - 调用方应根据返回的值进行相应的数据处理或界面显示逻辑。 + * + * 返回值: + * - 当前活跃的遥测类型值 + * ------------------------------------------------------------------------- */ uint16_t GlobalModel_GetActiveYcType(void) { return s_globalModel.activeYcType; } -void GlobalModel_SetMenuAction(uint16_t actionId, +/* ------------------------------------------------------------------------- + * 函数名:GlobalModel_SetMenuAction + * 功能: + * 设置当前菜单的动作信息,包括动作 ID、名称、提示文本和参数。 + * + * 参数: + * actionId - 菜单动作 ID,用于标识具体的菜单操作(如查看、设置等) + * menuName - 菜单名称字符串,显示在界面上的菜单标题 + * menuTip - 菜单提示文本字符串,用于显示辅助说明信息 + * menuPara - 菜单参数,传递与当前菜单相关的额外数据 + * + * 边界处理: + * - 若 menuName 或 menuTip 为 NULL,对应缓冲区将被置为空字符串。 + * - 名称和提示文本的长度会被限制在各自缓冲区大小内(50 字节),超长部分会被截断。 + * - 本函数不做输入参数的合法性校验,调用方应保证 actionId/menuPara 为有效值。 + * + * 说明: + * - 该函数用于更新全局模型中的菜单动作相关信息。 + * - 通过 GlobalModel_CopyText() 进行安全拷贝,确保不会发生缓冲区溢出。 + * - 设置后,系统其他模块可通过对应的 Get 系列函数查询当前菜单状态。 + * - 此函数通常在进入新菜单或切换菜单时调用,用于更新全局上下文信息。 + * + * 返回值: + * - 无 + * ------------------------------------------------------------------------- */ +void GlobalModel_SetMenuAction(uint16_t activeAttrib, const uint8_t *menuName, const uint8_t *menuTip, uint16_t menuPara) { - s_globalModel.activeActionId = actionId; + s_globalModel.activeAttrib = activeAttrib; s_globalModel.activeMenuPara = menuPara; GlobalModel_CopyText(s_globalModel.activeMenuName, (uint16_t)sizeof(s_globalModel.activeMenuName), @@ -64,22 +198,124 @@ void GlobalModel_SetMenuAction(uint16_t actionId, menuTip); } +/* ------------------------------------------------------------------------- + * 函数名:GlobalModel_GetMenuActionId + * 功能: + * 获取当前菜单的动作 ID。 + * + * 参数: + * 无 + * + * 边界处理: + * - 本函数不做任何校验,直接返回静态变量的值。 + * - 若未调用 SetMenuAction() 设置,将返回默认值 0。 + * + * 说明: + * - 该函数用于查询全局模型中的 activeActionId 字段。 + * - 返回值表示当前菜单对应的动作类型,可用于判断用户当前所处的菜单位置。 + * + * 返回值: + * - 当前菜单的动作 ID(menu_action_id_t 枚举值) + * ------------------------------------------------------------------------- */ uint16_t GlobalModel_GetMenuActionId(void) { return s_globalModel.activeActionId; } +/* ------------------------------------------------------------------------- + * 函数名:GlobalModel_GetMenuActionPara + * 功能: + * 获取当前菜单的参数值。 + * + * 参数: + * 无 + * + * 边界处理: + * - 本函数不做任何校验,直接返回静态变量的值。 + * - 若未调用 SetMenuAction() 设置,将返回默认值 0。 + * + * 说明: + * - 该函数用于查询全局模型中的 activeMenuPara 字段。 + * - 返回值是与当前菜单相关的额外参数数据,具体含义取决于菜单类型。 + * + * 返回值: + * - 当前菜单的参数值 + * ------------------------------------------------------------------------- */ uint16_t GlobalModel_GetMenuActionPara(void) { return s_globalModel.activeMenuPara; } +/* ------------------------------------------------------------------------- + * 函数名:GlobalModel_GetMenuActionName + * 功能: + * 获取当前菜单的名称字符串。 + * + * 参数: + * 无 + * + * 边界处理: + * - 本函数返回静态缓冲区的指针,调用方不应修改返回的字符串内容。 + * - 若未调用 SetMenuAction() 设置,将返回空字符串指针(内容为 "\0")。 + * + * 说明: + * - 该函数用于查询全局模型中的 activeMenuName 缓冲区。 + * - 返回的是 const 指针,表明调用方只能读取不能修改该字符串。 + * - 字符串长度最多为 49 个字符(预留 1 字节给结束符 '\0')。 + * + * 返回值: + * - 指向当前菜单名称字符串的常量指针 + * ------------------------------------------------------------------------- */ const uint8_t *GlobalModel_GetMenuActionName(void) { return s_globalModel.activeMenuName; } +/* ------------------------------------------------------------------------- + * 函数名:GlobalModel_GetMenuActionTip + * 功能: + * 获取当前菜单的提示文本字符串。 + * + * 参数: + * 无 + * + * 边界处理: + * - 本函数返回静态缓冲区的指针,调用方不应修改返回的字符串内容。 + * - 若未调用 SetMenuAction() 设置,将返回空字符串指针(内容为 "\0")。 + * + * 说明: + * - 该函数用于查询全局模型中的 activeMenuTip 缓冲区。 + * - 返回的是 const 指针,表明调用方只能读取不能修改该字符串。 + * - 字符串长度最多为 49 个字符(预留 1 字节给结束符 '\0')。 + * + * 返回值: + * - 指向当前菜单提示文本字符串的常量指针 + * ------------------------------------------------------------------------- */ const uint8_t *GlobalModel_GetMenuActionTip(void) { return s_globalModel.activeMenuTip; } + +/* ------------------------------------------------------------------------- + * 函数名:GlobalModel_GetMenuActionAttrib + * 功能: + * 获取当前菜单的动作属性。 + * + * 参数: + * 无 + * + * 边界处理: + * - 本函数不做任何校验,直接返回静态变量的值。 + * - 若未调用 SetMenuAction() 设置,将返回默认值 0。 + * + * 说明: + * - 该函数用于查询全局模型中的 activeAttrib 字段。 + * - 返回值是与当前菜单相关的额外参数数据,具体含义取决于菜单类型。 + * + * 返回值: + * - 当前菜单的动作属性 + * ------------------------------------------------------------------------- */ + uint16_t GlobalModel_GetMenuActionAttrib(void) + { + return s_globalModel.activeAttrib; + } diff --git a/src/Drv/pages/global/global_state.h b/src/Drv/pages/global/global_state.h index 35d7860..77aa1fa 100644 --- a/src/Drv/pages/global/global_state.h +++ b/src/Drv/pages/global/global_state.h @@ -46,11 +46,14 @@ typedef enum MENU_ACTION_YC_SET_ADJ_COE } menu_action_id_t; + + typedef struct { uint16_t activeYcType; uint16_t activeMenuPara; uint16_t activeActionId; + uint16_t activeAttrib; uint8_t activeMenuName[50]; uint8_t activeMenuTip[50]; } GlobalModel; @@ -59,7 +62,7 @@ void GlobalModel_Init(void); GlobalModel *GlobalModel_Instance(void); void GlobalModel_SetActiveYcType(uint16_t ycType); uint16_t GlobalModel_GetActiveYcType(void); -void GlobalModel_SetMenuAction(uint16_t actionId, +void GlobalModel_SetMenuAction(uint16_t activeAttrib, const uint8_t *menuName, const uint8_t *menuTip, uint16_t menuPara); @@ -67,5 +70,6 @@ uint16_t GlobalModel_GetMenuActionId(void); uint16_t GlobalModel_GetMenuActionPara(void); const uint8_t *GlobalModel_GetMenuActionName(void); const uint8_t *GlobalModel_GetMenuActionTip(void); +uint16_t GlobalModel_GetMenuActionAttrib(void); #endif diff --git a/src/Drv/pages/global/renderer_lcd.c b/src/Drv/pages/global/renderer_lcd.c index 609bd97..769c36f 100644 --- a/src/Drv/pages/global/renderer_lcd.c +++ b/src/Drv/pages/global/renderer_lcd.c @@ -4,6 +4,13 @@ #include "lcd_draw.h" #include "lcd_text.h" +/* MSVC 对含多字节/中文格式串的静态分析可能误报 C4474/C4996。 + * 本文件内的格式化输出均为受控 buffer,并用于显示文本渲染。 */ + #if defined(_MSC_VER) + #pragma warning(disable : 4474) + #pragma warning(disable : 4996) + #endif + static uint16_t PageRenderer_LcdSizeX(void) { return LCD_SIZE_X; @@ -53,7 +60,7 @@ static uint16_t PageRenderer_LcdGetASCIIHeight(void) * 返回值: * - UTF-8 字符串的显示宽度 * ------------------------------------------------------------------------- */ - static uint16_t PageRenderer_LcdGetUtf8Len(uint8_t *str) + static uint16_t PageRenderer_LcdGetUtf8Len(const uint8_t *str) { uint16_t strLen = 0; uint32_t unicode; @@ -76,6 +83,55 @@ static void PageRenderer_ClearScreen(void) { Lcd_FillRect(0, 0, LCD_SIZE_X - 1, LCD_SIZE_Y - 1, LCD_BACK); } +/* ------------------------------------------------------------------------- +* 函数名: PageRenderer_LcdDrawMeitou +* 功能: +* 绘制菜单标题装饰线(“眉头”样式):中间横线 + 左右两端斜线。 +* +* 参数: +* yStart - 装饰线基准 Y 坐标(横线所在行) +* width - 线宽参数(传递给 line_h/line) +* +* 边界处理: +* - 坐标范围合法性由上层布局计算保证。 +* +* 说明: +* - 颜色统一使用字体前景色(PageRenderer_LcdColorFont),确保装饰与文字风格一致。 +* - 绘制顺序: +* 1) 中间横线(x:16~144) +* 2) 左斜线(8, yStart-8 -> 16, yStart) +* 3) 右斜线(144, yStart -> 152, yStart-8) +* - 该函数用于视觉分隔与层次强调,不改变菜单状态数据。 +* +* 返回值: +* - 无 +* ------------------------------------------------------------------------- */ +static void PageRenderer_LcdDrawMeitou(uint16_t yStart, uint16_t width) +{ + uint8_t fontColor = PageRenderer_LcdColorFont(); + Lcd_LineH(16, 144, yStart, width, fontColor); + Lcd_Line(8, yStart - 8, 16, yStart, width, fontColor); + Lcd_Line(144, yStart, 152, yStart - 8, width, fontColor); +} + +void PageRenderer_LcdShowInfoPage(uint16_t wPageNum, uint16_t wPageMax ) +{ + /* show_str 期望的是 '\0' 结尾的 UTF-8 字符串 */ + uint8_t pbyTips[64]; + uint16_t y = LCD_SIZE_Y - 16; + + /* 格式化字符串(用于 LCD 文本显示) */ +#if defined(_MSC_VER) + (void)sprintf_s((char *)pbyTips, sizeof(pbyTips), "第%4u 页 , 共%4u 页", + (unsigned)wPageNum, (unsigned)wPageMax); +#else + (void)snprintf((char *)pbyTips, sizeof(pbyTips), "第%4u 页 , 共%4u 页", + (unsigned)wPageNum, (unsigned)wPageMax); +#endif + + Lcd_ShowStr(6, y, pbyTips); +} + static const PageRenderPort g_lcd_port = { .get_size_x = PageRenderer_LcdSizeX, .get_size_y = PageRenderer_LcdSizeY, @@ -93,6 +149,8 @@ static const PageRenderPort g_lcd_port = { .invert = Lcd_Invert, .show_str = Lcd_ShowStr, .clear_screen = PageRenderer_ClearScreen, + .draw_meitou = PageRenderer_LcdDrawMeitou, + .show_info_page = PageRenderer_LcdShowInfoPage, }; const PageRenderPort *PageRenderer_Lcd(void) diff --git a/src/Drv/pages/global/renderer_lcd.h b/src/Drv/pages/global/renderer_lcd.h index 703b184..16757c7 100644 --- a/src/Drv/pages/global/renderer_lcd.h +++ b/src/Drv/pages/global/renderer_lcd.h @@ -11,7 +11,7 @@ typedef struct uint8_t (*get_color_back)(void); uint16_t (*get_ascii_width)(void); uint16_t (*get_ascii_height)(void); - uint16_t (*get_utf8_len)(uint8_t *str); + uint16_t (*get_utf8_len)(const uint8_t *str); uint16_t (*get_row_space)(void); int8_t (*fill_rect)(uint16_t left_x, uint16_t top_y, uint16_t right_x, uint16_t bottom_y, uint8_t color); int8_t (*line_h)(uint16_t x_start, uint16_t x_end, uint16_t y, uint16_t width, uint8_t color); @@ -19,8 +19,10 @@ typedef struct int8_t (*line)(uint16_t x_start, uint16_t y_start, uint16_t x_end, uint16_t y_end, uint16_t width, uint8_t color); int8_t (*set_pixel)(uint16_t x, uint16_t y, uint8_t color); int8_t (*invert)(uint16_t left_x, uint16_t top_y, uint16_t right_x, uint16_t bottom_y); - int8_t (*show_str)(uint16_t x, uint16_t y, uint8_t *text); - int8_t (*clear_screen)(void); + int8_t (*show_str)(uint16_t x, uint16_t y, const uint8_t *text); + void (*clear_screen)(void); + void (*draw_meitou)(uint16_t yStart, uint16_t width); + void (*show_info_page)(uint16_t wPageNum, uint16_t wPageMax); } PageRenderPort; const PageRenderPort *PageRenderer_Lcd(void); diff --git a/src/Drv/pages/menu/display.h b/src/Drv/pages/menu/display.h index 06b8440..425ffe4 100644 --- a/src/Drv/pages/menu/display.h +++ b/src/Drv/pages/menu/display.h @@ -42,38 +42,7 @@ enum _SOFT_TYPE_NUMBER EN_SOFT_TYPE_END }; -enum _MEA_TYPE_ -{ - EN_MEA_RLY, - EN_MEA_RLY2, - EN_MEA_RLY3, - EN_MEA_ANA, - EN_MEA_ANA2, - EN_MEA_ANA3, - EN_MEA_AC, - EN_MEA_DC, - EN_MEA_SYN, - EN_MEA_POWER, - EN_MEA_DD, - EN_MEA_JLYC, - EN_MEA_GEAR, - EN_MEA_TQ, - EN_MEA_INPUT1, - EN_MEA_INPUT2, - EN_MEA_INPUT3, - EN_INPUT_RLY_ALL, - EN_INPUT_RLY_FAULT, - EN_INPUT_RLY_OTHER, - EN_INPUT_BS_ALL, - EN_INPUT_BS_FAULT, - EN_INPUT_BS_OTHER, - EN_MEA_ADJ, - EN_MEA_YX, - EN_OUTPUT_TRIP, - EN_OUTPUT_SIGN, - EN_MEA_LS, - EN_MEA_SCRLY -}; + enum _INDEX_VALUE_TYPE_ { diff --git a/src/Drv/pages/menu/presenter.c b/src/Drv/pages/menu/presenter.c index b5c602e..318eeb2 100644 --- a/src/Drv/pages/menu/presenter.c +++ b/src/Drv/pages/menu/presenter.c @@ -2,7 +2,7 @@ #include #include - +#include "../global/global_state.h" #include "../../key.h" /* ------------------------------------------------------------------------- @@ -163,6 +163,7 @@ static MenuNavResult MenuNavigator_ProcessKey(tagMenuCtrl *menuCtrl, uint8_t key } else if (ptCurrent->menuDef.pfnWinProc != NULL) { + GlobalModel_SetMenuAction(ptCurrent->menuDef.byAttrib, ptCurrent->menuDef.byName, ptCurrent->menuDef.byTip, ptCurrent->menuDef.wPara); /* 无子菜单但有回调函数:执行窗口回调(如打开弹窗) */ ptCurrent->menuDef.pfnWinProc(); } diff --git a/src/Drv/pages/menu/view.c b/src/Drv/pages/menu/view.c index b107ee7..e49d953 100644 --- a/src/Drv/pages/menu/view.c +++ b/src/Drv/pages/menu/view.c @@ -4,39 +4,6 @@ static const PageRenderPort *s_port = NULL; -/* ------------------------------------------------------------------------- - * 函数名: MenuView_DrawMeitou - * 功能: - * 绘制菜单标题装饰线(“眉头”样式):中间横线 + 左右两端斜线。 - * - * 参数: - * view - 菜单视图对象,提供底层渲染端口 - * yStart - 装饰线基准 Y 坐标(横线所在行) - * width - 线宽参数(传递给 line_h/line) - * - * 边界处理: - * - 本函数不做空指针判定,调用方需保证 view 与 s_port 有效。 - * - 坐标范围合法性由上层布局计算保证。 - * - * 说明: - * - 颜色统一使用字体前景色(get_color_font),确保装饰与文字风格一致。 - * - 绘制顺序: - * 1) 中间横线(x:16~144) - * 2) 左斜线(8, yStart-8 -> 16, yStart) - * 3) 右斜线(144, yStart -> 152, yStart-8) - * - 该函数用于视觉分隔与层次强调,不改变菜单状态数据。 - * - * 返回值: - * - 无 - * ------------------------------------------------------------------------- */ -static void MenuView_DrawMeitou(MenuView *view, uint16_t yStart, uint16_t width) -{ - uint8_t fontColor = s_port->get_color_font(); - s_port->line_h(16, 144, yStart, width, fontColor); - s_port->line(8, yStart - 8, 16, yStart, width, fontColor); - s_port->line(144, yStart, 152, yStart - 8, width, fontColor); -} - /* ------------------------------------------------------------------------- * 函数名: MenuView_DrawBoundaryBox * 功能: @@ -155,7 +122,7 @@ static void MenuView_DrawBoundaryBox(MenuView *view, uint16_t leftX, uint16_t to * * 说明: * - 先清空顶部区域(y: 0~32),避免旧文案残留。 - * - 再调用 MenuView_DrawMeitou() 绘制标题装饰线,保持页面视觉一致性。 + * - 再调用 s_port->draw_meitou(16, 2) 绘制标题装饰线,保持页面视觉一致性。 * - 模式文案映射: * MODE_OVERFLOW_PROTECTION -> "当前模式: 过流保护" * MODE_LOCAL_FEEDER_SEGMENT -> "就地馈线: 分段模式" @@ -170,7 +137,7 @@ static void MenuView_ShowTopLevel(MenuView *view, MenuMode mode) { uint16_t lcdSizeX = s_port->get_size_x(); s_port->fill_rect(0, 0, lcdSizeX - 1, 32, s_port->get_color_back()); - MenuView_DrawMeitou(view, 16, 2); + s_port->draw_meitou(16, 2); /* 在 0 级菜单标题栏下方显示当前运行模式提示文字 */ if (mode == MODE_OVERFLOW_PROTECTION) { diff --git a/src/Drv/pages/page.h b/src/Drv/pages/page.h index 4759e0d..1ef5fda 100644 --- a/src/Drv/pages/page.h +++ b/src/Drv/pages/page.h @@ -11,6 +11,7 @@ * PAGE_ID_NONE - 无效页面 ID / 未初始化占位值 * PAGE_ID_MENU - 菜单页 ID(当前主运行页) * PAGE_ID_APP_INFO - 装置信息页 ID(在 main 中与菜单页一并注册) + * PAGE_ID_YC - 遥测页 ID * PAGE_ID_MAX - 上界哨兵,不可作为有效页面 ID 使用 * * 使用约束: @@ -22,6 +23,7 @@ typedef enum PAGE_ID_NONE = 0, PAGE_ID_MENU = 1, PAGE_ID_APP_INFO = 2, /* 装置信息页:AppInfoPage_GetInstance */ + PAGE_ID_YC = 3, /* 遥测页:YCPage_GetInstance */ PAGE_ID_MAX } page_id_t; diff --git a/src/main.c b/src/main.c index 2a25586..aeb20d0 100644 --- a/src/main.c +++ b/src/main.c @@ -33,6 +33,7 @@ static int getch(void) #include "Drv/pages/page_manager.h" #include "Drv/pages/AppInfo/page.h" #include "Drv/pages/menu/page.h" +#include "Drv/pages/YC/page.h" #include "TCP/tcp.h" #include "remoteDisplay.h" #include "Drv/key.h" @@ -71,6 +72,7 @@ int main(void) Lcd_Init(); /* 初始化屏幕显存:由入口统一完成 */ (void)PageManager_Register(MenuPage_GetInstance()); (void)PageManager_Register(AppInfoPage_GetInstance()); + (void)PageManager_Register(YCPage_GetInstance()); (void)PageManager_Navigate(PAGE_ID_MENU); Key_Init(); /* 初始化按键 */ printf("PC 端 HMI 菜单模拟启动(TCP 服务在单独线程,端口 7003)。\n"); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0346f3c..ccc6698 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -101,6 +101,7 @@ add_dtu_test( "${CMAKE_SOURCE_DIR}/src/Drv/pages/menu/view.c" "${CMAKE_SOURCE_DIR}/src/Drv/pages/menu/presenter.c" "${CMAKE_SOURCE_DIR}/src/Drv/pages/menu/page.c" + "${CMAKE_SOURCE_DIR}/src/Drv/pages/global/global_state.c" "${CMAKE_SOURCE_DIR}/src/Drv/pages/global/renderer_lcd.c" "${CMAKE_SOURCE_DIR}/src/Drv/lcd/lcd_text.c" "${CMAKE_SOURCE_DIR}/src/Drv/lcd/lcd.c"