You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

492 lines
13 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "StdAfx.h"
#include "PlcCommunicationMgr.h"
#include "Propertie.h"
#include "PropertieMgr.h"
#include "AuthorityMgr.h"
#include "FileMgr.h"
#include "CStringFuc.h"
#include "CommPortMgr.h"
#include "LogMgr.h"
#include "GlobalFunction.h"
#include "DeviceStateMgr.h"
#include "WarningMgr.h"
#include "MsgBox.h"
#include "MotionCtrl.h"
#include "AllThreadMgr.h"
#include "DeviceStateMgr.h"
#include "ProgramLaserTuiHuo.h"
#include "TransferArmMgr.h"
#include "ExceptionMsg.h"
#include "IO_CtrlMgr.h"
#include "SemiSecsCommMgr.h"
#include "TransferArmMgr.h"
#include "CriticalSection.h"
#include "PLCTcp/PLCFinsPacketCtl.h"
#define BUF_LEN 256
#define PLC_RECV_BUF_LEN 1024*2
static unique_ptr<char> g_pDataBuf(new char[PLC_RECV_BUF_LEN]);
static int GetRWAddrRange()
{
#ifdef PLC_TCP_CTL
return RW_REGISTER_D_SECTION_CNT;
#else
return RW_REGISTER_CNT;
#endif
}
CPlcCommunicationMgr *gPlcCommunicationMgr = new CPlcCommunicationMgr;
CPlcCommunicationMgr::CPlcCommunicationMgr(void)
{
m_bCommSuc = false;//通信是否正常
//初始化读写寄存器容器
InitRwRegisterBitVec();
}
CPlcCommunicationMgr::~CPlcCommunicationMgr(void)
{
}
void CPlcCommunicationMgr::OnAppInitialize()
{
#ifdef PLC_TCP_CTL
//地址端口是固定的
m_pPlcTcpCtl = make_unique<CPlcTcpCtl>();
if (m_pPlcTcpCtl.get())
{
m_pPlcTcpCtl->Init();
m_pPlcTcpCtl->OpenDev("10.110.59.3", 9600);
}
#else
m_PLcSocketUDP.BingRwRegisterBitVec(&m_RwRegisterBitVec);
m_PLcSocketUDP.InitSocket(10000, 9600, ("10.110.59.3"));
#endif
}
//软件退出时检查(默认可以退出)
bool CPlcCommunicationMgr::CloseAppCheck()
{
return true;
}
void CPlcCommunicationMgr::OnExitApp()
{
}
#if 1//新的PLC 读写方式(网口)
//初始化读写寄存器容器
void CPlcCommunicationMgr::InitRwRegisterBitVec()
{
int nRegister = 0;
#ifdef PLC_TCP_CTL
nRegister = RW_REGISTER_D_SECTION_CNT;
#else
nRegister = RW_REGISTER_CNT;
#endif
for (int k = 0; k < nRegister; k++)
{
m_RwRegisterBitVec.push_back(0);
}
}
void CPlcCommunicationMgr::SetbEnableOnRevData(bool b)
{
#ifdef PLC_TCP_CTL
#else
m_PLcSocketUDP.SetbEnableOnRevData(b);
#endif
return;
}
//获取寄存器RegisterIdx 的第BitIdx 位是否为1
bool CPlcCommunicationMgr::GetRegisterBitState(int RegisterIdx,int BitIdx)
{
if(!CheckRegisterPar(RegisterIdx,BitIdx))
return false;
return IsBitOn(m_RwRegisterBitVec[RegisterIdx],BitIdx);
}
//获取寄存器RegisterIdx 的值-->寄存器是16 位
int CPlcCommunicationMgr::GetRwRegisterVal(int RegisterIdx)
{
if(!CheckRange(RegisterIdx, 0, (GetRWAddrRange() - 1)))
return false;
return m_RwRegisterBitVec[RegisterIdx];
}
double CPlcCommunicationMgr::GetRwRegisterDbVal(int RegisterIdx)
{
if (!CheckRange(RegisterIdx + 1, 0, (GetRWAddrRange() - 1)))
return 0;
char szBuf[4];
memcpy_s(szBuf, 4, &m_RwRegisterBitVec[RegisterIdx], 2);
memcpy_s(&szBuf[2], 2, &m_RwRegisterBitVec[RegisterIdx + 1], 2);
float nRet = 0;
memcpy_s(&nRet, sizeof(nRet), szBuf, 4);
return nRet;
}
void CPlcCommunicationMgr::InitLogPath(const char*pLogPath)
{
m_pPlcTcpCtl->SetLogPath(pLogPath);
}
int CPlcCommunicationMgr::PLCTcpHandShake()
{
CSingleLock lock(&gCriticalSection_PlcComm, true);
int nRet = 0;
if (g_pDataBuf.get())
{
int nSendLen = 0;
unsigned char szBuf[BUF_LEN];
nRet = PLC_TcpFinsEncode(false, true, true, FINS_FRAME_CMD_SECTION_D_WORD
, READ_START_REGISTER_ADRR, 0, NULL, 0, szBuf, BUF_LEN, nSendLen);
if (0 == nRet)
{
if (0 == m_pPlcTcpCtl->SendData(szBuf, nSendLen, 1000,true))
{
int nRecv = m_pPlcTcpCtl->RecvData((unsigned char*)g_pDataBuf.get(), PLC_RECV_BUF_LEN, 1000, true);
if (nRecv > 0)
{
//完整报文校验
while (!IsCompletePacket(g_pDataBuf.get(), nRecv))
{
//再接收一次够了 数据量不大
int nRevTmp = m_pPlcTcpCtl->RecvData((unsigned char*)g_pDataBuf.get() + nRecv, PLC_RECV_BUF_LEN, 1000, true);
if (nRevTmp <= 0)
{
return -1;
}
nRecv += nRevTmp;
}
vector<int> vecValue;
nRet = PLC_TcpFinsDecode(g_pDataBuf.get(), nRecv, vecValue);
if (0 == nRet)
{
m_pPlcTcpCtl->SetHandShakeState(true);
}
}
}
}
}
return nRet;
}
//检查寄存器索引值的安全性
bool CPlcCommunicationMgr::CheckRegisterPar(int RegisterIdx,int BitIdx)
{
int nMaxIndex = 0;
#ifdef PLC_TCP_CTL
nMaxIndex = RW_REGISTER_D_SECTION_CNT - 1;
#else
nMaxIndex = RW_REGISTER_CNT - 1;
#endif
return(CheckRange(RegisterIdx, 0, nMaxIndex) && CheckRange(BitIdx, 0, 15));
}
//比如寄存器D300 -->RegisterAdr=300[0x01][0x2C]
//CtrlWordCnt最大255
//WriteValVec 只有写的时候才需要
int CPlcCommunicationMgr::GetCmdBuf(BYTE *buf,bool bRead,int RegisterAdr,int CtrlWordCnt,int WriteVal)
{
int Idx = 0;
//0~10字节是固定的(对应固定的IP 设置)
buf[Idx++] = 0x80;
buf[Idx++] = 0x00;
buf[Idx++] = 0x02;
buf[Idx++] = 0x00;
buf[Idx++] = 0x03;
buf[Idx++] = 0x00;
buf[Idx++] = 0x00;
buf[Idx++] = 0xC0;
buf[Idx++] = 0x00;
buf[Idx++] = 0x00;
buf[Idx++] = 0x01;
buf[Idx++] = (bRead)?(0x01):(0x02);//读/写
if(bRead)
buf[Idx++] = 0xB1;//按字节读(idx 13)
else
buf[Idx++] = 0x31;//按位写
buf[Idx++] = RegisterAdr >> 8; //寄存器地址(高位)
buf[Idx++] = RegisterAdr % 256;//寄存器地址(低位)
if(bRead)
{
//下面三个字节表示读取的寄存器数量(读的少的话只用最低的字节就可以了)
buf[Idx++] = 0x00;
buf[Idx++] = 0x00;
buf[Idx++] = CtrlWordCnt;//从WordIdx_Start开始读取位数(低位)
}
else//按bit 写
{
buf[Idx++] = CtrlWordCnt;//bit idx
buf[Idx++] = 0x00;
buf[Idx++] = 0x01;//写1位
buf[Idx++] = WriteVal;//bit val
}
return Idx;
}
//读取寄存器状态
/*
例子:从第15 字节开始,每两个字节表示一个寄存器
发送:80000200030000C000000101B10001000001
接收:C0 00 02 00 C0 00 00 03 00 00 01 01 00 00 00 FD //(W01值:00 FD)
*/
int CPlcCommunicationMgr::ReadRwRegisterBitState()
{
if (!m_pPlcTcpCtl->GetHandShakeState())
{
PLCTcpHandShake();
return 0;
}
CSingleLock lock(&gCriticalSection_PlcComm,true);
#ifdef PLC_TCP_CTL
if (g_pDataBuf.get())
{
int nSendLen = 0;
unsigned char szBuf[BUF_LEN];
int nRet = PLC_TcpFinsEncode(true, false, true, FINS_FRAME_CMD_SECTION_D_WORD
, READ_START_REGISTER_ADRR, 0,NULL, RW_REGISTER_D_SECTION_CNT, szBuf, BUF_LEN, nSendLen);
if (0 == nRet)
{
if (0 == m_pPlcTcpCtl->SendData(szBuf, nSendLen, 1000))
{
int nRecv = m_pPlcTcpCtl->RecvData((unsigned char*)g_pDataBuf.get(), PLC_RECV_BUF_LEN, 1000);
if (nRecv > 0)
{
//完整报文校验
while (!IsCompletePacket(g_pDataBuf.get(), nRecv))
{
int nRevTmp = m_pPlcTcpCtl->RecvData((unsigned char*)g_pDataBuf.get() + nRecv, PLC_RECV_BUF_LEN, 1000);
if (nRevTmp <= 0)
{
return -1;
}
nRecv += nRevTmp;
}
vector<int> vecValue;
PLC_TcpFinsDecode(g_pDataBuf.get(), nRecv, vecValue);
//校验通过
if (vecValue.size() == RW_REGISTER_D_SECTION_CNT*2)
{
for (int i = 0; i < RW_REGISTER_D_SECTION_CNT; i++)
{
m_RwRegisterBitVec[i] = TwoByte2Int(vecValue[i*2 + 1], vecValue[i * 2]);//ByteLow 低8位,ByteHigh 高8位
}
}
else
{
//读取和解析出来长度不一致
return -1;
}
}
}
}
}
return -1;
#else
if (!m_PLcSocketUDP.IsSocketInit())
return;
gCriticalSection_PlcComm.Lock();
BYTE buf[BUF_LEN];
memset(buf, 0, BUF_LEN);
int WriteVal = 0;
int nBufLen = GetCmdBuf(buf, true, READ_START_REGISTER_ADRR, GetRWAddrRange(), WriteVal);
m_PLcSocketUDP.SendBuf(buf, nBufLen);
#endif
}
//设置写入位状态
//RegisterIdx 是从READ_START_REGISTER_ADRR 开始的第几个寄存器
//一次只操作一个寄存器
template< class _Type >
bool SetBit(_Type &_src, int _bit_idx, bool _bit) {
if (_bit_idx + 1 > sizeof(_src) * 8) {
//不属于你的数据不能瞎搞。
return false;
}
char *p = (char *)&_src + (_bit_idx) / 8;
if (_bit) {
*p = *p | (1 << ((_bit_idx) % 8));
}
else {
*p = *p & ~(1 << ((_bit_idx) % 8));
}
return true;
}
int CPlcCommunicationMgr::WriteRwRegisterBitState(CRwRegisterPar RegisterPar)
{
CSingleLock lock(&gCriticalSection_PlcComm, true);
if (!CheckRegisterPar(RegisterPar.m_RegisterIdx, RegisterPar.m_BitIdx))
return -1;
#ifdef PLC_TCP_CTL
//先交换高低位 PLC 和我们上位机高低位相反
WORD dwOldValue = m_RwRegisterBitVec[RegisterPar.m_RegisterIdx];//保存一下旧值 设置失败时好重新置回去
WORD dwValue = m_RwRegisterBitVec[RegisterPar.m_RegisterIdx];
SetBit(dwValue, RegisterPar.m_BitIdx, RegisterPar.m_bOn);
dwValue = ChangeHightLowBit(dwValue);
//再先交换高低位 用于正常读取点位
m_RwRegisterBitVec[RegisterPar.m_RegisterIdx] = ChangeHightLowBit(dwValue);
int nSendLen = 0;
unsigned char szBuf[BUF_LEN];
int nRet = PLC_TcpFinsEncode(false, false, true, FINS_FRAME_CMD_SECTION_D_WORD
, WRITE_START_REGISTER_ADRR + RegisterPar.m_RegisterIdx, 0, (unsigned char*)&dwValue, 1, szBuf, BUF_LEN, nSendLen);
if (0 == nRet)
{
if (0 == m_pPlcTcpCtl->SendData((unsigned char*)szBuf, nSendLen, 1000))
{
int nRecv = m_pPlcTcpCtl->RecvData((unsigned char*)g_pDataBuf.get(), PLC_RECV_BUF_LEN, 1000);
if (nRecv > 0)
{
//完整报文校验
while (!IsCompletePacket(g_pDataBuf.get(), nRecv))
{
int nRevTmp = m_pPlcTcpCtl->RecvData((unsigned char*)g_pDataBuf.get() + nRecv, PLC_RECV_BUF_LEN, 1000);
if (nRevTmp <= 0)
{
return -1;
}
nRecv += nRevTmp;
}
vector<int> vecValue;
nRet = PLC_TcpFinsDecode(g_pDataBuf.get(), nRecv, vecValue);
if (0 != nRet)
{
m_RwRegisterBitVec[RegisterPar.m_RegisterIdx] = dwOldValue;
}
}
}
}
#else
if(!m_PLcSocketUDP.IsSocketInit())
return;
if(!m_PLcSocketUDP.IsbCommSuc())
return;
//发送
BYTE buf[BUF_LEN];
memset(buf, 0, BUF_LEN);
int nBufLen = GetCmdBuf(buf,false,READ_START_REGISTER_ADRR+RegisterPar.m_RegisterIdx,RegisterPar.m_BitIdx,RegisterPar.m_bOn);
m_PLcSocketUDP.SendBuf(buf,nBufLen);
#endif
return nRet;
}
//初始化IO测试用的comb
void CPlcCommunicationMgr::InitIOTestComb(CComboBox &PlcRegistComb,CComboBox &PlcRegistBitComb)
{
CString Str;
//插入可以选择的寄存器
for(int k=0;k<GetRWAddrRange();k++)
{
Str.Format("W%ld",k);
PlcRegistComb.AddString(Str);
}
//插入可以选择的位
for(int k=0;k<16;k++)
{
Str.Format("位%ld",k);
PlcRegistBitComb.AddString(Str);
}
PlcRegistComb.SetCurSel(0);
PlcRegistBitComb.SetCurSel(0);
}
int CPlcCommunicationMgr::WriteRwRegisterFloatValue(int RegisterIdx, float fVlaue)
{
const int nWriteLen = 2;
unsigned char szValue[10];
memcpy_s(szValue, 10, &fVlaue, sizeof(fVlaue));
//PLC 每个WORD 高低位需要交换
char chTmp = szValue[0];
szValue[0] = szValue[1];
szValue[1] = chTmp;
chTmp = szValue[2];
szValue[2] = szValue[3];
szValue[3] = chTmp;
int nSendLen = 0;
unsigned char szBuf[BUF_LEN];
int nRet = PLC_TcpFinsEncode(false, false, true, FINS_FRAME_CMD_SECTION_D_WORD
, WRITE_START_REGISTER_ADRR+ RegisterIdx, 0, szValue, sizeof(float)/2, szBuf, BUF_LEN, nSendLen);
if (0 == nRet)
{
CSingleLock lock(&gCriticalSection_PlcComm, true);
if (0 == m_pPlcTcpCtl->SendData((unsigned char*)szBuf, nSendLen, 1000))
{
int nRecv = m_pPlcTcpCtl->RecvData((unsigned char*)g_pDataBuf.get(), PLC_RECV_BUF_LEN, 1000);
if (nRecv > 0)
{
//完整报文校验
while (!IsCompletePacket(g_pDataBuf.get(), nRecv))
{
int nRevTmp = m_pPlcTcpCtl->RecvData((unsigned char*)g_pDataBuf.get() + nRecv, PLC_RECV_BUF_LEN, 1000);
if (nRevTmp <= 0)
{
return -1;
}
nRecv += nRevTmp;
}
vector<int> vecValue;
nRet = PLC_TcpFinsDecode(g_pDataBuf.get(), nRecv, vecValue);
}
}
}
return nRet;
}
int CPlcCommunicationMgr::WriteRwRegisterWORDValue(int RegisterIdx, WORD dwlaue)
{
const int nWriteLen = 2;
unsigned char szValue[nWriteLen];
memcpy_s(szValue, nWriteLen, &dwlaue, sizeof(WORD));
BYTE byTmp = szValue[0];
szValue[0]= szValue[1];
szValue[1] = byTmp;
int nSendLen = 0;
unsigned char szBuf[BUF_LEN];
int nRet = PLC_TcpFinsEncode(false, false, true, FINS_FRAME_CMD_SECTION_D_WORD
, WRITE_START_REGISTER_ADRR + RegisterIdx, 0, szValue, 1, szBuf, BUF_LEN, nSendLen);
if (0 == nRet)
{
CSingleLock lock(&gCriticalSection_PlcComm, true);
if (0 == m_pPlcTcpCtl->SendData((unsigned char*)szBuf, nSendLen, 1000))
{
int nRecv = m_pPlcTcpCtl->RecvData((unsigned char*)g_pDataBuf.get(), PLC_RECV_BUF_LEN, 1000);
if (nRecv > 0)
{
//完整报文校验
while (!IsCompletePacket(g_pDataBuf.get(), nRecv))
{
//再接收一次够了 数据量不大
int nRevTmp = m_pPlcTcpCtl->RecvData((unsigned char*)g_pDataBuf.get() + nRecv, PLC_RECV_BUF_LEN, 1000);
if (nRevTmp <= 0)
{
return -1;
}
nRecv += nRevTmp;
}
vector<int> vecValue;
nRet = PLC_TcpFinsDecode(g_pDataBuf.get(), nRecv, vecValue);
}
}
}
return nRet;
}
//IO 测试写入寄存器
void CPlcCommunicationMgr::IOTestWriteRwRegister(CRwRegisterPar *pRwRegisterPar)
{
CString log;
log.Format(":W%ld .%ld = %ld",pRwRegisterPar->m_RegisterIdx,pRwRegisterPar->m_BitIdx,pRwRegisterPar->m_bOn);
CLogInfo LogInfo;
LogInfo.m_ClassName = "CPlcCommunicationMgr";
LogInfo.m_FuncName = "IOTestWriteRwRegister";
LogInfo.m_LogMsg = log;
gLogMgr->WriteLogInfo(LogInfo);
WriteRwRegisterBitState(*pRwRegisterPar);
}
#endif