综合平台编程器项目的远程存储
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 

171 строка
5.3 KiB

  1. #include "data_point_service.h"
  2. #include "project_service.h"
  3. #include <algorithm>
  4. namespace {
  5. bool nodeUsesAddress(const LogicNode &node, const RegisterAddress &address)
  6. {
  7. return std::visit(
  8. [&address](const auto &config) { return config.address == address; },
  9. node.config);
  10. }
  11. } // namespace
  12. DataPointService::DataPointService(ProjectService &project_service)
  13. : project_service_(project_service)
  14. {
  15. }
  16. const std::vector<DataPoint> &DataPointService::dataPoints() const
  17. {
  18. return project_service_.project().dataPoints;
  19. }
  20. const DataPoint *DataPointService::find(const RegisterAddress &address) const
  21. {
  22. const auto &points = dataPoints();
  23. const auto found = std::find_if(
  24. points.cbegin(), points.cend(),
  25. [&address](const DataPoint &point) { return point.address == address; });
  26. return found == points.cend() ? nullptr : &*found;
  27. }
  28. DataPointResult DataPointService::add(const DataPoint &data_point)
  29. {
  30. const DataPointResult validation = validateUnique(data_point, nullptr);
  31. if (!validation.succeeded)
  32. {
  33. return validation;
  34. }
  35. project_service_.editProject().dataPoints.push_back(data_point);
  36. return {true, DataPointError::None, {}};
  37. }
  38. DataPointResult DataPointService::update(
  39. const RegisterAddress &old_address, const DataPoint &data_point)
  40. {
  41. const auto existing = std::find_if(
  42. dataPoints().cbegin(), dataPoints().cend(),
  43. [&old_address](const DataPoint &candidate)
  44. {
  45. return candidate.address == old_address;
  46. });
  47. if (existing == dataPoints().cend())
  48. {
  49. return {false, DataPointError::NotFound, "data point was not found"};
  50. }
  51. const DataPointResult validation = validateUnique(data_point, &old_address);
  52. if (!validation.succeeded)
  53. {
  54. return validation;
  55. }
  56. if (data_point.address != old_address && !references(old_address).empty())
  57. {
  58. return {false, DataPointError::AddressInUse,
  59. "referenced data point address cannot be changed"};
  60. }
  61. Project &project = project_service_.editProject();
  62. const auto point = std::find_if(
  63. project.dataPoints.begin(), project.dataPoints.end(),
  64. [&old_address](const DataPoint &candidate)
  65. {
  66. return candidate.address == old_address;
  67. });
  68. *point = data_point;
  69. return {true, DataPointError::None, {}};
  70. }
  71. DataPointResult DataPointService::remove(const RegisterAddress &address)
  72. {
  73. if (find(address) == nullptr)
  74. {
  75. return {false, DataPointError::NotFound, "data point was not found"};
  76. }
  77. if (!references(address).empty())
  78. {
  79. return {false, DataPointError::AddressInUse,
  80. "data point is still referenced by HMI or ladder logic"};
  81. }
  82. Project &project = project_service_.editProject();
  83. project.dataPoints.erase(
  84. std::remove_if(
  85. project.dataPoints.begin(), project.dataPoints.end(),
  86. [&address](const DataPoint &point) { return point.address == address; }),
  87. project.dataPoints.end());
  88. return {true, DataPointError::None, {}};
  89. }
  90. std::vector<DataPointReference> DataPointService::references(
  91. const RegisterAddress &address) const
  92. {
  93. std::vector<DataPointReference> result;
  94. const Project &project = project_service_.project();
  95. for (const HmiPage &page : project.hmiPages)
  96. {
  97. for (const HmiControl &control : page.controls)
  98. {
  99. if (control.binding.has_value() && *control.binding == address)
  100. {
  101. result.push_back({"HMI/" + page.name + '/' + control.id});
  102. }
  103. }
  104. }
  105. for (const ControlLogic &logic : project.controlLogics)
  106. {
  107. for (const LadderRung &rung : logic.rungs)
  108. {
  109. if (rung.condition.has_value())
  110. {
  111. std::vector<const LogicNode *> nodes;
  112. collectConditionNodes(*rung.condition, &nodes);
  113. for (const LogicNode *node : nodes)
  114. {
  115. if (nodeUsesAddress(*node, address))
  116. {
  117. result.push_back({"LAD/" + logic.name + '/' + rung.name + '/' + node->id});
  118. }
  119. }
  120. }
  121. if (rung.output.has_value() && nodeUsesAddress(*rung.output, address))
  122. {
  123. result.push_back({"LAD/" + logic.name + '/' + rung.name + '/'
  124. + rung.output->id});
  125. }
  126. }
  127. }
  128. return result;
  129. }
  130. DataPointResult DataPointService::validateUnique(
  131. const DataPoint &data_point,
  132. const RegisterAddress *ignored_address) const
  133. {
  134. std::string error;
  135. if (!data_point.validate(&error))
  136. {
  137. return {false, DataPointError::InvalidDataPoint, error};
  138. }
  139. for (const DataPoint &existing : dataPoints())
  140. {
  141. if (ignored_address != nullptr && existing.address == *ignored_address)
  142. {
  143. continue;
  144. }
  145. if (existing.address == data_point.address)
  146. {
  147. return {false, DataPointError::DuplicateAddress,
  148. "data point address already exists"};
  149. }
  150. if (existing.name == data_point.name)
  151. {
  152. return {false, DataPointError::DuplicateName,
  153. "data point name already exists"};
  154. }
  155. }
  156. return {true, DataPointError::None, {}};
  157. }