blob: ced5815258753cfc1731fa47e1ae2eb0aa036b66 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012, 2022 AIT, ACIN, HIT robot group
* 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.
*
* SPDX-License-Identifier: EPL-2.0
*
* 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
*******************************************************************************/
#include "opcconnectionimpl.h"
#include "../../arch/devlog.h"
#include "opceventhandler.h"
#include "opcconnection.h"
#include "OPCClient.h"
#include "OPCHost.h"
#include "OPCServer.h"
#include "OPCGroup.h"
#include "OPCItem.h"
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) {
}
COpcConnectionImpl::~COpcConnectionImpl(){
DEVLOG_DEBUG("COpcConnectionImpl ~COpcConnectionImpl\n");
}
bool COpcConnectionImpl::isConnected(){
return mConnected;
}
void COpcConnectionImpl::disconnect(){//const char* paGroupName){
DEVLOG_INFO("COpcConnectionImpl disconnect\n");
if (isConnected())
{
COPCClient::stop();
mConnected = false;
this->clearGroup();
}
}
bool COpcConnectionImpl::connect(const char* paGroupName){
if(isConnected()){
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){
DEVLOG_ERROR("CoInitializeEx init failed\n");
return false;
}
COPCClient::init();
mOpcHost = COPCClient::makeHost(mHost);
mOpcServer = mOpcHost->connectDAServer(mServerName);
} catch (OPCException &e){
DEVLOG_ERROR("connect OPC server failed:%s[%s]\n",(LPCTSTR)(e.reasonString()),paGroupName);
return false;
}
DEVLOG_INFO("successfully connect OPC server in COpcConnectionImpl[%s]\n",paGroupName);
mConnected = true;
return true;
}
void COpcConnectionImpl::addItemList(const char* paGroupName, std::vector<std::string> paReadItems,
std::vector<std::string> paWriteItems){
//we assume all the items in pa_lNewItems are of same group
const char * groupName = nullptr;
TItemDataList itemList;
unsigned int nreadSize = 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){
itemGroup = getOpcGroup(groupName, false);
}
else{
itemGroup = getOpcGroup(groupName, true);
}
if (itemGroup == nullptr){
DEVLOG_INFO("there is no group for this item:%s [%s]\n", paReadItems[i].c_str(), groupName);
//pa_pNewItem->setIsActive(false);
this->disconnect();
mConnected = false;
mOpcConn->response_connect(false, groupName);
return;
}
ATL::CString itemName(paReadItems[i].c_str());
try
{
COPCItem *newItem = itemGroup->addItem(itemName, true);
//pa_pNewItem->setIsActive(true);
mOpcItems[itemGroup->getName()].push_back(newItem);
}
catch (OPCException &e)
{
DEVLOG_ERROR("addItem failed with exception:%s[%s:%s]\n", (LPCTSTR)(e.reasonString()),
groupName,paReadItems[i].c_str());
if(strcmp((LPCTSTR)(e.reasonString()),"Failed to add item") != 0){
//pa_pNewItem->setIsActive(false);
this->disconnect();
mConnected = false;
mOpcConn->response_connect(false, groupName);
return;
}
else{
DEVLOG_ERROR("Check the opc item name: %s, probably it is wrong![%s]\n",
paReadItems[i].c_str(),groupName);
itemList.push_back(new SOpcItemData(paReadItems[i].c_str(), (Variant)NAN ));
}
}
}
if (!paReadItems.empty()){
mOpcConn->response_connect(true, groupName);
}
if(!itemList.empty()){
mOpcConn->response_dataReceived(groupName,itemList);
}
}
bool COpcConnectionImpl::addGroup(const char* paGroupName, unsigned long paReqUpdateRate, float paDeadBand){
if(nullptr == paGroupName){
DEVLOG_INFO("COpcConnectionImpl::addGroup: group name is nullptr\n");
return false;
}
DEVLOG_INFO("addGroup in COpcConnectionImpl[%s]\n", paGroupName);
for(auto var : mOpcGroupSettingsList){
if(strcmp(var->mGroupName,paGroupName) == 0){
DEVLOG_INFO("COpcConnectionImpl::addGroup: %s is already added\n", paGroupName);
return false;
}
}
mOpcGroupSettingsList.push_back(new SOpcGroupSettings(paGroupName, paReqUpdateRate, paDeadBand));
return true;
}
void COpcConnectionImpl::removeGroup(const char* paGroupName){
if(paGroupName == nullptr){
DEVLOG_INFO("nullptr is passed to removeGroup,clear the group\n");
}
else{
DEVLOG_INFO("removeGroup in COpcConnectionImpl[%s]\n",paGroupName);
}
for(auto group = mOpcGroupSettingsList.begin(); group != mOpcGroupSettingsList.end();){
if(nullptr == paGroupName || 0 == strcmp((*group)->mGroupName, paGroupName)){
delete (*group)->mOpcGroupRead;
delete (*group)->mOpcGroupWrite;
group = mOpcGroupSettingsList.erase(group);
if(nullptr == paGroupName){
continue;
}
else{
break;
}
}
else{
group++;
}
}
return;
}
void COpcConnectionImpl::clearGroup(){
DEVLOG_INFO("clearGroup in COpcConnectionImpl\n");
mOpcItems.clear();
removeGroup(0);
}
int COpcConnectionImpl::sendItemData(const char *paGroupName, const char *paItemName, Variant paVar){
if(paGroupName == nullptr || paItemName == nullptr) {
DEVLOG_ERROR("nullptr is passed to COpcConnectionImpl::sendItemData\n");
return -1;
}
int rtn = -1;
DEVLOG_INFO("sendItemData in COpcConnectionImpl[%s:%s]\n",paGroupName,paItemName);
std::vector<COPCItem *> lItems;
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)){
try{
lItems[i]->writeSync(paVar);
}
catch (OPCException &e){
DEVLOG_ERROR("opcitem writesync failed with exception:%s[%s:%s]\n", (LPCTSTR)(e.reasonString()), writeGrpName, paItemName);
rtn = -1;
break;
}
rtn = 0;
break;
}
}
}
else{
DEVLOG_ERROR("there is no item in group:%s\n", writeGrpName);
rtn = -1;
}
mOpcConn->response_dataSent(paGroupName, paItemName, rtn == 0 ? true : false);
free(writeGrpName);
return 0;
}
void COpcConnectionImpl::OnDataChange(COPCGroup & paGroup, CAtlMap<COPCItem *, OPCItemData *> & 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));
}
const char *c_groupName = (const char*) paGroup.getName();
int position = 0;
const char * subStrRead = strstr(c_groupName, "_read");
if(subStrRead != nullptr) {
position = subStrRead - c_groupName;
}
else{
//TODO Should not happen error
}
char * groupName = (char*) malloc(position + 1);
strncpy(groupName, c_groupName, position);
groupName[position] = '\0';
mOpcConn->response_dataReceived(groupName, itemList);
free(groupName);
}
COPCGroup* COpcConnectionImpl::getOpcGroup(const char* paGroupName, bool paIfRead){
COPCGroup *retGroup = nullptr;
TOpcGroupSettingsList::iterator itEnd = mOpcGroupSettingsList.end();
for(TOpcGroupSettingsList::iterator it = mOpcGroupSettingsList.begin(); it != itEnd; ++it){
if(strcmp((*it)->mGroupName, paGroupName) == 0){
if(paIfRead){
if(!((*it)->mReadGroupAdded)){
char *groupName = (char*) malloc(strlen(paGroupName) + 5 + 1);
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)->mReadGroupAdded = true;
} catch (OPCException &e){
// TODO
DEVLOG_ERROR("exception in make opc group[%s]:%s\n",groupName,(LPCTSTR)(e.reasonString()));
(*it)->mOpcGroupRead = nullptr;
retGroup = nullptr;
}
free(groupName);
} else {
retGroup = (*it)->mOpcGroupRead;
}
} else{
if(!((*it)->mWriteGroupAdded)){
char *groupName = (char*) malloc(strlen(paGroupName) + 6 + 1);
strcpy(groupName, paGroupName);
strcat(groupName, "_write");
try{
(*it)->mOpcGroupWrite = retGroup = mOpcServer->makeGroup(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()));
(*it)->mOpcGroupWrite = nullptr;
(*it)->mOpcGroupWrite = nullptr;
retGroup = nullptr;
}
free(groupName);
} else {
retGroup = (*it)->mOpcGroupWrite;
}
}
break;
}
}
return retGroup;
}