综合平台编程器项目的远程存储
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

216 lines
5.7 KiB

  1. /**
  2. * @file hmi_model.h
  3. * @brief 定义可保存的 HMI 页面、控件和寄存器绑定模型
  4. * @author suyu
  5. * @date 2026-08-10
  6. */
  7. #pragma once
  8. #include "register_address.h"
  9. #include "register_value_type.h"
  10. #include "project_limits.h"
  11. #include <map>
  12. #include <optional>
  13. #include <string>
  14. #include <variant>
  15. #include <vector>
  16. namespace HmiAppearanceProperty
  17. {
  18. inline constexpr const char kTextColor[] = "textColor";
  19. inline constexpr const char kFontSize[] = "fontSize";
  20. inline constexpr const char kFontBold[] = "fontBold";
  21. inline constexpr const char kFontItalic[] = "fontItalic";
  22. } // namespace HmiAppearanceProperty
  23. /**
  24. * @brief 描述 HMI 控件在页面坐标系中的位置和尺寸
  25. *
  26. * 页面校验要求矩形的左上角非负且完整位于页面范围内
  27. */
  28. struct HmiRect
  29. {
  30. static constexpr int kDefaultWidth = 80;
  31. static constexpr int kDefaultHeight = 32;
  32. int x = 0;
  33. int y = 0;
  34. int width = kDefaultWidth;
  35. int height = kDefaultHeight;
  36. };
  37. /**
  38. * @brief HMI 控件的基础类型
  39. *
  40. * 按钮和指示灯只能绑定 M 位,数值控件只能绑定 D 字
  41. */
  42. enum class HmiControlType
  43. {
  44. Button, // 按钮
  45. Indicator, // 指示灯
  46. NumericDisplay, // 数值显示
  47. NumericInput, // 数值输入
  48. Label, // 标签
  49. StatusText, // 状态文本
  50. PageJump, // 页面跳转
  51. AlarmList, // 报警列表
  52. Count // 已注册控件类型数量,不作为实际控件使用
  53. };
  54. /**
  55. * @brief 按钮对绑定 M 位执行的操作
  56. */
  57. enum class HmiButtonOperation
  58. {
  59. SetOn, // 按下时写入 1
  60. SetOff, // 按下时写入 0
  61. Toggle, // 按下时写入当前读回值的反值
  62. MomentaryOn // 按下时写入 1,释放时写入 0
  63. };
  64. /** @brief HMI 按钮 D 数值启用条件的比较方式 */
  65. enum class HmiButtonConditionOperator
  66. {
  67. Equal,
  68. NotEqual,
  69. LessThan,
  70. LessThanOrEqual,
  71. GreaterThan,
  72. GreaterThanOrEqual
  73. };
  74. struct HmiButtonBitEnableCondition
  75. {
  76. RegisterAddress address{RegisterArea::M, 0};
  77. bool expected = false;
  78. bool operator==(const HmiButtonBitEnableCondition &other) const
  79. {
  80. return address == other.address && expected == other.expected;
  81. }
  82. };
  83. struct HmiButtonWordEnableCondition
  84. {
  85. RegisterAddress address{RegisterArea::D, 0};
  86. RegisterDataType dataType = RegisterDataType::Int16;
  87. HmiButtonConditionOperator operation = HmiButtonConditionOperator::Equal;
  88. double value = 0.0;
  89. bool operator==(const HmiButtonWordEnableCondition &other) const
  90. {
  91. return address == other.address
  92. && dataType == other.dataType
  93. && operation == other.operation
  94. && value == other.value;
  95. }
  96. };
  97. using HmiButtonEnableCondition = std::variant<
  98. HmiButtonBitEnableCondition,
  99. HmiButtonWordEnableCondition>;
  100. struct HmiPageJumpConfig
  101. {
  102. std::string targetPageId;
  103. };
  104. struct HmiStatusBitTextConfig
  105. {
  106. std::string offText;
  107. std::string onText;
  108. bool operator==(const HmiStatusBitTextConfig &other) const
  109. {
  110. return offText == other.offText && onText == other.onText;
  111. }
  112. };
  113. struct HmiStatusValueRange
  114. {
  115. std::optional<double> lowerBound;
  116. std::optional<double> upperBound;
  117. std::string text;
  118. bool operator==(const HmiStatusValueRange &other) const
  119. {
  120. return lowerBound == other.lowerBound
  121. && upperBound == other.upperBound
  122. && text == other.text;
  123. }
  124. };
  125. struct HmiStatusWordTextConfig
  126. {
  127. std::vector<HmiStatusValueRange> ranges;
  128. bool operator==(const HmiStatusWordTextConfig &other) const
  129. {
  130. return ranges == other.ranges;
  131. }
  132. };
  133. using HmiStatusTextConfig = std::variant<
  134. HmiStatusBitTextConfig,
  135. HmiStatusWordTextConfig>;
  136. /**
  137. * @brief 描述一个可保存的 HMI 控件及其显示和寄存器配置
  138. *
  139. * `properties` 保存未纳入公共字段的字符串扩展属性
  140. */
  141. struct HmiControl
  142. {
  143. std::string id;
  144. HmiControlType type = HmiControlType::Label;
  145. HmiRect bounds;
  146. std::string text;
  147. std::optional<RegisterAddress> binding;
  148. RegisterDataType dataType = RegisterDataType::Int16;
  149. std::map<std::string, std::string> properties;
  150. HmiButtonOperation buttonOperation = HmiButtonOperation::MomentaryOn;
  151. std::optional<HmiButtonEnableCondition> buttonEnableCondition;
  152. std::optional<HmiPageJumpConfig> pageJump;
  153. std::optional<HmiStatusTextConfig> statusText;
  154. /**
  155. * @brief 校验控件的标识、尺寸、扩展属性和寄存器绑定
  156. * @param error 可选错误输出,失败时写入首个校验原因
  157. * @return 配置完整且满足控件类型绑定规则时返回 true
  158. *
  159. * 位控件必须绑定有效 M 地址,字控件必须绑定有效 D 地址
  160. */
  161. bool validate(std::string *error = nullptr) const;
  162. bool isConfigured() const;
  163. };
  164. /**
  165. * @brief 描述一个 HMI 页面及其控件集合
  166. *
  167. * 控件标识在同一页面内必须唯一,所有控件必须完整位于页面边界内
  168. */
  169. struct HmiPage
  170. {
  171. std::string id;
  172. std::string name;
  173. int width = ProjectLimits::kDefaultHmiPageWidth;
  174. int height = ProjectLimits::kDefaultHmiPageHeight;
  175. std::vector<HmiControl> controls;
  176. /**
  177. * @brief 校验页面尺寸、控件标识唯一性和全部控件配置
  178. * @param error 可选错误输出,失败时写入首个校验原因
  179. * @return 页面及其全部控件有效时返回 true
  180. */
  181. bool validate(
  182. const ProjectLimitSettings &limits,
  183. std::string *error = nullptr) const;
  184. bool validateForRunning(
  185. const ProjectLimitSettings &limits,
  186. std::string *error = nullptr) const;
  187. };