Files
DTU-HMI/README.md

17 KiB
Raw Blame History

DTU-HMI

PC 端 HMI 菜单逻辑模拟程序,纯 C 实现支持菜单树、LCD 显示、TCP 远程显示RemoDispBus 协议)及 UTF-8 汉字库。


快速开始

mkdir build
cd build
cmake ..
cmake --build .

生成可执行文件 DTU-HMI.exeWindowsDTU-HMILinux


目录结构

DTU-HMI/
├── CMakeLists.txt
├── gen_utf8_hz12.py        # 12×12 UTF-8 汉字库生成脚本
├── remo_disp_server.py      # 远程显示 Python 服务端
├── include/
│   └── types.h
├── src/
│   ├── main.c
│   ├── thread_utils.c/h
│   ├── remoteDisplay.c/h
│   ├── TCP/tcp.c, tcp.h
│   └── Drv/
│       ├── menu.c/h
│       ├── display.c/h
│       ├── lcd.c/h
│       ├── Ascii.c/h
│       └── utf8_hz12_data.c/h  # 由脚本生成
└── build/

环境要求

  • CMake 3.10+
  • 编译器Windows 默认 MSVCLinux 需 GCC/Clang
  • 编码:源文件 UTF-8CMake 已配置 MSVC /utf-8

构建步骤

Windows

mkdir build
cd build
cmake ..
cmake --build .

Linux / macOS

mkdir build
cd build
cmake ..
cmake --build .

TCP 通信

程序监听端口 7003RemoDispBus 默认)。使用 remo_disp_server.py 连接后可实时查看 LCD 显存画面。协议支持 CMD_INITCMD_LCDMEMCMD_KEYCMD_KEEPLIVE


菜单系统

1. 概述

菜单由静态表 g_tMenuModelTab 定义,经 Menu_Main_Creat_01 构建为可遍历树 g_tMenuItem[]。每个结点有 ptHigher/ptLower/ptBefore/ptBehind 四个指针,同级首尾成环。

2. 数据结构

2.1 静态菜单定义tagMenuModel

typedef struct
{
    uint8_t   byClass;      // 菜单分级标志 0/1/2/3
    uint8_t   byName[50];   // 菜单字符串
    uint8_t   byTip[50];    // 菜单提示文本
    uint8_t   byAttrib;     // 菜单属性
    uint16_t  wPassword;    // 访问密码0x0000 表示无密码
    uint16_t  wPara;        // 菜单执行函数参数
    FUNCPTR   pfnWinProc;   // 界面执行函数指针
} tagMenuModel, *tagPMenuModel;

/* 注意:表定义时顺序不能乱,需从 0 级开始,一级一级按顺序写入 */
const tagMenuModel g_tMenuModelTab[] = { ... };

2.2 菜单遍历树tagMenuItem

/* 每个菜单包含:一、上下前后等级关系;二、属性与内容;三、显示坐标 */
typedef struct _MENU_ITEM_
{
    struct _MENU_ITEM_ *ptHigher;   // 上级菜单指针
    struct _MENU_ITEM_ *ptLower;   // 下级菜单指针
    struct _MENU_ITEM_ *ptBefore;  // 同级上方指针
    struct _MENU_ITEM_ *ptBehind;  // 同级下方指针

    uint8_t   byClass;
    uint8_t   byName[50];
    uint8_t   byTip[50];
    uint8_t   byAttrib;
    uint16_t  wPassword;
    uint16_t  wPara;
    FUNCPTR   pfnWinProc;

    uint16_t  wPos, wNum;
    uint16_t  wSPosX, wSPosY, wEPosX, wEPosY;
} tagMenuItem, *tagPMenuItem;

tagMenuItem g_tMenuItem[300];  /* 所有菜单存储于此数组 */

3. 菜单构建示例

3.1 静态表g_tMenuModelTab

