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

228 lines
7.5 KiB

#include "modbusmaster.h"
#include <QModbusTcpClient>
#include <QModbusRtuSerialMaster>
#include <qdebug.h>
#include "serialportexception.h"
enum { NumColumn = 0, CoilsColumn = 1, HoldingColumn = 2, ColumnCount = 3, RowCount = 10 };
modBusMaster::modBusMaster(QObject *parent) : QObject(parent)
{
m_coils.resize(2);
m_holdingRegisters.resize(2);
}
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 _serverId)
{
serialPort=_serialPort;
serverId=_serverId;
if (!modbusDevice)
return;
if (modbusDevice->state() != QModbusDevice::ConnectedState)
{
modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter,
serialPort);
#if QT_CONFIG(modbus_serialport)
modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter,
modbusSettings.parity);
modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter,
modbusSettings.baud);
modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter,
modbusSettings.dataBits);
modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter,
modbusSettings.stopBits);
#endif
modbusDevice->setTimeout(modbusSettings.responseTime);
modbusDevice->setNumberOfRetries(modbusSettings.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;
m_coils.setBit(0,coilFlag);
writeRequest(QModbusDataUnit::RegisterType::Coils, startAddress, 1);
}
void modBusMaster::setMultipleCoil(int startAddress, quint16 writeSize, QBitArray someCoilFlags)
{
if (!modbusDevice)
return;
m_coils = someCoilFlags;
writeRequest(QModbusDataUnit::RegisterType::Coils, startAddress, writeSize);
}
void modBusMaster::setSingleRgister(int startAddress, quint16 RegisterValue)
{
if (!modbusDevice)
return;
m_holdingRegisters[0]=RegisterValue;
writeRequest(QModbusDataUnit::RegisterType::HoldingRegisters, startAddress, 1);
}
void modBusMaster::setMultipleRegister(int startAddress, quint16 writeSize , QVector<quint16> someRegisterValue)
{
if (!modbusDevice)
return;
m_holdingRegisters = someRegisterValue;
writeRequest(QModbusDataUnit::RegisterType::HoldingRegisters, startAddress, writeSize);
}
void modBusMaster::getCoil(int startAddress, quint16 readSize)
{
if (!modbusDevice)
return;
readRequest(QModbusDataUnit::RegisterType::Coils, startAddress, readSize);
}
void modBusMaster::getInputCoil(int startAddress, quint16 readSize)
{
if (!modbusDevice)
return;
readRequest(QModbusDataUnit::RegisterType::DiscreteInputs, startAddress, readSize);
}
void modBusMaster::getInputRegister(int startAddress, quint16 readSize)
{
if (!modbusDevice)
return;
readRequest(QModbusDataUnit::RegisterType::InputRegisters, startAddress, readSize);
}
void modBusMaster::getHoldingRegister(int startAddress, quint16 readSize)
{
if (!modbusDevice)
return;
readRequest(QModbusDataUnit::RegisterType::HoldingRegisters, startAddress, readSize);
}
void modBusMaster::readRequest(QModbusDataUnit::RegisterType registerType, int startAddress, quint16 readSize)
{
auto table =registerType;
reply=modbusDevice->sendReadRequest(QModbusDataUnit(table, startAddress, readSize), serverId) ;
if (reply)
{
if (!reply->isFinished())
connect(reply, &QModbusReply::finished, this, &modBusMaster::readReady);
else
delete reply; // broadcast replies return immediately
}
else
{
throw serialPortException(modbusDevice->errorString());
}
}
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, m_coils[i + writeUnit.startAddress()]);
else
writeUnit.setValue(i, m_holdingRegisters[i + writeUnit.startAddress()]);
}
if (auto *reply = modbusDevice->sendWriteRequest(writeUnit, serverId)) {
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 {
// broadcast replies return immediately
reply->deleteLater();
}
} else {
throw serialPortException(tr("Write error: ") + modbusDevice->errorString());
}
}
void modBusMaster::readReady()
{
auto reply = qobject_cast<QModbusReply *>(sender());
if (!reply)
return;
QString readedParameter;
if (reply->error() == QModbusDevice::NoError) {
const QModbusDataUnit unit = reply->result();
for (uint i = 0; i < unit.valueCount(); i++) {
const QString entry = tr("Address: %1, Value: %2").arg(static_cast<quint16>(unit.startAddress())+ i)
.arg(QString::number(unit.value(i),
unit.registerType() <= QModbusDataUnit::Coils ? 10 : 16));
readedParameter += (entry + "\n" );
}
emit dataFromClient(readedParameter);
} 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));
}
reply->deleteLater();
}