QT-C++ 西门子snap7通讯库接口
#include "Snap7ConObject.h"
#include "snap7.h"
#include <QDebug>
#include <QTime>
#include <QDataStream>
struct sSnapData
{
int nErrorCount = 0;
bool bExit = false;
bool bConneted = false;
TS7Client *pClient = nullptr;
QMutex funMutex; // 为了保证通讯的稳定性,函数接口锁为必须
};
// 不阻塞定时器
struct sSnap7Timer
{
QTime time;
uint32_t interval;
void start(uint32_t t)
{
interval = t;
time.restart();
};
bool isTimeOut()
{
return time.elapsed() > interval;
};
};
cSnapConObject::cSnapConObject(QObject *parent)
: QThread(parent)
, m_ptr(new sSnapData())
{
m_ptr->pClient = new TS7Client();
this->start();
}
cSnapConObject::~cSnapConObject()
{
}
/**
* @brief 获取示例对象
* @param[IN]
* @param[OUT]
* @return 对象指针
*
* @note
*/
cSnapConObject *cSnapConObject::getInstance()
{
static cSnapConObject instance;
return &instance;
}
void cSnapConObject::run()
{
static int nStep = 0;
static sSnap7Timer timeout;
while (true)
{
QThread::msleep(100);
if (m_ptr->bExit)
return;
switch (nStep)
{
case 0:
{
// 掉线重新连接
if (m_ptr->nErrorCount > 50)
{
nStep = 1;
}
}break;
case 1:
{
if (!m_ptr->pClient->Connected())
{
int nRet = m_ptr->pClient->ConnectTo(m_strIp.toStdString().c_str(), m_nRackNumber, m_nSlotNumber);
if (nRet == 0)
{
m_ptr->nErrorCount = 0;
m_ptr->bConneted = true;
}
else
m_ptr->bConneted = false;
}
else
{
m_ptr->nErrorCount = 0;
}
timeout.start(5 * 1000);
nStep = 2;
}break;
case 2:
{
if (timeout.isTimeOut())
{
nStep = 0;
}
}break;
default:
break;
}
}
}
// 连接
bool cSnapConObject::connect(QString strIp, int nPort, int nRack, int nSlot)
{
m_strIp = strIp;
m_nPort = nPort;
m_nRackNumber = nRack;
m_nSlotNumber = nSlot;
int nRet = m_ptr->pClient->ConnectTo(strIp.toStdString().c_str(), nRack, nSlot);
if (nRet == 0)
m_ptr->bConneted = true;
else
m_ptr->bConneted = false;
return m_ptr->bConneted;
}
// 读取VW寄存器值(16)位
bool cSnapConObject::readInt16(uint16_t uAddr, int16_t &nValue,int nDb)
{
if (!m_ptr->bConneted)
return false;
int16_t buffer[1] = { 0 };
bool bRet = readMultInt16(uAddr, 1, buffer, nDb);
nValue = buffer[0];
return bRet;
}
// 批量读取16位
bool cSnapConObject::readMultInt16(uint16_t uStartAddr, int nCount, int16_t *buffer, int nDb)
{
if (!m_ptr->bConneted)
return false;
// 创建用于读取的数据缓冲区
QByteArray data(nCount * sizeof(int16_t), 0);
int nRet = m_ptr->pClient->ReadArea(S7AreaDB, nDb, uStartAddr, nCount * sizeof(int16_t), S7WLByte, data.data());
if (nRet == 0)
{
// 如果没有错误
QDataStream dataStream(data);
dataStream.setByteOrder(QDataStream::BigEndian); // 设置字节序为大端
// 逐个读取 qint16 数据并转换
for (int i = 0; i < nCount; ++i)
{
int16_t value;
dataStream >> value; // 读取 qint16 值
//buffer[i] = bigEndianToLittleEndian(value);
buffer[i] = (value);
}
return true;
}
else
m_ptr->nErrorCount++;
return false;
}
// 读取VD寄存器值(32)位
bool cSnapConObject::readInt32(uint16_t uAddr, int32_t &nValue, int nDb)
{
if (!m_ptr->bConneted)
return false;
int32_t buffer[1] = { 0 };
bool bRet = readMultiInt32(uAddr, 1, buffer, nDb);
nValue = buffer[0];
return bRet;
}
// 批量读取32位
bool cSnapConObject::readMultiInt32(uint16_t uStartAddr, int nCount, int32_t *buffer, int nDb)
{
if (!m_ptr->bConneted)
return false;
// 创建用于读取的数据缓冲区
QByteArray data(nCount * sizeof(int32_t), 0);
int nRet = m_ptr->pClient->ReadArea(S7AreaDB, nDb, uStartAddr, nCount * sizeof(int32_t), S7WLByte, data.data());
if (nRet == 0)
{
// 如果没有错误
QDataStream dataStream(data);
dataStream.setByteOrder(QDataStream::BigEndian); // 设置字节序为大端
// 逐个读取 int32_t 数据并转换
for (int i = 0; i < nCount; ++i)
{
int32_t value;
dataStream >> value; // 读取 int32_t 值
//buffer[i] = bigEndianToLittleEndian(value);
buffer[i] = (value);
}
return true;
}
return false;
}
// 读取浮点
bool cSnapConObject::readFloat(uint16_t uAddr, float &fValue, int nDb)
{
float fArray[1] = {0.0};
bool bRet = readMultiFloat(uAddr,1,fArray);
fValue = fArray[0];
return bRet;
}
// 读取多个浮点数寄存器
bool cSnapConObject::readMultiFloat(uint16_t uStartAddr, int nCount, float *buffer, int nDb)
{
if (!m_ptr->bConneted)
return false;
// 创建用于读取的数据缓冲区
int nSize = sizeof(float);
QByteArray data(nCount * sizeof(float), 0);
int nRet = m_ptr->pClient->ReadArea(S7AreaDB, nDb, uStartAddr, nCount * sizeof(float), S7WLByte, data.data());
if (nRet == 0)
{
// 如果没有错误
QDataStream dataStream(data);
//dataStream.setByteOrder(QDataStream::BigEndian); // 设置字节序为大端
dataStream.setFloatingPointPrecision(QDataStream::SinglePrecision);
// 逐个读取 float 数据并转换
for (int i = 0; i < nCount; ++i)
{
float value;
dataStream >> value; // 读取 float 值
buffer[i] = (value);
}
return true;
}
return false;
}
// 读取M x.x
bool cSnapConObject::readM(uint16_t uStartByte, uint16_t uBitOffset, bool &bState, int nDb)
{
if (!m_ptr->bConneted)
return false;
uint8_t boolValue = 0; // 存储读取到的布尔值
int nRet = m_ptr->pClient->ReadArea(S7AreaMK, nDb, uStartByte, 1, S7WLBit, &boolValue);
if (nRet == 0)
{
bState = (boolValue & (1 << uBitOffset)) != 0;
return true;
}
else
m_ptr->nErrorCount++;
return false;
}
// 读取输入点
bool cSnapConObject::readInput_X(uint16_t uStartByte, uint16_t uBitOffset, bool &bState, int nDb)
{
if (!m_ptr->bConneted)
return false;
uint8_t boolValue = 0;
int nRet = m_ptr->pClient->ReadArea(S7AreaPE, nDb, uStartByte, 1, S7WLBit, &boolValue);
if (nRet == 0)
{
bState = (boolValue & (1 << uBitOffset)) != 0;
return true;
}
else
m_ptr->nErrorCount++;
return false;
}
// 读取输出点
bool cSnapConObject::readOutput_Y(uint16_t uStartByte, uint16_t uBitOffset, bool &bState, int nDb)
{
if (!m_ptr->bConneted)
return false;
uint8_t boolValue = 0;
int nRet = m_ptr->pClient->ReadArea(S7AreaPA, nDb, uStartByte, 1, S7WLBit, &boolValue);
if (nRet == 0)
{
bState = (boolValue & (1 << uBitOffset)) != 0;
return true;
}
else
m_ptr->nErrorCount++;
return false;
}
// 写入16位整数
bool cSnapConObject::writeInt16(uint16_t uAddr, int16_t nValue, int nDb)
{
int16_t buffer[1] = { nValue };
return writeMultiInt16(uAddr, 1, buffer, nDb);
}
// 批量写入
bool cSnapConObject::writeMultiInt16(uint16_t uStartAddr, int nCount, int16_t *buffer, int nDb)
{
if (!m_ptr->bConneted)
return false;
std::vector<byte> bufferTemp(nCount * sizeof(int16_t));
// 将 INT16 数据转换为大端格式并填入缓冲区
for (size_t i = 0; i < nCount; ++i)
{
convertInt16ToBigEndian(buffer[i], &bufferTemp[i * sizeof(int16_t)]);
}
int nRet = m_ptr->pClient->WriteArea(S7AreaDB, nDb, uStartAddr,nCount*sizeof(int16_t), S7WLByte, bufferTemp.data());
if (nRet == 0)
return true;
else
m_ptr->nErrorCount++;
return false;
}
// 写入32位整数
bool cSnapConObject::writeInt32(uint16_t uAddr, int32_t nValue, int nDb)
{
if (!m_ptr->bConneted)
return false;
int32_t buffer[1] = { nValue };
return writeMultiInt32(uAddr,1,buffer,nDb);
}
// 批量写入
bool cSnapConObject::writeMultiInt32(uint16_t uStartAddr, int nCount, int32_t *buffer, int nDb)
{
if (!m_ptr->bConneted)
return false;
std::vector<byte> bufferTemp(nCount * sizeof(int32_t));
// 将 INT32 数据转换为大端格式并填入缓冲区
for (size_t i = 0; i < nCount; ++i)
{
convertInt32ToBigEndian(buffer[i], &bufferTemp[i * sizeof(int32_t)]);
}
int nRet = m_ptr->pClient->WriteArea(S7AreaDB, nDb, uStartAddr,nCount*sizeof(int32_t), S7WLByte, bufferTemp.data());
if (nRet == 0)
return true;
else
m_ptr->nErrorCount++;
return false;
}
// 写入浮点数
bool cSnapConObject::writeFloat(uint16_t uAddr, float fValue, int nDb)
{
float buffer[1] = { fValue };
return writeMultiFloat(uAddr,1,buffer,nDb);
}
// 批量写入浮点数
bool cSnapConObject::writeMultiFloat(uint16_t uStartAddr, int nCount, float *buffer, int nDb)
{
if (!m_ptr->bConneted)
return false;
// 准备要写入的数据的字节数组
QByteArray byteArray;
for (size_t i = 0; i < nCount; ++i)
{
float value = buffer[i];
QByteArray tempData(reinterpret_cast<const char*>(&value), sizeof(float));
// 大端转换:将字节顺序反转
for (int j = sizeof(float) - 1; j >= 0; --j)
{
byteArray.append(tempData[j]);
}
}
int nRet = m_ptr->pClient->WriteArea(S7AreaDB, nDb, uStartAddr, byteArray.size(), S7WLByte, byteArray.data());
if (nRet == 0)
return true;
else
m_ptr->nErrorCount++;
return false;
}
// 写入M x.x
bool cSnapConObject::writeM(uint16_t uStartByte, uint16_t uBitOffset, bool bState, int nDb)
{
if (!m_ptr->bConneted)
return false;
// 准备写入的数据
uint8_t dataToWrite = 0;
if (bState)
dataToWrite = (1 << uBitOffset); // 构造要写入的数据
// 读取当前的值
uint8_t currentData = 0;
int nRet = m_ptr->pClient->ReadArea(S7AreaMK, nDb, uStartByte, 1, S7WLBit, ¤tData);
if (nRet != 0)
{
m_ptr->nErrorCount++;
return false;
}
// 更新数据
if (bState)
currentData |= dataToWrite; // eg.设置 M2.2 对应的位
else
currentData &= ~dataToWrite; // eg.清除 M2.2 对应的位
// 写入
int nRet1 = m_ptr->pClient->ReadArea(S7AreaMK, nDb, uStartByte, 1, S7WLBit