OneApiConnect(一) Fins欧姆龙通讯协议实现源代码

本文介绍了OneConnectAPI,一种旨在解决不同PLC厂商协议差异的高效接口解决方案,它能适应各类设备,降低开发成本,提升PLC读写性能,特别适用于工控行业,如光伏和半导体,强调了其稳定性和低资源占用。
摘要由CSDN通过智能技术生成

每家PLC厂商都有自己的通讯协议,三菱有MC、倍福有ADS,然而没有统一性的接口协议。
为适应每一家通讯,每一家设备商、MES和工厂等都需要针对每款产品开发相应的通讯接口。
OneConnectAPI为实现统一的接口,去适配每一家厂商的协议。为中国工控行业快速发展而贡献,每一家公司都需要重新制造轮子,这是非常浪费时间和金钱,同时也不能保证稳定性以及持续的维护。
我们采取高效的多线程处理方案,保证极其高效的读写性能,对电脑性能要求极其低,一直进行读写操作,CPU使用率不超过1%(Atom E3940下测试)。
用户可以在一台工控机上进行对上百台的PLC主动读写操作,我们在光伏行业大量应用和测试过。
我们在半导体行业深耕多年,积累大量的经验,实现功能的同时,也需要保证极其严格的稳定性,晶圆生成设备7*24小时不能出任何故障。
下边是我们的接口库以及源代码。
下载链接:www.semisecs.com
在这里插入图片描述

在这里插入图片描述
接口代码


```cpp
#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;

};


Fins实现代码

```cpp
#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;
}












  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值