diff --git a/src/com/opc/CMakeLists.txt b/src/com/opc/CMakeLists.txt index 31e98364..8fa8fd65 100644 --- a/src/com/opc/CMakeLists.txt +++ b/src/com/opc/CMakeLists.txt @@ -1,5 +1,5 @@ #******************************************************************************* -# Copyright (c) 2012, 2021 AIT, ACIN, fortiss GmbH, Hit robot group +# Copyright (c) 2012, 2024 AIT, ACIN, fortiss GmbH, Hit robot group, Samator Indo Gas # This program and the accompanying materials are made available under the # terms of the Eclipse Public License 2.0 which is available at # http://www.eclipse.org/legal/epl-2.0. @@ -9,6 +9,7 @@ # Contributors: # Filip Andren, Alois Zoitl - initial API and implementation and/or initial documentation # Tibalt Zhao - Ease the workload to compile OPC DA +# Ketut Kumajaya - set OPCClientToolKit as an external sub project # *******************************************************************************/ ############################################################################# # OPC Com Layer @@ -31,9 +32,14 @@ if(FORTE_COM_OPC) forte_add_include_directories( ${FORTE_COM_OPC_BOOST_ROOT} ) - forte_add_include_directories( ${FORTE_COM_OPC_LIB_ROOT}/include ) - forte_add_link_directories( ${FORTE_COM_OPC_LIB_ROOT}/lib ) - - forte_add_link_library( OPCClientToolKit.lib ) + forte_add_include_directories( ${FORTE_COM_OPC_LIB_ROOT} ) + if(EXISTS ${FORTE_COM_OPC_LIB_ROOT}/CMakeLists.txt) + set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) + add_subdirectory( ${FORTE_COM_OPC_LIB_ROOT} OPCClientToolKit ) + else() + message(SEND_ERROR "FORTE_COM_OPC_LIB_ROOT not set or a compatible OPCClientToolKit does not exist") + endif() + forte_add_link_library( OPCClientToolKit ) + install(TARGETS OPCClientToolKit RUNTIME DESTINATION bin) endif(FORTE_COM_OPC) endif("${FORTE_ARCHITECTURE}" STREQUAL "Win32") \ No newline at end of file diff --git a/src/com/opc/opccomlayer.cpp b/src/com/opc/opccomlayer.cpp index 41841ca9..b6377463 100644 --- a/src/com/opc/opccomlayer.cpp +++ b/src/com/opc/opccomlayer.cpp @@ -99,11 +99,11 @@ EComResponse COpcComLayer::processInterrupt(){ switch (mConnectionState){ case e_Connected: { CIEC_ANY **apoRDs = mFb->getRDs(); - unsigned int nrRDs = mFb->getNumRD(); + size_t nrRDs = mFb->getNumRD(); TOpcProcessVarList::iterator itEnd = mFBOutputVars.end(); TOpcProcessVarList::iterator it = mFBOutputVars.begin(); - for(unsigned int i = 0; i < nrRDs && it != itEnd; i++, ++it){ + for(size_t i = 0; i < nrRDs && it != itEnd; i++, ++it){ setOutputValue(&apoRDs[i]->unwrap(), &(*it)->updateValue()); } diff --git a/src/com/opc/opcconnection.cpp b/src/com/opc/opcconnection.cpp index ed02e2d2..dcb14193 100644 --- a/src/com/opc/opcconnection.cpp +++ b/src/com/opc/opcconnection.cpp @@ -142,6 +142,9 @@ int COpcConnection::send_disconnect(const char *paGroupName){ mOpcGroupMapList.size(),mConnectionState, paGroupName); DEVLOG_INFO("remove group %s\n", paGroupName); removeGroup(paGroupName); + //remove fb goup and all group items + this->mOpcConnectionImpl->removeGroup(paGroupName); + this->mOpcConnectionImpl->removeItems(paGroupName); return -1 ; } diff --git a/src/com/opc/opcconnectionimpl.cpp b/src/com/opc/opcconnectionimpl.cpp index ced58152..abadae96 100644 --- a/src/com/opc/opcconnectionimpl.cpp +++ b/src/com/opc/opcconnectionimpl.cpp @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2022 AIT, ACIN, HIT robot group + * Copyright (c) 2012, 2024 AIT, ACIN, HIT robot group, Samator Indo Gas * This program and the accompanying materials are made available under the * terms of the Eclipse Public License 2.0 which is available at * http://www.eclipse.org/legal/epl-2.0. @@ -9,6 +9,7 @@ * Contributors: * Filip Andren, Alois Zoitl - initial API and implementation and/or initial documentation * Tibalt Zhao - add the list of items instead of add item one by one + * Ketut Kumajaya - switch to OPCClientToolKit with 64bit support *******************************************************************************/ #include "opcconnectionimpl.h" #include "../../arch/devlog.h" @@ -22,6 +23,11 @@ #include "OPCGroup.h" #include "OPCItem.h" +#define S2WS(x) COPCHost::S2WS(x) +#define LPCSTR2WS(x) COPCHost::LPCSTR2WS(x) +#define S2LPCTSTR(x) COPCHost::S2LPCTSTR(x) +#define WS2LPCTSTR(x) COPCHost::WS2LPCTSTR(x) + COpcConnectionImpl::COpcConnectionImpl(const char *paHost, const char *paServerName, COpcConnection* paOpcConn) : mOpcConn(paOpcConn), mOpcHost(0), mOpcServer(0),mConnected(0), mHost(paHost), mServerName(paServerName), mGroupName(0), mReqUpdateRate(0), mRealUpdateRate(0), mDeadBand(0) { @@ -42,6 +48,16 @@ void COpcConnectionImpl::disconnect(){//const char* paGroupName){ COPCClient::stop(); mConnected = false; this->clearGroup(); + + if (mOpcHost) { + delete mOpcHost; + mOpcHost = nullptr; + } + + if (mOpcServer) { + delete mOpcServer; + mOpcServer = nullptr; + } } } @@ -53,19 +69,16 @@ bool COpcConnectionImpl::connect(const char* paGroupName){ try{ DEVLOG_INFO("try to connect OPC server in COpcConnectionImpl[%s]\n",paGroupName); - HRESULT result = CoInitializeEx(nullptr, COINIT_MULTITHREADED); - if(result != S_FALSE && result != S_OK){ + if (true != COPCClient::init(OPCOLEInitMode::MULTITHREADED)) { DEVLOG_ERROR("CoInitializeEx init failed\n"); return false; } - COPCClient::init(); - - mOpcHost = COPCClient::makeHost(mHost); + mOpcHost = COPCClient::makeHost(LPCSTR2WS(mHost)); - mOpcServer = mOpcHost->connectDAServer(mServerName); + mOpcServer = mOpcHost->connectDAServer(LPCSTR2WS(mServerName)); } catch (OPCException &e){ - DEVLOG_ERROR("connect OPC server failed:%s[%s]\n",(LPCTSTR)(e.reasonString()),paGroupName); + DEVLOG_ERROR("connect OPC server failed:%s[%s]\n",WS2LPCTSTR(e.reasonString()),paGroupName); return false; } DEVLOG_INFO("successfully connect OPC server in COpcConnectionImpl[%s]\n",paGroupName); @@ -78,7 +91,7 @@ void COpcConnectionImpl::addItemList(const char* paGroupName, std::vectoraddItem(itemName, true); - //pa_pNewItem->setIsActive(true); - mOpcItems[itemGroup->getName()].push_back(newItem); + mOpcItems[WS2LPCTSTR(itemGroup->getName())].push_back(newItem); } catch (OPCException &e) { - DEVLOG_ERROR("addItem failed with exception:%s[%s:%s]\n", (LPCTSTR)(e.reasonString()), + DEVLOG_ERROR("addItem failed with exception:%s[%s:%s]\n", WS2LPCTSTR(e.reasonString()), groupName,paReadItems[i].c_str()); - if(strcmp((LPCTSTR)(e.reasonString()),"Failed to add item") != 0){ + if(strcmp(WS2LPCTSTR(e.reasonString()),"Failed to add item") != 0){ //pa_pNewItem->setIsActive(false); this->disconnect(); mConnected = false; @@ -201,12 +213,12 @@ int COpcConnectionImpl::sendItemData(const char *paGroupName, const char *paItem if(it != mOpcItems.end()){ lItems = it->second; for(size_t i = 0; i < lItems.size(); i++){ - if(0 == strcmp((LPCTSTR)(lItems[i]->getName()), paItemName)){ + if(0 == strcmp(WS2LPCTSTR(lItems[i]->getName()), paItemName)){ try{ lItems[i]->writeSync(paVar); } catch (OPCException &e){ - DEVLOG_ERROR("opcitem writesync failed with exception:%s[%s:%s]\n", (LPCTSTR)(e.reasonString()), writeGrpName, paItemName); + DEVLOG_ERROR("opcitem writesync failed with exception:%s[%s:%s]\n", WS2LPCTSTR(e.reasonString()), writeGrpName, paItemName); rtn = -1; break; } @@ -224,15 +236,20 @@ int COpcConnectionImpl::sendItemData(const char *paGroupName, const char *paItem return 0; } -void COpcConnectionImpl::OnDataChange(COPCGroup & paGroup, CAtlMap & paChanges){ +void COpcConnectionImpl::OnDataChange(COPCGroup & paGroup, COPCItemDataMap & paChanges){ TItemDataList itemList; - for(POSITION pos = paChanges.GetStartPosition(); pos != nullptr;){ - OPCItemData *itemData = paChanges.GetValueAt(pos); - COPCItem *item = paChanges.GetNextKey(pos); - itemList.push_back(new SOpcItemData((LPCTSTR) (item->getName()), (Variant) itemData->vDataValue)); + POSITION pos = paChanges.GetStartPosition(); + while(pos){ + OPCItemData *data = paChanges.GetNextValue(pos); + if (data) { + const COPCItem *item = data->item(); + if (item) { + itemList.push_back(new SOpcItemData(WS2LPCTSTR(item->getName()), (Variant) data->vDataValue)); + } + } } - const char *c_groupName = (const char*) paGroup.getName(); + const char *c_groupName = WS2LPCTSTR(paGroup.getName()); int position = 0; const char * subStrRead = strstr(c_groupName, "_read"); @@ -264,12 +281,12 @@ COPCGroup* COpcConnectionImpl::getOpcGroup(const char* paGroupName, bool paIfRea strcpy(groupName, paGroupName); strcat(groupName, "_read"); try{ - (*it)->mOpcGroupRead = retGroup = mOpcServer->makeGroup(groupName, true, (*it)->mReqUpdateRate, (*it)->mRevisedUpdateRate, (*it)->mDeadBand); - (*it)->mOpcGroupRead->enableAsynch(*this); + (*it)->mOpcGroupRead = retGroup = mOpcServer->makeGroup(LPCSTR2WS(groupName), true, (*it)->mReqUpdateRate, (*it)->mRevisedUpdateRate, (*it)->mDeadBand); + (*it)->mOpcGroupRead->enableAsync(this); (*it)->mReadGroupAdded = true; } catch (OPCException &e){ // TODO - DEVLOG_ERROR("exception in make opc group[%s]:%s\n",groupName,(LPCTSTR)(e.reasonString())); + DEVLOG_ERROR("exception in make opc group[%s]:%s\n",groupName,WS2LPCTSTR(e.reasonString())); (*it)->mOpcGroupRead = nullptr; retGroup = nullptr; } @@ -283,11 +300,11 @@ COPCGroup* COpcConnectionImpl::getOpcGroup(const char* paGroupName, bool paIfRea strcpy(groupName, paGroupName); strcat(groupName, "_write"); try{ - (*it)->mOpcGroupWrite = retGroup = mOpcServer->makeGroup(groupName, true, (*it)->mReqUpdateRate, (*it)->mRevisedUpdateRate, (*it)->mDeadBand); + (*it)->mOpcGroupWrite = retGroup = mOpcServer->makeGroup(LPCSTR2WS(groupName), true, (*it)->mReqUpdateRate, (*it)->mRevisedUpdateRate, (*it)->mDeadBand); (*it)->mWriteGroupAdded = true; } catch (OPCException &e){ // TODO - DEVLOG_ERROR("exception in make opc group[%s]:%s\n",groupName,(LPCTSTR)(e.reasonString())); + DEVLOG_ERROR("exception in make opc group[%s]:%s\n",groupName,WS2LPCTSTR(e.reasonString())); (*it)->mOpcGroupWrite = nullptr; (*it)->mOpcGroupWrite = nullptr; retGroup = nullptr; @@ -304,3 +321,37 @@ COPCGroup* COpcConnectionImpl::getOpcGroup(const char* paGroupName, bool paIfRea return retGroup; } + +void COpcConnectionImpl::removeItems(const char *paGroupName){ + if(paGroupName == nullptr){ + DEVLOG_ERROR("nullptr is passed to COpcConnectionImpl::removeItems\n"); + return; + } + DEVLOG_INFO("removeItems in COpcConnectionImpl[%s]\n",paGroupName); + + char *readGrpName= (char*) malloc(strlen(paGroupName) + 5 + 1); + strcpy(readGrpName, paGroupName); + strcat(readGrpName, "_read"); + + TOpcItemsIt it = mOpcItems.find(readGrpName); + if(it != mOpcItems.end()){ + mOpcItems.erase(it); + } + else{ + DEVLOG_ERROR("there is no item in group:%s\n", readGrpName); + } + free(readGrpName); + + char *writeGrpName= (char*) malloc(strlen(paGroupName) + 6 + 1); + strcpy(writeGrpName, paGroupName); + strcat(writeGrpName, "_write"); + + it = mOpcItems.find(writeGrpName); + if(it != mOpcItems.end()){ + mOpcItems.erase(it); + } + else{ + DEVLOG_ERROR("there is no item in group:%s\n", writeGrpName); + } + free(writeGrpName); +} diff --git a/src/com/opc/opcconnectionimpl.h b/src/com/opc/opcconnectionimpl.h index 4bce8e1e..7fd44185 100644 --- a/src/com/opc/opcconnectionimpl.h +++ b/src/com/opc/opcconnectionimpl.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2022 AIT, fortiss GmbH, HIT robot group + * Copyright (c) 2012, 2024 AIT, fortiss GmbH, HIT robot group, Samator Indo Gas * This program and the accompanying materials are made available under the * terms of the Eclipse Public License 2.0 which is available at * http://www.eclipse.org/legal/epl-2.0. @@ -9,13 +9,13 @@ * Contributors: * Filip Andren, Alois Zoitl - initial API and implementation and/or initial documentation * Tibalt Zhao - add the list of items instead of add item one by one + * Ketut Kumajaya - switch to OPCClientToolKit with 64bit support *******************************************************************************/ #ifndef OPCCONNECTIONIMPL_H_ #define OPCCONNECTIONIMPL_H_ #include "opcprocessvar.h" // Includes from OPC library -#include "windows.h" #include "opcda.h" #include "OPCClient.h" #include @@ -23,7 +23,7 @@ class COpcConnection; -class COpcConnectionImpl : public IAsynchDataCallback{ +class COpcConnectionImpl : public IAsyncDataCallback{ public: COpcConnectionImpl(const char *paHost, const char *paServerName, COpcConnection* paOpcConn); ~COpcConnectionImpl(); @@ -33,6 +33,7 @@ class COpcConnectionImpl : public IAsynchDataCallback{ void addItemList(const char* paGroupName, std::vector paReadItems,std::vector paWriteItems); bool addGroup(const char* paGroupName, unsigned long paReqUpdateRate, float paDeadBand); void removeGroup(const char* paGroupName); + void removeItems(const char* paGroupName); int sendItemData(const char*paGroupName, const char* paItemName, Variant paVar); @@ -47,7 +48,7 @@ class COpcConnectionImpl : public IAsynchDataCallback{ bool isConnected(); - virtual void COpcConnectionImpl::OnDataChange(COPCGroup &paGroup, CAtlMap &paChanges); + virtual void COpcConnectionImpl::OnDataChange(COPCGroup &paGroup, COPCItemDataMap &paChanges); private: diff --git a/src/com/opc/readme.txt b/src/com/opc/readme.txt index 5d73fdef..369b5b23 100644 --- a/src/com/opc/readme.txt +++ b/src/com/opc/readme.txt @@ -1,45 +1,11 @@ Installation Instructions The OPC com layer requires the following packages - - OPC Client library release 0.4 (http://sourceforge.net/projects/opcclient/) + - OPC Client library (https://github.com/kumajaya/OPC-Client-X64.git) - Boost Lexical Cast (http://www.boost.org) -Before OPC Client is compiled the function init() in OPCClient.cpp must be changed from: -void COPCClient::init() -{ - HRESULT result = CoInitialize(NULL); - if (FAILED(result)) - { - throw OPCException("CoInitialize failed"); - } - - CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL); - - result = CoGetMalloc(MEMCTX_TASK, &iMalloc); - if (FAILED(result)) - { - throw OPCException("CoGetMalloc failed"); - } -} - -to: -void COPCClient::init() -{ - CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL); - - HRESULT result = CoGetMalloc(MEMCTX_TASK, &iMalloc); - if (FAILED(result)) - { - throw OPCException("CoGetMalloc failed"); - } -} - - -Once the OPC Client library is compiled performe the steps below: -1. Place OPC Client library in the following folder structure: - /include - all headers should be placed here - /lib - OPCClientToolkit.lib -2. Choose for FORTE_COM_OPC_LIB_ROOT in CMake -3. Choose Boost root folder for FORTE_COM_OPC_BOOST_ROOT +Once the two libraries above are available locally, performe the steps below: +1. Choose /OPCClientToolKit for FORTE_COM_OPC_LIB_ROOT in CMake +2. Choose Boost root folder for FORTE_COM_OPC_BOOST_ROOT (the lexical_cast.hpp header must be available in /boost) Parameter Documentation (all values are required)