12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154 |
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- *
- * Copyright (c) 2017-2018 Fraunhofer IOSB (Author: Andreas Ebner)
- * Copyright (c) 2019 Kalycito Infotech Private Limited
- */
- #include "ua_pubsub_ns0.h"
- #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL /* conditional compilation */
- typedef struct{
- UA_NodeId parentNodeId;
- UA_UInt32 parentClassifier;
- UA_UInt32 elementClassiefier;
- } UA_NodePropertyContext;
- //Prototypes
- #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
- static UA_StatusCode addWriterGroupAction(UA_Server *server,
- const UA_NodeId *sessionId, void *sessionHandle,
- const UA_NodeId *methodId, void *methodContext,
- const UA_NodeId *objectId, void *objectContext,
- size_t inputSize, const UA_Variant *input,
- size_t outputSize, UA_Variant *output);
- static UA_StatusCode removeGroupAction(UA_Server *server,
- const UA_NodeId *sessionId, void *sessionHandle,
- const UA_NodeId *methodId, void *methodContext,
- const UA_NodeId *objectId, void *objectContext,
- size_t inputSize, const UA_Variant *input,
- size_t outputSize, UA_Variant *output);
- static UA_StatusCode addDataSetWriterAction(UA_Server *server,
- const UA_NodeId *sessionId, void *sessionHandle,
- const UA_NodeId *methodId, void *methodContext,
- const UA_NodeId *objectId, void *objectContext,
- size_t inputSize, const UA_Variant *input,
- size_t outputSize, UA_Variant *output);
- #endif
- static UA_StatusCode
- addPubSubObjectNode(UA_Server *server, char* name, UA_UInt32 objectid,
- UA_UInt32 parentid, UA_UInt32 referenceid, UA_UInt32 type_id) {
- UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
- object_attr.displayName = UA_LOCALIZEDTEXT("", name);
- return UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(0, objectid),
- UA_NODEID_NUMERIC(0, parentid),
- UA_NODEID_NUMERIC(0, referenceid),
- UA_QUALIFIEDNAME(0, name),
- UA_NODEID_NUMERIC(0, type_id),
- object_attr, NULL, NULL);
- }
- static UA_StatusCode
- writePubSubNs0VariableArray(UA_Server *server, UA_UInt32 id, void *v,
- size_t length, const UA_DataType *type) {
- UA_Variant var;
- UA_Variant_init(&var);
- UA_Variant_setArray(&var, v, length, type);
- return UA_Server_writeValue(server, UA_NODEID_NUMERIC(0, id), var);
- }
- static UA_NodeId
- findSingleChildNode(UA_Server *server, UA_QualifiedName targetName,
- UA_NodeId referenceTypeId, UA_NodeId startingNode){
- UA_NodeId resultNodeId;
- UA_RelativePathElement rpe;
- UA_RelativePathElement_init(&rpe);
- rpe.referenceTypeId = referenceTypeId;
- rpe.isInverse = false;
- rpe.includeSubtypes = false;
- rpe.targetName = targetName;
- UA_BrowsePath bp;
- UA_BrowsePath_init(&bp);
- bp.startingNode = startingNode;
- bp.relativePath.elementsSize = 1;
- bp.relativePath.elements = &rpe;
- UA_BrowsePathResult bpr =
- UA_Server_translateBrowsePathToNodeIds(server, &bp);
- if(bpr.statusCode != UA_STATUSCODE_GOOD ||
- bpr.targetsSize < 1)
- return UA_NODEID_NULL;
- if(UA_NodeId_copy(&bpr.targets[0].targetId.nodeId, &resultNodeId) != UA_STATUSCODE_GOOD){
- UA_BrowsePathResult_deleteMembers(&bpr);
- return UA_NODEID_NULL;
- }
- UA_BrowsePathResult_deleteMembers(&bpr);
- return resultNodeId;
- }
- static void
- onRead(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
- const UA_NodeId *nodeid, void *context,
- const UA_NumericRange *range, const UA_DataValue *data) {
- UA_Variant value;
- UA_Variant_init(&value);
- const UA_NodePropertyContext *nodeContext = (const UA_NodePropertyContext*)context;
- const UA_NodeId *myNodeId = &nodeContext->parentNodeId;
- switch(nodeContext->parentClassifier){
- case UA_NS0ID_PUBSUBCONNECTIONTYPE: {
- UA_PubSubConnection *pubSubConnection =
- UA_PubSubConnection_findConnectionbyId(server, *myNodeId);
- switch(nodeContext->elementClassiefier) {
- case UA_NS0ID_PUBSUBCONNECTIONTYPE_PUBLISHERID:
- if(pubSubConnection->config->publisherIdType == UA_PUBSUB_PUBLISHERID_STRING) {
- UA_Variant_setScalar(&value, &pubSubConnection->config->publisherId.numeric,
- &UA_TYPES[UA_TYPES_STRING]);
- } else {
- UA_Variant_setScalar(&value, &pubSubConnection->config->publisherId.numeric,
- &UA_TYPES[UA_TYPES_UINT32]);
- }
- break;
- default:
- UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
- "Read error! Unknown property.");
- }
- break;
- }
- case UA_NS0ID_WRITERGROUPTYPE: {
- UA_WriterGroup *writerGroup = UA_WriterGroup_findWGbyId(server, *myNodeId);
- if(!writerGroup)
- return;
- switch(nodeContext->elementClassiefier){
- case UA_NS0ID_WRITERGROUPTYPE_PUBLISHINGINTERVAL:
- UA_Variant_setScalar(&value, &writerGroup->config.publishingInterval,
- &UA_TYPES[UA_TYPES_DURATION]);
- break;
- default:
- UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
- "Read error! Unknown property.");
- }
- break;
- }
- case UA_NS0ID_PUBLISHEDDATAITEMSTYPE: {
- UA_PublishedDataSet *publishedDataSet = UA_PublishedDataSet_findPDSbyId(server, *myNodeId);
- if(!publishedDataSet)
- return;
- switch(nodeContext->elementClassiefier) {
- case UA_NS0ID_PUBLISHEDDATAITEMSTYPE_PUBLISHEDDATA: {
- UA_PublishedVariableDataType *pvd = (UA_PublishedVariableDataType *)
- UA_calloc(publishedDataSet->fieldSize, sizeof(UA_PublishedVariableDataType));
- size_t counter = 0;
- UA_DataSetField *field;
- LIST_FOREACH(field, &publishedDataSet->fields, listEntry) {
- pvd[counter].attributeId = UA_ATTRIBUTEID_VALUE;
- pvd[counter].publishedVariable = field->config.field.variable.publishParameters.publishedVariable;
- //UA_NodeId_copy(&field->config.field.variable.publishParameters.publishedVariable, &pvd[counter].publishedVariable);
- counter++;
- }
- UA_Variant_setArray(&value, pvd, publishedDataSet->fieldSize,
- &UA_TYPES[UA_TYPES_PUBLISHEDVARIABLEDATATYPE]);
- break;
- }
- case UA_NS0ID_PUBLISHEDDATAITEMSTYPE_DATASETMETADATA: {
- UA_Variant_setScalarCopy(&value, &publishedDataSet->dataSetMetaData, &UA_TYPES[UA_TYPES_DATASETMETADATATYPE]);
- break;
- }
- case UA_NS0ID_PUBLISHEDDATAITEMSTYPE_CONFIGURATIONVERSION: {
- UA_Variant_setScalarCopy(&value, &publishedDataSet->dataSetMetaData.configurationVersion,
- &UA_TYPES[UA_TYPES_CONFIGURATIONVERSIONDATATYPE]);
- break;
- }
- default:
- UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
- "Read error! Unknown property.");
- }
- break;
- }
- default:
- UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
- "Read error! Unknown parent element.");
- }
- UA_Server_writeValue(server, *nodeid, value);
- }
- static void
- onWrite(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
- const UA_NodeId *nodeId, void *nodeContext,
- const UA_NumericRange *range, const UA_DataValue *data){
- UA_Variant value;
- UA_NodeId myNodeId;
- UA_WriterGroup *writerGroup = NULL;
- switch(((UA_NodePropertyContext *) nodeContext)->parentClassifier){
- case UA_NS0ID_PUBSUBCONNECTIONTYPE:
- //no runtime writable attributes
- break;
- case UA_NS0ID_WRITERGROUPTYPE:
- myNodeId = ((UA_NodePropertyContext *) nodeContext)->parentNodeId;
- writerGroup = UA_WriterGroup_findWGbyId(server, myNodeId);
- UA_WriterGroupConfig writerGroupConfig;
- memset(&writerGroupConfig, 0, sizeof(writerGroupConfig));
- if(!writerGroup)
- return;
- switch(((UA_NodePropertyContext *) nodeContext)->elementClassiefier){
- case UA_NS0ID_WRITERGROUPTYPE_PUBLISHINGINTERVAL:
- UA_Server_getWriterGroupConfig(server, writerGroup->identifier, &writerGroupConfig);
- writerGroupConfig.publishingInterval = *((UA_Duration *) data->value.data);
- UA_Server_updateWriterGroupConfig(server, writerGroup->identifier, &writerGroupConfig);
- UA_Variant_setScalar(&value, data->value.data, &UA_TYPES[UA_TYPES_DURATION]);
- UA_WriterGroupConfig_clear(&writerGroupConfig);
- break;
- default:
- UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
- "Write error! Unknown property element.");
- }
- break;
- default:
- UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
- "Read error! Unknown parent element.");
- }
- }
- static UA_StatusCode
- addVariableValueSource(UA_Server *server, UA_ValueCallback valueCallback,
- UA_NodeId node, UA_NodePropertyContext *context){
- UA_Server_setNodeContext(server, node, context);
- return UA_Server_setVariableNode_valueCallback(server, node, valueCallback);
- }
- /*************************************************/
- /* PubSubConnection */
- /*************************************************/
- UA_StatusCode
- addPubSubConnectionRepresentation(UA_Server *server, UA_PubSubConnection *connection){
- UA_StatusCode retVal = UA_STATUSCODE_GOOD;
- if(connection->config->name.length > 512)
- return UA_STATUSCODE_BADOUTOFMEMORY;
- UA_STACKARRAY(char, connectionName, sizeof(char) * connection->config->name.length +1);
- memcpy(connectionName, connection->config->name.data, connection->config->name.length);
- connectionName[connection->config->name.length] = '\0';
- //This code block must use a lock
- UA_NODESTORE_REMOVE(server, &connection->identifier);
- UA_NodeId pubSubConnectionNodeId;
- UA_ObjectAttributes attr = UA_ObjectAttributes_default;
- attr.displayName = UA_LOCALIZEDTEXT("de-DE", connectionName);
- retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,
- UA_NODEID_NUMERIC(0, connection->identifier.identifier.numeric),
- UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE),
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASPUBSUBCONNECTION),
- UA_QUALIFIEDNAME(0, connectionName),
- UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE),
- (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
- NULL, &pubSubConnectionNodeId);
- addPubSubObjectNode(server, "Address", connection->identifier.identifier.numeric+1,
- pubSubConnectionNodeId.identifier.numeric, UA_NS0ID_HASCOMPONENT,
- UA_NS0ID_NETWORKADDRESSURLTYPE);
- UA_Server_addNode_finish(server, pubSubConnectionNodeId);
- //End lock zone
- UA_NodeId addressNode, urlNode, interfaceNode, publisherIdNode, connectionPropertieNode, transportProfileUri;
- addressNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Address"),
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
- UA_NODEID_NUMERIC(0, connection->identifier.identifier.numeric));
- urlNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Url"),
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), addressNode);
- interfaceNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "NetworkInterface"),
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), addressNode);
- publisherIdNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublisherId"),
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
- UA_NODEID_NUMERIC(0, connection->identifier.identifier.numeric));
- connectionPropertieNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "ConnectionProperties"),
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
- UA_NODEID_NUMERIC(0, connection->identifier.identifier.numeric));
- transportProfileUri = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "TransportProfileUri"),
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
- UA_NODEID_NUMERIC(0, connection->identifier.identifier.numeric));
- if(UA_NodeId_equal(&addressNode, &UA_NODEID_NULL) ||
- UA_NodeId_equal(&urlNode, &UA_NODEID_NULL) ||
- UA_NodeId_equal(&interfaceNode, &UA_NODEID_NULL) ||
- UA_NodeId_equal(&publisherIdNode, &UA_NODEID_NULL) ||
- UA_NodeId_equal(&connectionPropertieNode, &UA_NODEID_NULL) ||
- UA_NodeId_equal(&transportProfileUri, &UA_NODEID_NULL)) {
- return UA_STATUSCODE_BADNOTFOUND;
- }
- retVal |= writePubSubNs0VariableArray(server, connectionPropertieNode.identifier.numeric,
- connection->config->connectionProperties,
- connection->config->connectionPropertiesSize,
- &UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
- UA_NetworkAddressUrlDataType *networkAddressUrlDataType = ((UA_NetworkAddressUrlDataType *) connection->config->address.data);
- UA_Variant value;
- UA_Variant_init(&value);
- UA_Variant_setScalar(&value, &networkAddressUrlDataType->url, &UA_TYPES[UA_TYPES_STRING]);
- UA_Server_writeValue(server, urlNode, value);
- UA_Variant_setScalar(&value, &networkAddressUrlDataType->networkInterface, &UA_TYPES[UA_TYPES_STRING]);
- UA_Server_writeValue(server, interfaceNode, value);
- UA_Variant_setScalar(&value, &connection->config->transportProfileUri, &UA_TYPES[UA_TYPES_STRING]);
- UA_Server_writeValue(server, transportProfileUri, value);
- UA_NodePropertyContext *connectionPublisherIdContext = (UA_NodePropertyContext *) UA_malloc(sizeof(UA_NodePropertyContext));
- connectionPublisherIdContext->parentNodeId = connection->identifier;
- connectionPublisherIdContext->parentClassifier = UA_NS0ID_PUBSUBCONNECTIONTYPE;
- connectionPublisherIdContext->elementClassiefier = UA_NS0ID_PUBSUBCONNECTIONTYPE_PUBLISHERID;
- UA_ValueCallback valueCallback;
- valueCallback.onRead = onRead;
- valueCallback.onWrite = NULL;
- retVal |= addVariableValueSource(server, valueCallback, publisherIdNode, connectionPublisherIdContext);
- #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
- retVal |= UA_Server_addReference(server, connection->identifier,
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
- UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDWRITERGROUP), true);
- retVal |= UA_Server_addReference(server, connection->identifier,
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
- UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDREADERGROUP), true);
- retVal |= UA_Server_addReference(server, connection->identifier,
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
- UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_REMOVEGROUP), true);
- #endif
- return retVal;
- }
- #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
- static UA_StatusCode
- addPubSubConnectionAction(UA_Server *server,
- const UA_NodeId *sessionId, void *sessionHandle,
- const UA_NodeId *methodId, void *methodContext,
- const UA_NodeId *objectId, void *objectContext,
- size_t inputSize, const UA_Variant *input,
- size_t outputSize, UA_Variant *output){
- UA_StatusCode retVal = UA_STATUSCODE_GOOD;
- UA_PubSubConnectionDataType pubSubConnectionDataType = *((UA_PubSubConnectionDataType *) input[0].data);
- UA_NetworkAddressUrlDataType networkAddressUrlDataType;
- memset(&networkAddressUrlDataType, 0, sizeof(networkAddressUrlDataType));
- UA_ExtensionObject eo = pubSubConnectionDataType.address;
- if(eo.encoding == UA_EXTENSIONOBJECT_DECODED){
- if(eo.content.decoded.type == &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]){
- if(UA_NetworkAddressUrlDataType_copy((UA_NetworkAddressUrlDataType *) eo.content.decoded.data,
- &networkAddressUrlDataType) != UA_STATUSCODE_GOOD){
- return UA_STATUSCODE_BADOUTOFMEMORY;
- }
- }
- }
- UA_PubSubConnectionConfig connectionConfig;
- memset(&connectionConfig, 0, sizeof(UA_PubSubConnectionConfig));
- connectionConfig.transportProfileUri = pubSubConnectionDataType.transportProfileUri;
- connectionConfig.name = pubSubConnectionDataType.name;
- //TODO set real connection state
- connectionConfig.enabled = pubSubConnectionDataType.enabled;
- //connectionConfig.enabled = pubSubConnectionDataType.enabled;
- UA_Variant_setScalar(&connectionConfig.address, &networkAddressUrlDataType,
- &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]);
- if(pubSubConnectionDataType.publisherId.type == &UA_TYPES[UA_TYPES_UINT32]){
- connectionConfig.publisherId.numeric = * ((UA_UInt32 *) pubSubConnectionDataType.publisherId.data);
- } else if(pubSubConnectionDataType.publisherId.type == &UA_TYPES[UA_TYPES_STRING]){
- connectionConfig.publisherIdType = UA_PUBSUB_PUBLISHERID_STRING;
- UA_String_copy((UA_String *) pubSubConnectionDataType.publisherId.data, &connectionConfig.publisherId.string);
- } else {
- UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, "Unsupported PublisherId Type used.");
- //TODO what's the best default behaviour here?
- connectionConfig.publisherId.numeric = 0;
- }
- //call API function and create the connection
- UA_NodeId connectionId;
- retVal |= UA_Server_addPubSubConnection(server, &connectionConfig, &connectionId);
- if(retVal != UA_STATUSCODE_GOOD){
- return retVal;
- }
- for(size_t i = 0; i < pubSubConnectionDataType.writerGroupsSize; i++){
- //UA_PubSubConnection_addWriterGroup(server, UA_NODEID_NULL, NULL, NULL);
- }
- for(size_t i = 0; i < pubSubConnectionDataType.readerGroupsSize; i++){
- //UA_Server_addReaderGroup(server, NULL, NULL, NULL);
- }
- UA_NetworkAddressUrlDataType_deleteMembers(&networkAddressUrlDataType);
- //set ouput value
- UA_Variant_setScalarCopy(output, &connectionId, &UA_TYPES[UA_TYPES_NODEID]);
- return UA_STATUSCODE_GOOD;
- }
- #endif
- UA_StatusCode
- removePubSubConnectionRepresentation(UA_Server *server, UA_PubSubConnection *connection){
- UA_StatusCode retVal = UA_STATUSCODE_GOOD;
- #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
- retVal |= UA_Server_deleteReference(server, connection->identifier, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
- UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDWRITERGROUP),
- false);
- retVal |= UA_Server_deleteReference(server, connection->identifier, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
- UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDREADERGROUP),
- false);
- retVal |= UA_Server_deleteReference(server, connection->identifier, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
- UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_REMOVEGROUP),
- false);
- #endif
- retVal |= UA_Server_deleteNode(server, connection->identifier, true);
- return retVal;
- }
- #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
- static UA_StatusCode
- removeConnectionAction(UA_Server *server,
- const UA_NodeId *sessionId, void *sessionHandle,
- const UA_NodeId *methodId, void *methodContext,
- const UA_NodeId *objectId, void *objectContext,
- size_t inputSize, const UA_Variant *input,
- size_t outputSize, UA_Variant *output){
- UA_StatusCode retVal = UA_STATUSCODE_GOOD;
- UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data);
- retVal |= UA_Server_removePubSubConnection(server, nodeToRemove);
- if(retVal == UA_STATUSCODE_BADNOTFOUND)
- retVal = UA_STATUSCODE_BADNODEIDUNKNOWN;
- return retVal;
- }
- #endif
- /**********************************************/
- /* DataSetReader */
- /**********************************************/
- UA_StatusCode
- addDataSetReaderRepresentation(UA_Server *server, UA_DataSetReader *dataSetReader){
- //TODO implement reader part
- return UA_STATUSCODE_BADNOTIMPLEMENTED;
- }
- #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
- static UA_StatusCode
- addDataSetReaderAction(UA_Server *server,
- const UA_NodeId *sessionId, void *sessionHandle,
- const UA_NodeId *methodId, void *methodContext,
- const UA_NodeId *objectId, void *objectContext,
- size_t inputSize, const UA_Variant *input,
- size_t outputSize, UA_Variant *output){
- UA_StatusCode retVal = UA_STATUSCODE_BADNOTIMPLEMENTED;
- //TODO implement reader part
- return retVal;
- }
- #endif
- UA_StatusCode
- removeDataSetReaderRepresentation(UA_Server *server, UA_DataSetReader* dataSetReader){
- //TODO implement reader part
- return UA_STATUSCODE_BADNOTIMPLEMENTED;
- }
- #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
- static UA_StatusCode
- removeDataSetReaderAction(UA_Server *server,
- const UA_NodeId *sessionId, void *sessionHandle,
- const UA_NodeId *methodId, void *methodContext,
- const UA_NodeId *objectId, void *objectContext,
- size_t inputSize, const UA_Variant *input,
- size_t outputSize, UA_Variant *output){
- UA_StatusCode retVal = UA_STATUSCODE_BADNOTIMPLEMENTED;
- //TODO implement reader part
- return retVal;
- }
- #endif
- /*************************************************/
- /* PublishedDataSet */
- /*************************************************/
- #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
- static UA_StatusCode
- addDataSetFolderAction(UA_Server *server,
- const UA_NodeId *sessionId, void *sessionHandle,
- const UA_NodeId *methodId, void *methodContext,
- const UA_NodeId *objectId, void *objectContext,
- size_t inputSize, const UA_Variant *input,
- size_t outputSize, UA_Variant *output){
- /* defined in R 1.04 9.1.4.5.7 */
- UA_StatusCode retVal = UA_STATUSCODE_GOOD;
- UA_String newFolderName = *((UA_String *) input[0].data);
- UA_NodeId generatedId;
- UA_ObjectAttributes objectAttributes = UA_ObjectAttributes_default;
- UA_LocalizedText name = {UA_STRING("en-US"), newFolderName};
- objectAttributes.displayName = name;
- retVal |= UA_Server_addObjectNode(server, UA_NODEID_NULL, *objectId, UA_NODEID_NUMERIC(0,UA_NS0ID_ORGANIZES),
- UA_QUALIFIEDNAME(0, "DataSetFolder"), UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE),
- objectAttributes, NULL, &generatedId);
- UA_Variant_setScalarCopy(output, &generatedId, &UA_TYPES[UA_TYPES_NODEID]);
- #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
- retVal |= UA_Server_addReference(server, generatedId,
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
- UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDPUBLISHEDDATAITEMS), true);
- retVal |= UA_Server_addReference(server, generatedId,
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
- UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEPUBLISHEDDATASET), true);
- retVal |= UA_Server_addReference(server, generatedId,
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
- UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDDATASETFOLDER), true);
- retVal |= UA_Server_addReference(server, generatedId,
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
- UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEDATASETFOLDER), true);
- #endif
- return retVal;
- }
- #endif
- #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
- static UA_StatusCode
- removeDataSetFolderAction(UA_Server *server,
- const UA_NodeId *sessionId, void *sessionHandle,
- const UA_NodeId *methodId, void *methodContext,
- const UA_NodeId *objectId, void *objectContext,
- size_t inputSize, const UA_Variant *input,
- size_t outputSize, UA_Variant *output){
- UA_StatusCode retVal = UA_STATUSCODE_GOOD;
- UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data);
- #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
- retVal |= UA_Server_deleteReference(server, nodeToRemove, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
- UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDPUBLISHEDDATAITEMS),
- false);
- retVal |= UA_Server_deleteReference(server, nodeToRemove, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
- UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEPUBLISHEDDATASET),
- false);
- retVal |= UA_Server_deleteReference(server, nodeToRemove, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
- UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDDATASETFOLDER),
- false);
- retVal |= UA_Server_deleteReference(server, nodeToRemove, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
- UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEDATASETFOLDER),
- false);
- #endif
- retVal |= UA_Server_deleteNode(server, nodeToRemove, false);
- return retVal;
- }
- #endif
- UA_StatusCode
- addPublishedDataItemsRepresentation(UA_Server *server, UA_PublishedDataSet *publishedDataSet) {
- UA_StatusCode retVal = UA_STATUSCODE_GOOD;
- if(publishedDataSet->config.name.length > 512)
- return UA_STATUSCODE_BADOUTOFMEMORY;
- UA_STACKARRAY(char, pdsName, sizeof(char) * publishedDataSet->config.name.length +1);
- memcpy(pdsName, publishedDataSet->config.name.data, publishedDataSet->config.name.length);
- pdsName[publishedDataSet->config.name.length] = '\0';
- //This code block must use a lock
- UA_NODESTORE_REMOVE(server, &publishedDataSet->identifier);
- retVal |= addPubSubObjectNode(server, pdsName, publishedDataSet->identifier.identifier.numeric,
- UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS,
- UA_NS0ID_HASPROPERTY, UA_NS0ID_PUBLISHEDDATAITEMSTYPE);
- //End lock zone
- UA_ValueCallback valueCallback;
- valueCallback.onRead = onRead;
- valueCallback.onWrite = NULL;
- UA_NodeId configurationVersionNode =
- findSingleChildNode(server, UA_QUALIFIEDNAME(0, "ConfigurationVersion"),
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
- UA_NODEID_NUMERIC(0, publishedDataSet->identifier.identifier.numeric));
- if(UA_NodeId_equal(&configurationVersionNode, &UA_NODEID_NULL))
- return UA_STATUSCODE_BADNOTFOUND;
- UA_NodePropertyContext * configurationVersionContext = (UA_NodePropertyContext *)
- UA_malloc(sizeof(UA_NodePropertyContext));
- configurationVersionContext->parentNodeId = publishedDataSet->identifier;
- configurationVersionContext->parentClassifier = UA_NS0ID_PUBLISHEDDATAITEMSTYPE;
- configurationVersionContext->elementClassiefier =
- UA_NS0ID_PUBLISHEDDATAITEMSTYPE_CONFIGURATIONVERSION;
- retVal |= addVariableValueSource(server, valueCallback, configurationVersionNode,
- configurationVersionContext);
- UA_NodeId publishedDataNode =
- findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublishedData"),
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
- UA_NODEID_NUMERIC(0, publishedDataSet->identifier.identifier.numeric));
- if(UA_NodeId_equal(&publishedDataNode, &UA_NODEID_NULL))
- return UA_STATUSCODE_BADNOTFOUND;
- UA_NodePropertyContext * publishingIntervalContext = (UA_NodePropertyContext *)
- UA_malloc(sizeof(UA_NodePropertyContext));
- publishingIntervalContext->parentNodeId = publishedDataSet->identifier;
- publishingIntervalContext->parentClassifier = UA_NS0ID_PUBLISHEDDATAITEMSTYPE;
- publishingIntervalContext->elementClassiefier = UA_NS0ID_PUBLISHEDDATAITEMSTYPE_PUBLISHEDDATA;
- retVal |= addVariableValueSource(server, valueCallback, publishedDataNode,
- publishingIntervalContext);
- UA_NodeId dataSetMetaDataNode =
- findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetMetaData"),
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
- UA_NODEID_NUMERIC(0, publishedDataSet->identifier.identifier.numeric));
- if(UA_NodeId_equal(&dataSetMetaDataNode, &UA_NODEID_NULL))
- return UA_STATUSCODE_BADNOTFOUND;
- UA_NodePropertyContext *metaDataContext = (UA_NodePropertyContext *)
- UA_malloc(sizeof(UA_NodePropertyContext));
- metaDataContext->parentNodeId = publishedDataSet->identifier;
- metaDataContext->parentClassifier = UA_NS0ID_PUBLISHEDDATAITEMSTYPE;
- metaDataContext->elementClassiefier = UA_NS0ID_PUBLISHEDDATAITEMSTYPE_DATASETMETADATA;
- retVal |= addVariableValueSource(server, valueCallback, dataSetMetaDataNode, metaDataContext);
- #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
- retVal |= UA_Server_addReference(server, publishedDataSet->identifier,
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
- UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBLISHEDDATAITEMSTYPE_ADDVARIABLES), true);
- retVal |= UA_Server_addReference(server, publishedDataSet->identifier,
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
- UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBLISHEDDATAITEMSTYPE_REMOVEVARIABLES), true);
- #endif
- return retVal;
- }
- #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
- static UA_StatusCode
- addPublishedDataItemsAction(UA_Server *server,
- const UA_NodeId *sessionId, void *sessionHandle,
- const UA_NodeId *methodId, void *methodContext,
- const UA_NodeId *objectId, void *objectContext,
- size_t inputSize, const UA_Variant *input,
- size_t outputSize, UA_Variant *output){
- UA_StatusCode retVal = UA_STATUSCODE_GOOD;
- size_t fieldNameAliasesSize = input[1].arrayLength;
- UA_String * fieldNameAliases = (UA_String *) input[1].data;
- size_t fieldFlagsSize = input[2].arrayLength;
- UA_DataSetFieldFlags * fieldFlags = (UA_DataSetFieldFlags *) input[2].data;
- size_t variablesToAddSize = input[3].arrayLength;
- UA_PublishedVariableDataType *variablesToAddField = (UA_PublishedVariableDataType *) input[3].data;
- if(!(fieldNameAliasesSize == fieldFlagsSize || fieldFlagsSize == variablesToAddSize))
- return UA_STATUSCODE_BADINVALIDARGUMENT;
- UA_PublishedDataSetConfig publishedDataSetConfig;
- memset(&publishedDataSetConfig, 0, sizeof(publishedDataSetConfig));
- publishedDataSetConfig.name = *((UA_String *) input[0].data);
- publishedDataSetConfig.publishedDataSetType = UA_PUBSUB_DATASET_PUBLISHEDITEMS;
- UA_NodeId dataSetItemsNodeId;
- retVal |= UA_Server_addPublishedDataSet(server, &publishedDataSetConfig, &dataSetItemsNodeId).addResult;
- UA_DataSetFieldConfig dataSetFieldConfig;
- for(size_t j = 0; j < variablesToAddSize; ++j) {
- memset(&dataSetFieldConfig, 0, sizeof(dataSetFieldConfig));
- dataSetFieldConfig.dataSetFieldType = UA_PUBSUB_DATASETFIELD_VARIABLE;
- dataSetFieldConfig.field.variable.fieldNameAlias = fieldNameAliases[j];
- if(fieldFlags[j] == UA_DATASETFIELDFLAGS_PROMOTEDFIELD){
- dataSetFieldConfig.field.variable.promotedField = UA_TRUE;
- }
- dataSetFieldConfig.field.variable.publishParameters = variablesToAddField[j];
- UA_Server_addDataSetField(server, dataSetItemsNodeId, &dataSetFieldConfig, NULL);
- }
- UA_PublishedVariableDataType_clear(variablesToAddField);
- return retVal;
- }
- #endif
- #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
- static UA_StatusCode
- addVariablesAction(UA_Server *server,
- const UA_NodeId *sessionId, void *sessionHandle,
- const UA_NodeId *methodId, void *methodContext,
- const UA_NodeId *objectId, void *objectContext,
- size_t inputSize, const UA_Variant *input,
- size_t outputSize, UA_Variant *output){
- UA_StatusCode retVal = UA_STATUSCODE_GOOD;
- return retVal;
- }
- static UA_StatusCode
- removeVariablesAction(UA_Server *server,
- const UA_NodeId *sessionId, void *sessionHandle,
- const UA_NodeId *methodId, void *methodContext,
- const UA_NodeId *objectId, void *objectContext,
- size_t inputSize, const UA_Variant *input,
- size_t outputSize, UA_Variant *output){
- UA_StatusCode retVal = UA_STATUSCODE_GOOD;
- return retVal;
- }
- #endif
- UA_StatusCode
- removePublishedDataSetRepresentation(UA_Server *server, UA_PublishedDataSet *publishedDataSet){
- UA_StatusCode retVal = UA_STATUSCODE_GOOD;
- retVal |= UA_Server_deleteNode(server, publishedDataSet->identifier, false);
- return retVal;
- }
- #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
- static UA_StatusCode
- removePublishedDataSetAction(UA_Server *server,
- const UA_NodeId *sessionId, void *sessionHandle,
- const UA_NodeId *methodId, void *methodContext,
- const UA_NodeId *objectId, void *objectContext,
- size_t inputSize, const UA_Variant *input,
- size_t outputSize, UA_Variant *output){
- UA_StatusCode retVal = UA_STATUSCODE_GOOD;
- UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data);
- retVal |= UA_Server_removePublishedDataSet(server, nodeToRemove);
- return retVal;
- }
- #endif
- /**********************************************/
- /* WriterGroup */
- /**********************************************/
- static UA_StatusCode
- readContentMask(UA_Server *server, const UA_NodeId *sessionId,
- void *sessionContext, const UA_NodeId *nodeId,
- void *nodeContext, UA_Boolean includeSourceTimeStamp,
- const UA_NumericRange *range, UA_DataValue *value) {
- UA_WriterGroup *writerGroup = (UA_WriterGroup*)nodeContext;
- if((writerGroup->config.messageSettings.encoding != UA_EXTENSIONOBJECT_DECODED &&
- writerGroup->config.messageSettings.encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) ||
- writerGroup->config.messageSettings.content.decoded.type !=
- &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE])
- return UA_STATUSCODE_BADINTERNALERROR;
- UA_UadpWriterGroupMessageDataType *wgm = (UA_UadpWriterGroupMessageDataType*)
- writerGroup->config.messageSettings.content.decoded.data;
- UA_Variant_setScalarCopy(&value->value, &wgm->networkMessageContentMask,
- &UA_TYPES[UA_TYPES_UADPNETWORKMESSAGECONTENTMASK]);
- value->hasValue = true;
- return UA_STATUSCODE_GOOD;
- }
- static UA_StatusCode
- writeContentMask(UA_Server *server, const UA_NodeId *sessionId,
- void *sessionContext, const UA_NodeId *nodeId,
- void *nodeContext, const UA_NumericRange *range,
- const UA_DataValue *value) {
- UA_WriterGroup *writerGroup = (UA_WriterGroup*)nodeContext;
- if((writerGroup->config.messageSettings.encoding != UA_EXTENSIONOBJECT_DECODED &&
- writerGroup->config.messageSettings.encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) ||
- writerGroup->config.messageSettings.content.decoded.type !=
- &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE])
- return UA_STATUSCODE_BADINTERNALERROR;
- UA_UadpWriterGroupMessageDataType *wgm = (UA_UadpWriterGroupMessageDataType*)
- writerGroup->config.messageSettings.content.decoded.data;
- if(!value->value.type)
- return UA_STATUSCODE_BADTYPEMISMATCH;
- if(value->value.type->typeKind != UA_DATATYPEKIND_ENUM &&
- value->value.type->typeKind != UA_DATATYPEKIND_INT32)
- return UA_STATUSCODE_BADTYPEMISMATCH;
- wgm->networkMessageContentMask = *(UA_UadpNetworkMessageContentMask*)value->value.data;
- return UA_STATUSCODE_GOOD;
- }
- UA_StatusCode
- addWriterGroupRepresentation(UA_Server *server, UA_WriterGroup *writerGroup){
- UA_StatusCode retVal = UA_STATUSCODE_GOOD;
- if(writerGroup->config.name.length > 512)
- return UA_STATUSCODE_BADOUTOFMEMORY;
- UA_STACKARRAY(char, wgName, sizeof(char) * writerGroup->config.name.length + 1);
- memcpy(wgName, writerGroup->config.name.data, writerGroup->config.name.length);
- wgName[writerGroup->config.name.length] = '\0';
- //This code block must use a lock
- UA_NODESTORE_REMOVE(server, &writerGroup->identifier);
- retVal |= addPubSubObjectNode(server, wgName, writerGroup->identifier.identifier.numeric,
- writerGroup->linkedConnection.identifier.numeric,
- UA_NS0ID_HASCOMPONENT, UA_NS0ID_WRITERGROUPTYPE);
- //End lock zone
- UA_NodeId keepAliveNode =
- findSingleChildNode(server, UA_QUALIFIEDNAME(0, "KeepAliveTime"),
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
- UA_NODEID_NUMERIC(0, writerGroup->identifier.identifier.numeric));
- UA_NodeId publishingIntervalNode =
- findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublishingInterval"),
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
- UA_NODEID_NUMERIC(0, writerGroup->identifier.identifier.numeric));
- if(UA_NodeId_equal(&keepAliveNode, &UA_NODEID_NULL) ||
- UA_NodeId_equal(&publishingIntervalNode, &UA_NODEID_NULL))
- return UA_STATUSCODE_BADNOTFOUND;
- UA_NodePropertyContext * publishingIntervalContext = (UA_NodePropertyContext *)
- UA_malloc(sizeof(UA_NodePropertyContext));
- publishingIntervalContext->parentNodeId = writerGroup->identifier;
- publishingIntervalContext->parentClassifier = UA_NS0ID_WRITERGROUPTYPE;
- publishingIntervalContext->elementClassiefier = UA_NS0ID_WRITERGROUPTYPE_PUBLISHINGINTERVAL;
- UA_ValueCallback valueCallback;
- valueCallback.onRead = onRead;
- valueCallback.onWrite = onWrite;
- retVal |= addVariableValueSource(server, valueCallback,
- publishingIntervalNode, publishingIntervalContext);
- UA_Server_writeAccessLevel(server, publishingIntervalNode,
- UA_ACCESSLEVELMASK_READ ^ UA_ACCESSLEVELMASK_WRITE);
- UA_NodeId priorityNode =
- findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Priority"),
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
- UA_NODEID_NUMERIC(0, writerGroup->identifier.identifier.numeric));
- UA_NodeId writerGroupIdNode =
- findSingleChildNode(server, UA_QUALIFIEDNAME(0, "WriterGroupId"),
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
- UA_NODEID_NUMERIC(0, writerGroup->identifier.identifier.numeric));
- UA_Variant value;
- UA_Variant_init(&value);
- UA_Variant_setScalar(&value, &writerGroup->config.publishingInterval, &UA_TYPES[UA_TYPES_DURATION]);
- UA_Server_writeValue(server, publishingIntervalNode, value);
- UA_Variant_setScalar(&value, &writerGroup->config.keepAliveTime, &UA_TYPES[UA_TYPES_DURATION]);
- UA_Server_writeValue(server, keepAliveNode, value);
- UA_Variant_setScalar(&value, &writerGroup->config.priority, &UA_TYPES[UA_TYPES_BYTE]);
- UA_Server_writeValue(server, priorityNode, value);
- UA_Variant_setScalar(&value, &writerGroup->config.writerGroupId, &UA_TYPES[UA_TYPES_UINT16]);
- UA_Server_writeValue(server, writerGroupIdNode, value);
- retVal |= addPubSubObjectNode(server, "MessageSettings", 0,
- writerGroup->identifier.identifier.numeric,
- UA_NS0ID_HASCOMPONENT, UA_NS0ID_UADPWRITERGROUPMESSAGETYPE);
- /* Find the variable with the content mask */
- UA_NodeId messageSettingsId =
- findSingleChildNode(server, UA_QUALIFIEDNAME(0, "MessageSettings"),
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
- UA_NODEID_NUMERIC(0, writerGroup->identifier.identifier.numeric));
- UA_NodeId contentMaskId =
- findSingleChildNode(server, UA_QUALIFIEDNAME(0, "NetworkMessageContentMask"),
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), messageSettingsId);
- if(UA_NodeId_equal(&messageSettingsId, &UA_NODEID_NULL) ||
- UA_NodeId_equal(&contentMaskId, &UA_NODEID_NULL)) {
- return UA_STATUSCODE_BADNOTFOUND;
- }
- /* Set the callback */
- UA_DataSource ds;
- ds.read = readContentMask;
- ds.write = writeContentMask;
- UA_Server_setVariableNode_dataSource(server, contentMaskId, ds);
- UA_Server_setNodeContext(server, contentMaskId, writerGroup);
- /* Make writable */
- UA_Server_writeAccessLevel(server, contentMaskId,
- UA_ACCESSLEVELMASK_WRITE | UA_ACCESSLEVELMASK_READ);
- return retVal;
- }
- #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
- static UA_StatusCode
- addWriterGroupAction(UA_Server *server,
- const UA_NodeId *sessionId, void *sessionHandle,
- const UA_NodeId *methodId, void *methodContext,
- const UA_NodeId *objectId, void *objectContext,
- size_t inputSize, const UA_Variant *input,
- size_t outputSize, UA_Variant *output){
- UA_StatusCode retVal = UA_STATUSCODE_GOOD;
- UA_WriterGroupDataType *writerGroupDataType = ((UA_WriterGroupDataType *) input[0].data);
- UA_NodeId generatedId;
- UA_WriterGroupConfig writerGroupConfig;
- memset(&writerGroupConfig, 0, sizeof(UA_WriterGroupConfig));
- writerGroupConfig.name = writerGroupDataType->name;
- writerGroupConfig.publishingInterval = writerGroupDataType->publishingInterval;
- writerGroupConfig.writerGroupId = writerGroupDataType->writerGroupId;
- writerGroupConfig.enabled = writerGroupDataType->enabled;
- writerGroupConfig.priority = writerGroupDataType->priority;
- //TODO remove hard coded UADP
- writerGroupConfig.encodingMimeType = UA_PUBSUB_ENCODING_UADP;
- //ToDo transfer all arguments to internal WGConfiguration
- retVal |= UA_Server_addWriterGroup(server, *objectId, &writerGroupConfig, &generatedId);
- UA_Variant_setScalarCopy(output, &generatedId, &UA_TYPES[UA_TYPES_NODEID]);
- return retVal;
- }
- #endif
- UA_StatusCode
- removeGroupRepresentation(UA_Server *server, UA_WriterGroup *writerGroup) {
- UA_StatusCode retVal = UA_STATUSCODE_GOOD;
- retVal |= UA_Server_deleteNode(server, writerGroup->identifier, false);
- return retVal;
- }
- #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
- static UA_StatusCode
- removeGroupAction(UA_Server *server,
- const UA_NodeId *sessionId, void *sessionHandle,
- const UA_NodeId *methodId, void *methodContext,
- const UA_NodeId *objectId, void *objectContext,
- size_t inputSize, const UA_Variant *input,
- size_t outputSize, UA_Variant *output){
- UA_StatusCode retVal = UA_STATUSCODE_GOOD;
- UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data);
- if(UA_WriterGroup_findWGbyId(server, nodeToRemove) != NULL)
- retVal |= UA_Server_removeWriterGroup(server, nodeToRemove);
- //else
- //retVal |= UA_Server_removeReaderGroup(server, nodeToRemve);
- return retVal;
- }
- #endif
- /**********************************************/
- /* ReaderGroup */
- /**********************************************/
- UA_StatusCode
- addReaderGroupRepresentation(UA_Server *server, UA_ReaderGroup *readerGroup){
- //TODO implement reader part
- return UA_STATUSCODE_BADNOTIMPLEMENTED;
- }
- #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
- static UA_StatusCode
- addReaderGroupAction(UA_Server *server,
- const UA_NodeId *sessionId, void *sessionHandle,
- const UA_NodeId *methodId, void *methodContext,
- const UA_NodeId *objectId, void *objectContext,
- size_t inputSize, const UA_Variant *input,
- size_t outputSize, UA_Variant *output){
- UA_StatusCode retVal = UA_STATUSCODE_GOOD;
- //TODO implement reader part
- return retVal;
- }
- #endif
- /**********************************************/
- /* DataSetWriter */
- /**********************************************/
- UA_StatusCode
- addDataSetWriterRepresentation(UA_Server *server, UA_DataSetWriter *dataSetWriter){
- UA_StatusCode retVal = UA_STATUSCODE_GOOD;
- if(dataSetWriter->config.name.length > 512)
- return UA_STATUSCODE_BADOUTOFMEMORY;
- UA_STACKARRAY(char, dswName, sizeof(char) * dataSetWriter->config.name.length + 1);
- memcpy(dswName, dataSetWriter->config.name.data, dataSetWriter->config.name.length);
- dswName[dataSetWriter->config.name.length] = '\0';
- //This code block must use a lock
- UA_NODESTORE_REMOVE(server, &dataSetWriter->identifier);
- retVal |= addPubSubObjectNode(server, dswName, dataSetWriter->identifier.identifier.numeric,
- dataSetWriter->linkedWriterGroup.identifier.numeric,
- UA_NS0ID_HASDATASETWRITER, UA_NS0ID_DATASETWRITERTYPE);
- //End lock zone
- retVal |= UA_Server_addReference(server, dataSetWriter->connectedDataSet,
- UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETTOWRITER),
- UA_EXPANDEDNODEID_NUMERIC(0, dataSetWriter->identifier.identifier.numeric), true);
- retVal |= addPubSubObjectNode(server, "MessageSettings", 0,
- dataSetWriter->identifier.identifier.numeric,
- UA_NS0ID_HASCOMPONENT, UA_NS0ID_UADPDATASETWRITERMESSAGETYPE);
- return retVal;
- }
- #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
- static UA_StatusCode
- addDataSetWriterAction(UA_Server *server,
- const UA_NodeId *sessionId, void *sessionHandle,
- const UA_NodeId *methodId, void *methodContext,
- const UA_NodeId *objectId, void *objectContext,
- size_t inputSize, const UA_Variant *input,
- size_t outputSize, UA_Variant *output){
- UA_DataSetWriterDataType *dataSetWriterDataType = (UA_DataSetWriterDataType *) input[0].data;
- UA_NodeId targetPDS = UA_NODEID_NULL;
- for(size_t i = 0; i < server->pubSubManager.publishedDataSetsSize; ++i) {
- if(UA_String_equal(&dataSetWriterDataType->dataSetName,
- &server->pubSubManager.publishedDataSets[i].config.name)){
- targetPDS = server->pubSubManager.publishedDataSets[i].identifier;
- }
- }
- if(UA_NodeId_isNull(&targetPDS))
- return UA_STATUSCODE_BADPARENTNODEIDINVALID;
- UA_NodeId generatedId;
- UA_DataSetWriterConfig dataSetWriterConfig;
- memset(&dataSetWriterConfig, 0, sizeof(UA_DataSetWriterConfig));
- dataSetWriterConfig.name = dataSetWriterDataType->name;
- dataSetWriterConfig.dataSetName = dataSetWriterDataType->dataSetName;
- dataSetWriterConfig.keyFrameCount = dataSetWriterDataType->keyFrameCount;
- dataSetWriterConfig.dataSetWriterId = dataSetWriterDataType->dataSetWriterId;
- UA_Server_addDataSetWriter(server, *objectId, targetPDS, &dataSetWriterConfig, &generatedId);
- UA_Variant_setScalarCopy(output, &generatedId, &UA_TYPES[UA_TYPES_NODEID]);
- return UA_STATUSCODE_GOOD;
- }
- #endif
- UA_StatusCode
- removeDataSetWriterRepresentation(UA_Server *server, UA_DataSetWriter *dataSetWriter) {
- UA_StatusCode retVal = UA_STATUSCODE_GOOD;
- retVal |= UA_Server_deleteNode(server, dataSetWriter->identifier, false);
- return retVal;
- }
- #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
- static UA_StatusCode
- removeDataSetWriterAction(UA_Server *server,
- const UA_NodeId *sessionId, void *sessionHandle,
- const UA_NodeId *methodId, void *methodContext,
- const UA_NodeId *objectId, void *objectContext,
- size_t inputSize, const UA_Variant *input,
- size_t outputSize, UA_Variant *output){
- UA_StatusCode retVal = UA_STATUSCODE_GOOD;
- UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data);
- retVal |= UA_Server_removeDataSetWriter(server, nodeToRemove);
- return retVal;
- }
- #endif
- /**********************************************/
- /* Destructors */
- /**********************************************/
- static void
- connectionTypeDestructor(UA_Server *server,
- const UA_NodeId *sessionId, void *sessionContext,
- const UA_NodeId *typeId, void *typeContext,
- const UA_NodeId *nodeId, void **nodeContext) {
- UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND, "Connection destructor called!");
- UA_NodeId publisherIdNode;
- publisherIdNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublisherId"),
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId);
- UA_NodePropertyContext *internalConnectionContext;
- UA_Server_getNodeContext(server, publisherIdNode, (void **) &internalConnectionContext);
- if(!UA_NodeId_equal(&UA_NODEID_NULL , &publisherIdNode)){
- UA_free(internalConnectionContext);
- }
- }
- static void
- writerGroupTypeDestructor(UA_Server *server,
- const UA_NodeId *sessionId, void *sessionContext,
- const UA_NodeId *typeId, void *typeContext,
- const UA_NodeId *nodeId, void **nodeContext) {
- UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND, "WriterGroup destructor called!");
- UA_NodeId intervalNode;
- intervalNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublishingInterval"),
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId);
- UA_NodePropertyContext *internalConnectionContext;
- UA_Server_getNodeContext(server, intervalNode, (void **) &internalConnectionContext);
- if(!UA_NodeId_equal(&UA_NODEID_NULL , &intervalNode)){
- UA_free(internalConnectionContext);
- }
- }
- static void
- readerGroupTypeDestructor(UA_Server *server,
- const UA_NodeId *sessionId, void *sessionContext,
- const UA_NodeId *typeId, void *typeContext,
- const UA_NodeId *nodeId, void **nodeContext) {
- UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND, "ReaderGroup destructor called!");
- }
- static void
- dataSetWriterTypeDestructor(UA_Server *server,
- const UA_NodeId *sessionId, void *sessionContext,
- const UA_NodeId *typeId, void *typeContext,
- const UA_NodeId *nodeId, void **nodeContext) {
- UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND, "DataSetWriter destructor called!");
- }
- static void
- dataSetReaderTypeDestructor(UA_Server *server,
- const UA_NodeId *sessionId, void *sessionContext,
- const UA_NodeId *typeId, void *typeContext,
- const UA_NodeId *nodeId, void **nodeContext) {
- UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND, "DataSetReader destructor called!");
- }
- static void
- publishedDataItemsTypeDestructor(UA_Server *server,
- const UA_NodeId *sessionId, void *sessionContext,
- const UA_NodeId *typeId, void *typeContext,
- const UA_NodeId *nodeId, void **nodeContext) {
- UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND,
- "PublishedDataItems destructor called!");
- void *childContext;
- UA_NodeId node = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublishedData"),
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId);
- UA_Server_getNodeContext(server, node, (void**)&childContext);
- if(!UA_NodeId_equal(&UA_NODEID_NULL , &node))
- UA_free(childContext);
- node = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "ConfigurationVersion"),
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
- *nodeId);
- UA_Server_getNodeContext(server, node, (void**)&childContext);
- if(!UA_NodeId_equal(&UA_NODEID_NULL , &node))
- UA_free(childContext);
- node = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetMetaData"),
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId);
- UA_Server_getNodeContext(server, node, (void**)&childContext);
- if(!UA_NodeId_equal(&node, &UA_NODEID_NULL))
- UA_free(childContext);
- }
- UA_StatusCode
- UA_Server_initPubSubNS0(UA_Server *server) {
- UA_StatusCode retVal = UA_STATUSCODE_GOOD;
- UA_String profileArray[1];
- profileArray[0] = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp");
- retVal |= writePubSubNs0VariableArray(server, UA_NS0ID_PUBLISHSUBSCRIBE_SUPPORTEDTRANSPORTPROFILES,
- profileArray,
- 1, &UA_TYPES[UA_TYPES_STRING]);
- #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
- retVal |= UA_Server_setMethodNode_callback(server,
- UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_ADDCONNECTION), addPubSubConnectionAction);
- retVal |= UA_Server_setMethodNode_callback(server,
- UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_REMOVECONNECTION), removeConnectionAction);
- retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS),
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
- UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDDATASETFOLDER), true);
- retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS),
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
- UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDPUBLISHEDDATAITEMS), true);
- retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS),
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
- UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEPUBLISHEDDATASET), true);
- retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS),
- UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
- UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEDATASETFOLDER), true);
- retVal |= UA_Server_setMethodNode_callback(server,
- UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDDATASETFOLDER), addDataSetFolderAction);
- retVal |= UA_Server_setMethodNode_callback(server,
- UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEDATASETFOLDER), removeDataSetFolderAction);
- retVal |= UA_Server_setMethodNode_callback(server,
- UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDPUBLISHEDDATAITEMS), addPublishedDataItemsAction);
- retVal |= UA_Server_setMethodNode_callback(server,
- UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEPUBLISHEDDATASET), removePublishedDataSetAction);
- retVal |= UA_Server_setMethodNode_callback(server,
- UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHEDDATAITEMSTYPE_ADDVARIABLES), addVariablesAction);
- retVal |= UA_Server_setMethodNode_callback(server,
- UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHEDDATAITEMSTYPE_REMOVEVARIABLES), removeVariablesAction);
- retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDWRITERGROUP), addWriterGroupAction);
- retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDREADERGROUP), addReaderGroupAction);
- retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_REMOVEGROUP), removeGroupAction);
- retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_WRITERGROUPTYPE_ADDDATASETWRITER), addDataSetWriterAction);
- retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_WRITERGROUPTYPE_REMOVEDATASETWRITER), removeDataSetWriterAction);
- retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_READERGROUPTYPE_ADDDATASETREADER), addDataSetReaderAction);
- retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_READERGROUPTYPE_REMOVEDATASETREADER), removeDataSetReaderAction);
- #else
- retVal |= UA_Server_deleteReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
- UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_ADDCONNECTION),
- false);
- retVal |= UA_Server_deleteReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
- UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_REMOVECONNECTION),
- false);
- #endif
- UA_NodeTypeLifecycle liveCycle;
- liveCycle.constructor = NULL;
- liveCycle.destructor = connectionTypeDestructor;
- UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE), liveCycle);
- liveCycle.destructor = writerGroupTypeDestructor;
- UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_WRITERGROUPTYPE), liveCycle);
- liveCycle.destructor = readerGroupTypeDestructor;
- UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_READERGROUPTYPE), liveCycle);
- liveCycle.destructor = dataSetWriterTypeDestructor;
- UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETWRITERDATATYPE), liveCycle);
- liveCycle.destructor = publishedDataItemsTypeDestructor;
- UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHEDDATAITEMSTYPE), liveCycle);
- liveCycle.destructor = dataSetReaderTypeDestructor;
- UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETREADERDATATYPE), liveCycle);
- return retVal;
- }
- #endif /* UA_ENABLE_PUBSUB_INFORMATIONMODEL */
|