ChimeraTK-ControlSystemAdapter-OPCUAAdapter 04.00.05
Loading...
Searching...
No Matches
void_type.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) 2023-2024 Fraunhofer IOSB (Author: Florian Düwel)
18 */
19
20#include "void_type.h"
21
22#include "csa_processvariable.h"
23#include "open62541/plugin/log_stdout.h"
24
25#include <functional>
26using namespace std;
27namespace ChimeraTK {
28 static UA_StatusCode fireVoidEvent(void_observer_data* data, const string& pv_name, const UA_Logger* logger) {
29 UA_NodeId outId;
30 UA_NodeId void_event_NodeId = UA_NODEID_STRING(1, const_cast<char*>("VoidEventType"));
31 UA_StatusCode retval = UA_Server_createEvent(data->mappedServer, void_event_NodeId, &outId);
32 if(retval != UA_STATUSCODE_GOOD) {
33 string error_message = "Creation of the void Event failed with StatusCode ";
34 error_message.append(UA_StatusCode_name(retval));
35 throw std::logic_error(error_message);
36 }
37 auto pv = data->csManager->getProcessVariable(pv_name);
38 auto eventValidity = static_cast<UA_Int32>(pv->dataValidity());
39 retval = UA_Server_writeObjectProperty_scalar(data->mappedServer, outId,
40 UA_QUALIFIEDNAME(1, const_cast<char*>("Validity")), &eventValidity, &UA_TYPES[UA_TYPES_INT32]);
41 if(retval != UA_STATUSCODE_GOOD) {
42 string error_message = "Setting void event validity failed with StatusCode ";
43 error_message.append(UA_StatusCode_name(retval));
44 throw std::logic_error(error_message);
45 }
46 UA_String eventSourceName = UA_String_fromChars(pv_name.c_str());
47 retval = UA_Server_writeObjectProperty_scalar(data->mappedServer, outId,
48 UA_QUALIFIEDNAME(0, const_cast<char*>("SourceName")), &eventSourceName, &UA_TYPES[UA_TYPES_STRING]);
49 if(retval != UA_STATUSCODE_GOOD) {
50 string error_message = "Setting void event SourceName failed with StatusCode ";
51 error_message.append(UA_StatusCode_name(retval));
52 throw std::logic_error(error_message);
53 }
54 UA_String_clear(&eventSourceName);
55 UA_LocalizedText eventMessage =
56 UA_LOCALIZEDTEXT(const_cast<char*>("en-US"), const_cast<char*>("ChimeraTK::Void written."));
57 retval = UA_Server_writeObjectProperty_scalar(data->mappedServer, outId,
58 UA_QUALIFIEDNAME(0, const_cast<char*>("Message")), &eventMessage, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
59 if(retval != UA_STATUSCODE_GOOD) {
60 string error_message = "Setting void event Message failed with StatusCode ";
61 error_message.append(UA_StatusCode_name(retval));
62 throw std::logic_error(error_message);
63 }
64 UA_UInt16 eventSeverity = 100;
65 retval = UA_Server_writeObjectProperty_scalar(data->mappedServer, outId,
66 UA_QUALIFIEDNAME(0, const_cast<char*>("Severity")), &eventSeverity, &UA_TYPES[UA_TYPES_UINT16]);
67 if(retval != UA_STATUSCODE_GOOD) {
68 string error_message = "Setting void event Severity failed with StatusCode ";
69 error_message.append(UA_StatusCode_name(retval));
70 throw std::logic_error(error_message);
71 }
72 UA_UInt16_clear(&eventSeverity);
73 UA_NodeId id;
74 UA_NodeId_init(&id);
75 id.namespaceIndex = 1;
76 id.identifierType = UA_NODEIDTYPE_STRING;
77 id.identifier.string = UA_String_fromChars((data->rootFolder + /*"/" +*/ pv_name).c_str());
78 retval = UA_Server_writeObjectProperty_scalar(
79 data->mappedServer, outId, UA_QUALIFIEDNAME(1, const_cast<char*>("cs_path")), &id, &UA_TYPES[UA_TYPES_NODEID]);
80 if(retval != UA_STATUSCODE_GOOD) {
81 string error_message = "Setting void event cs_path failed with StatusCode ";
82 error_message.append(UA_StatusCode_name(retval));
83 throw std::logic_error(error_message);
84 }
85 UA_NodeId_clear(&id);
86 UA_String eventDescription = UA_String_fromChars(pv->getDescription().c_str());
87 const UA_String null_str = UA_STRING_NULL;
88 if(UA_String_equal(&eventDescription, &null_str) != true) {
89 retval = UA_Server_writeObjectProperty_scalar(data->mappedServer, outId,
90 UA_QUALIFIEDNAME(1, const_cast<char*>("Description")), &eventDescription, &UA_TYPES[UA_TYPES_STRING]);
91 if(retval != UA_STATUSCODE_GOOD) {
92 string error_message = "Setting void event description failed with StatusCode ";
93 error_message.append(UA_StatusCode_name(retval));
94 throw std::logic_error(error_message);
95 }
96 }
97 UA_String_clear(&eventDescription);
98 UA_String eventType = UA_String_fromChars("Void");
99 retval = UA_Server_writeObjectProperty_scalar(data->mappedServer, outId,
100 UA_QUALIFIEDNAME(1, const_cast<char*>("Type")), &eventType, &UA_TYPES[UA_TYPES_STRING]);
101 if(retval != UA_STATUSCODE_GOOD) {
102 string error_message = "Setting void event Type failed with StatusCode ";
103 error_message.append(UA_StatusCode_name(retval));
104 throw std::logic_error(error_message);
105 }
106 UA_String_clear(&eventType);
107 UA_DateTime eventTime = UA_DateTime_now();
108 retval = UA_Server_writeObjectProperty_scalar(data->mappedServer, outId,
109 UA_QUALIFIEDNAME(0, const_cast<char*>("Time")), &eventTime, &UA_TYPES[UA_TYPES_DATETIME]);
110 if(retval != UA_STATUSCODE_GOOD) {
111 string error_message = "Setting void event Time failed with StatusCode ";
112 error_message.append(UA_StatusCode_name(retval));
113 throw std::logic_error(error_message);
114 }
115 UA_DateTime_clear(&eventTime);
116
117 retval = UA_Server_triggerEvent(data->mappedServer, outId, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), nullptr, UA_TRUE);
118 if(retval != UA_STATUSCODE_GOOD) {
119 string error_message = "Triggering void event failed with StatusCode ";
120 error_message.append(UA_StatusCode_name(retval));
121 throw std::logic_error(error_message);
122 }
123 UA_LOG_DEBUG(logger, UA_LOGCATEGORY_USERLAND, "Fire Void Event for PV with ID %s", pv_name.c_str());
124 return retval;
125 }
126
127 static void updateLoop(void_observer_data* data, const UA_Logger* logger) {
128 try {
129 ReadAnyGroup group;
130 std::map<TransferElementID, std::string> idToNameMap;
131 for(auto pv : data->pvs) {
132 group.add(data->csManager->getProcessArray<Void>(pv));
133 idToNameMap[data->csManager->getProcessArray<Void>(pv)->getId()] = pv;
134 //}
135 }
136 /*vector<ProcessVariable::SharedPtr> allProcessVariables = data->csManager->getAllProcessVariables();
137 for(const ProcessVariable::SharedPtr& oneProcessVariable : allProcessVariables) {
138 std::type_info const& valueType = oneProcessVariable->getValueType();
139 if(valueType == typeid(Void)) {
140 // Check if PV is writable - if not assume it is an VoidInput
141 if(!oneProcessVariable->isWriteable()) {
142 group.add(data->csManager->getProcessArray<Void>(oneProcessVariable->getName()));
143 idToNameMap[data->csManager->getProcessArray<Void>(oneProcessVariable->getName())->getId()] =
144 oneProcessVariable->getName();
145 }
146 else {
147 UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
148 "Ignoring Void input %s. Void inputs are not yet supported.", oneProcessVariable->getName().c_str());
149 }
150 }
151 }*/
152 group.finalise();
153
154 while(data->adapter->isRunning()) {
155 // wait for next event
156 auto id = group.readAny();
157 fireVoidEvent(data, idToNameMap.at(id), logger);
158 }
159 UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "Void observer thread terminated.");
160 UA_free(data);
161 }
162 catch(boost::thread_interrupted&) {
163 UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "Void observer thread terminated.");
164 UA_free(data);
165 }
166 }
167
168 void startVoidObserverThread(void_observer_data* data, const UA_Logger* logger) {
169 updateLoop(data, logger);
170 }
171
172 /*
173 * declare the eventtype for void nodes and add it to the server
174 * */
175 UA_StatusCode addEventProperty(UA_Server* server, UA_NodeId eventNodeId, char* property_name, UA_NodeId dtype) {
176 UA_NodeId propertyNodeId;
177 UA_VariableAttributes vattr = UA_VariableAttributes_default;
178 vattr.dataType = dtype;
179 vattr.displayName = UA_LOCALIZEDTEXT(const_cast<char*>("en-us"), property_name);
180 vattr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
181 UA_StatusCode retval = UA_Server_addVariableNode(server, UA_NODEID_NULL, eventNodeId,
182 UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), UA_QUALIFIEDNAME(1, property_name),
183 UA_NODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), vattr, nullptr, &propertyNodeId);
184 if(retval != UA_STATUSCODE_GOOD) {
185 string error_message = "Failed to add the property ";
186 error_message.append(property_name);
187 error_message.append(" with StatusCode ");
188 error_message.append(UA_StatusCode_name(retval));
189 throw std::logic_error(error_message);
190 }
191 retval = UA_Server_addReference(server, propertyNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE),
192 UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY), true);
193 if(retval != UA_STATUSCODE_GOOD) {
194 string error_message = "Failed to set the reference to property ";
195 error_message.append(property_name);
196 error_message.append(" mandatory with StatusCode ");
197 error_message.append(UA_StatusCode_name(retval));
198 throw std::logic_error(error_message);
199 }
200 return retval;
201 }
202
203 UA_StatusCode add_void_event_type(UA_Server* server) {
204 UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
205 attr.displayName = UA_LOCALIZEDTEXT(const_cast<char*>("en-US"), const_cast<char*>("VoidEventType"));
206 attr.description = UA_LOCALIZEDTEXT(const_cast<char*>("en-US"), const_cast<char*>("The EventType for void nodes"));
207 UA_NodeId void_event_NodeId = UA_NODEID_STRING(1, const_cast<char*>("VoidEventType"));
208 UA_StatusCode retval = UA_Server_addObjectTypeNode(server, void_event_NodeId,
209 UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE), UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
210 UA_QUALIFIEDNAME(1, const_cast<char*>("VoidEventType")), attr, nullptr, nullptr);
211 if(retval != UA_STATUSCODE_GOOD) {
212 string error_message = "Failed to add the VoidEventType with StatusCode ";
213 error_message.append(UA_StatusCode_name(retval));
214 throw std::logic_error(error_message);
215 }
216 retval |=
217 addEventProperty(server, void_event_NodeId, const_cast<char*>("cs_path"), UA_TYPES[UA_TYPES_NODEID].typeId);
218 retval |=
219 addEventProperty(server, void_event_NodeId, const_cast<char*>("Description"), UA_TYPES[UA_TYPES_STRING].typeId);
220 retval |= addEventProperty(server, void_event_NodeId, const_cast<char*>("Type"), UA_TYPES[UA_TYPES_STRING].typeId);
221 retval |=
222 addEventProperty(server, void_event_NodeId, const_cast<char*>("Validity"), UA_TYPES[UA_TYPES_INT32].typeId);
223 return retval;
224 }
225} // namespace ChimeraTK
void startVoidObserverThread(void_observer_data *data, const UA_Logger *logger)
UA_StatusCode add_void_event_type(UA_Server *server)
UA_StatusCode addEventProperty(UA_Server *server, UA_NodeId eventNodeId, char *property_name, UA_NodeId dtype)