OneApiConnect通讯demo,fins欧姆龙协议实现
每家PLC厂商都有自己的通讯协议,三菱有MC、倍福有ADS,然而没有统一性的接口协议。
为适应每一家通讯,每一家设备商、MES和工厂等都需要针对每款产品开发相应的通讯接口。
OneConnectAPI为实现统一的接口,去适配每一家厂商的协议。为中国工控行业快速发展而贡献,每一家公司都需要重新制造轮子,这是非常浪费时间和金钱,同时也不能保证稳定性以及持续的维护。
我们采取高效的多线程处理方案,保证极其高效的读写性能,对电脑性能要求极其低,一直进行读写操作,CPU使用率不超过1%(Atom E3940下测试)。
用户可以在一台工控机上进行对上百台的PLC主动读写操作,我们在光伏行业大量应用和测试过。
我们在半导体行业深耕多年,积累大量的经验,实现功能的同时,也需要保证极其严格的稳定性,晶圆生成设备7*24小时不能出任何故障。
下载地址 软件及资料书www.secsgemc.om
下边 https://gitee.com/secsgem/one-api-connect/tree/master/
https://github.com/SECSGEM/Fins
#pragma once
#include <string>
#include "InterfaceExport.h"
#include "ModuleDevelopH.h"// 欧姆龙Fins协议
class CFins
{
public:CFins();virtual ~CFins();// 参数CResult SetIP(std::string pIP); // 设置地址CResult SetPort(int nPort); // 设置端口号CResult SetTimeout(int nTimeMs); // 设置超时// 读出CResult Read(std::string pAddr, char& pData); CResult Read(std::string pAddr, __int16& pData); CResult Read(std::string pAddr, __int32& pData); CResult Read(std::string pAddr, __int64& pData);CResult Read(std::string pAddr, char* pData, int nSize); CResult Read(std::string pAddr, __int16* pData, int nSize); CResult Read(std::string pAddr, __int32* pData, int nSize); CResult Read(std::string pAddr, __int64* pData, int nSize); // 写入 CResult Write(std::string pAddr, char& pData); CResult Write(std::string pAddr, __int16& pData); CResult Write(std::string pAddr, __int32& pData); CResult Write(std::string pAddr, __int64& pData); CResult Write(std::string pAddr, char* pData, __int32 nSize); CResult Write(std::string pAddr, __int16* pData, __int32 nSize); CResult Write(std::string pAddr, __int32* pData, __int32 nSize); CResult Write(std::string pAddr, __int64* pData, __int32 nSize); private:CResult SetParament(std::string pName, std::string pValue); CResult SetParament(std::string pName, int nValue); private:CInterfaceExport* m_pFins;CMgrDllDelegate m_pLoadInterface;};
#include "stdafx.h"
#include "FinsHandle.h"CFinsHandle::CFinsHandle()
{m_bEstablishCommunicationByFins = false;m_nIpNode = 0;
}// 重写数据接收,用于协议识别
void CFinsHandle::OnDataRecv(char* pData, int nSize)
{if (nSize > 0){ m_pRecvData.Append(pData, nSize);if (m_pRecvData.Size() >= FINS_TCP_HEAD_SIZE){FINS_TCP_HEAD pHead;pHead.SetData(m_pRecvData.GetString());int nAllSize = pHead.GetLength();if (m_pRecvData.Size() >= nAllSize){SetRecvComplete(nAllSize);}}}
}// 重写数据接收,开始接收数据,用于协议识别
void CFinsHandle::OnBeginRecv()
{m_pRecvData.SetSize(0);
}// 通讯关闭
void CFinsHandle::OnCloseConnect()
{m_bEstablishCommunicationByFins = false;
}long CFinsHandle::ReadMemoryData(int nAddr, int nSize, FINS_DATA_TYPE::ENUM nType, __int16* pData)
{long nCode = 0;if(nCode = EstablishCommunicationByFins()){return nCode;}CMyString pSendData;// 获取发送内存int nAllSize;nAllSize = FINS_TCP_HEAD_SIZE;nAllSize += FINS_CONTROL_HEAD_SIZE;nAllSize += FINS_MEMORY_AREA_READ_SIZE; pSendData.SetSize(nAllSize);char* pBuff = pSendData.GetString();// 头部信息FINS_TCP_HEAD pHead; pHead.nCommand = FINS_TCP_CMD_DATA;pHead.SetLength(nAllSize); //长度pHead.GetData(pBuff);// control部分FINS_CONTROL_HEAD pControlHead;pControlHead.nDA1 = 0; pControlHead.nSA1 = m_nIpNode;pControlHead.nCmd1 = 0x01;pControlHead.nCmd2 = 0x01;pControlHead.GetData(pBuff + FINS_TCP_HEAD_SIZE);// 数据部分FINS_MEMORY_AREA_READ pMemory;pMemory.nAreaCode = nType;pMemory.nAddr = nAddr;pMemory.nBitNo = 0;pMemory.nLength = nSize;pMemory.GetData(pBuff + FINS_TCP_HEAD_SIZE + FINS_CONTROL_HEAD_SIZE);// // 发送数据CMyString pRecvData;nCode = SendSyncData(pSendData, pRecvData);if (nCode == 0){// 先判断答复数据的头数据是否正确 if(nCode = CheckReplyDataIsError(pRecvData.GetString(), pRecvData.Size())){return nCode;}// 数据头FINS_TCP_HEAD pHeadReply;pHeadReply.SetData(pRecvData.GetString());// 答复长度要求int nMinSize = FINS_TCP_HEAD_SIZE + FINS_CONTROL_HEAD_SIZE + FINS_MEMORY_AREA_READ_FIX_R_SIZE + nSize * 2;if(pHeadReply.GetLength() < nMinSize){return FINS_REPLY_READ_DATA_TOO_SHORT;}else{// FINS协议部分FINS_CONTROL_HEAD pControlHeadReply;pControlHeadReply.SetData(pRecvData.GetString());if (pControlHeadReply.nCmd1 != pControlHead.nCmd1 ||pControlHeadReply.nCmd2 != pControlHead.nCmd2){// 命令不一致return FINS_REPLY_CMD_NO_IS_REQUST_CMD;}// 答复数据FINS_MEMORY_AREA_READ_REPLY pReplyData;pReplyData.SetData(pRecvData.GetString(), pRecvData.Size()); if(pReplyData.nEndCode != 0){return FINS_REPLY_READ_DATA_FAIL; }// 拷贝数据int nReadByte = nSize * 2;if (pReplyData.GetDataBytsSize() == nReadByte){memcpy(pData, pReplyData.GetData(), nReadByte);}else{ return FINS_REPLY_READ_DATA_TOO_SHORT; }}}return nCode;
}long CFinsHandle::WriteMemoryData(int nAddr, int nSize, FINS_DATA_TYPE::ENUM nType, __int16* pData)
{long nCode = 0;if(nCode = EstablishCommunicationByFins()){return nCode;}CMyString pSendData;int nBytsSize = nSize * 2;// 获取发送内存int nAllSize;nAllSize = FINS_TCP_HEAD_SIZE;nAllSize += FINS_CONTROL_HEAD_SIZE;nAllSize += FINS_MEMORY_AREA_READ_SIZE; nAllSize += nBytsSize;pSendData.SetSize(nAllSize);char* pBuff = pSendData.GetString();// 头部信息FINS_TCP_HEAD pHead; pHead.nCommand = FINS_TCP_CMD_DATA;pHead.SetLength(nAllSize); //长度pHead.GetData(pBuff);// control部分FINS_CONTROL_HEAD pControlHead;pControlHead.nDA1 = 0; pControlHead.nSA1 = m_nIpNode;pControlHead.nCmd1 = 0x01;pControlHead.nCmd2 = 0x02;pControlHead.GetData(pBuff + FINS_TCP_HEAD_SIZE);// 数据部分FINS_MEMORY_AREA_WRITE pMemory;pMemory.nAreaCode = nType;pMemory.nAddr = nAddr;pMemory.nBitNo = 0;pMemory.nLength = nSize;pMemory.pData.Append((char*)pData, nBytsSize);pMemory.GetData(pBuff + FINS_TCP_HEAD_SIZE + FINS_CONTROL_HEAD_SIZE);// // 发送数据CMyString pRecvData;nCode = SendSyncData(pSendData, pRecvData);if (nCode == 0){// 先判断答复数据的头数据是否正确 if(nCode = CheckReplyDataIsError(pRecvData.GetString(), pRecvData.Size())){return nCode;}// 数据头FINS_TCP_HEAD pHeadReply;pHeadReply.SetData(pRecvData.GetString());// 答复长度要求int nMinSize = FINS_TCP_HEAD_SIZE + FINS_CONTROL_HEAD_SIZE + FINS_MEMORY_AREA_WRITE_R_SIZE;if(pHeadReply.GetLength() < nMinSize){return FINS_REPLY_READ_DATA_TOO_SHORT;}else{// FINS协议部分FINS_CONTROL_HEAD pControlHeadReply;pControlHeadReply.SetData(pRecvData.GetString());if (pControlHeadReply.nCmd1 != pControlHead.nCmd1 ||pControlHeadReply.nCmd2 != pControlHead.nCmd2){// 命令不一致return FINS_REPLY_CMD_NO_IS_REQUST_CMD;}// 答复数据FINS_MEMORY_AREA_WRITE_REPLY pReplyData;pReplyData.SetData(pRecvData.GetString()); if(pReplyData.nEndCode != 0){return FINS_REPLY_WRITE_DATA_FAIL; }}}return nCode;
}// 获取fins节点地址
long CFinsHandle::GetFinsNodeAddress()
{return 0;
}// 检查答复数据是否错误
long CFinsHandle::CheckReplyDataIsError(char* pData, int nSize)
{if (nSize < FINS_TCP_HEAD_SIZE){// 小于最小要求数据return FINS_REPLY_DATA_TOO_SHORT;}// 消息错误FINS_TCP_HEAD pHeadReply;pHeadReply.SetData(pData);if (pHeadReply.nErrorCode){return FINS_REPLY_ERROR_BY_MESSAGE;}return 0;
}// 建立通讯
long CFinsHandle::EstablishCommunicationByFins()
{if (m_bEstablishCommunicationByFins){// 已经建立通讯连接了return 0;}long nCode = 0;CMyString pSendData;// 获取发送内存int nAllSize;nAllSize = FINS_TCP_HEAD_SIZE;nAllSize += FINS_CONNECT_REQUST_SIZE;pSendData.SetSize(nAllSize); char* pBuff = pSendData.GetString();// 头部信息FINS_TCP_HEAD pHead; pHead.nCommand = FINS_TCP_CMD_CONNECT_REQUST;pHead.SetLength(nAllSize); //长度pHead.GetData(pBuff);// IP地址FINS_CONNECT_REQUST pConnectRequst; pConnectRequst.GetData(pBuff + FINS_TCP_HEAD_SIZE);// 发送数据CMyString pRecvData;if(nCode = SendSyncData(pSendData, pRecvData)){return nCode;}// 处理返回值FINS_TCP_HEAD pHeadReply;pHeadReply.SetData(pRecvData.GetString());// 检查头信息if (pHeadReply.nErrorCode == 0 &&pHeadReply.nCommand == FINS_TCP_CMD_CONNECT_RESPONSE){// 提取 IP Node信息if (pHeadReply.GetLength() == FINS_TCP_HEAD_SIZE + FINS_CONNECT_RESPONS_SIZE){// 提取FINS_CONNECT_RESPONSE pConnectResponse;pConnectResponse.SetData(pRecvData.GetString());m_nIpNode = pConnectResponse.pClientAddrss[3];// 建立通讯成功m_bEstablishCommunicationByFins = true;return 0;} } return FINS_REQUST_CONNECT_FAIL;
}
#pragma once
// 用于TCP/IP通讯
class CCommunication
{
public:
CCommunication();
virtual ~CCommunication();
// 释放
void Release();
void SetTimeout(int nMs); // 设置超时
void SetMode(bool bLongConnect); // 长连接或者短连接模式
void SetTcpIP(const char* pIP); // socket参数
void SetTcpPort(int nPort); // socket参数
int GetTimeout();
long SendSyncData(CMyString pSendData, CMyString& pRecvData); // 数据发读
void Disconnect(); // 断开通讯
protected:
// 数据接收
void SetRecvComplete(int nSize); // 告诉通讯,数据接收完成
virtual void OnBeginRecv(); // 重写数据接收,开始接收数据,用于协议识别
virtual void OnDataRecv(char* pData, int nSize) = 0; // 重写数据接收,用于协议识别
virtual void OnCloseConnect(); // 通讯关闭
private:
long Connect(); // TCP连接
void CloseConnect(); // TCP关闭连接
void InitSockWSA();
void ReleaseSockWSA();
// 接收数据线程
void CreateRecvThread(); // 创建接收线程
void ExitRecvThread(); // 退出接收线程
static void RunRecvThread(void* lp);
void RecvHandle();
bool IsExitThread();
void OneRecvData(); // 一次接收数据
void StartRecvData(); // 开始接收数据
void StopRecvData();
// 数据读取,从缓存内读取
long RecvData(CMyString& pRecvData);
private:
bool m_bLongConnect; // 长连接
int m_nRecvTimeout; // 接收超时
// socket
SOCKET m_hSock;
struct sockaddr_in m_pSA;
vCritical m_syncLock; // 每次只能单个tcp读写
vCritical m_syncLockTcp; // soekct操作
HANDLE m_hRecvTimeoutEvent; // 接收线程超时
HANDLE m_hRecvExitFinish; // 定时器线程退出完毕
HANDLE m_hRecvExit; // 接收退出
HANDLE m_hRecvStartData; // 开始接收数据
CMyString m_pRecvData; // 接收到的数据
long m_nRecvCode; // 读取错误代码
// 临时缓
int m_nSize;
int m_nRecvSize;
char m_pBuff[200];
};
#pragma once
#include "Communication.h"
class CFinsHandle : public CCommunication
{
public:
CFinsHandle();
long ReadMemoryData(int nAddr, int nSize, FINS_DATA_TYPE::ENUM nType, __int16* pData);
long WriteMemoryData(int nAddr, int nSize, FINS_DATA_TYPE::ENUM nType, __int16* pData);
private:
virtual void OnBeginRecv(); // 重写数据接收,开始接收数据
virtual void OnDataRecv(char* pData, int nSize); // 重写数据接收,用于协议识别
virtual void OnCloseConnect(); // 通讯关闭
// 检查答复数据是否错误
long CheckReplyDataIsError(char* pData, int nSize); // 检查答复数据是否错误
long GetFinsNodeAddress(); // 获取fins节点地址
long EstablishCommunicationByFins(); // 建立Fins通讯
private:
CMyString m_pRecvData;
bool m_bEstablishCommunicationByFins; // 与Fins建立通讯
int m_nIpNode; // IP节点
};
#pragma once
#include "Export/InterfaceExport.h"
#include "FinsHandle.h"
class CFinsReadWrite : public CInterfaceExport
{
public:
// 参数
virtual CResult SetParament(const char* pName, const char* pValue);
// 初始化模块
virtual CResult Connect();
virtual CResult Disconnect();
// 释放
virtual void Release();
public:
// 读出
virtual CResult Read(const char* pAddr, char* pData, __int32 size, char* pCtrlData);
virtual CResult Read(const char* pAddr, __int16* pData, __int32 size, char* pCtrlData);
virtual CResult Read(const char* pAddr, __int32* pData, __int32 size, char* pCtrlData);
virtual CResult Read(const char* pAddr, __int64* pData, __int32 size, char* pCtrlData);
// 写入
virtual CResult Write(const char* pAddr, char* pData, __int32 size, char* pCtrlData);
virtual CResult Write(const char* pAddr, __int16* pData, __int32 size, char* pCtrlData);
virtual CResult Write(const char* pAddr, __int32* pData, __int32 size, char* pCtrlData);
virtual CResult Write(const char* pAddr, __int64* pData, __int32 size, char* pCtrlData);
private:
long ReadData(int nAddr, __int16* pData, int nSize, int nDataType); // 读取2字节一次
long WriteData(int nAddr, __int16* pData, int nSize, int nDataType); // 读取2字节一次
void GetDataTypeAndAddr(string pAddr, int& nDataType, int& nAddr); // 获取数据地址
int GetDataArea(string pArea); // 获取数据区
private:
CFinsHandle m_pHandle;
};
#include "stdafx.h"
#include "Communication.h"
CCommunication::CCommunication()
{
m_nRecvTimeout = 5000;
m_bLongConnect = true;
m_hSock = INVALID_SOCKET;
InitSockWSA();
memset(&m_pSA, 0, sizeof(struct sockaddr_in));
m_hRecvExit = CreateEvent(NULL, TRUE, FALSE, NULL);
m_hRecvExitFinish = CreateEvent(NULL, TRUE, FALSE, NULL);
m_hRecvTimeoutEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
m_hRecvStartData = CreateEvent(NULL, TRUE, FALSE, NULL);
CreateRecvThread();
}
CCommunication::~CCommunication()
{
ExitRecvThread();
ReleaseSockWSA();
CloseHandle(m_hRecvExit);
CloseHandle(m_hRecvExitFinish);
CloseHandle(m_hRecvTimeoutEvent);
CloseHandle(m_hRecvStartData);
}
void CCommunication::InitSockWSA()
{
// 必须的
WSADATA wsaData;
if(WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
{
}
}
void CCommunication::ReleaseSockWSA()
{
// 必须的
if(WSACleanup() != 0)
{
}
}
// 释放
void CCommunication::Release()
{
}
// TCP连接
long CCommunication::Connect()
{
if(m_hSock == INVALID_SOCKET)
{
m_hSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(m_hSock != INVALID_SOCKET)
{
if(connect(m_hSock, (struct sockaddr*)&m_pSA, sizeof(m_pSA)) < 0)
{
closesocket(m_hSock);
m_hSock = INVALID_SOCKET;
return FINS_SOCKET_CONNECT_FAIL;
}
}
else
{
return FINS_SOCKET_CREATE_FAIL;
}
}
return 0;
}
// TCP关闭连接
void CCommunication::CloseConnect()
{
vLocker lock(&m_syncLockTcp);
if (m_hSock != INVALID_SOCKET)
{
shutdown(m_hSock, 2);
closesocket(m_hSock);
m_hSock = INVALID_SOCKET;
OnCloseConnect();
}
}
// 设置超时
void CCommunication::SetTimeout(__int32 nMs)
{
if(nMs < 100)
{
nMs = 100;
}
m_nRecvTimeout = nMs;
}
int CCommunication::GetTimeout()
{
return m_nRecvTimeout;
}
// 长连接或者短连接模式
void CCommunication::SetMode(bool bLongConnect)
{
m_bLongConnect = bLongConnect;
}
// socket参数
void CCommunication::SetTcpIP(const char* pIP)
{
m_pSA.sin_family = AF_INET;
m_pSA.sin_addr.s_addr = inet_addr(pIP);
}
// socket参数
void CCommunication::SetTcpPort(__int32 nPort)
{
m_pSA.sin_family = AF_INET;
m_pSA.sin_port = htons(nPort);
}
// 数据发读
long CCommunication::SendSyncData(CMyString pSendData, CMyString& pRecvData)
{
vLocker lock(&m_syncLock);
long nCode = Connect();
if(nCode != 0)
{
return nCode;
}
// 清空原来的数据
m_pRecvData.SetSize(0);
// 发送数据
int res = send(m_hSock, pSendData.GetString(), pSendData.Size(), 0);
if(res == SOCKET_ERROR)
{
CloseConnect();
return FINS_SEND_FAIL;
}
// 数据读取
nCode = RecvData(pRecvData);
// 短连接每次都关闭
if(!m_bLongConnect)
{
CloseConnect();
}
return nCode;
}
// 数据读取
// 带超时处理
long CCommunication::RecvData(CMyString& pRecvData)
{
long nCode = 0;
StartRecvData();
// 等待接收
ResetEvent(m_hRecvTimeoutEvent);
DWORD rs = WaitForSingleObject(m_hRecvTimeoutEvent, m_nRecvTimeout);
// 成功返回值
if (rs == WAIT_OBJECT_0)
{
pRecvData = m_pRecvData;
}
// 超时等其他错误
else
{
StopRecvData();
CloseConnect();
nCode = FINS_RECV_WAIT_TIMEOUT;
}
return nCode;
}
// 创建接收线程
//
void CCommunication::CreateRecvThread()
{
ResetEvent(m_hRecvExitFinish);
_beginthread(RunRecvThread, 0, this);
}
// 退出接收线程
//
void CCommunication::ExitRecvThread()
{
CloseConnect();
SetEvent(m_hRecvExit);
SetEvent(m_hRecvStartData);
WaitForSingleObject(m_hRecvExitFinish, INFINITE);
}
// 定时器线程
void CCommunication::RunRecvThread(void* lp)
{
CCommunication* pMC = (CCommunication*)lp;
pMC->RecvHandle();
SetEvent(pMC->m_hRecvExitFinish); // 处理完毕
}
// 定时器
void CCommunication::RecvHandle()
{
while (!IsExitThread())
{
WaitForSingleObject(m_hRecvStartData, INFINITE);
if (IsExitThread())
{
break;
}
OneRecvData();
}
}
// 一次接收数据
void CCommunication::OneRecvData()
{
m_nSize = 200;
m_nRecvSize = recv(m_hSock, m_pBuff, m_nSize, 0);
if(m_nRecvSize == SOCKET_ERROR)
{
CloseConnect();
m_nRecvCode = FINS_SOCKET_CONNECT_ERR;
}
else
{
m_pRecvData.Append(m_pBuff, m_nRecvSize);
m_nRecvCode = 0;
OnDataRecv(m_pBuff, m_nRecvSize);
}
}
// 告诉通讯,数据接收完成
void CCommunication::SetRecvComplete(int nSize)
{
ResetEvent(m_hRecvStartData); // 复位接收
SetEvent(m_hRecvTimeoutEvent); // 接收成功
}
// 重写数据接收,开始接收数据,用于协议识别
void CCommunication::OnBeginRecv()
{
}
// 通讯关闭
void CCommunication::OnCloseConnect()
{
}
bool CCommunication::IsExitThread()
{
if(WaitForSingleObject(m_hRecvExit, 0) == WAIT_OBJECT_0)
{
return true;
}
return false;
}
// 开始接收数据
void CCommunication::StartRecvData()
{
OnBeginRecv();
SetEvent(m_hRecvStartData);
}
// 停止接收数据
void CCommunication::StopRecvData()
{
ResetEvent(m_hRecvStartData);
}
// 断开通讯
void CCommunication::Disconnect()
{
}
#include "stdafx.h"
#include "FinsReadWrite.h"
// 参数
CResult CFinsReadWrite::SetParament(const char* pName, const char* pValue)
{
if(pName == nullptr ||
pValue == nullptr)
{
return CResult(FINS_PARAM_POINT_ENTPY, "FINS 参数指针为空");
}
string pNameString = pName;
if (pNameString == "IP")
{
m_pHandle.SetTcpIP(pValue);
}
else if (pNameString == "PORT")
{
int nPort = ::atoi(pValue);
m_pHandle.SetTcpPort(nPort);
}
else if (pNameString == "TIMEOUT")
{
int nTimerOut = ::atoi(pValue);
m_pHandle.SetTimeout(nTimerOut);
}
return CResult(0);
}
// 初始化模块
CResult CFinsReadWrite::Connect()
{
return CResult(0);
}
CResult CFinsReadWrite::Disconnect()
{
return CResult(0);
}
// 释放
void CFinsReadWrite::Release()
{
delete this;
}
// 1字节
CResult CFinsReadWrite::Read(const char* pAddr, char* pData, __int32 nSize, char* pCtrlData)
{
if (pAddr == nullptr ||
pData == nullptr ||
pCtrlData == nullptr)
{
return CResult(FINS_PARAM_POINT_ENTPY, "FINS 参数指针为空");
}
int nDataType; // 数据类型
int nAddr; // 数据地址
GetDataTypeAndAddr(pAddr, nDataType, nAddr);
long nCode = 0;
if(nSize % 2)
{
// 奇数处理
int nReadSize = nSize;
nReadSize++;
__int16* pReadData = (__int16*)malloc(nReadSize);
if (pReadData == nullptr)
{
return FINS_MALLOC_FAIL;
}
// 读取数据
nCode = ReadData(nAddr, pReadData, nReadSize / 2, nDataType);
if(nCode == 0)
{
memcpy(pData, pReadData, nSize);
}
free(pReadData);
}
else
{
nCode = ReadData(nAddr, (__int16*)pData, nSize / 2, nDataType);
}
return nCode;
}
// 2字节
CResult CFinsReadWrite::Read(const char* pAddr, __int16* pData, __int32 nSize, char* pCtrlData)
{
long nCode = 0;
int nDataType; // 数据类型
int nAddr; // 数据地址
GetDataTypeAndAddr(pAddr, nDataType, nAddr);
nCode = ReadData(nAddr, pData, nSize, nDataType);
return CResult(nCode);
}
// 4字节
CResult CFinsReadWrite::Read(const char* pAddr, __int32* pData, __int32 nSize, char* pCtrlData)
{
long nCode = 0;
int nDataType; // 数据类型
int nAddr; // 数据地址
GetDataTypeAndAddr(pAddr, nDataType, nAddr);
nCode = ReadData(nAddr, (__int16*)pData, nSize * 2, nDataType);
return CResult(nCode);
}
// 8字节
CResult CFinsReadWrite::Read(const char* pAddr, __int64* pData, __int32 nSize, char* pCtrlData)
{
long nCode = 0;
int nDataType; // 数据类型
int nAddr; // 数据地址
GetDataTypeAndAddr(pAddr, nDataType, nAddr);
nCode = ReadData(nAddr, (__int16*)pData, nSize * 2, nDataType);
return CResult(nCode);
}
// 读取2字节一次
long CFinsReadWrite::ReadData(int nAddr, __int16* pData, int nSize, int nDataType)
{
FINS_DATA_TYPE::ENUM nType = (FINS_DATA_TYPE::ENUM)nDataType;
switch(nType)
{
case FINS_DATA_TYPE::DM:
{
return m_pHandle.ReadMemoryData(nAddr, nSize, nType, pData);
}
break;
}
return FINS_NOT_DATA_AREA;
}
// 1字节
CResult CFinsReadWrite::Write(const char* pAddr, char* pData, __int32 nSize, char* pCtrlData)
{
if (pAddr == nullptr ||
pData == nullptr ||
pCtrlData == nullptr)
{
return CResult(FINS_PARAM_POINT_ENTPY, "FINS 参数指针为空");
}
long nCode = 0;
int nDataType; // 数据类型
int nAddr; // 数据地址
// 获取PLC区域和地址
GetDataTypeAndAddr(pAddr, nDataType, nAddr);
if(nSize % 2)
{
// 奇数处理
int nReadSize = nSize;
nReadSize++;
__int8* pReadData = (__int8*)malloc(nReadSize);
if (pReadData == nullptr)
{
return FINS_MALLOC_FAIL;
}
memset(pReadData, 0, nReadSize);
memcpy(pReadData, pData, nSize);
// 读取数据
nCode = WriteData(nAddr, (__int16*)pReadData, nReadSize / 2, nDataType);
free(pReadData);
}
else
{
nCode = WriteData(nAddr, (__int16*)pData, nSize / 2, nDataType);
}
return nCode;
}
// 2字节
CResult CFinsReadWrite::Write(const char* pAddr, __int16* pData, __int32 nSize, char* pCtrlData)
{
if (pAddr == nullptr ||
pData == nullptr ||
pCtrlData == nullptr)
{
return CResult(FINS_PARAM_POINT_ENTPY, "FINS 参数指针为空");
}
long nCode = 0;
int nDataType; // 数据类型
int nAddr; // 数据地址
// 获取PLC区域和地址
GetDataTypeAndAddr(pAddr, nDataType, nAddr);
nCode = WriteData(nAddr, pData, nSize, nDataType);
return nCode;
}
// 4字节
CResult CFinsReadWrite::Write(const char* pAddr, __int32* pData, __int32 nSize, char* pCtrlData)
{
if (pAddr == nullptr ||
pData == nullptr ||
pCtrlData == nullptr)
{
return CResult(FINS_PARAM_POINT_ENTPY, "FINS 参数指针为空");
}
long nCode = 0;
int nDataType; // 数据类型
int nAddr; // 数据地址
// 获取PLC区域和地址
GetDataTypeAndAddr(pAddr, nDataType, nAddr);
nCode = WriteData(nAddr, (__int16*)pData, nSize * 2, nDataType);
return nCode;
}
// 8字节
CResult CFinsReadWrite::Write(const char* pAddr, __int64* pData, __int32 nSize, char* pCtrlData)
{
if (pAddr == nullptr ||
pData == nullptr ||
pCtrlData == nullptr)
{
return CResult(FINS_PARAM_POINT_ENTPY, "FINS 参数指针为空");
}
long nCode = 0;
int nDataType; // 数据类型
int nAddr; // 数据地址
// 获取PLC区域和地址
GetDataTypeAndAddr(pAddr, nDataType, nAddr);
nCode = WriteData(nAddr, (__int16*)pData, nSize * 4, nDataType);
return nCode;
}
// 读取2字节一次
long CFinsReadWrite::WriteData(int nAddr, __int16* pData, int nSize, int nDataType)
{
FINS_DATA_TYPE::ENUM nType = (FINS_DATA_TYPE::ENUM)nDataType;
switch(nType)
{
case FINS_DATA_TYPE::DM:
{
return m_pHandle.WriteMemoryData(nAddr, nSize, nType, pData);
}
break;
}
return FINS_NOT_DATA_AREA;
}
// 获取数据地址
void CFinsReadWrite::GetDataTypeAndAddr(string pAddr, int& nDataType, int& nAddr)
{
unsigned int i = 0;
for (; i < pAddr.size(); i++)
{
if(pAddr[i] >= '0' && pAddr[i] <= '9')
{
break;
}
}
// 数据类型
string pType = pAddr.substr(0, i);
nDataType = GetDataArea(pType);
// 数据地址
string pStartAddr = pAddr.substr(i, pAddr.size() - i);
nAddr = ::atol(pStartAddr.c_str());
}
// 获取数据区
int CFinsReadWrite::GetDataArea(string pArea)
{
int nDataType = 0;
if (pArea == "DM") { nDataType = FINS_DATA_TYPE::DM; }
else if (pArea == "dm") { nDataType = FINS_DATA_TYPE::DM; }
else { nDataType = FINS_DATA_TYPE::ERR; }
return nDataType;
}
OneApiConnect通讯demo,fins欧姆龙协议实现相关推荐
- Labview Ethernetip TCP网口通讯欧姆龙PLC OmronNX1P2NJ501NJ301PLC标签通讯 CIP通讯比Fins通讯更完美
Labview Ethernetip TCP网口通讯欧姆龙PLC OmronNX1P2NJ501NJ301PLC标签通讯 CIP通讯比Fins通讯更完美. 1.自定义变量读写 2.支持 Bool单点或 ...
- 爱普生机器人与欧姆龙PLC Fins/Tcp协议驱动程序 自己开发,提供项目源码Fins/Tcp协议源码
爱普生机器人与欧姆龙PLC Fins/Tcp协议驱动程序 自己开发,提供项目源码Fins/Tcp协议源码
- 串行通讯RS485 Modbus RTU协议控制
一.内容简介 本文主要介绍欧姆龙CP1E做上位与SMC的LECP6电缸 之间串行通讯RS485 Modbus RTU协议程序控制说明. 二.设备简介 硬件:CP1E.CP1W-CIF1 ...
- java xmpp即时通讯_基于XMPP协议即时通讯工具开发总结
一.概要 转眼毕业了,毕业设计的课题是"基于XMPP协议的通讯工具",开发平台式android,实现了基本的离线消息,文字聊天,表情聊天,文件传输,语音聊天的功能. 本文主要介绍开 ...
- C#上位机开发源码基于RS485通讯总线的ModbusRtu协议,支持用户权限管理
C#上位机开发源码 上位机项目源代码 采用基于RS485通讯总线的ModbusRtu协议,支持用户权限管理.sqlite数据库.实时曲线.历史曲线.历史报表.导出Excel.主界面布局可调带记忆等功能 ...
- labview串口,网口,DSC可用OPC通讯链接三菱欧姆龙西门子等PLC
labview串口,网口,DSC可用OPC通讯链接三菱欧姆龙西门子等PLC. 通过NI-OPC控制三菱,欧姆龙西门子等各种型号PLC 编号:7450645066968702听雪无声.
- 基于Ethernet KRL,上位机C#通过TCP/IP与KUKA库卡机械臂通讯Demo
目录 0.引言: 1.本文使用的相关软硬件或产品: 2.一些注意事项: 2.1.涉及到的一些概念: 2.2.配置以太网连接以及以及发送接收结构: 2.3.上位机应当如何传输: 2.4.通过smartH ...
- 现场解析服务化 即时通讯方案丨网络协议,应用层协议的选择
90分钟解析服务化 即时通讯方案,(不要错过) 1. 网络协议选择 udp/tcp 2. 应用层协议选择 protobuf/xmpp/mqtt 3. 数据库表的设计 视频讲解如下,点击观看: [Lin ...
- 威纶和s7200通讯线_S7-200作为从站用一个通讯口同时与组态王和维纶触摸屏通讯,用PPI协议,可以吗?...
说明:1.PLC为CPU224XP; 2.两个通讯口,一个要与流量计通讯,走modbus RTU协议 解决方案:1.PPI多主站,组态王和触摸屏都作为主站,PLC作为从站.不知硬件怎么配置,软件怎么配 ...
- C#上位机开发源码 采用基于RS485通讯总线的ModbusRtu协议,支持用户权限管理
C#上位机开发源码 采用基于RS485通讯总线的ModbusRtu协议,支持用户权限管理 采用基于RS485通讯总线的ModbusRtu协议,支持用户权限管理.sqlite数据库.实时曲线.历史曲线. ...
最新文章
- 通过grub硬盘安装centos7
- GDI+中发生一般性错误
- Linux 文件系统结构介绍
- 叛逆的仔:不听老板的话,还要用行动给老板来个响亮耳光!
- 北京2019高考分数线:本科理423文480
- in java中文版百度云 thinking_小程序订阅消息推送(含源码)java实现小程序推送,springboot实现微信消息推送...
- python telnet 交互_用Python怎么telnet到网络设备
- git gui提交无法获知你的身份 20
- 【前端】Canvas通过toDataURL保存时在Mac上分辨率扩大问题
- ffmpeg转码参数
- 十六进制转二进制(转)
- Programming Ruby 读书笔记(三)
- python 函数进阶_python之函数进阶
- UE4 LOD Screen Size
- 游戏数据后台,kafka代替rsync同步日志数据
- TCP三次握手中SYN,ACK,seq ack的含义
- “我们没有竞争对手”专访Splunk中国区总经理严立忠
- 计算机计算芯片原理,集成电路-CPU运行基本原理 CPU是计算机的核心,弄清楚CPU的运行基本原理,也就明白了计算机系统中各种芯片的数据处理和存储功能是如何实现。 在往期... - 雪球...
- __attribute__
- 索尼在用于汽车激光雷达的单芯片中堆叠 SPAD 传感器和逻辑
热门文章
- 模式分解的无损性判断
- Github渗透测试工具库
- Office 365网络链接概览(三)--专线express route
- 各种计算机绘图的应用场合,cad制图员面试技巧
- Flink的State与Rescale
- 公司电脑策略强制自动锁屏解决方案
- 『 论文阅读』Attention-Based Recurrent Neural Network Models for Joint Intent Detection and Slot Filling
- p9刷Android原生系统,华为P9怎么刷机 华为P9卡刷机方法【图文教程】
- mapreduce 和hive 的区别
- vue项目之微信分享