ChimeraTK-ControlSystemAdapter-OPCUAAdapter 04.00.05
Loading...
Searching...
No Matches
csa_opcua_adapter.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ChimeraTKs ControlSystem-OPC-UA-Adapter.
3 *
4 * ChimeraTKs ControlSystem-OPC-UA-Adapter is free software: you can
5 * redistribute it and/or modify it under the terms of the Lesser GNU
6 * General Public License as published by the Free Software Foundation,
7 * either version 3 of the License, or (at your option) any later version.
8 *
9 * ChimeraTKs ControlSystem-OPC-UA-Adapter is distributed in the hope
10 * that it will be useful, but WITHOUT ANY WARRANTY; without even the
11 * implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 * See the Lesser GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Foobar. If not, see https://www.gnu.org/licenses/lgpl.html
16 *
17 * Copyright (c) 2016 Chris Iatrou <Chris_Paul.Iatrou@tu-dresden.de>
18 * Copyright (c) 2016 Julian Rahm <Julian.Rahm@tu-dresden.de>
19 * Copyright (c) 2023 Andreas Ebner <Andreas.Ebner@iosb.fraunhofer.de>
20 */
21
22extern "C" {
23#include "unistd.h"
24}
25
26#include "csa_opcua_adapter.h"
27#include "csa_processvariable.h"
28#include "ua_adapter.h"
29#include "void_type.h"
30
31#include <iostream>
32#include <utility>
33
34namespace ChimeraTK {
35 csa_opcua_adapter::csa_opcua_adapter(boost::shared_ptr<ControlSystemPVManager> csManager, string configFile) {
36 this->csManager = std::move(csManager);
37
38 // Create new server adapter
39 adapter = std::make_shared<ua_uaadapter>(std::move(configFile));
40 UA_LOG_INFO(this->getLogger(), UA_LOGCATEGORY_USERLAND, "Start the mapping of %s", configFile.c_str());
41 UA_LOG_INFO(this->getLogger(), UA_LOGCATEGORY_USERLAND, "Create the adapter");
42
43 // Pre-Processing - get list of PV's to skip excluding
44 vector<string> mappedPvSources = adapter->getAllMappedPvSourceNames();
45 if(mappedPvSources.size() > 0) {
46 std::stringstream ss;
47 for(const auto& f : mappedPvSources) {
48 ss << "\n\t\t - " << f;
49 }
50 UA_LOG_INFO(this->getLogger(), UA_LOGCATEGORY_USERLAND,
51 "Mapped %zu process variables. To list them use logging level debug.", mappedPvSources.size());
52 UA_LOG_DEBUG(
53 this->getLogger(), UA_LOGCATEGORY_USERLAND, "List of mapped process variables: %s", ss.str().c_str());
54 }
55
56 vector<ProcessVariable::SharedPtr> allProcessVariables = this->csManager->getAllProcessVariables();
57
58 // start implicit var mapping
59 bool skip_var = false;
60 for(const ProcessVariable::SharedPtr& oneProcessVariable : allProcessVariables) {
61 std::type_info const& valueType = oneProcessVariable->getValueType();
62 if(valueType == typeid(Void)) {
63 /*skip_var = true;*/
64 UA_LOG_DEBUG(this->getLogger(), UA_LOGCATEGORY_USERLAND, "Skip Variable: Variable: %s has a void type",
65 oneProcessVariable->getName().c_str());
66 continue;
67 }
68 for(auto e : this->adapter->exclude) {
69 string suffix_1 = "/*", suffix_2 = "*";
70 if(e.rfind(suffix_1) == e.size() - suffix_1.size()) {
71 if(oneProcessVariable->getName().rfind(e.substr(0, e.size() - 1)) == 0) {
72 bool pv_used = false;
73 for(const auto& ele : mappedPvSources) {
74 if(ele == oneProcessVariable->getName().substr(1, oneProcessVariable->getName().size() - 1)) {
75 UA_LOG_WARNING(this->getLogger(), UA_LOGCATEGORY_USERLAND,
76 "Skip exclude node - Used in pv-mapping (directory match) PV: %s",
77 oneProcessVariable->getName().c_str());
78 pv_used = true;
79 break;
80 }
81 }
82 if(!pv_used) {
83 for(auto folder : this->adapter->folder_with_history) {
84 if(oneProcessVariable->getName().substr(0, folder.size()) == folder) {
85 UA_LOG_WARNING(this->getLogger(), UA_LOGCATEGORY_USERLAND,
86 "Skip exclude node - Used in folder history setting: %s", oneProcessVariable->getName().c_str());
87 pv_used = true;
88 break;
89 }
90 }
91 }
92 if(!pv_used) {
93 UA_LOG_INFO(this->getLogger(), UA_LOGCATEGORY_USERLAND, "Directory var exclude (/*) from mapping %s",
94 oneProcessVariable->getName().c_str());
95 skip_var = true;
96 }
97 }
98 }
99 else if(e.rfind(suffix_2) == e.size() - suffix_2.size()) {
100 if(oneProcessVariable->getName().rfind(e.substr(0, e.size() - 1), 0) == 0) {
101 bool pv_used = false;
102 for(const auto& ele : mappedPvSources) {
103 if(ele == oneProcessVariable->getName().substr(1, oneProcessVariable->getName().size() - 1)) {
104 UA_LOG_WARNING(this->getLogger(), UA_LOGCATEGORY_USERLAND,
105 "Skip exclude node - Used in pv-mapping (greedy match) PV: %s",
106 oneProcessVariable->getName().c_str());
107 pv_used = true;
108 break;
109 }
110 }
111 for(auto folder : this->adapter->folder_with_history) {
112 if(oneProcessVariable->getName().substr(1, folder.size() - 1) == folder) {
113 UA_LOG_WARNING(this->getLogger(), UA_LOGCATEGORY_USERLAND,
114 "Skip exclude node - Used in folder history setting: %s", oneProcessVariable->getName().c_str());
115 pv_used = true;
116 break;
117 }
118 }
119 if(!pv_used) {
120 UA_LOG_INFO(this->getLogger(), UA_LOGCATEGORY_USERLAND, "Greedy var exclude (*) from mapping %s",
121 oneProcessVariable->getName().c_str());
122 skip_var = true;
123 }
124 }
125 }
126 else if(oneProcessVariable->getName() == e) {
127 // check if this node is mapped later
128 if(std::find(mappedPvSources.begin(), mappedPvSources.end(), e.substr(1, e.size() - 1)) !=
129 mappedPvSources.end()) {
130 UA_LOG_WARNING(this->getLogger(), UA_LOGCATEGORY_USERLAND,
131 "Skip exclude node - Used in pv-mapping (direct match) PV: %s", oneProcessVariable->getName().c_str());
132 }
133 else {
134 UA_LOG_INFO(this->getLogger(), UA_LOGCATEGORY_USERLAND, "Direct exclude var (direct match) from mapping %s",
135 oneProcessVariable->getName().c_str());
136 skip_var = true;
137 }
138 for(auto folder : this->adapter->folder_with_history) {
139 if(oneProcessVariable->getName().substr(1, folder.size() - 1) == folder) {
140 UA_LOG_WARNING(this->getLogger(), UA_LOGCATEGORY_USERLAND,
141 "Skip exclude node - Used in folder history setting: %s", oneProcessVariable->getName().c_str());
142 skip_var = false;
143 break;
144 }
145 }
146 }
147 }
148 if(!skip_var) {
149 adapter->implicitVarMapping(oneProcessVariable->getName(), this->csManager);
150 }
151 else {
152 // variable is skipped and therefore unused
153 this->unusedVariables.insert(oneProcessVariable->getName());
154 skip_var = false;
155 }
156 }
157
158 adapter->applyMapping(this->csManager);
159 vector<string> allNotMappedVariables = adapter->getAllNotMappableVariablesNames();
160 if(!allNotMappedVariables.empty()) {
161 std::stringstream ss;
162 for(const string& var : allNotMappedVariables) {
163 ss << "\t" << var << endl;
164 }
165 UA_LOG_WARNING(this->getLogger(), UA_LOGCATEGORY_USERLAND,
166 "The following VariableNodes cant be mapped, because they are not member in PV-Manager: \n%s",
167 ss.str().c_str());
168 }
169 }
170
174
175 boost::shared_ptr<ControlSystemPVManager> const& csa_opcua_adapter::getControlSystemManager() const {
176 return this->csManager;
177 }
178
179 std::shared_ptr<ua_uaadapter> csa_opcua_adapter::getUAAdapter() {
180 return adapter;
181 }
182
184 if(!this->adapter_thread.joinable()) {
185 this->adapter_thread = std::thread(&ua_uaadapter::workerThread, this->adapter.get());
186 }
187 // start void observer loop
188 void_observer_data* data = (void_observer_data*)UA_calloc(1, sizeof(void_observer_data));
189 vector<ProcessVariable::SharedPtr> allProcessVariables = csManager->getAllProcessVariables();
190 for(const ProcessVariable::SharedPtr& oneProcessVariable : allProcessVariables) {
191 std::type_info const& valueType = oneProcessVariable->getValueType();
192 if(valueType == typeid(Void)) {
193 // Check if PV is writable - if not assume it is an VoidInput
194 if(!oneProcessVariable->isWriteable()) {
195 data->pvs.insert(data->pvs.end(), oneProcessVariable->getName());
196 UA_LOG_INFO(this->getLogger(), UA_LOGCATEGORY_USERLAND, "Adding variable %s to void thread.",
197 oneProcessVariable->getName().c_str());
198 }
199 else {
200 UA_LOG_WARNING(this->getLogger(), UA_LOGCATEGORY_USERLAND,
201 "Ignoring Void input %s. Void inputs are not yet supported.", oneProcessVariable->getName().c_str());
202 }
203 }
204 }
205 if(!data->pvs.empty()) {
206 add_void_event_type(adapter->mappedServer);
207 auto conf = adapter->get_server_config();
208 data->rootFolder = conf.rootFolder;
209 data->adapter = this;
210 data->mappedServer = adapter->getMappedServer();
211 data->csManager = csManager;
212 this->observer_thread = std::thread(&startVoidObserverThread, data, this->getLogger());
213 this->observer_thread.detach();
214 }
215 else {
216 UA_free(data);
217 }
218 }
219
221 if(this->adapter_thread.joinable()) {
222 adapter->running = false;
223 this->adapter_thread.join();
224 }
225 if(this->observer_thread.joinable()) {
226 this->observer_thread.join();
227 }
228 }
229
231 return this->adapter_thread.joinable();
232 }
233 const set<string>& csa_opcua_adapter::getUnusedVariables() const {
234 return unusedVariables;
235 }
236
237 const UA_Logger* csa_opcua_adapter::getLogger() {
238 return adapter->server_config->logging;
239 }
240} // namespace ChimeraTK
bool isRunning()
Checks if the opcua server is still running and return the suitable bool value.
~csa_opcua_adapter()
Destructor to stop the running thread, hence it stops the OPC UA server.
void start()
Start all objects in single threads for this case only the opc ua server.
csa_opcua_adapter(boost::shared_ptr< ControlSystemPVManager > csManager, string configFile)
Constructor for ControlSystemAdapter-OPC-UA-Adapter.
const UA_Logger * getLogger()
Get the adapter logger.
const set< string > & getUnusedVariables() const
std::shared_ptr< ua_uaadapter > getUAAdapter()
Return the uaadapter, hence the OPC UA server.
void stop()
Stop all objects in single threads for this case only the opc ua server.
boost::shared_ptr< ControlSystemPVManager > const & getControlSystemManager() const
Return the ControlsystemPVManager of the class.
void workerThread()
Create and start a thread for the opcua server instance.
boost::shared_ptr< ChimeraTK::ControlSystemPVManager > csManager
void startVoidObserverThread(void_observer_data *data, const UA_Logger *logger)
UA_StatusCode add_void_event_type(UA_Server *server)
vector< std::string > pvs
Definition void_type.h:34
boost::shared_ptr< ControlSystemPVManager > csManager
Definition void_type.h:30
csa_opcua_adapter * adapter
Definition void_type.h:33