日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux/windows下基于opc ua协议使用open62541开发客户端-上

發(fā)布時(shí)間:2023/12/14 linux 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux/windows下基于opc ua协议使用open62541开发客户端-上 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

最近公司想把windows下軟件遷移到linux下,在與plc通訊方面西門子只提供windows下的庫,linux下沒有對(duì)應(yīng)庫,幸好發(fā)現(xiàn)有open62541這個(gè)協(xié)議外接庫,對(duì)應(yīng)的plc最低型號(hào)為s1200,還必須升級(jí)固件才行。官方貌似有實(shí)例代碼,但是看起來雜亂無章,現(xiàn)在整理一下。
很想直接上代碼,但是先簡(jiǎn)單介紹一下,使用博圖16版本進(jìn)行配合使用,連接有兩種方式,一種匿名連接,一種有名連接,根據(jù)需要自己選擇。
同時(shí)我們必須要了解節(jié)點(diǎn),NodeId 是節(jié)點(diǎn)的唯一編號(hào),NodeClass 是節(jié)點(diǎn)類型,BrowseName用于瀏覽,DisplayName 是節(jié)點(diǎn)的名稱,TypeDefinitionId是類型定義的唯一編號(hào)。我們所需要的是要知道節(jié)點(diǎn)的作用域以及節(jié)點(diǎn)編號(hào),這個(gè)可以在博圖16中看到,而且最多只能有500個(gè)點(diǎn)位,類似于snap7中的DB塊之類的東西,然后響應(yīng)時(shí)間之類的設(shè)置自己可以用博圖軟件修改。
下面上實(shí)現(xiàn)類代碼的頭文件:
這是對(duì)應(yīng)我們公司所需的,open62541中是直接看節(jié)點(diǎn)的,節(jié)點(diǎn)類型有Numberic、string、StringAlloc、ByteString、GUID等類型,我司只用到Numberic類型,該類型下就對(duì)應(yīng)int、dint、word、dword、bool、byte等數(shù)據(jù)類型的讀寫。

#ifndef CXNOPC_H #define CXNOPC_H#include "open62541.h" #include <QString> #include <QTime> #include <vector> #include <QThread> #include <QFile> #include <QTextStream> #include <QDateTime>using namespace std;/** NodeId 是節(jié)點(diǎn)的唯一編號(hào),NodeClass 是節(jié)點(diǎn)類型,BrowseName用于瀏覽,DisplayName 是節(jié)點(diǎn)的名稱,TypeDefinitionId是類型定義的唯一編號(hào)。*/class CXNOpc : public QThread {Q_OBJECT public:CXNOpc(QObject *parent = 0);~CXNOpc();public:bool InitXNOPC(QString qsUrl, QString qsLogFile, UA_ClientStateCallback stateCallback);bool ConnectOPCByUserName(QString qsUserName, QString qsPassWord);bool ConnectOPCByVisitor();void* GetOpcValueNumberic(UA_UInt16 nsIndex, UA_UInt32 identifier, int Type, int& length);bool SetOpcValueNumberic(UA_UInt16 nsIndex, UA_UInt32 identifier, int Type,void* value);bool AddNumbericMonitor(UA_UInt16 nsIndex, vector<UA_UInt32> identifier, UA_Client_DataChangeNotificationCallback callback);bool SetOpcMonitorTime(int time = 1);bool StartMonitorTask();bool StopMonitorTask();QString OutLogTime();protected:void run();private:bool ReadOpcNumberic(UA_UInt16 nsIndex, UA_UInt32 identifier, UA_Variant *val);bool ReadOpcString(UA_UInt16 nsIndex, char *chars, UA_Variant *val);bool ReadOpcStringAlloc(UA_UInt16 nsIndex, const char *chars, UA_Variant *val);bool ReadOpcGuid(UA_UInt16 nsIndex, UA_Guid guid, UA_Variant *val);bool ReadOpcByteString(UA_UInt16 nsIndex, char *chars, UA_Variant *val);bool ReadOpcByteStringAlloc(UA_UInt16 nsIndex, const char *chars, UA_Variant *val);bool WriteOpcNumberic(UA_UInt16 nsIndex, UA_UInt32 identifier, UA_Variant *myVariant);bool WriteOpcString(UA_UInt16 nsIndex, char *chars, UA_Variant *myVariant);bool WriteOpcStringAlloc(UA_UInt16 nsIndex, const char *chars, UA_Variant *myVariant);bool WriteOpcGuid(UA_UInt16 nsIndex, UA_Guid guid, UA_Variant *myVariant);bool WriteOpcByteString(UA_UInt16 nsIndex, char *chars, UA_Variant *myVariant);bool WriteOpcByteStringAlloc(UA_UInt16 nsIndex, const char *chars, UA_Variant *myVariant);bool AddSubscription();public:QTextStream* m_qOutLog;private:bool m_bIsInit;bool m_bIsConnect;bool m_bStatus;int m_time;QFile* m_qLogFile;QDateTime m_qLogTime;QString m_qsUrl;UA_UInt32 m_subId;UA_Client* m_pClient; };#endif // CXNOPC_H