const tagMenuModel g_tMenuModelTab[] =
{
    {   0,  " ",           "",                   0,                  0x0000,             0,                  (FUNCPTR)Menu_NonPfunc              },
    {   1,  "装置信息",    "查看装置信息",         0,                  0x0000,             EN_ANA_0,           (FUNCPTR)MenuProc_See_AppInfo       },
    {   1,  "实时数据",    "装置实时数据",         0,                  0x0000,             0,                  (FUNCPTR)Menu_NonPfunc              },
    {   2,  "交流量",      "查看遥测交流量",       EN_MEA_AC,          0x0000,             EN_ANA_0,           (FUNCPTR)MenuProc_See_YC            },
    {   2,  "直流量",      "查看遥测直流量",       EN_MEA_DC,          0x0000,             EN_ANA_0,           (FUNCPTR)MenuProc_See_YC            },
    {   2,  "遥信量",      "查看遥信开入量",       EN_INPUT_RLY_ALL,   0x0000,             EN_INPUT_0,         (FUNCPTR)MenuProc_See_Input         },
    {   1,  "参数定值",    "保护参数查看与修改",    0,                  0x0000,             0,                  (FUNCPTR)Menu_NonPfunc              },
    {   2,  "整定",        "整定装置保护参数",     0,                  0x0000,             0,                  (FUNCPTR)Menu_NonPfunc              },
    {   3,  "参数",        "查看设备参数定值",     EN_FIGURE_SET,      CN_USER_PWD,        EN_SIDE_BASIC,      (FUNCPTR)MenuProc_Set_Value         },
    {   3,  "定值",        "设置装置数值定值",     EN_FIGURE_SET,      CN_USER_PWD,        EN_SIDE_DEF,        (FUNCPTR)MenuProc_Set_Value         },
    {   3,  "控制字",      "设置装置控制字",       EN_SOFT_SET,        CN_USER_PWD,        EN_SIDE_DEF,        (FUNCPTR)MenuProc_Set_Value         },
    {   3,  "软压板",      "设置软压板",           0,                  CN_USER_PWD,        EN_SOFT_PRO,        (FUNCPTR)MenuProc_Set_Soft          },
    {   2,  "查看",        "查看装置保护参数",     0,                  0x0000,             0,                  (FUNCPTR)Menu_NonPfunc              },
    {   3,  "参数",        "设置设备参数定值",     EN_FIGURE_SET,      0x0000,             EN_SIDE_BASIC,      (FUNCPTR)MenuProc_See_Set           },
    {   3,  "定值",        "查看数值型定值",       EN_FIGURE_SET,      0x0000,             EN_SIDE_DEF,        (FUNCPTR)MenuProc_See_Set           },
    {   3,  "控制字",      "查看控制字定值",       EN_SOFT_SET,        0x0000,             EN_SIDE_DEF,        (FUNCPTR)MenuProc_See_Set           },
    {   3,  "软压板",      "查看软压板",           0,                  0x0000,             EN_SOFT_PRO,        (FUNCPTR)MenuProc_See_Soft          },
    {   1,  "三遥设置",    "",                     0,                  0x0000,             0,                  (FUNCPTR)Menu_NonPfunc              },
    {   2,  "遥测死区",    "设置遥测量死区门槛",   0,                  CN_USER_PWD,        0,                  (FUNCPTR)MenuProc_YC_SetSqValue     },
    {   2,  "遥测系数",    "设置遥测量微调系数",   EN_MEA_ADJ,         CN_USER_PWD,        0,                  (FUNCPTR)MenuProc_YC_SetAdjCoe      },
    {   2,  "遥信类型",    "设置遥信类型",         0,                  CN_USER_PWD,        0,                  (FUNCPTR)MenuProc_YX_SetCommType    },
    {   2,  "遥信防抖",    "设置遥信防抖时间",     0,                  CN_USER_PWD,        0,                  (FUNCPTR)MenuProc_YX_SetWidth       },
    {   2,  "双点遥信",    "设置双点遥信虚端子",   0,                  CN_USER_PWD,        0,                  (FUNCPTR)MenuProc_YX_SetTwin        },
    {   1,  "装置维护",    "",                     0,                  0x0000,             0,                  (FUNCPTR)Menu_NonPfunc              },
    {   2,  "时钟设置",    "设置系统时钟",         0,                  CN_USER_PWD,        0,                  (FUNCPTR)MenuProc_Cfg_Time          },
    {   2,  "强制复归",    "可复归未返回事件",     EN_REV_FORCE,       CN_USER_PWD,        0,                  (FUNCPTR)MenuProc_Cfg_RevEvent      },
    {   2,  "手动录波",    "启动手动录波",         0,                  CN_USER_PWD,        0,                  (FUNCPTR)MenuProc_Cfg_ManualWave    },
    {   2,  "清除记录",    "",                     0,                  CN_USER_PWD,        0,                  (FUNCPTR)MenuProc_Cfg_ClrRec        },
    {   1,  "通讯参数",    "",                     0,                  0x0000,             0,                  (FUNCPTR)Menu_NonPfunc              },
    {   2,  "通讯设置",    "外部通讯设置",         0,                  CN_USER_PWD,        0,                  (FUNCPTR)MenuProc_Cfg_ComPara       },
    {   2,  "网口设置",    "",                     0,                  CN_USER_PWD,        0,                  (FUNCPTR)MenuProc_Cfg_EditIP        },
    {   2,  "SNTP设置",    "",                     0,                  CN_USER_PWD,        0,                  (FUNCPTR)MenuProc_Cfg_EditSntp      },
    {   1,  "记录查询",    "查看各种装置记录",     0,                  0x0000,             0,                  (FUNCPTR)Menu_NonPfunc              },
    {   2,  "SOE记录",     "",                     0,                  0x0000,             0,                  (FUNCPTR)MenuProc_See_RecSOE        },
    {   2,  "事故记录",    "",                     0,                  0x0000,             0,                  (FUNCPTR)MenuProc_See_RecAct        },
    {   2,  "操作记录",    "",                     0,                  0x0000,             0,                  (FUNCPTR)MenuProc_See_RecOpt        },
    {   2,  "保护告警",    "",                     0,                  0x0000,             0,                  (FUNCPTR)MenuProc_See_RecAlm        },
    {   2,  "保护启动",    "",                     0,                  0x0000,             0,                  (FUNCPTR)MenuProc_See_RecStart      },
    {   2,  "遥控记录",    "",                     0,                  0x0000,             0,                  (FUNCPTR)MenuProc_See_RecYK         },
    {   2,  "自检记录",    "",                     0,                  0x0000,             0,                  (FUNCPTR)MenuProc_See_RecChk        },
    {   2,  "运行记录",    "",                     0,                  0x0000,             0,                  (FUNCPTR)MenuProc_See_RecRun        },
    {   2,  "运行报告",    "",                     0,                  0x0000,             0,                  (FUNCPTR)MenuProc_See_RecFault      },
    {   0,  "厂家设置",    "设置装置相关参数",     0,                  CN_COP_PWD,         0,                  (FUNCPTR)Menu_NonPfunc              },
    {   1,  "元件配置",    "配置元件配置",         0,                  CN_COP_PWD,         EN_FACTORY_PASSWORD,(FUNCPTR)MenuProc_Cfg_CellConf      },
    {   1,  "恢复默认",    "恢复默认元件定值参数", 0,                  CN_COP_PWD,         0,                  (FUNCPTR)Menu_NonPfunc              },
    {   2,  "全部恢复",    "全部参数恢复默认",     0,                  CN_COP_PWD,         EN_NO_USER_PWD,     (FUNCPTR)MenuProc_AllInf_Default    },
    {   2,  "默认参数",    "当前参数恢复默认",     0,                  CN_COP_PWD,         EN_NO_USER_PWD,     (FUNCPTR)MenuProc_Para_Default      },
    {   2,  "默认定值",    "当前定值区恢复默认",   0,                  CN_COP_PWD,         EN_NO_USER_PWD,     (FUNCPTR)MenuProc_Set_Default       },
    {   2,  "软压板",      "当前软压板恢复默认",   0,                  CN_COP_PWD,         EN_NO_USER_PWD,     (FUNCPTR)MenuProc_Resume_Soft       },
    {   2,  "元件配置",    "元件配置恢复默认",     0,                  CN_COP_PWD,         EN_NO_USER_PWD,     (FUNCPTR)MenuProc_Cfg_CellDef       },
    {   1,  "交流显示",    "交流显示方式设置",     0,                  CN_COP_PWD,         0,                  (FUNCPTR)MenuProc_Cfg_ShowAnaType   },
    {   1,  "装置调试",    "调试装置",             0,                  0x0000,             0,                  (FUNCPTR)Menu_NonPfunc              },
    {   2,  "虚拟遥信",    "设置虚拟遥信值",       0,                  CN_COP_PWD,         0,                  (FUNCPTR)MenuProc_Dbg_XuYX          },
    {   2,  "交流虚遥测",  "设置虚拟交流遥测值",   EN_MEA_AC,          CN_COP_PWD,         EN_ANA_0,           (FUNCPTR)MenuProc_Dbg_XuYC          },
    {   2,  "直流虚遥测",  "设置虚拟直流遥测值",   EN_MEA_DC,          CN_COP_PWD,         EN_ANA_0,           (FUNCPTR)MenuProc_Dbg_XuYC          },
    {   2,  "电度虚遥测",  "设置虚拟电度遥测值",   EN_MEA_POWER,       CN_COP_PWD,         EN_ANA_0,           (FUNCPTR)MenuProc_Dbg_XuYC          },
    {   2,  "动作虚事件",  "设置虚拟动作事件",     EN_ACT_REC,         CN_COP_PWD,         0,                  (FUNCPTR)MenuProc_Dbg_XuEvent       },
    {   2,  "告警虚事件",  "设置虚拟告警事件",     EN_ALM_REC,         CN_COP_PWD,         0,                  (FUNCPTR)MenuProc_Dbg_XuEvent       },
    {   2,  "动作出口",    "进入此菜单保护退出",   EN_OUTPUT_TRIP,     CN_COP_PWD,         EN_INPUT_0,         (FUNCPTR)MenuProc_Dbg_Relay         },
    {   2,  "信号出口",    "进入此菜单保护退出",   EN_OUTPUT_SIGN,     CN_COP_PWD,         0,                  (FUNCPTR)MenuProc_Dbg_Relay         },
    {   1,  "版本信息",    "查看板件版本信息",     0,                  CN_COP_PWD,         0,                  (FUNCPTR)MenuProc_See_VersionBoard },
};

