24 #include "csa_config.h"
30 #include "open62541/plugin/log_stdout.h"
38 boost::shared_ptr<ControlSystemPVManager>
csManager,
const UA_Logger*
logger,
string overwriteNodeString)
40 nodeStringIdOverwrite(std::move(overwriteNodeString)), array(false),
ua_mapped_class(server, basenodeid) {
41 this->mapSelfToNamespace(
logger);
47 UA_NodeId_clear(&this->ownNodeId);
51 const UA_NodeId* ,
void* ,
const UA_NodeId* ,
void* nodeContext,
52 UA_Boolean includeSourceTimeStamp,
const UA_NumericRange* , UA_DataValue* value) {
55 UA_String ua_val = UA_String_fromChars((
char*)thisObj->getName().c_str());
56 UA_Variant_setScalarCopy(&value->value, &ua_val, &UA_TYPES[UA_TYPES_STRING]);
57 UA_String_clear(&ua_val);
58 value->hasValue =
true;
59 if(includeSourceTimeStamp) {
60 value->sourceTimestamp = thisObj->getSourceTimeStamp();
61 value->hasSourceTimestamp =
true;
63 return UA_STATUSCODE_GOOD;
72 const UA_NodeId* ,
void* ,
const UA_NodeId* ,
void* nodeContext,
73 const UA_NumericRange* ,
const UA_DataValue* value) {
77 s = (
char*)malloc(((UA_String) * ((UA_String*)value->value.data)).length + 1);
78 memset(s, 0, ((UA_String) * ((UA_String*)value->value.data)).length + 1);
79 memcpy(s, ((UA_String) * ((UA_String*)value->value.data)).data,
80 ((UA_String) * ((UA_String*)value->value.data)).length);
81 cpps.assign(s, ((UA_String) * ((UA_String*)value->value.data)).length);
83 theClass->setEngineeringUnit(cpps);
84 return UA_STATUSCODE_GOOD;
88 this->engineeringUnit = std::move(engineeringUnit);
92 const UA_NodeId* ,
void* ,
const UA_NodeId* ,
void* nodeContext,
93 UA_Boolean includeSourceTimeStamp,
const UA_NumericRange* , UA_DataValue* value) {
96 UA_String ua_val = UA_String_fromChars((
char*)thisObj->getEngineeringUnit().c_str());
97 UA_Variant_setScalarCopy(&value->value, &ua_val, &UA_TYPES[UA_TYPES_STRING]);
98 UA_String_clear(&ua_val);
99 value->hasValue =
true;
100 if(includeSourceTimeStamp) {
101 value->sourceTimestamp = thisObj->getSourceTimeStamp();
102 value->hasSourceTimestamp =
true;
104 return UA_STATUSCODE_GOOD;
108 if(!this->engineeringUnit.empty()) {
109 return this->engineeringUnit;
112 this->engineeringUnit = this->csManager->getProcessVariable(this->namePV)->getUnit();
113 return this->engineeringUnit;
119 const UA_NodeId* ,
void* ,
const UA_NodeId* ,
void* nodeContext,
120 const UA_NumericRange* ,
const UA_DataValue* value) {
124 s = (
char*)malloc(((UA_String) * ((UA_String*)value->value.data)).length + 1);
125 memset(s, 0, ((UA_String) * ((UA_String*)value->value.data)).length + 1);
126 memcpy(s, ((UA_String) * ((UA_String*)value->value.data)).data,
127 ((UA_String) * ((UA_String*)value->value.data)).length);
128 cpps.assign(s, ((UA_String) * ((UA_String*)value->value.data)).length);
130 theClass->setDescription(cpps);
131 return UA_STATUSCODE_GOOD;
135 this->description = std::move(description);
139 const UA_NodeId* ,
void* ,
const UA_NodeId* ,
void* nodeContext,
140 UA_Boolean includeSourceTimeStamp,
const UA_NumericRange* , UA_DataValue* value) {
143 UA_String ua_val = UA_String_fromChars((
char*)thisObj->getDescription().c_str());
144 UA_Variant_setScalarCopy(&value->value, &ua_val, &UA_TYPES[UA_TYPES_STRING]);
145 UA_String_clear(&ua_val);
146 value->hasValue =
true;
147 if(includeSourceTimeStamp) {
148 value->sourceTimestamp = thisObj->getSourceTimeStamp();
149 value->hasSourceTimestamp =
true;
151 return UA_STATUSCODE_GOOD;
155 const UA_NodeId* ,
void* ,
const UA_NodeId* ,
void* nodeContext,
156 UA_Boolean includeSourceTimeStamp,
const UA_NumericRange* , UA_DataValue* value) {
158 DataValidity dv = thisObj->csManager->getProcessVariable(thisObj->namePV)->dataValidity();
161 case DataValidity::ok:
164 case DataValidity::faulty:
170 UA_Variant_setScalarCopy(&value->value, &validity, &UA_TYPES[UA_TYPES_INT32]);
171 value->hasValue =
true;
172 if(includeSourceTimeStamp) {
173 value->sourceTimestamp = thisObj->getSourceTimeStamp();
174 value->hasSourceTimestamp =
true;
176 return UA_STATUSCODE_GOOD;
180 if(!this->description.empty()) {
181 return this->description;
184 this->description = this->csManager->getProcessVariable(this->namePV)->getDescription();
185 return this->description;
191 const UA_NodeId* ,
void* ,
const UA_NodeId* ,
void* nodeContext,
192 UA_Boolean includeSourceTimeStamp,
const UA_NumericRange* , UA_DataValue* value) {
195 UA_String ua_val = UA_String_fromChars((
char*)thisObj->getType().c_str());
196 UA_Variant_setScalarCopy(&value->value, &ua_val, &UA_TYPES[UA_TYPES_STRING]);
197 UA_String_clear(&ua_val);
198 value->hasValue =
true;
199 if(includeSourceTimeStamp) {
200 value->sourceTimestamp = thisObj->getSourceTimeStamp();
201 value->hasSourceTimestamp =
true;
203 return UA_STATUSCODE_GOOD;
208 std::type_info
const& valueType = this->csManager->getProcessVariable(this->namePV)->getValueType();
209 if(valueType ==
typeid(int8_t))
211 else if(valueType ==
typeid(uint8_t))
213 else if(valueType ==
typeid(int16_t))
215 else if(valueType ==
typeid(uint16_t))
217 else if(valueType ==
typeid(int32_t))
219 else if(valueType ==
typeid(uint32_t))
221 else if(valueType ==
typeid(int64_t))
223 else if(valueType ==
typeid(uint64_t))
225 else if(valueType ==
typeid(
float))
227 else if(valueType ==
typeid(
double))
229 else if(valueType ==
typeid(
string))
231 else if(valueType ==
typeid(Boolean))
233 else if(valueType ==
typeid(Void))
236 return "Unsupported type";
241 const UA_NodeId* ,
void* ,
const UA_NodeId* ,
void* nodeContext,
242 UA_Boolean includeSourceTimeStamp,
const UA_NumericRange* range, UA_DataValue* value) {
244 UA_StatusCode rv = UA_STATUSCODE_GOOD;
245 rv = thisObj->
getValue<T>(&value->value, range);
246 if(rv == UA_STATUSCODE_GOOD) {
247 value->hasValue =
true;
248 if(includeSourceTimeStamp) {
249 value->sourceTimestamp = thisObj->getSourceTimeStamp();
250 value->hasSourceTimestamp =
true;
258 UA_StatusCode rv = UA_STATUSCODE_BADINTERNALERROR;
259 if(this->csManager->getProcessVariable(this->namePV)->isReadable()) {
260 this->csManager->getProcessArray<T>(this->namePV)->readLatest();
262 if(this->csManager->getProcessArray<T>(this->namePV)->accessChannel(0).size() == 1) {
263 T ival = this->csManager->getProcessArray<T>(this->namePV)->accessChannel(0).at(0);
264 rv = UA_Variant_setScalarCopy(v, &ival, &UA_TYPES[fusion::at_key<T>(typesMap)]);
267 std::vector<T> iarr = this->csManager->getProcessArray<T>(this->namePV)->accessChannel(0);
268 v->type = &UA_TYPES[fusion::at_key<T>(typesMap)];
269 if(range !=
nullptr) {
272 UA_Variant tmpVariant;
273 UA_Variant_setArray(&tmpVariant, iarr.data(), iarr.size(), &UA_TYPES[fusion::at_key<T>(typesMap)]);
274 rv = UA_Variant_copyRange(&tmpVariant, v, *range);
277 rv = UA_Variant_setArrayCopy(v, iarr.data(), iarr.size(), &UA_TYPES[fusion::at_key<T>(typesMap)]);
284 UA_StatusCode ua_processvariable::getValue<string>(UA_Variant* v,
const UA_NumericRange* ) {
285 UA_StatusCode rv = UA_STATUSCODE_BADINTERNALERROR;
286 if(this->csManager->getProcessVariable(this->namePV)->isReadable()) {
287 this->csManager->getProcessArray<
string>(this->namePV)->readLatest();
289 if(this->csManager->getProcessArray<
string>(this->namePV)->accessChannel(0).size() == 1) {
290 string sval = this->csManager->getProcessArray<
string>(this->namePV)->accessChannel(0).at(0);
291 UA_String ua_val = UA_String_fromChars((
char*)sval.c_str());
292 rv = UA_Variant_setScalarCopy(v, &ua_val, &UA_TYPES[UA_TYPES_STRING]);
293 UA_String_clear(&ua_val);
296 std::vector<string> sarr = this->csManager->getProcessArray<
string>(this->namePV)->accessChannel(0);
297 auto* sarrayval =
new UA_String[sarr.size()];
298 for(
size_t i = 0; i < sarr.size(); i++) {
299 sarrayval[i] = UA_String_fromChars((
char*)sarr[i].c_str());
301 rv = UA_Variant_setArrayCopy(v, sarrayval, sarr.size(), &UA_TYPES[UA_TYPES_STRING]);
309 const UA_NodeId* ,
void* ,
const UA_NodeId* ,
void* nodeContext,
310 const UA_NumericRange* ,
const UA_DataValue* value) {
311 UA_StatusCode retval = UA_STATUSCODE_BADINTERNALERROR;
313 retval = theClass->
setValue<T>(&value->value);
319 UA_StatusCode retval = UA_STATUSCODE_BADINTERNALERROR;
321 if(this->csManager->getProcessVariable(this->namePV)->isWriteable()) {
322 vector<T> valueArray;
323 if(UA_Variant_isScalar(data) && (!array)) {
324 T value = *((T*)data->data);
325 valueArray.push_back(value);
327 else if((!UA_Variant_isScalar(data)) && array) {
328 auto* v = (T*)data->data;
329 valueArray.resize(data->arrayLength);
330 for(
size_t i = 0; i < valueArray.size(); i++) {
331 valueArray.at(i) = v[i];
333 if(this->csManager->getProcessArray<T>(this->namePV)->accessChannel(0).size() != data->arrayLength) {
334 return UA_STATUSCODE_BADINVALIDARGUMENT;
337 this->csManager->getProcessArray<T>(this->namePV)->accessChannel(0) = valueArray;
338 this->csManager->getProcessArray<T>(this->namePV)->write();
339 retval = UA_STATUSCODE_GOOD;
342 retval = UA_STATUSCODE_BADNOTWRITABLE;
349 UA_StatusCode ua_processvariable::setValue<std::string>(
const UA_Variant* data) {
350 UA_StatusCode retval = UA_STATUSCODE_BADINTERNALERROR;
352 if(this->
csManager->getProcessVariable(this->namePV)->isWriteable()) {
353 vector<string> valueArray;
354 if(UA_Variant_isScalar(data) && (!array)) {
358 valueArray.push_back(cpps);
360 else if((!UA_Variant_isScalar(data)) && array) {
362 auto* vdata = (UA_String*)data->data;
363 valueArray.resize(data->arrayLength);
364 for(uint32_t i = 0; i < valueArray.size(); i++) {
367 valueArray.at(i) = cpps;
369 if(this->
csManager->getProcessArray<
string>(this->namePV)->accessChannel(0).size() != data->arrayLength) {
370 return UA_STATUSCODE_BADINVALIDARGUMENT;
373 this->
csManager->getProcessArray<
string>(this->namePV)->accessChannel(0) = valueArray;
374 this->
csManager->getProcessArray<
string>(this->namePV)->write();
375 retval = UA_STATUSCODE_GOOD;
378 retval = UA_STATUSCODE_BADNOTWRITABLE;
384 UA_StatusCode ua_processvariable::mapSelfToNamespace(
const UA_Logger*
logger) {
385 UA_StatusCode retval = UA_STATUSCODE_GOOD;
386 UA_NodeId createdNodeId = UA_NODEID_NULL;
387 if(!nodeStringIdOverwrite.empty()) this->nameNew = nodeStringIdOverwrite;
389 if(UA_NodeId_equal(&this->
baseNodeId, &createdNodeId))
390 return UA_STATUSCODE_GOOD;
392 UA_LocalizedText description;
393 description = UA_LOCALIZEDTEXT(
const_cast<char*
>(
"en_US"),
394 const_cast<char*
>(this->csManager->getProcessVariable(this->namePV)->getDescription().c_str()));
397 UA_VariableAttributes attr;
398 UA_VariableAttributes_init(&attr);
399 attr = UA_VariableAttributes_default;
401 attr.minimumSamplingInterval = -1.;
402 attr.displayName = UA_LOCALIZEDTEXT(
const_cast<char*
>(
"en_US"),
const_cast<char*
>(this->nameNew.c_str()));
403 attr.description = description;
404 attr.dataType = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE);
406 if(this->csManager->getProcessVariable(this->namePV)->isWriteable()) {
407 attr.writeMask = UA_ACCESSLEVELMASK_READ ^ UA_ACCESSLEVELMASK_WRITE;
408 attr.accessLevel = UA_ACCESSLEVELMASK_READ ^ UA_ACCESSLEVELMASK_WRITE;
413 string baseNodeIdName;
414 if(this->
baseNodeId.identifierType == UA_NODEIDTYPE_STRING) {
417 if(!baseNodeIdName.empty()) {
418 baseNodeIdName.resize(baseNodeIdName.size() - 3);
424 UA_NODEID_STRING(1,
const_cast<char*
>((baseNodeIdName +
"/" + this->nameNew).c_str())),
425 &result) == UA_STATUSCODE_GOOD) {
426 return UA_STATUSCODE_BADNODEIDEXISTS;
429 UA_NODEID_STRING(1,
const_cast<char*
>((baseNodeIdName +
"/" + this->nameNew).c_str())), this->
baseNodeId,
430 UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), UA_QUALIFIEDNAME(1,
const_cast<char*
>(this->nameNew.c_str())),
431 UA_NODEID_NUMERIC(CSA_NSID, 1001), attr, (
void*)
this, &createdNodeId);
432 UA_NodeId_copy(&createdNodeId, &this->ownNodeId);
437 this->addPVChildNodes(createdNodeId, baseNodeIdName, mapDs);
439 UA_Variant arrayDimensions;
440 UA_Variant_init(&arrayDimensions);
442 std::type_info
const& valueType = this->csManager->getProcessVariable(this->namePV)->getValueType();
445 mapElem.
typeTemplateId = UA_NODEID_NUMERIC(CSA_NSID, CSA_NSID_VARIABLE);
446 mapElem.description = description;
448 UA_Variant uaArrayDimensions;
449 UA_UInt32 arrayDims[1];
451 if(valueType ==
typeid(int8_t)) {
452 arrayDims[0] = typeSpecificSetup<int8_t>(mapElem, createdNodeId);
454 else if(valueType ==
typeid(uint8_t)) {
455 arrayDims[0] = typeSpecificSetup<uint8_t>(mapElem, createdNodeId);
457 else if(valueType ==
typeid(int16_t)) {
458 arrayDims[0] = typeSpecificSetup<int16_t>(mapElem, createdNodeId);
460 else if(valueType ==
typeid(uint16_t)) {
461 arrayDims[0] = typeSpecificSetup<uint16_t>(mapElem, createdNodeId);
463 else if(valueType ==
typeid(int32_t)) {
464 arrayDims[0] = typeSpecificSetup<int32_t>(mapElem, createdNodeId);
466 else if(valueType ==
typeid(uint32_t)) {
467 arrayDims[0] = typeSpecificSetup<uint32_t>(mapElem, createdNodeId);
469 else if(valueType ==
typeid(int64_t)) {
470 arrayDims[0] = typeSpecificSetup<int64_t>(mapElem, createdNodeId);
472 else if(valueType ==
typeid(uint64_t)) {
473 arrayDims[0] = typeSpecificSetup<uint64_t>(mapElem, createdNodeId);
475 else if(valueType ==
typeid(
float)) {
476 arrayDims[0] = typeSpecificSetup<float>(mapElem, createdNodeId);
478 else if(valueType ==
typeid(
double)) {
479 arrayDims[0] = typeSpecificSetup<double>(mapElem, createdNodeId);
481 else if(valueType ==
typeid(
string)) {
482 arrayDims[0] = typeSpecificSetup<std::string>(mapElem, createdNodeId);
484 else if(valueType ==
typeid(Boolean)) {
485 arrayDims[0] = typeSpecificSetup<Boolean>(mapElem, createdNodeId);
487 else if(valueType !=
typeid(Void)) {
489 auto* demangledName = abi::__cxa_demangle(valueType.name(),
nullptr,
nullptr, &status);
492 UA_LOG_WARNING(
logger, UA_LOGCATEGORY_USERLAND,
"Cannot proxy unknown type %s for variable %s", demangledName,
493 this->namePV.c_str());
497 UA_LOG_WARNING(
logger, UA_LOGCATEGORY_USERLAND,
498 "Cannot proxy unknown type %s (demangling failed) for variable %s", valueType.name(), this->namePV.c_str());
502 if(!this->csManager->getProcessVariable(this->namePV)->isWriteable()) {
503 mapElem.dataSource.write =
nullptr;
506 UA_Server_writeValueRank(this->
mappedServer, createdNodeId, UA_VALUERANK_ONE_DIMENSION);
507 UA_Variant_setArray(&uaArrayDimensions, arrayDims, 1, &UA_TYPES[UA_TYPES_UINT32]);
508 UA_Server_writeArrayDimensions(this->
mappedServer, createdNodeId, uaArrayDimensions);
511 UA_Server_writeValueRank(this->
mappedServer, createdNodeId, UA_VALUERANK_SCALAR);
515 UA_NodeId_copy(&createdNodeId, &mapElem.concreteNodeId);
516 mapDs.push_back(mapElem);
518 UA_NodeId nodeIdVariableType = UA_NODEID_NUMERIC(CSA_NSID, CSA_NSID_VARIABLE);
521 for(
auto i : mapDs) {
522 retval |= UA_Server_setVariableNode_dataSource(this->
mappedServer, i.concreteNodeId, i.dataSource);
523 UA_NodeId_clear(&i.concreteNodeId);
524 UA_NodeId_clear(&i.typeTemplateId);
526 UA_NodeId_clear(&createdNodeId);
530 UA_StatusCode ua_processvariable::addPVChildNodes(
532 UA_NodeId createdNodeId = UA_NODEID_NULL;
533 UA_VariableAttributes attr;
534 UA_StatusCode addResult;
538 mapElemName.
typeTemplateId = UA_NODEID_NUMERIC(CSA_NSID, CSA_NSID_VARIABLE_NAME);
539 mapElemName.description = UA_LOCALIZEDTEXT(
const_cast<char*
>(
"en_US"),
const_cast<char*
>(
""));
541 mapElemName.dataSource.write =
nullptr;
543 UA_VariableAttributes_init(&attr);
544 attr = UA_VariableAttributes_default;
545 attr.displayName = UA_LOCALIZEDTEXT(
const_cast<char*
>(
"en_US"),
const_cast<char*
>(
"Name"));
546 attr.description = UA_LOCALIZEDTEXT(
const_cast<char*
>(
"en_US"),
const_cast<char*
>(
""));
547 attr.valueRank = UA_VALUERANK_SCALAR;
548 attr.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
549 UA_String opcua_node_variable_t_ns_2_i_6004_variant_DataContents = UA_STRING_ALLOC(
const_cast<char*
>(
""));
550 UA_Variant_setScalar(
551 &attr.value, &opcua_node_variable_t_ns_2_i_6004_variant_DataContents, &UA_TYPES[UA_TYPES_STRING]);
552 addResult = UA_Server_addVariableNode(this->
mappedServer,
553 UA_NODEID_STRING(1,
const_cast<char*
>((baseNodePath +
"/" + this->nameNew +
"/Name").c_str())), pvNodeId,
554 UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), UA_QUALIFIEDNAME(1,
const_cast<char*
>(
"Name")),
555 UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), attr,
this, &createdNodeId);
556 if(addResult == UA_STATUSCODE_GOOD) {
557 UA_NodeId nameVariable = UA_NODEID_NUMERIC(CSA_NSID, CSA_NSID_VARIABLE_NAME);
559 UA_NodeId_copy(&createdNodeId, &mapElemName.concreteNodeId);
560 map.push_back(mapElemName);
563 UA_NodeId_clear(&createdNodeId);
566 UA_NodeId_clear(&createdNodeId);
567 createdNodeId = UA_NODEID_NULL;
571 mapElemDesc.
typeTemplateId = UA_NODEID_NUMERIC(CSA_NSID, CSA_NSID_VARIABLE_DESC);
572 mapElemDesc.description = UA_LOCALIZEDTEXT(
const_cast<char*
>(
"en_US"),
const_cast<char*
>(
""));
574 mapElemDesc.dataSource.write =
nullptr;
576 UA_VariableAttributes_init(&attr);
577 attr = UA_VariableAttributes_default;
578 attr.displayName = UA_LOCALIZEDTEXT(
const_cast<char*
>(
"en_US"),
const_cast<char*
>(
"Description"));
579 attr.description = UA_LOCALIZEDTEXT(
const_cast<char*
>(
"en_US"),
const_cast<char*
>(
""));
580 attr.accessLevel = UA_ACCESSLEVELMASK_READ;
581 attr.userAccessLevel = UA_ACCESSLEVELMASK_READ;
582 attr.valueRank = UA_VALUERANK_SCALAR;
583 attr.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
584 UA_String opcua_node_variable_t_ns_2_i_6001_variant_DataContents = UA_STRING(
const_cast<char*
>(
""));
585 UA_Variant_setScalar(
586 &attr.value, &opcua_node_variable_t_ns_2_i_6001_variant_DataContents, &UA_TYPES[UA_TYPES_STRING]);
587 addResult = UA_Server_addVariableNode(this->
mappedServer,
588 UA_NODEID_STRING(1,
const_cast<char*
>((baseNodePath +
"/" + this->nameNew +
"/Description").c_str())), pvNodeId,
589 UA_NODEID_NUMERIC(0, 47), UA_QUALIFIEDNAME(1,
const_cast<char*
>(
"Description")), UA_NODEID_NUMERIC(0, 63), attr,
590 this, &createdNodeId);
591 if(addResult == UA_STATUSCODE_GOOD) {
592 UA_NodeId descVariable = UA_NODEID_NUMERIC(CSA_NSID, CSA_NSID_VARIABLE_DESC);
594 UA_NodeId_copy(&createdNodeId, &mapElemDesc.concreteNodeId);
595 map.push_back(mapElemDesc);
598 UA_NodeId_clear(&createdNodeId);
602 UA_NodeId_clear(&createdNodeId);
603 createdNodeId = UA_NODEID_NULL;
607 mapElemEU.
typeTemplateId = UA_NODEID_NUMERIC(CSA_NSID, CSA_NSID_VARIABLE_UNIT);
608 mapElemEU.description = UA_LOCALIZEDTEXT(
const_cast<char*
>(
"en_US"),
const_cast<char*
>(
""));
610 mapElemEU.dataSource.write =
nullptr;
611 UA_VariableAttributes_init(&attr);
612 attr = UA_VariableAttributes_default;
613 attr.displayName = UA_LOCALIZEDTEXT(
const_cast<char*
>(
"en_US"),
const_cast<char*
>(
"EngineeringUnit"));
614 attr.description = UA_LOCALIZEDTEXT(
const_cast<char*
>(
"en_US"),
const_cast<char*
>(
""));
615 attr.accessLevel = UA_ACCESSLEVELMASK_READ;
616 attr.userAccessLevel = UA_ACCESSLEVELMASK_READ;
617 attr.valueRank = UA_VALUERANK_SCALAR;
618 attr.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
619 UA_String defaultEngineeringUnit = UA_STRING(
const_cast<char*
>(
""));
620 UA_Variant_setScalar(&attr.value, &defaultEngineeringUnit, &UA_TYPES[UA_TYPES_STRING]);
621 addResult = UA_Server_addVariableNode(this->
mappedServer,
622 UA_NODEID_STRING(1,
const_cast<char*
>((baseNodePath +
"/" + this->nameNew +
"/EngineeringUnit").c_str())),
623 pvNodeId, UA_NODEID_NUMERIC(0, 47), UA_QUALIFIEDNAME(1,
const_cast<char*
>(
"EngineeringUnit")),
624 UA_NODEID_NUMERIC(0, 63), attr,
this, &createdNodeId);
625 if(addResult == UA_STATUSCODE_GOOD) {
626 UA_NodeId engineeringunitVariable = UA_NODEID_NUMERIC(CSA_NSID, CSA_NSID_VARIABLE_UNIT);
628 UA_NodeId_copy(&createdNodeId, &mapElemEU.concreteNodeId);
629 map.push_back(mapElemEU);
632 UA_NodeId_clear(&createdNodeId);
636 UA_NodeId_clear(&createdNodeId);
637 createdNodeId = UA_NODEID_NULL;
641 mapElemType.
typeTemplateId = UA_NODEID_NUMERIC(CSA_NSID, CSA_NSID_VARIABLE_TYPE);
642 mapElemType.description = UA_LOCALIZEDTEXT(
const_cast<char*
>(
"en_US"),
const_cast<char*
>(
""));
644 mapElemType.dataSource.write =
nullptr;
645 UA_VariableAttributes_init(&attr);
646 attr = UA_VariableAttributes_default;
647 attr.displayName = UA_LOCALIZEDTEXT(
const_cast<char*
>(
"en_US"),
const_cast<char*
>(
"Type"));
648 attr.description = UA_LOCALIZEDTEXT(
const_cast<char*
>(
"en_US"),
const_cast<char*
>(
"Data type used in ChimeraTK"));
649 attr.accessLevel = UA_ACCESSLEVELMASK_READ;
650 attr.userAccessLevel = UA_ACCESSLEVELMASK_READ;
651 attr.valueRank = UA_VALUERANK_SCALAR;
652 attr.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
653 UA_String opcua_node_variable_t_ns_2_i_6012_variant_DataContents = UA_STRING(
const_cast<char*
>(
""));
654 UA_Variant_setScalar(
655 &attr.value, &opcua_node_variable_t_ns_2_i_6012_variant_DataContents, &UA_TYPES[UA_TYPES_STRING]);
656 UA_NodeId nodeId = UA_NODEID_NUMERIC(2, 6012);
657 UA_NodeId typeDefinition = UA_NODEID_NUMERIC(0, 63);
658 UA_NodeId parentNodeId = UA_NODEID_NUMERIC(2, 1001);
659 addResult = UA_Server_addVariableNode(this->
mappedServer,
660 UA_NODEID_STRING(1,
const_cast<char*
>((baseNodePath +
"/" + this->nameNew +
"/Type").c_str())), pvNodeId,
661 UA_NODEID_NUMERIC(0, 47), UA_QUALIFIEDNAME(1,
const_cast<char*
>(
"Type")), UA_NODEID_NUMERIC(0, 63), attr,
this,
663 if(addResult == UA_STATUSCODE_GOOD) {
664 UA_NodeId typeVariable = UA_NODEID_NUMERIC(CSA_NSID, CSA_NSID_VARIABLE_TYPE);
666 UA_NodeId_copy(&createdNodeId, &mapElemType.concreteNodeId);
667 map.push_back(mapElemType);
670 UA_NodeId_clear(&createdNodeId);
674 UA_NodeId_clear(&createdNodeId);
675 createdNodeId = UA_NODEID_NULL;
679 mapElemValidity.
typeTemplateId = UA_NODEID_NUMERIC(CSA_NSID, CSA_NSID_VARIABLE_VALIDITY);
680 mapElemValidity.description = UA_LOCALIZEDTEXT(
const_cast<char*
>(
"en_US"),
const_cast<char*
>(
""));
682 mapElemValidity.dataSource.write =
nullptr;
683 UA_VariableAttributes_init(&attr);
684 attr = UA_VariableAttributes_default;
685 attr.displayName = UA_LOCALIZEDTEXT(
const_cast<char*
>(
"en_US"),
const_cast<char*
>(
"Validity"));
687 UA_LOCALIZEDTEXT(
const_cast<char*
>(
"en_US"),
const_cast<char*
>(
"Data validity. 0: faulty, 1: ok"));
688 attr.accessLevel = UA_ACCESSLEVELMASK_READ;
689 attr.userAccessLevel = UA_ACCESSLEVELMASK_READ;
690 attr.valueRank = UA_VALUERANK_SCALAR;
691 attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
692 UA_Int32 defaultValidity = -1;
693 UA_Variant_setScalar(&attr.value, &defaultValidity, &UA_TYPES[UA_TYPES_INT32]);
694 addResult = UA_Server_addVariableNode(this->
mappedServer,
695 UA_NODEID_STRING(1,
const_cast<char*
>((baseNodePath +
"/" + this->nameNew +
"/Validity").c_str())), pvNodeId,
696 UA_NODEID_NUMERIC(0, 47), UA_QUALIFIEDNAME(1,
const_cast<char*
>(
"Validity")), UA_NODEID_NUMERIC(0, 63), attr,
697 this, &createdNodeId);
698 if(addResult == UA_STATUSCODE_GOOD) {
699 UA_NodeId vadilityVariable = UA_NODEID_NUMERIC(CSA_NSID, CSA_NSID_VARIABLE_VALIDITY);
701 UA_NodeId_copy(&createdNodeId, &mapElemValidity.concreteNodeId);
702 map.push_back(mapElemValidity);
705 UA_NodeId_clear(&createdNodeId);
709 UA_NodeId_clear(&createdNodeId);
718 auto t = this->csManager->getProcessVariable(this->namePV)->getVersionNumber().getTime();
719 auto microseconds = std::chrono::time_point_cast<std::chrono::microseconds>(t).time_since_epoch().count();
721 if(microseconds == 0) {
722 microseconds = std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::system_clock::now())
726 return (microseconds * UA_DATETIME_USEC) + UA_DATETIME_UNIX_EPOCH;
730 UA_NodeId outputNode;
731 UA_NodeId_copy(&this->ownNodeId, &outputNode);
738 mapElem.
dataSource.read = ua_processvariable::ua_readproxy_ua_processvariable_getValue<T>;
739 if(this->csManager->getProcessVariable(this->namePV)->isWriteable()) {
740 mapElem.
dataSource.write = ua_processvariable::ua_writeproxy_ua_processvariable_setValue<T>;
742 if(this->csManager->getProcessArray<T>(this->namePV)->accessChannel(0).size() == 1) {
747 arrayDims = this->csManager->getProcessArray<T>(this->namePV)->accessChannel(0).size();
749 UA_Server_writeDataType(this->
mappedServer, nodeId, UA_TYPES[fusion::at_key<T>(typesMap)].typeId);