下面是對(duì)應(yīng)的初始化客戶端以及兩種連接plc代碼

#include "cxnopc.h" #include <stdio.h> #include <unistd.h> #include <QDateTime>#define print(format, ...) \do \{ \printf(format, ##__VA_ARGS__); \} while (0)CXNOpc::CXNOpc(QObject *parent) : m_bIsInit(false),m_bIsConnect(false),m_bStatus(false),m_time(1),m_qLogFile(NULL),m_qOutLog(NULL) {}CXNOpc::~CXNOpc() {if(m_pClient != NULL && m_bIsConnect){if(m_subId > 0)UA_Client_Subscriptions_deleteSingle(m_pClient, m_subId);UA_Client_disconnect(m_pClient);UA_Client_delete(m_pClient);}if(m_bStatus){terminate();quit();}if(m_qLogFile != NULL){m_qLogFile->close();delete m_qLogFile;}if(m_qOutLog != NULL)delete m_qOutLog; }QString CXNOpc::OutLogTime() {m_qLogTime = QDateTime::currentDateTime();QString qStr = m_qLogTime.toString("yyy-MM-dd hh:mm::ss ddd");return qStr; }bool CXNOpc::InitXNOPC(QString qsUrl, QString qsLogFile, UA_ClientStateCallback stateCallback) {if(m_bIsInit)return m_bIsInit;if( qsUrl.size() == 0 )return m_bIsInit;elsem_qsUrl = qsUrl;m_qLogFile = new QFile(qsLogFile);if (!m_qLogFile->open(QIODevice::QIODevice::WriteOnly | QIODevice::Text))printf("Fail to open logfile\n");elsem_qOutLog = new QTextStream(m_qLogFile);QByteArray ba = qsUrl.toLatin1();char* pchUrl = ba.data();size_t szEndpointArraySize = 0;UA_ClientConfig clentConfig = UA_ClientConfig_default;clentConfig.stateCallback = stateCallback;m_pClient = UA_Client_new(clentConfig);UA_EndpointDescription* pEndpointArray = NULL;//查詢服務(wù)器節(jié)點(diǎn),存儲(chǔ)到結(jié)構(gòu)體數(shù)組中UA_EndpointDescriptionUA_StatusCode retvalue = UA_Client_getEndpoints(m_pClient, pchUrl,&szEndpointArraySize, &pEndpointArray);if(retvalue != UA_STATUSCODE_GOOD){UA_Array_delete(pEndpointArray, szEndpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);//刪除獲取的節(jié)點(diǎn)UA_Client_delete(m_pClient);//刪除客戶端return m_bIsInit;}//打印節(jié)點(diǎn)信息printf("%i endpoints found\n", (int)szEndpointArraySize); //1 1 endpoints foundfor(size_t i=0;i<szEndpointArraySize;i++)printf("URL of endpoint %i is %.*s\n", (int)i, (int)pEndpointArray[i].endpointUrl.length,pEndpointArray[i].endpointUrl.data);UA_Array_delete(pEndpointArray,szEndpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);m_bIsInit = true;return m_bIsInit; }bool CXNOpc::ConnectOPCByUserName(QString qsUserName, QString qsPassWord) {if(!m_bIsInit || m_bIsConnect)return m_bIsConnect;printf("%s-%s-%s\n",m_qsUrl.toLatin1().data(), qsUserName.toUtf8().data(), qsPassWord.toStdString().c_str());UA_StatusCode retvalue = UA_Client_connect_username(m_pClient, m_qsUrl.toLatin1().data(), qsUserName.toUtf8().data(), qsPassWord.toStdString().c_str());if(retvalue != UA_STATUSCODE_GOOD){UA_Client_delete(m_pClient);return m_bIsConnect;}//初始化 瀏覽請(qǐng)求UA_BrowseRequest uaBrowReq;UA_BrowseRequest_init(&uaBrowReq);uaBrowReq.requestedMaxReferencesPerNode = 0;uaBrowReq.nodesToBrowse = UA_BrowseDescription_new();uaBrowReq.nodesToBrowseSize = 1;uaBrowReq.nodesToBrowse[0].nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); /* browse objects folder */uaBrowReq.nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL; /* return everything *///瀏覽指定節(jié)點(diǎn)下NODEUA_BrowseResponse uaBrowResp = UA_Client_Service_browse(m_pClient, uaBrowReq);print("%-9s %-16s %-16s %-16s\n", "NAMESPACE", "NODEID", "BROWSE NAME", "DISPLAY NAME");for(size_t i = 0; i < uaBrowResp.resultsSize; ++i){for(size_t j = 0; j < uaBrowResp.results[i].referencesSize; ++j){UA_ReferenceDescription *puaReferDescrip = &(uaBrowResp.results[i].references[j]);if(puaReferDescrip->nodeId.nodeId.identifierType == UA_NODEIDTYPE_NUMERIC)print("%-9d %-16d %-16.*s %-16.*s\n", puaReferDescrip->nodeId.nodeId.namespaceIndex,puaReferDescrip->nodeId.nodeId.identifier.numeric, (int)puaReferDescrip->browseName.name.length,puaReferDescrip->browseName.name.data, (int)puaReferDescrip->displayName.text.length,puaReferDescrip->displayName.text.data);else if(puaReferDescrip->nodeId.nodeId.identifierType == UA_NODEIDTYPE_STRING)print("%-9d %-16.*s %-16.*s %-16.*s\n", puaReferDescrip->nodeId.nodeId.namespaceIndex,(int)puaReferDescrip->nodeId.nodeId.identifier.string.length,puaReferDescrip->nodeId.nodeId.identifier.string.data,(int)puaReferDescrip->browseName.name.length, puaReferDescrip->browseName.name.data,(int)puaReferDescrip->displayName.text.length, puaReferDescrip->displayName.text.data);}}fflush(stdout);UA_BrowseRequest_deleteMembers(&uaBrowReq);UA_BrowseResponse_deleteMembers(&uaBrowResp);m_bIsConnect = true;return m_bIsConnect; }bool CXNOpc::ConnectOPCByVisitor() {if(!m_bIsInit || m_bIsConnect)return m_bIsConnect;UA_StatusCode retvalue = UA_Client_connect(m_pClient, m_qsUrl.toLatin1().data());if(retvalue != UA_STATUSCODE_GOOD){UA_Client_delete(m_pClient);return m_bIsConnect;}//初始化 瀏覽請(qǐng)求UA_BrowseRequest uaBrowReq;UA_BrowseRequest_init(&uaBrowReq);uaBrowReq.requestedMaxReferencesPerNode = 0;uaBrowReq.nodesToBrowse = UA_BrowseDescription_new();uaBrowReq.nodesToBrowseSize = 1;uaBrowReq.nodesToBrowse[0].nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); /* browse objects folder */uaBrowReq.nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL; /* return everything *///瀏覽指定節(jié)點(diǎn)下NODEUA_BrowseResponse uaBrowResp = UA_Client_Service_browse(m_pClient, uaBrowReq);print("%-9s %-16s %-16s %-16s\n", "NAMESPACE", "NODEID", "BROWSE NAME", "DISPLAY NAME");for(size_t i = 0; i < uaBrowResp.resultsSize; ++i){for(size_t j = 0; j < uaBrowResp.results[i].referencesSize; ++j){UA_ReferenceDescription *puaReferDescrip = &(uaBrowResp.results[i].references[j]);if(puaReferDescrip->nodeId.nodeId.identifierType == UA_NODEIDTYPE_NUMERIC)print("%-9d %-16d %-16.*s %-16.*s\n", puaReferDescrip->nodeId.nodeId.namespaceIndex,puaReferDescrip->nodeId.nodeId.identifier.numeric, (int)puaReferDescrip->browseName.name.length,puaReferDescrip->browseName.name.data, (int)puaReferDescrip->displayName.text.length,puaReferDescrip->displayName.text.data);else if(puaReferDescrip->nodeId.nodeId.identifierType == UA_NODEIDTYPE_STRING)print("%-9d %-16.*s %-16.*s %-16.*s\n", puaReferDescrip->nodeId.nodeId.namespaceIndex,(int)puaReferDescrip->nodeId.nodeId.identifier.string.length,puaReferDescrip->nodeId.nodeId.identifier.string.data,(int)puaReferDescrip->browseName.name.length, puaReferDescrip->browseName.name.data,(int)puaReferDescrip->displayName.text.length, puaReferDescrip->displayName.text.data);}}fflush(stdout);UA_BrowseRequest_deleteMembers(&uaBrowReq);UA_BrowseResponse_deleteMembers(&uaBrowResp);m_bIsConnect = true;return m_bIsConnect; }

剩下的讀寫點(diǎn)的方式后面再介紹,有需要的伙伴可以qq我 965434757

總結(jié)

以上是生活随笔為你收集整理的linux/windows下基于opc ua协议使用open62541开发客户端-上的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。