3.2 解析后的树形结构

根据上表,Menu_Main_Creat_01 解析后的菜单树为:

0 级目录 {
    1.装置信息
    1.实时数据 {
        2.交流量
        2.直流量
        2.遥信量
    }
    1.参数定值 {
        2.整定 {
            3.参数
            3.定值
            3.控制字
            3.软压板
        }
        2.查看 {
            3.参数
            3.定值
            3.控制字
            3.软压板
        }
    }
    1.三遥设置 {
        2.遥测死区
        2.遥测系数
        2.遥信类型
        2.遥信防抖
        2.双点遥信
    }
    1.装置维护 {
        2.时钟设置
        2.强制复归
        2.手动录波
        2.清除记录
        2.通讯参数
        2.通讯设置
        2.网口设置
        2.SNTP设置
    }
    1.记录查询 {
        2.SOE记录
        2.事故记录
        2.操作记录
        2.保护告警
        2.保护启动
        2.遥控记录
        2.自检记录
        2.运行记录
        2.运行报告
    }
}

0.厂家设置 {
    1.元件配置
    1.恢复默认 {
        2.全部恢复
        2.默认参数
        2.默认定值
        2.软压板
        2.元件配置
    }
    1.交流显示
    1.装置调试 {
        2.虚拟遥信
        2.交流虚遥测
        2.直流虚遥测
        2.电度虚遥测
        2.动作虚事件
        2.告警虚事件
        2.动作出口
        2.信号出口
    }
    1.版本信息
}

