#include "data_point_service.h" #include "project_service.h" #include namespace { bool nodeUsesAddress(const LogicNode &node, const RegisterAddress &address) { return std::visit( [&address](const auto &config) { return config.address == address; }, node.config); } } // namespace DataPointService::DataPointService(ProjectService &project_service) : project_service_(project_service) { } const std::vector &DataPointService::dataPoints() const { return project_service_.project().dataPoints; } const DataPoint *DataPointService::find(const RegisterAddress &address) const { const auto &points = dataPoints(); const auto found = std::find_if( points.cbegin(), points.cend(), [&address](const DataPoint &point) { return point.address == address; }); return found == points.cend() ? nullptr : &*found; } DataPointResult DataPointService::add(const DataPoint &data_point) { const DataPointResult validation = validateUnique(data_point, nullptr); if (!validation.succeeded) { return validation; } project_service_.editProject().dataPoints.push_back(data_point); return {true, DataPointError::None, {}}; } DataPointResult DataPointService::update( const RegisterAddress &old_address, const DataPoint &data_point) { const auto existing = std::find_if( dataPoints().cbegin(), dataPoints().cend(), [&old_address](const DataPoint &candidate) { return candidate.address == old_address; }); if (existing == dataPoints().cend()) { return {false, DataPointError::NotFound, "data point was not found"}; } const DataPointResult validation = validateUnique(data_point, &old_address); if (!validation.succeeded) { return validation; } if (data_point.address != old_address && !references(old_address).empty()) { return {false, DataPointError::AddressInUse, "referenced data point address cannot be changed"}; } Project &project = project_service_.editProject(); const auto point = std::find_if( project.dataPoints.begin(), project.dataPoints.end(), [&old_address](const DataPoint &candidate) { return candidate.address == old_address; }); *point = data_point; return {true, DataPointError::None, {}}; } DataPointResult DataPointService::remove(const RegisterAddress &address) { if (find(address) == nullptr) { return {false, DataPointError::NotFound, "data point was not found"}; } if (!references(address).empty()) { return {false, DataPointError::AddressInUse, "data point is still referenced by HMI or ladder logic"}; } Project &project = project_service_.editProject(); project.dataPoints.erase( std::remove_if( project.dataPoints.begin(), project.dataPoints.end(), [&address](const DataPoint &point) { return point.address == address; }), project.dataPoints.end()); return {true, DataPointError::None, {}}; } std::vector DataPointService::references( const RegisterAddress &address) const { std::vector result; const Project &project = project_service_.project(); for (const HmiPage &page : project.hmiPages) { for (const HmiControl &control : page.controls) { if (control.binding.has_value() && *control.binding == address) { result.push_back({"HMI/" + page.name + '/' + control.id}); } } } for (const ControlLogic &logic : project.controlLogics) { for (const LadderRung &rung : logic.rungs) { if (rung.condition.has_value()) { std::vector nodes; collectConditionNodes(*rung.condition, &nodes); for (const LogicNode *node : nodes) { if (nodeUsesAddress(*node, address)) { result.push_back({"LAD/" + logic.name + '/' + rung.name + '/' + node->id}); } } } if (rung.output.has_value() && nodeUsesAddress(*rung.output, address)) { result.push_back({"LAD/" + logic.name + '/' + rung.name + '/' + rung.output->id}); } } } return result; } DataPointResult DataPointService::validateUnique( const DataPoint &data_point, const RegisterAddress *ignored_address) const { std::string error; if (!data_point.validate(&error)) { return {false, DataPointError::InvalidDataPoint, error}; } for (const DataPoint &existing : dataPoints()) { if (ignored_address != nullptr && existing.address == *ignored_address) { continue; } if (existing.address == data_point.address) { return {false, DataPointError::DuplicateAddress, "data point address already exists"}; } if (existing.name == data_point.name) { return {false, DataPointError::DuplicateName, "data point name already exists"}; } } return {true, DataPointError::None, {}}; }