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: Upgrade to OPCClientToolKit with 64bit support #37

Merged
merged 1 commit into from
Mar 26, 2024
Merged
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
7 changes: 4 additions & 3 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 - switch to OPCClientToolKit with 64bit support
# *******************************************************************************/
#############################################################################
# OPC Com Layer
Expand All @@ -31,9 +32,9 @@ 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_include_directories( ${FORTE_COM_OPC_LIB_ROOT}/include/OPCClientToolKit )
forte_add_link_directories( ${FORTE_COM_OPC_LIB_ROOT}/lib )

forte_add_link_library( OPCClientToolKit.lib )
forte_add_link_library( OPCClientToolKit )
endif(FORTE_COM_OPC)
endif("${FORTE_ARCHITECTURE}" STREQUAL "Win32")
4 changes: 2 additions & 2 deletions src/com/opc/opccomlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}

Expand Down
19 changes: 16 additions & 3 deletions src/com/opc/opcconnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ void COpcConnection::removeGroup(const char* paGroupName){
} else{
removeGroupCallbackDesc(paGroupName);
}
//remove fb group and all group items
this->mOpcConnectionImpl->removeGroup(paGroupName);
}

bool COpcConnection::ifLetEventPass(EOpcConnectionEvents paEvent, const char* paGroupName){
Expand Down Expand Up @@ -152,7 +154,7 @@ int COpcConnection::maintainGroupMapInfo(COpcProcessVar* paNewItem){
if(paNewItem->getItemFunction() == COpcProcessVar::e_FBOutput){
//check if item already added
for(auto item = (*group)->mReadItemsList.begin(); item != (*group)->mReadItemsList.end(); ++item){
if(strcmp((*item)->mItemName, paNewItem->getItemName()) == 0){
if((*item)->mItemName.compare(paNewItem->getItemName()) == 0){
return 1;
}
}
Expand All @@ -162,7 +164,7 @@ int COpcConnection::maintainGroupMapInfo(COpcProcessVar* paNewItem){
else if(paNewItem->getItemFunction() == COpcProcessVar::e_FBInput){
//check if item already added
for(auto item = (*group)->mWriteItemsList.begin(); item != (*group)->mWriteItemsList.end(); ++item){
if(strcmp((*item)->mItemName, paNewItem->getItemName()) == 0){
if((*item)->mItemName.compare(paNewItem->getItemName()) == 0){
return 1;
}
}
Expand Down Expand Up @@ -214,7 +216,7 @@ void COpcConnection::response_dataReceived(const char *paGroupName, TItemDataLis
for(auto item = (*group)->mReadItemsList.begin(); item != (*group)->mReadItemsList.end(); ++item){
// Loop through OpcItems in ItemDataList
for(auto newItem = paItemDataList.begin(); newItem != paItemDataList.end(); ++newItem){
if(strcmp((*newItem)->mItemName, (*item)->mItemName) == 0){
if((*newItem)->mItemName.compare((*item)->mItemName) == 0){
(*item)->mItemData = (*newItem)->mItemData;
paItemDataList.erase(newItem);
break;
Expand All @@ -226,6 +228,17 @@ void COpcConnection::response_dataReceived(const char *paGroupName, TItemDataLis
break;
}
}
// Should not happen unless something is manipulating the contents of the string
if(!paItemDataList.empty()){
int count = 0;
for(size_t i = 0; i < paItemDataList.size(); i++){
DEVLOG_INFO("deleting item from onchange itemlist[%s:%s]\n",paGroupName,paItemDataList[i]->mItemName);
delete paItemDataList[i];
count++;
}
paItemDataList.clear();
DEVLOG_ERROR("there are %d items cleared from onchange itemlist[%s]\n",count,paGroupName);
}
}

void COpcConnection::response_dataSent(const char* paGroupName,const char* paItemName, bool paSuccess){
Expand Down
6 changes: 3 additions & 3 deletions src/com/opc/opcconnection.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ class COpcProcessVar;
class COpcEventHandler;

struct SOpcItemData{
const char* mItemName;
const std::string mItemName;
Variant mItemData;

explicit SOpcItemData(const char* paItemName) :
explicit SOpcItemData(const std::string paItemName) :
mItemName(paItemName){
mItemData.set<SHORT>(0);
}
SOpcItemData(const char* paItemName, Variant paItemData) :
SOpcItemData(const std::string paItemName, Variant paItemData) :
mItemName(paItemName), mItemData(paItemData){
}
};
Expand Down
120 changes: 81 additions & 39 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 All @@ -22,6 +23,9 @@
#include "OPCGroup.h"
#include "OPCItem.h"

#define S2WS(x) COPCHost::S2WS(x)
#define WS2S(x) COPCHost::WS2S(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) {
Expand All @@ -39,33 +43,39 @@ void COpcConnectionImpl::disconnect(){//const char* paGroupName){
DEVLOG_INFO("COpcConnectionImpl disconnect\n");
if (isConnected())
{
COPCClient::stop();
mConnected = false;
this->clearGroup();
if (mOpcHost != nullptr) {
delete mOpcHost;
mOpcHost = nullptr;
}

if (mOpcServer != nullptr) {
delete mOpcServer;
mOpcServer = nullptr;
}

COPCClient::stop();
mConnected = false;
}
}

bool COpcConnectionImpl::connect(const char* paGroupName){
if(isConnected()){
DEVLOG_DEBUG("COpcConnectionImpl::connect: already connected[%s]\n",paGroupName);
return true;
DEVLOG_DEBUG("COpcConnectionImpl::connect: already connected[%s]\n",paGroupName);
return true;
}

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(S2WS(std::string(mHost)));

mOpcServer = mOpcHost->connectDAServer(mServerName);
mOpcServer = mOpcHost->connectDAServer(S2WS(std::string(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",WS2S(e.reasonString()).c_str(),paGroupName);
return false;
}
DEVLOG_INFO("successfully connect OPC server in COpcConnectionImpl[%s]\n",paGroupName);
Expand All @@ -78,14 +88,14 @@ void COpcConnectionImpl::addItemList(const char* paGroupName, std::vector<std::s
//we assume all the items in pa_lNewItems are of same group
const char * groupName = nullptr;
TItemDataList itemList;
unsigned int nreadSize = paReadItems.size();
DEVLOG_INFO("adding items in COpcConnectionImpl[%s]\n", paGroupName);
size_t readSize = paReadItems.size();
//now paReadItems contains read and write items
paReadItems.insert(paReadItems.end(), paWriteItems.begin(), paWriteItems.end());
for(size_t i = 0; i < paReadItems.size(); i++){
groupName = paGroupName;
DEVLOG_INFO("adding item %s in COpcConnectionImpl[%s]\n", paReadItems[i].c_str(),groupName);
COPCGroup *itemGroup = nullptr;
if(i + 1 > nreadSize){
if(i + 1 > readSize){
itemGroup = getOpcGroup(groupName, false);
}
else{
Expand All @@ -100,18 +110,19 @@ void COpcConnectionImpl::addItemList(const char* paGroupName, std::vector<std::s
return;
}

ATL::CString itemName(paReadItems[i].c_str());
DEVLOG_DEBUG("adding item %s in COpcConnectionImpl[%s]\n", paReadItems[i].c_str(), WS2S(itemGroup->getName()).c_str());
std::wstring itemName(S2WS(paReadItems[i]));
try
{
COPCItem *newItem = itemGroup->addItem(itemName, true);
//pa_pNewItem->setIsActive(true);
mOpcItems[itemGroup->getName()].push_back(newItem);
mOpcItems[WS2S(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", WS2S(e.reasonString()).c_str(),
groupName,paReadItems[i].c_str());
if(strcmp((LPCTSTR)(e.reasonString()),"Failed to add item") != 0){
if(e.reasonString().compare(L"COPCGroup::addItem: FAILED to add item") != 0){
//pa_pNewItem->setIsActive(false);
this->disconnect();
mConnected = false;
Expand All @@ -132,7 +143,6 @@ void COpcConnectionImpl::addItemList(const char* paGroupName, std::vector<std::s
if(!itemList.empty()){
mOpcConn->response_dataReceived(groupName,itemList);
}

}

bool COpcConnectionImpl::addGroup(const char* paGroupName, unsigned long paReqUpdateRate, float paDeadBand){
Expand All @@ -152,6 +162,29 @@ bool COpcConnectionImpl::addGroup(const char* paGroupName, unsigned long paReqUp
return true;
}

void COpcConnectionImpl::removeItems(const char* paGroupName){
if(nullptr == paGroupName){
DEVLOG_INFO("COpcConnectionImpl::removeItems: group name is nullptr\n");
return;
}
DEVLOG_INFO("removing items in COpcConnectionImpl[%s]\n", paGroupName);
std::vector<COPCItem *> items;

TOpcItemsIt it = mOpcItems.find(paGroupName);
if(it != mOpcItems.end()){
items = it->second;
for(size_t i = 0; i < items.size(); i++){
DEVLOG_DEBUG("removing item %s in COpcConnectionImpl[%s]\n", WS2S(items[i]->getName()).c_str(), paGroupName);
delete items[i];
}
items.clear();
mOpcItems.erase(it);
}
else{
DEVLOG_ERROR("there is no item in group:%s\n", paGroupName);
}
}

void COpcConnectionImpl::removeGroup(const char* paGroupName){
if(paGroupName == nullptr){
DEVLOG_INFO("nullptr is passed to removeGroup,clear the group\n");
Expand All @@ -161,6 +194,8 @@ void COpcConnectionImpl::removeGroup(const char* paGroupName){
}
for(auto group = mOpcGroupSettingsList.begin(); group != mOpcGroupSettingsList.end();){
if(nullptr == paGroupName || 0 == strcmp((*group)->mGroupName, paGroupName)){
removeItems(WS2S((*group)->mOpcGroupRead->getName()).c_str());
removeItems(WS2S((*group)->mOpcGroupWrite->getName()).c_str());
delete (*group)->mOpcGroupRead;
delete (*group)->mOpcGroupWrite;
group = mOpcGroupSettingsList.erase(group);
Expand Down Expand Up @@ -191,22 +226,23 @@ int COpcConnectionImpl::sendItemData(const char *paGroupName, const char *paItem
}
int rtn = -1;
DEVLOG_INFO("sendItemData in COpcConnectionImpl[%s:%s]\n",paGroupName,paItemName);
std::vector<COPCItem *> lItems;
std::vector<COPCItem *> items;

char *writeGrpName= (char*) malloc(strlen(paGroupName) + 6 + 1);
strcpy(writeGrpName, paGroupName);
strcat(writeGrpName, "_write");

TOpcItemsIt it = mOpcItems.find(writeGrpName);
if(it != mOpcItems.end()){
lItems = it->second;
for(size_t i = 0; i < lItems.size(); i++){
if(0 == strcmp((LPCTSTR)(lItems[i]->getName()), paItemName)){
items = it->second;
for(size_t i = 0; i < items.size(); i++){
std::string itemName = WS2S(items[i]->getName());
if(0 == strcmp(itemName.c_str(), paItemName)){
try{
lItems[i]->writeSync(paVar);
items[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", WS2S(e.reasonString()).c_str(), writeGrpName, paItemName);
rtn = -1;
break;
}
Expand All @@ -224,17 +260,23 @@ 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) {
// Possible unpredictable string behavior in a multi-threaded program
std::string itemName = WS2S(data->item()->getName());
itemList.push_back(new SOpcItemData(itemName.c_str(), (Variant) data->vDataValue));
}
}

const char *c_groupName = (const char*) paGroup.getName();
// Possible unpredictable string behavior in a multi-threaded program
std::string s_groupName = WS2S(paGroup.getName());
const char *c_groupName = s_groupName.c_str();

int position = 0;
long long position = 0;
const char * subStrRead = strstr(c_groupName, "_read");
if(subStrRead != nullptr) {
position = subStrRead - c_groupName;
Expand Down Expand Up @@ -264,12 +306,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(S2WS(std::string(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,WS2S(e.reasonString()).c_str());
(*it)->mOpcGroupRead = nullptr;
retGroup = nullptr;
}
Expand All @@ -283,11 +325,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(S2WS(std::string(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,WS2S(e.reasonString()).c_str());
(*it)->mOpcGroupWrite = nullptr;
(*it)->mOpcGroupWrite = nullptr;
retGroup = nullptr;
Expand Down
Loading