From 82dfb88fffc0a8f3c4fe88c3bfbdcd5c85faf5e0 Mon Sep 17 00:00:00 2001 From: Markus Meingast Date: Tue, 14 Jan 2025 17:40:35 +0100 Subject: [PATCH] Add support for sending data with nested Structs --- src/com/opc_ua/opcua_local_handler.cpp | 47 ++++++++++++++++++++ src/com/opc_ua/opcua_local_handler.h | 16 +++++++ src/com/opc_ua/opcua_objectstruct_helper.cpp | 13 +++++- src/com/opc_ua/struct_action_info.h | 4 ++ 4 files changed, 78 insertions(+), 2 deletions(-) diff --git a/src/com/opc_ua/opcua_local_handler.cpp b/src/com/opc_ua/opcua_local_handler.cpp index 482e51835..771fecefc 100644 --- a/src/com/opc_ua/opcua_local_handler.cpp +++ b/src/com/opc_ua/opcua_local_handler.cpp @@ -30,6 +30,7 @@ #include "forte_printer.h" #include "../../arch/utils/mainparam_utils.h" #include "opcua_local_handler.h" +#include "struct_action_info.h" #ifdef FORTE_COM_OPC_UA_MULTICAST #include "detail/lds_me_handler.h" #endif //FORTE_COM_OPC_UA_MULTICAST @@ -361,6 +362,24 @@ UA_StatusCode COPC_UA_Local_Handler::executeAction(CActionInfo &paActionInfo) { return retVal; } +UA_StatusCode COPC_UA_Local_Handler::executeStructAction(CActionInfo &paActionInfo, CIEC_ANY &paMember) { + UA_StatusCode retVal = UA_STATUSCODE_BADINTERNALERROR; + + CCriticalRegion criticalRegion(mServerAccessMutex); + switch(paActionInfo.getAction()){ + case CActionInfo::eWrite: + retVal = executeStructWrite(paActionInfo, paMember); + break; + default: //eCallMethod, eSubscribe will never reach here since they weren't initialized. eRead is a Subscribe FB + DEVLOG_ERROR("[OPC UA LOCAL]: Struct Action %d to be executed is unknown or invalid\n", paActionInfo.getAction()); + break; + } + + mServerNeedsIteration.inc(); + + return retVal; +} + UA_StatusCode COPC_UA_Local_Handler::uninitializeAction(CActionInfo &paActionInfo) { UA_StatusCode retVal = UA_STATUSCODE_BADINTERNALERROR; CCriticalRegion criticalRegion(mServerAccessMutex); @@ -871,6 +890,34 @@ UA_StatusCode COPC_UA_Local_Handler::executeWrite(CActionInfo &paActionInfo) { return retVal; } +UA_StatusCode COPC_UA_Local_Handler::executeStructWrite(CActionInfo &paActionInfo, CIEC_ANY &paMember) { + UA_StatusCode retVal = UA_STATUSCODE_GOOD; + + if(paMember.getDataTypeID() == CIEC_ANY::e_STRUCT) { + CIEC_STRUCT& structType = static_cast(paMember); + CStructActionInfo &structActionInfo = static_cast(paActionInfo); + std::vector> memberActionInfos = structActionInfo.getMemberActionInfos(); + for(size_t i = 0; i < memberActionInfos.size(); i++) { + std::shared_ptr memberActionInfo = memberActionInfos[i]; + CIEC_ANY *member = structType.getMember(i); + retVal = executeStructWrite(*memberActionInfo, *member); + if(retVal != UA_STATUSCODE_GOOD) { + return retVal; + } + } + } else { + auto it = paActionInfo.getNodePairInfo().begin(); + retVal = updateNodeValue(*it->getNodeId(), &paMember); + if(UA_STATUSCODE_GOOD != retVal) { + DEVLOG_ERROR("[OPC UA LOCAL]: Could not convert value to write for node %s at FB %s. Error: %s\n", + (*paActionInfo.getNodePairInfo().begin()).getBrowsePath(), + paActionInfo.getLayer().getCommFB()->getInstanceName(), UA_StatusCode_name(retVal)); + return retVal; + } + } + return retVal; +} + UA_StatusCode COPC_UA_Local_Handler::executeCreateMethod(CActionInfo &paActionInfo) { //This is the return of a local method call, when RSP is triggered diff --git a/src/com/opc_ua/opcua_local_handler.h b/src/com/opc_ua/opcua_local_handler.h index 79628db22..c7da16a41 100644 --- a/src/com/opc_ua/opcua_local_handler.h +++ b/src/com/opc_ua/opcua_local_handler.h @@ -87,6 +87,14 @@ class COPC_UA_Local_Handler : public COPC_UA_HandlerAbstract, public CThread { */ UA_StatusCode initializeActionForObjectStruct(std::shared_ptr &paActionInfo, CIEC_ANY &paMember); + /** + * Execute action for the given struct member + * @param paActionInfo Action of Struct member to be executed + * @param paMember Struct member + * @return UA_STATUSCODE_GOOD if no problem occurred, other value otherwise + */ + UA_StatusCode executeStructAction(CActionInfo &paActionInfo, CIEC_ANY &paMember); + /** * Splits a browsepath into folders and node name. The non-existing folders are created in the local server * @param paBrowsePath Browsepath to be splitted @@ -524,6 +532,14 @@ class COPC_UA_Local_Handler : public COPC_UA_HandlerAbstract, public CThread { */ UA_StatusCode executeWrite(CActionInfo &paActionInfo); + /** + * Execute the write action for a struct member + * @param paActionInfo Action to be executed + * @param paMember Struct member + * @return UA_STATUSCODE_GOOD is no problem occurred, other value otherwise + */ + UA_StatusCode executeStructWrite(CActionInfo &paActionInfo, CIEC_ANY &paMember); + /** * When the FB of the local method is triggered to signalize the end of the method, this function is called * @param paActionInfo Action to be executed diff --git a/src/com/opc_ua/opcua_objectstruct_helper.cpp b/src/com/opc_ua/opcua_objectstruct_helper.cpp index 100eef525..d22271302 100644 --- a/src/com/opc_ua/opcua_objectstruct_helper.cpp +++ b/src/com/opc_ua/opcua_objectstruct_helper.cpp @@ -260,8 +260,17 @@ CIEC_ANY const *COPC_UA_ObjectStruct_Helper::getStructMember(CActionInfo &paActi } forte::com_infra::EComResponse COPC_UA_ObjectStruct_Helper::executeStructAction() { - for(std::shared_ptr actionInfo : mStructMemberActionInfos) { - if(UA_STATUSCODE_GOOD != mHandler->executeAction(*actionInfo)) { + COPC_UA_Local_Handler* localHandler = static_cast(mHandler); + if(!localHandler) { + DEVLOG_ERROR("[OPC UA OBJECT STRUCT HELPER]: Failed to get LocalHandler because LocalHandler is null!\n"); + return e_InitTerminated; + } + CIEC_ANY** apoDataPorts = mLayer.getCommFB()->getSDs(); + CIEC_STRUCT& structType = static_cast(apoDataPorts[0]->unwrap()); + for(size_t i = 0; i < mStructMemberActionInfos.size(); i++) { + std::shared_ptr actionInfo = mStructMemberActionInfos[i]; + CIEC_ANY *member = structType.getMember(i); + if(localHandler->executeStructAction(*actionInfo, *member) != UA_STATUSCODE_GOOD) { return e_ProcessDataSendFailed; } } diff --git a/src/com/opc_ua/struct_action_info.h b/src/com/opc_ua/struct_action_info.h index c3d717cc6..2561c2407 100644 --- a/src/com/opc_ua/struct_action_info.h +++ b/src/com/opc_ua/struct_action_info.h @@ -28,6 +28,10 @@ class CStructActionInfo : public CStructMemberActionInfo { mStructMemberActionInfos.insert(mStructMemberActionInfos.end(), paActionInfos.begin(), paActionInfos.end()); } + std::vector> &getMemberActionInfos() { + return mStructMemberActionInfos; + } + private: std::vector> mStructMemberActionInfos;