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/opcconnectionimpl.cpp b/src/com/opc/opcconnectionimpl.cpp index ced58152..1c0450e3 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" @@ -42,6 +43,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; + } } } @@ -61,11 +72,11 @@ bool COpcConnectionImpl::connect(const char* paGroupName){ COPCClient::init(); - mOpcHost = COPCClient::makeHost(mHost); + mOpcHost = COPCClient::makeHost(COPCHost::LPCSTR2WS(mHost)); - mOpcServer = mOpcHost->connectDAServer(mServerName); + mOpcServer = mOpcHost->connectDAServer(COPCHost::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); @@ -100,18 +111,17 @@ void COpcConnectionImpl::addItemList(const char* paGroupName, std::vectoraddItem(itemName, true); - //pa_pNewItem->setIsActive(true); - mOpcItems[itemGroup->getName()].push_back(newItem); + mOpcItems[itemGroup->getName().c_str()].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 +211,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 +234,18 @@ 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(); + 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 +277,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(COPCHost::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 +296,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(COPCHost::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; diff --git a/src/com/opc/opcconnectionimpl.h b/src/com/opc/opcconnectionimpl.h index 4bce8e1e..70160630 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,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 *******************************************************************************/ #ifndef OPCCONNECTIONIMPL_H_ #define OPCCONNECTIONIMPL_H_ @@ -23,7 +24,7 @@ class COpcConnection; -class COpcConnectionImpl : public IAsynchDataCallback{ +class COpcConnectionImpl : public IAsyncDataCallback{ public: COpcConnectionImpl(const char *paHost, const char *paServerName, COpcConnection* paOpcConn); ~COpcConnectionImpl(); @@ -47,10 +48,28 @@ class COpcConnectionImpl : public IAsynchDataCallback{ bool isConnected(); - virtual void COpcConnectionImpl::OnDataChange(COPCGroup &paGroup, CAtlMap &paChanges); + virtual void COpcConnectionImpl::OnDataChange(COPCGroup &paGroup, COPCItemDataMap &paChanges); private: + static const char* WS2LPCTSTR(const std::wstring &wstr) { + const wchar_t *input = wstr.c_str(); + // Count required buffer size (plus one for null-terminator). + size_t size = (wcslen(input) + 1) * sizeof(wchar_t); + char *buffer = new char[size]; + #ifdef __STDC_LIB_EXT1__ + // wcstombs_s is only guaranteed to be available if __STDC_LIB_EXT1__ is defined + size_t convertedSize; + std::wcstombs_s(&convertedSize, buffer, size, input, size); + #else + std::wcstombs(buffer, input, size); + #endif + const char *ret = (const char*) buffer; + // Free allocated memory: + delete buffer; + return ret; + } + COPCGroup* getOpcGroup(const char* paGroupName, bool paIfRead); void clearGroup(); diff --git a/src/com/opc/readme.txt b/src/com/opc/readme.txt index 5d73fdef..2a2b7f9c 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, 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)