Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OPC DA: Switch to OPCClientToolKit with 64bit support #32

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions src/com/opc/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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
Expand All @@ -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")
57 changes: 35 additions & 22 deletions src/com/opc/opcconnectionimpl.cpp
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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"
Expand Down Expand Up @@ -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;
}
}
}

Expand All @@ -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);
Expand Down Expand Up @@ -100,18 +111,17 @@ void COpcConnectionImpl::addItemList(const char* paGroupName, std::vector<std::s
return;
}

ATL::CString itemName(paReadItems[i].c_str());
std::wstring itemName(COPCHost::S2WS(paReadItems[i]));
try
{
COPCItem *newItem = itemGroup->addItem(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;
Expand Down Expand Up @@ -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;
}
Expand All @@ -224,15 +234,18 @@ int COpcConnectionImpl::sendItemData(const char *paGroupName, const char *paItem
return 0;
}

void COpcConnectionImpl::OnDataChange(COPCGroup & paGroup, CAtlMap<COPCItem *, OPCItemData *> & 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");
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
Expand Down
25 changes: 22 additions & 3 deletions src/com/opc/opcconnectionimpl.h
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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_
Expand All @@ -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();
Expand All @@ -47,10 +48,28 @@ class COpcConnectionImpl : public IAsynchDataCallback{

bool isConnected();

virtual void COpcConnectionImpl::OnDataChange(COPCGroup &paGroup, CAtlMap<COPCItem *, OPCItemData *> &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();

Expand Down
42 changes: 4 additions & 38 deletions src/com/opc/readme.txt
Original file line number Diff line number Diff line change
@@ -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:
<opcclientroot>/include - all headers should be placed here
<opcclientroot>/lib - OPCClientToolkit.lib
2. Choose <opcclientroot> for FORTE_COM_OPC_LIB_ROOT in CMake
3. Choose Boost root folder <boostroot> for FORTE_COM_OPC_BOOST_ROOT
Once the two libraries above are available, performe the steps below:
1. Choose <opcclientroot>/OPCClientToolKit for FORTE_COM_OPC_LIB_ROOT in CMake
2. Choose Boost root folder <boostroot> for FORTE_COM_OPC_BOOST_ROOT
(the lexical_cast.hpp header must be available in <boostroot>/boost)

Parameter Documentation (all values are required)
Expand Down