综合平台编程器项目的远程存储
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 

315 řádky
7.5 KiB

  1. #include "control_logic_model.h"
  2. #include <algorithm>
  3. namespace {
  4. void setError(std::string *error, const std::string &message)
  5. {
  6. if (error != nullptr)
  7. {
  8. *error = message;
  9. }
  10. }
  11. bool validateConfig(const ContactNodeConfig &config, std::string *error)
  12. {
  13. if (!config.address.isValid() || config.address.area() != RegisterArea::M)
  14. {
  15. setError(error, "contact node requires a valid M address");
  16. return false;
  17. }
  18. if (config.mode != ContactMode::NormallyOpen
  19. && config.mode != ContactMode::NormallyClosed)
  20. {
  21. setError(error, "contact node has an unsupported mode");
  22. return false;
  23. }
  24. return true;
  25. }
  26. bool validateConfig(const CoilNodeConfig &config, std::string *error)
  27. {
  28. if (!config.address.isValid() || config.address.area() != RegisterArea::M)
  29. {
  30. setError(error, "coil node requires a valid M address");
  31. return false;
  32. }
  33. if (config.mode != CoilMode::Normal
  34. && config.mode != CoilMode::Set
  35. && config.mode != CoilMode::Reset)
  36. {
  37. setError(error, "coil node has an unsupported mode");
  38. return false;
  39. }
  40. return true;
  41. }
  42. bool validateConfig(const CompareNodeConfig &config, std::string *error)
  43. {
  44. if (!config.address.isValid() || config.address.area() != RegisterArea::D)
  45. {
  46. setError(error, "comparison node requires a valid D address");
  47. return false;
  48. }
  49. if (config.comparison != ComparisonOperator::Equal
  50. && config.comparison != ComparisonOperator::NotEqual
  51. && config.comparison != ComparisonOperator::LessThan
  52. && config.comparison != ComparisonOperator::LessThanOrEqual
  53. && config.comparison != ComparisonOperator::GreaterThan
  54. && config.comparison != ComparisonOperator::GreaterThanOrEqual)
  55. {
  56. setError(error, "comparison node has an unsupported operator");
  57. return false;
  58. }
  59. return true;
  60. }
  61. template<typename TItem>
  62. bool hasDuplicateId(const std::vector<TItem> &items)
  63. {
  64. for (auto current = items.cbegin(); current != items.cend(); ++current)
  65. {
  66. if (std::find_if(
  67. current + 1,
  68. items.cend(),
  69. [&current](const TItem &candidate)
  70. {
  71. return candidate.id == current->id;
  72. }) != items.cend())
  73. {
  74. return true;
  75. }
  76. }
  77. return false;
  78. }
  79. } // namespace
  80. bool LogicNode::validate(std::string *error) const
  81. {
  82. if (id.empty())
  83. {
  84. setError(error, "logic node id must not be empty");
  85. return false;
  86. }
  87. return std::visit(
  88. [error](const auto &config)
  89. {
  90. return validateConfig(config, error);
  91. },
  92. config);
  93. }
  94. bool LogicNode::isConfigured() const
  95. {
  96. return configured;
  97. }
  98. bool LogicNode::isCondition() const
  99. {
  100. return !std::holds_alternative<CoilNodeConfig>(config);
  101. }
  102. bool LogicNode::isOutput() const
  103. {
  104. return std::holds_alternative<CoilNodeConfig>(config);
  105. }
  106. bool LadderStage::validate(std::string *error) const
  107. {
  108. if (id.empty() || branches.empty())
  109. {
  110. setError(error, "ladder stage id and branches must not be empty");
  111. return false;
  112. }
  113. if (hasDuplicateId(branches))
  114. {
  115. setError(error, "parallel branch node ids must be unique");
  116. return false;
  117. }
  118. for (const LogicNode &node : branches)
  119. {
  120. if (!node.validate(error))
  121. {
  122. return false;
  123. }
  124. if (!node.isCondition())
  125. {
  126. setError(error, "ladder stage may contain condition nodes only");
  127. return false;
  128. }
  129. }
  130. return true;
  131. }
  132. bool LadderStage::validateForRunning(std::string *error) const
  133. {
  134. if (!validate(error))
  135. {
  136. return false;
  137. }
  138. for (const LogicNode &node : branches)
  139. {
  140. if (!node.isConfigured())
  141. {
  142. setError(error, "ladder condition " + node.id + " is not configured");
  143. return false;
  144. }
  145. }
  146. return true;
  147. }
  148. bool LadderRung::validate(std::string *error) const
  149. {
  150. return validateStructure(error);
  151. }
  152. bool LadderRung::validateForRunning(std::string *error) const
  153. {
  154. if (!validateStructure(error))
  155. {
  156. return false;
  157. }
  158. if (stages.empty() && !output.has_value())
  159. {
  160. return true;
  161. }
  162. if (stages.empty() || !output.has_value())
  163. {
  164. setError(error, "incomplete ladder network requires conditions and an output coil");
  165. return false;
  166. }
  167. for (const LadderStage &stage : stages)
  168. {
  169. if (!stage.validateForRunning(error))
  170. {
  171. return false;
  172. }
  173. }
  174. if (!output->isConfigured())
  175. {
  176. setError(error, "output coil " + output->id + " is not configured");
  177. return false;
  178. }
  179. return true;
  180. }
  181. bool LadderRung::validateStructure(std::string *error) const
  182. {
  183. if (id.empty() || name.empty())
  184. {
  185. setError(error, "ladder rung id and name must not be empty");
  186. return false;
  187. }
  188. if (hasDuplicateId(stages))
  189. {
  190. setError(error, "ladder stage ids must be unique within a rung");
  191. return false;
  192. }
  193. std::vector<std::string> node_ids;
  194. for (const LadderStage &stage : stages)
  195. {
  196. if (!stage.validate(error))
  197. {
  198. return false;
  199. }
  200. for (const LogicNode &node : stage.branches)
  201. {
  202. node_ids.push_back(node.id);
  203. }
  204. }
  205. if (output.has_value())
  206. {
  207. if (!output->validate(error))
  208. {
  209. return false;
  210. }
  211. if (!output->isOutput())
  212. {
  213. setError(error, "ladder rung output must be a coil node");
  214. return false;
  215. }
  216. node_ids.push_back(output->id);
  217. }
  218. std::sort(node_ids.begin(), node_ids.end());
  219. if (std::adjacent_find(node_ids.cbegin(), node_ids.cend()) != node_ids.cend())
  220. {
  221. setError(error, "logic node ids must be unique within a rung");
  222. return false;
  223. }
  224. return true;
  225. }
  226. bool ControlLogic::validate(std::string *error) const
  227. {
  228. if (!validateStructure(error))
  229. {
  230. return false;
  231. }
  232. for (const LadderRung &rung : rungs)
  233. {
  234. if (!rung.validate(error))
  235. {
  236. return false;
  237. }
  238. }
  239. return true;
  240. }
  241. bool ControlLogic::validateStructure(std::string *error) const
  242. {
  243. if (id.empty() || name.empty())
  244. {
  245. setError(error, "control logic id and name must not be empty");
  246. return false;
  247. }
  248. if (hasDuplicateId(rungs))
  249. {
  250. setError(error, "ladder rung ids must be unique within a logic");
  251. return false;
  252. }
  253. std::vector<std::string> node_ids;
  254. for (const LadderRung &rung : rungs)
  255. {
  256. if (!rung.validateStructure(error))
  257. {
  258. return false;
  259. }
  260. for (const LadderStage &stage : rung.stages)
  261. {
  262. for (const LogicNode &node : stage.branches)
  263. {
  264. node_ids.push_back(node.id);
  265. }
  266. }
  267. if (rung.output.has_value())
  268. {
  269. node_ids.push_back(rung.output->id);
  270. }
  271. }
  272. std::sort(node_ids.begin(), node_ids.end());
  273. if (std::adjacent_find(node_ids.cbegin(), node_ids.cend()) != node_ids.cend())
  274. {
  275. setError(error, "logic node ids must be unique within a logic");
  276. return false;
  277. }
  278. return true;
  279. }
  280. bool ControlLogic::validateForRunning(std::string *error) const
  281. {
  282. if (!validateStructure(error))
  283. {
  284. return false;
  285. }
  286. for (const LadderRung &rung : rungs)
  287. {
  288. if (!rung.validateForRunning(error))
  289. {
  290. return false;
  291. }
  292. }
  293. return true;
  294. }