|
|
|
#include "ModbusMaster.h"
|
|
|
|
#include <QModbusTcpClient>
|
|
|
|
#include <QModbusRtuSerialMaster>
|
|
|
|
#include <qdebug.h>
|
|
|
|
#include "QtConcurrent/QtConcurrent"
|
|
|
|
#include "SerialportException.h"
|
|
|
|
enum { NumColumn = 0, CoilsColumn = 1, HoldingColumn = 2, ColumnCount = 3, RowCount = 10 };
|
|
|
|
modBusMaster::modBusMaster(QObject *parent) : QObject(parent)
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void modBusMaster::init()
|
|
|
|
{
|
|
|
|
|
|
|
|
close();
|
|
|
|
modbusDevice = nullptr;
|
|
|
|
|
|
|
|
modbusDevice = new QModbusRtuSerialMaster(this);
|
|
|
|
connect(modbusDevice, &QModbusClient::errorOccurred, [this](QModbusDevice::Error)
|
|
|
|
{
|
|
|
|
throw serialPortException(modbusDevice->errorString());
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!modbusDevice)
|
|
|
|
throw serialPortException("Could not create Modbus master.");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void modBusMaster::open(QString serialPort , int slaveAddress)
|
|
|
|
{
|
|
|
|
|
|
|
|
_serialPort = serialPort;
|
|
|
|
_slaveAddress = slaveAddress;
|
|
|
|
if (!modbusDevice)
|
|
|
|
return;
|
|
|
|
if (modbusDevice->state() != QModbusDevice::ConnectedState)
|
|
|
|
{
|
|
|
|
modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter,
|
|
|
|
serialPort);
|
|
|
|
modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter,
|
|
|
|
_modbusSettings.modbusSetting.parity);
|
|
|
|
modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter,
|
|
|
|
_modbusSettings.modbusSetting.baud);
|
|
|
|
modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter,
|
|
|
|
_modbusSettings.modbusSetting.dataBits);
|
|
|
|
modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter,
|
|
|
|
_modbusSettings.modbusSetting.stopBits);
|
|
|
|
modbusDevice->setTimeout(_modbusSettings.modbusSetting.responseTime);
|
|
|
|
modbusDevice->setNumberOfRetries(_modbusSettings.modbusSetting.numberOfRetries);
|
|
|
|
emit modbusConnectionState(true);
|
|
|
|
}
|
|
|
|
if (!modbusDevice->connectDevice())
|
|
|
|
{
|
|
|
|
throw serialPortException(modbusDevice->errorString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void modBusMaster::close()
|
|
|
|
{
|
|
|
|
if (modbusDevice)
|
|
|
|
modbusDevice->disconnectDevice();
|
|
|
|
delete modbusDevice;
|
|
|
|
}
|
|
|
|
|
|
|
|
void modBusMaster::stop()
|
|
|
|
{
|
|
|
|
if (modbusDevice)
|
|
|
|
modbusDevice->disconnectDevice();
|
|
|
|
emit modbusConnectionState(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void modBusMaster::setSingleCoil(int startAddress,bool coilFlag)
|
|
|
|
{
|
|
|
|
if (!modbusDevice)
|
|
|
|
return;
|
|
|
|
_coilFlags.setBit(0,coilFlag);
|
|
|
|
writeRequest(QModbusDataUnit::RegisterType::Coils, startAddress, 1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void modBusMaster::setMultipleCoil(int startAddress, quint16 writeSize, QBitArray coilFlags)
|
|
|
|
{
|
|
|
|
if (!modbusDevice)
|
|
|
|
return;
|
|
|
|
_coilFlags = coilFlags;
|
|
|
|
writeRequest(QModbusDataUnit::RegisterType::Coils, startAddress, writeSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
void modBusMaster::setSingleRegister(int startAddress, quint16 registerValue)
|
|
|
|
{
|
|
|
|
if (!modbusDevice)
|
|
|
|
return;
|
|
|
|
_registerValues[0]=registerValue;
|
|
|
|
writeRequest(QModbusDataUnit::RegisterType::HoldingRegisters, startAddress, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void modBusMaster::setMultipleRegister(int startAddress, quint16 writeSize , QVector<quint16> registerValues)
|
|
|
|
{
|
|
|
|
if (!modbusDevice)
|
|
|
|
return;
|
|
|
|
_registerValues = registerValues;
|
|
|
|
writeRequest(QModbusDataUnit::RegisterType::HoldingRegisters, startAddress, writeSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QBitArray modBusMaster::getCoil(int startAddress, quint16 readSize)
|
|
|
|
{
|
|
|
|
QModbusDataUnit unit = readRequest(QModbusDataUnit::RegisterType::Coils, startAddress, readSize);
|
|
|
|
mutex.lock();
|
|
|
|
if(!freeThread)
|
|
|
|
modBusAnswerNotReady.wait(&mutex);
|
|
|
|
mutex.unlock();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QBitArray coils;
|
|
|
|
coils.resize(2);
|
|
|
|
auto num = unit.valueCount();
|
|
|
|
coils.resize(static_cast<int>(num));
|
|
|
|
for (uint i = 0; i < unit.valueCount(); i++)
|
|
|
|
{
|
|
|
|
coils.setBit((unit.value(i)));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return coils ;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
QBitArray modBusMaster::getInputCoil(int startAddress, quint16 readSize)
|
|
|
|
{
|
|
|
|
|
|
|
|
QModbusDataUnit unit = readRequest(QModbusDataUnit::RegisterType::DiscreteInputs, startAddress, readSize);
|
|
|
|
QBitArray coils;
|
|
|
|
coils.resize(2);
|
|
|
|
auto num = unit.valueCount();
|
|
|
|
coils.resize(static_cast<int>(num));
|
|
|
|
for (uint i = 0; i < unit.valueCount(); i++)
|
|
|
|
{
|
|
|
|
coils.setBit((unit.value(i)));
|
|
|
|
}
|
|
|
|
return coils ;
|
|
|
|
}
|
|
|
|
|
|
|
|
QVector<quint16> modBusMaster::getInputRegister(int startAddress, quint16 readSize)
|
|
|
|
{
|
|
|
|
|
|
|
|
QModbusDataUnit unit = readRequest(QModbusDataUnit::RegisterType::InputRegisters, startAddress, readSize);
|
|
|
|
QVector<quint16> registerValues;
|
|
|
|
registerValues.resize(2);
|
|
|
|
auto num = unit.valueCount();
|
|
|
|
registerValues.resize(static_cast<int>(num));
|
|
|
|
for (uint i = 0; i < unit.valueCount(); i++)
|
|
|
|
{
|
|
|
|
registerValues[i]=unit.value(i);
|
|
|
|
}
|
|
|
|
return registerValues ;
|
|
|
|
}
|
|
|
|
|
|
|
|
QVector<quint16> modBusMaster::getHoldingRegister(int startAddress, quint16 readSize)
|
|
|
|
{
|
|
|
|
// if (!modbusDevice)
|
|
|
|
// return;
|
|
|
|
QModbusDataUnit unit = readRequest(QModbusDataUnit::RegisterType::HoldingRegisters, startAddress, readSize);
|
|
|
|
QVector<quint16> registerValues;
|
|
|
|
registerValues.resize(2);
|
|
|
|
auto num = unit.valueCount();
|
|
|
|
registerValues.resize(static_cast<int>(num));
|
|
|
|
for (uint i = 0; i < unit.valueCount(); i++)
|
|
|
|
{
|
|
|
|
registerValues[i]=unit.value(i);
|
|
|
|
}
|
|
|
|
return registerValues ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QModbusDataUnit modBusMaster::readRequest(QModbusDataUnit::RegisterType registerType, int startAddress, quint16 readSize)
|
|
|
|
{
|
|
|
|
|
|
|
|
auto table =registerType;
|
|
|
|
if (auto *reply =modbusDevice->sendReadRequest(QModbusDataUnit(table, startAddress, readSize), _slaveAddress))
|
|
|
|
{
|
|
|
|
QFuture<void> future = QtConcurrent::run([this, reply]() {
|
|
|
|
// while(!reply->isFinished())
|
|
|
|
// {
|
|
|
|
// qDebug() << "reply->isFinished() " << reply->isFinished();
|
|
|
|
// qDebug() << "Hello from thread " << QThread::currentThread();
|
|
|
|
// }
|
|
|
|
|
|
|
|
if (!freeThread)
|
|
|
|
{
|
|
|
|
if (!reply->isFinished())
|
|
|
|
{
|
|
|
|
qDebug() << "1reply->isFinished() " << reply->isFinished();
|
|
|
|
connect(reply, &QModbusReply::finished, this, &modBusMaster::modbusReplyRecieved, Qt::ConnectionType::BlockingQueuedConnection);
|
|
|
|
qDebug() << "2reply->isFinished() " << reply->isFinished();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// freeThread=true;
|
|
|
|
mutex.lock();
|
|
|
|
if (freeThread)
|
|
|
|
modBusAnswerNotReady.wakeAll();
|
|
|
|
mutex.unlock();
|
|
|
|
|
|
|
|
if(!checkForError(reply))
|
|
|
|
{
|
|
|
|
const QModbusDataUnit unit = reply->result();
|
|
|
|
return unit;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw serialPortException(modbusDevice->errorString());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
reply->deleteLater();
|
|
|
|
}
|
|
|
|
bool modBusMaster::checkForError(QModbusReply *_reply)
|
|
|
|
{
|
|
|
|
if (_reply->error() == QModbusDevice::NoError)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
|
|
|
|
} else if (_reply->error() == QModbusDevice::ProtocolError)
|
|
|
|
{
|
|
|
|
throw serialPortException(tr("Read response error: %1 (Mobus exception: 0x%2)").
|
|
|
|
arg(reply->errorString()).
|
|
|
|
arg(reply->rawResult().exceptionCode(), -1, 16));
|
|
|
|
} else {
|
|
|
|
throw serialPortException(tr("Read response error: %1 (code: 0x%2)").
|
|
|
|
arg(reply->errorString()).
|
|
|
|
arg(reply->error(), -1, 16));
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void modBusMaster::modbusReplyRecieved()
|
|
|
|
{
|
|
|
|
|
|
|
|
// auto reply = qobject_cast<QModbusReply *>(sender());
|
|
|
|
// if (!reply)
|
|
|
|
// return;
|
|
|
|
|
|
|
|
// modbusReplyFromClient = reply;
|
|
|
|
freeThread=true;
|
|
|
|
|
|
|
|
// reply->deleteLater();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void modBusMaster::writeRequest(QModbusDataUnit::RegisterType registerType, int startAddress, quint16 writeSize)
|
|
|
|
{
|
|
|
|
qDebug() << " ---- setSingleCoil coilFlag writeRequest ";
|
|
|
|
auto table =registerType;
|
|
|
|
Q_ASSERT(startAddress >= 0 && startAddress < 10);
|
|
|
|
QModbusDataUnit writeUnit = QModbusDataUnit(table, startAddress, writeSize);
|
|
|
|
qDebug() << " ---- writeUnit.valueCount()" << writeUnit.valueCount();
|
|
|
|
for (int i = 0; i < writeUnit.valueCount(); i++) {
|
|
|
|
if (table == QModbusDataUnit::Coils)
|
|
|
|
writeUnit.setValue(i, _coilFlags[i + writeUnit.startAddress()]);
|
|
|
|
else
|
|
|
|
writeUnit.setValue(i, _registerValues[i + writeUnit.startAddress()]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (auto *reply = modbusDevice->sendWriteRequest(writeUnit, _slaveAddress)) {
|
|
|
|
|
|
|
|
QFuture<void> future = QtConcurrent::run([this, reply]() {
|
|
|
|
while(!reply->isFinished())
|
|
|
|
{
|
|
|
|
qDebug() << "reply->isFinished() " << reply->isFinished();
|
|
|
|
}
|
|
|
|
qDebug() << "reply->isFinished() after " << reply->isFinished();
|
|
|
|
if(!checkForError(reply))
|
|
|
|
{
|
|
|
|
const QModbusDataUnit unit = reply->result();
|
|
|
|
|
|
|
|
}
|
|
|
|
});
|
|
|
|
// future.waitForFinished();
|
|
|
|
|
|
|
|
// if (!reply->isFinished()) {
|
|
|
|
// connect(reply, &QModbusReply::finished, this, [reply]() {
|
|
|
|
// if (reply->error() == QModbusDevice::ProtocolError) {
|
|
|
|
// throw serialPortException(tr("Write response error: %1 (Mobus exception: 0x%2)")
|
|
|
|
// .arg(reply->errorString()).arg(reply->rawResult().exceptionCode(), -1, 16));
|
|
|
|
// } else if (reply->error() != QModbusDevice::NoError) {
|
|
|
|
// throw serialPortException(tr("Write response error: %1 (code: 0x%2)").
|
|
|
|
// arg(reply->errorString()).arg(reply->error(), -1, 16));
|
|
|
|
|
|
|
|
// }
|
|
|
|
// reply->deleteLater();
|
|
|
|
// });
|
|
|
|
// } else {
|
|
|
|
//reply->deleteLater();
|
|
|
|
//}
|
|
|
|
qDebug() << " ---- sreply reply "<< reply->error();
|
|
|
|
} else {
|
|
|
|
throw serialPortException(tr("Write error: ") + modbusDevice->errorString());
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|