3.3 单例解析示例:直流量

{2,"直流量","查看遥测直流量",EN_MEA_DC,0x0000,EN_ANA_0,(FUNCPTR)MenuProc_See_YC} 为例,构建后该菜单项的指针与属性为:

{
    ptHigher  = 1.实时数据;
    ptLower   = NULL;
    ptBefore  = 2.交流量;
    ptBehind  = 2.遥信量;

    byClass   = 2;
    byName    = 直流量;
    byTip     = 查看遥测直流量;
    byAttrib  = EN_MEA_DC;
    wPassword = 0x0000;
    wPara     = 0;
    pfnWinProc = MenuProc_See_YC;
}

3.4 同级首尾成环

同级菜单中,首尾通过 ptBefore/ptBehind 相连形成环。例如 2 级子菜单:

2.虚拟遥信
2.交流虚遥测
2.直流虚遥测
2.电度虚遥测
2.动作虚事件
2.告警虚事件
2.动作出口
2.信号出口

其中:

  • 2.虚拟遥信ptBefore 指向 2.信号出口(首的前一个是尾)
  • 2.信号出口ptBehind 指向 2.虚拟遥信(尾的后一个是首)

4. 构建流程Menu_Main_Creat_01

g_tMenuModelTab 的定义顺序逐项处理,通过比较 byCurClassbyNextClass 设置每个菜单的层级指针。

情况 1byCurClass < byNextClass下一项更深进入子菜单

    ptCurrent                    ptNextNode
    (当前)                        (下一项,更深一级)
        │                              │
        │  ptLower ──────────────────►│
        │◄───────────────── ptHigher   │
        │                              │
    该级尾不变                    新一级的 首=尾=ptNextNode

情况 2byCurClass == byNextClass同级并列

    ptCurrent ─── ptBehind ──► ptNextNode
        │                          │
        │     ptBefore ◄───────────┤
        │                          │
        └──── ptHigher (同) ────────┘
    该级 尾 更新为 ptNextNode

情况 3byCurClass > byNextClass下一项更浅回到上层

    ... byCurClass 级 ...     byNextClass 级 ...
         ptLast[byNextClass] 已存在
                    │
                    │ ptBehind ──► ptNextNode
                    │                 │
                    │◄── ptBefore ────┤
                    │                 ptHigher = 该级尾的 ptHigher
    同时:从 byCurClass 到 byNextClass+1 各级首尾成环
          ptLast[级]──►ptFirst[级]ptFirst[级]──►ptLast[级]

最后:各级首尾成环

表遍历完后,从 0 级到当前结点所在级,把该级首尾连成环:

    ptFirst[级] ◄──────────────► ptLast[级]
         │                             │
         └──── ptBehind ───────────────┘
         ◄──────── ptBefore ────────────┘