diff --git a/modbus/modbusrtumaster.cpp b/modbus/modbusrtumaster.cpp index 57a45af..d702c3b 100644 --- a/modbus/modbusrtumaster.cpp +++ b/modbus/modbusrtumaster.cpp @@ -54,7 +54,6 @@ ModbusRTUMaster::ModbusRTUMaster(QString serialPort, uint baudrate, QSerialPort: connect(m_reconnectTimer, &QTimer::timeout, this, &ModbusRTUMaster::onReconnectTimer); } - ModbusRTUMaster::~ModbusRTUMaster() { if (!m_modbusRtuSerialMaster) { diff --git a/modbuscommander/integrationpluginmodbuscommander.cpp b/modbuscommander/integrationpluginmodbuscommander.cpp index 0057354..cae1683 100644 --- a/modbuscommander/integrationpluginmodbuscommander.cpp +++ b/modbuscommander/integrationpluginmodbuscommander.cpp @@ -31,6 +31,10 @@ #include "integrationpluginmodbuscommander.h" #include "plugininfo.h" +#include "hardwaremanager.h" +#include "hardware/modbus/modbusrtumaster.h" +#include "hardware/modbus/modbusrtuhardwareresource.h" + #include IntegrationPluginModbusCommander::IntegrationPluginModbusCommander() @@ -39,8 +43,6 @@ IntegrationPluginModbusCommander::IntegrationPluginModbusCommander() void IntegrationPluginModbusCommander::init() { - connect(this, &IntegrationPluginModbusCommander::configValueChanged, this, &IntegrationPluginModbusCommander::onPluginConfigurationChanged); - m_slaveAddressParamTypeId.insert(coilThingClassId, coilThingSlaveAddressParamTypeId); m_slaveAddressParamTypeId.insert(inputRegisterThingClassId, inputRegisterThingSlaveAddressParamTypeId); m_slaveAddressParamTypeId.insert(discreteInputThingClassId, discreteInputThingSlaveAddressParamTypeId); @@ -62,46 +64,49 @@ void IntegrationPluginModbusCommander::init() m_valueStateTypeId.insert(inputRegisterThingClassId, inputRegisterValueStateTypeId); m_valueStateTypeId.insert(discreteInputThingClassId, discreteInputValueStateTypeId); m_valueStateTypeId.insert(holdingRegisterThingClassId, holdingRegisterValueStateTypeId); + + // Plugin configuration + connect(this, &IntegrationPluginModbusCommander::configValueChanged, this, &IntegrationPluginModbusCommander::onPluginConfigurationChanged); + + // Modbus RTU hardware resource + connect(hardwareManager()->modbusRtuResource(), &ModbusRtuHardwareResource::modbusRtuMasterRemoved, this, [=](const QUuid &modbusUuid){ + qCDebug(dcModbusCommander()) << "Modbus RTU master has been removed" << modbusUuid.toString(); + + // Check if there is any device using this resource + foreach (Thing *thing, m_modbusRtuMasters.keys()) { + if (m_modbusRtuMasters.value(thing)->modbusUuid() == modbusUuid) { + qCWarning(dcModbusCommander()) << "Hardware resource removed for" << thing << ". The thing will not be functional any more until a new resource has been configured for it."; + m_modbusRtuMasters.remove(thing); + thing->setStateValue(m_connectedStateTypeId[thing->thingClassId()], false); + + // Set all child things disconnected + foreach (Thing *childThing, myThings()) { + if (childThing->parentId() == thing->id()) { + thing->setStateValue(m_connectedStateTypeId[childThing->thingClassId()], false); + } + } + } + } + }); } void IntegrationPluginModbusCommander::discoverThings(ThingDiscoveryInfo *info) { ThingClassId thingClassId = info->thingClassId(); if (thingClassId == modbusRTUClientThingClassId) { - Q_FOREACH(QSerialPortInfo port, QSerialPortInfo::availablePorts()) { - qCDebug(dcModbusCommander()) << "Found serial port:" << port.systemLocation() << "manufacturer" << port.manufacturer() << "description" << port.description() << "serial number" << port.serialNumber(); - if (port.isBusy()) { - qCDebug(dcModbusCommander()) << "Serial port ist busy, skipping."; - continue; + foreach (ModbusRtuMaster *modbusMaster, hardwareManager()->modbusRtuResource()->modbusRtuMasters()) { + qCDebug(dcModbusCommander()) << "Found RTU master resource" << modbusMaster; + if (modbusMaster->connected()) { + ParamList parameters; + ThingDescriptor thingDescriptor(thingClassId, "Modbus RTU master", modbusMaster->serialPort()); + parameters.append(Param(modbusRTUClientThingModbusMasterUuidParamTypeId, modbusMaster->modbusUuid())); + thingDescriptor.setParams(parameters); + info->addThingDescriptor(thingDescriptor); + } else { + qCWarning(dcModbusCommander()) << "Found configured resource" << modbusMaster << "but it is not connected. Skipping."; } - QString manufacturer = port.manufacturer(); - if (manufacturer.isEmpty()) { - manufacturer = "unknown"; - } - QString description = port.description()+" Manufacturer: "+port.manufacturer(); - ThingDescriptor thingDescriptor(thingClassId, "Modbus RTU interface", description); - ParamList parameters; - QString serialPort = port.systemLocation(); - QString serialnumber = port.serialNumber(); - if (serialnumber.isEmpty()) { - serialnumber = port.manufacturer()+QString::number(port.productIdentifier(), 16); - - } - qCDebug(dcModbusCommander()) << " - Serial number" << serialnumber; - Q_FOREACH (Thing *exisingThing, myThings().filterByParam(modbusRTUClientThingClassId)) { - thingDescriptor.setThingId(exisingThing->id()); - // Rediscovery is broken because of a missing unique device id - // This is a workaround and doesnt work if multiple uart converters are attached. - // ThingDiscoveryInfo may be extended to distinquish between discovery and rediscovery - break; - } - parameters.append(Param(modbusRTUClientThingSerialPortParamTypeId, serialPort)); - parameters.append(Param(modbusRTUClientThingSerialnumberParamTypeId, serialnumber)); - thingDescriptor.setParams(parameters); - info->addThingDescriptor(thingDescriptor); } - //FIXME missing info if it is a rediscovery info->finish(Thing::ThingErrorNoError); return; } else if (thingClassId == discreteInputThingClassId) { @@ -112,7 +117,7 @@ void IntegrationPluginModbusCommander::discoverThings(ThingDiscoveryInfo *info) info->addThingDescriptor(descriptor); } if (clientThing->thingClassId() == modbusRTUClientThingClassId) { - ThingDescriptor descriptor(thingClassId, "Discrete input", clientThing->name() + " " + clientThing->paramValue(modbusRTUClientThingSerialPortParamTypeId).toString()); + ThingDescriptor descriptor(thingClassId, "Discrete input", clientThing->name() + " " + clientThing->paramValue(modbusRTUClientThingModbusMasterUuidParamTypeId).toString()); descriptor.setParentId(clientThing->id()); info->addThingDescriptor(descriptor); } @@ -128,7 +133,7 @@ void IntegrationPluginModbusCommander::discoverThings(ThingDiscoveryInfo *info) info->addThingDescriptor(descriptor); } if (clientThing->thingClassId() == modbusRTUClientThingClassId) { - ThingDescriptor descriptor(thingClassId, "Coil", clientThing->name() + " " + clientThing->paramValue(modbusRTUClientThingSerialPortParamTypeId).toString()); + ThingDescriptor descriptor(thingClassId, "Coil", clientThing->name() + " " + clientThing->paramValue(modbusRTUClientThingModbusMasterUuidParamTypeId).toString()); descriptor.setParentId(clientThing->id()); info->addThingDescriptor(descriptor); } @@ -143,7 +148,7 @@ void IntegrationPluginModbusCommander::discoverThings(ThingDiscoveryInfo *info) info->addThingDescriptor(descriptor); } if (clientThing->thingClassId() == modbusRTUClientThingClassId) { - ThingDescriptor descriptor(thingClassId, "Holding register", clientThing->name() + " " + clientThing->paramValue(modbusRTUClientThingSerialPortParamTypeId).toString()); + ThingDescriptor descriptor(thingClassId, "Holding register", clientThing->name() + " " + clientThing->paramValue(modbusRTUClientThingModbusMasterUuidParamTypeId).toString()); descriptor.setParentId(clientThing->id()); info->addThingDescriptor(descriptor); } @@ -159,7 +164,7 @@ void IntegrationPluginModbusCommander::discoverThings(ThingDiscoveryInfo *info) info->addThingDescriptor(descriptor); } if (clientThing->thingClassId() == modbusRTUClientThingClassId) { - ThingDescriptor descriptor(thingClassId, "Input register", clientThing->name() + " " + clientThing->paramValue(modbusRTUClientThingSerialPortParamTypeId).toString()); + ThingDescriptor descriptor(thingClassId, "Input register", clientThing->name() + " " + clientThing->paramValue(modbusRTUClientThingModbusMasterUuidParamTypeId).toString()); descriptor.setParentId(clientThing->id()); info->addThingDescriptor(descriptor); } @@ -215,74 +220,51 @@ void IntegrationPluginModbusCommander::setupThing(ThingSetupInfo *info) } }); connect(thing, &Thing::settingChanged, thing, [thing, modbusTCPMaster] (const ParamTypeId ¶mTypeId, const QVariant &value) { - if (paramTypeId == modbusTCPClientSettingsNumberOfRetriesParamTypeId) { - qCDebug(dcModbusCommander()) << "Set number of retries" << thing->name() << value.toUInt(); - modbusTCPMaster->setNumberOfRetries(value.toUInt()); - } else if (paramTypeId == modbusTCPClientSettingsTimeoutParamTypeId) { - qCDebug(dcModbusCommander()) << "Set timeout " << thing->name() << value.toUInt(); - modbusTCPMaster->setTimeout(value.toUInt()); - } - }); + if (paramTypeId == modbusTCPClientSettingsNumberOfRetriesParamTypeId) { + qCDebug(dcModbusCommander()) << "Set number of retries" << thing->name() << value.toUInt(); + modbusTCPMaster->setNumberOfRetries(value.toUInt()); + } else if (paramTypeId == modbusTCPClientSettingsTimeoutParamTypeId) { + qCDebug(dcModbusCommander()) << "Set timeout " << thing->name() << value.toUInt(); + modbusTCPMaster->setTimeout(value.toUInt()); + } + }); modbusTCPMaster->connectDevice(); } else if (thing->thingClassId() == modbusRTUClientThingClassId) { + QUuid modbusUuid = thing->paramValue(modbusRTUClientThingModbusMasterUuidParamTypeId).toUuid(); - QString serialPort = thing->paramValue(modbusRTUClientThingSerialPortParamTypeId).toString(); - uint baudrate = thing->paramValue(modbusRTUClientThingBaudRateParamTypeId).toUInt(); - uint stopBits = thing->paramValue(modbusRTUClientThingStopBitsParamTypeId).toUInt(); - uint dataBits = thing->paramValue(modbusRTUClientThingDataBitsParamTypeId).toUInt(); - uint numberOfRetries = thing->setting(modbusRTUClientSettingsNumberOfRetriesParamTypeId).toUInt(); - uint timeout = thing->setting(modbusRTUClientSettingsTimeoutParamTypeId).toUInt(); - QSerialPort::Parity parity = QSerialPort::Parity::NoParity; - QString parityString = thing->paramValue(modbusRTUClientThingParityParamTypeId).toString(); - if (parityString.contains("No")) { - parity = QSerialPort::Parity::NoParity; - } else if (parityString.contains("Even")) { - parity = QSerialPort::Parity::EvenParity; - } else if (parityString.contains("Odd")) { - parity = QSerialPort::Parity::OddParity; - } - qCDebug(dcModbusCommander()) << "Setting up RTU client" << thing->name(); - qCDebug(dcModbusCommander()) << " baud:" << baudrate; - qCDebug(dcModbusCommander()) << " stop bits:" << stopBits; - qCDebug(dcModbusCommander()) << " data bits:" << dataBits; - qCDebug(dcModbusCommander()) << " parity:" << parityString; - qCDebug(dcModbusCommander()) << " number of retries:" << numberOfRetries; - qCDebug(dcModbusCommander()) << " timeout:" << timeout; - - - if (m_modbusRTUMasters.contains(thing)) { - // In case of a rediscovery - m_modbusRTUMasters.take(thing)->deleteLater(); + if (!hardwareManager()->modbusRtuResource()->available()) { + qCWarning(dcModbusCommander()) << "Cannot set up thing" << thing << ". The modbus RTU hardware resource is not available."; + info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("The modbus RTU hardware resource is not available")); + return; } - ModbusRTUMaster *modbusRTUMaster = new ModbusRTUMaster(serialPort, baudrate, parity, dataBits, stopBits, this); - modbusRTUMaster->setTimeout(timeout); - modbusRTUMaster->setNumberOfRetries(numberOfRetries); - connect(modbusRTUMaster, &ModbusRTUMaster::connectionStateChanged, this, &IntegrationPluginModbusCommander::onConnectionStateChanged); - connect(modbusRTUMaster, &ModbusRTUMaster::requestExecuted, this, &IntegrationPluginModbusCommander::onRequestExecuted); - connect(modbusRTUMaster, &ModbusRTUMaster::requestError, this, &IntegrationPluginModbusCommander::onRequestError); - connect(modbusRTUMaster, &ModbusRTUMaster::receivedCoil, this, &IntegrationPluginModbusCommander::onReceivedCoil); - connect(modbusRTUMaster, &ModbusRTUMaster::receivedDiscreteInput, this, &IntegrationPluginModbusCommander::onReceivedDiscreteInput); - connect(modbusRTUMaster, &ModbusRTUMaster::receivedHoldingRegister, this, &IntegrationPluginModbusCommander::onReceivedHoldingRegister); - connect(modbusRTUMaster, &ModbusRTUMaster::receivedInputRegister, this, &IntegrationPluginModbusCommander::onReceivedInputRegister); - connect(modbusRTUMaster, &ModbusRTUMaster::connectionStateChanged, info, [info, modbusRTUMaster, this] (bool connected) { - if (connected) { - info->finish(Thing::ThingErrorNoError); - m_modbusRTUMasters.insert(info->thing(), modbusRTUMaster); + if (!hardwareManager()->modbusRtuResource()->hasModbusRtuMaster(modbusUuid)) { + qCWarning(dcModbusCommander()) << "Cannot set up thing" << thing << ". The modbus RTU hardware resource" << modbusUuid.toString() << "does not exist any more. Reconfiguration required."; + info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("Configured modbus RTU master could not be found. Please reconfigure the client and assign a new valid modbus RTU master.")); + return; + } + + ModbusRtuMaster *modbusMaster = hardwareManager()->modbusRtuResource()->getModbusRtuMaster(modbusUuid); + qCDebug(dcModbusCommander()) << "Setting up" << thing << "using" << modbusMaster; + m_modbusRtuMasters.insert(thing, modbusMaster); + + connect(modbusMaster, &ModbusRtuMaster::connectedChanged, thing, [=](bool connected){ + qCDebug(dcModbusCommander()) << "Modbus RTU client" << modbusMaster << "connected changed" << connected; + thing->setStateValue(modbusRTUClientConnectedStateTypeId, connected); + + // Note: only set the connected state for the child things if disconnected. + // The child things will be evaluated upon read requests if the slave is connected or not. + if (!connected) { + foreach (Thing *childThing, myThings()) { + if (childThing->parentId() == thing->id()) { + thing->setStateValue(m_connectedStateTypeId[childThing->thingClassId()], connected); + } + } } }); - connect(thing, &Thing::settingChanged, thing, [thing, modbusRTUMaster] (const ParamTypeId ¶mTypeId, const QVariant &value) { - if (paramTypeId == modbusRTUClientSettingsNumberOfRetriesParamTypeId) { - qCDebug(dcModbusCommander()) << "Set number of retries" << thing->name() << value.toUInt(); - modbusRTUMaster->setNumberOfRetries(value.toUInt()); - } else if (paramTypeId == modbusRTUClientSettingsTimeoutParamTypeId) { - qCDebug(dcModbusCommander()) << "Set timeout " << thing->name() << value.toUInt(); - modbusRTUMaster->setTimeout(value.toUInt()); - } - }); - modbusRTUMaster->connectDevice(); + info->finish(Thing::ThingErrorNoError); } else if ((thing->thingClassId() == coilThingClassId) || (thing->thingClassId() == discreteInputThingClassId) || (thing->thingClassId() == holdingRegisterThingClassId) @@ -362,9 +344,6 @@ void IntegrationPluginModbusCommander::thingRemoved(Thing *thing) if (thing->thingClassId() == modbusTCPClientThingClassId) { ModbusTCPMaster *modbus = m_modbusTCPMasters.take(thing); modbus->deleteLater(); - } else if (thing->thingClassId() == modbusRTUClientThingClassId) { - ModbusRTUMaster *modbus = m_modbusRTUMasters.take(thing); - modbus->deleteLater(); } if (myThings().empty()) { @@ -392,12 +371,7 @@ void IntegrationPluginModbusCommander::onPluginConfigurationChanged(const ParamT void IntegrationPluginModbusCommander::onConnectionStateChanged(bool status) { auto modbus = sender(); - - if (m_modbusRTUMasters.values().contains(static_cast(modbus))) { - Thing *thing = m_modbusRTUMasters.key(static_cast(modbus)); - qCDebug(dcModbusCommander()) << "Connections state changed" << thing->name() << status; - thing->setStateValue(modbusRTUClientConnectedStateTypeId, status); - } else if (m_modbusTCPMasters.values().contains(static_cast(modbus))) { + if (m_modbusTCPMasters.values().contains(static_cast(modbus))) { Thing *thing = m_modbusTCPMasters.key(static_cast(modbus)); qCDebug(dcModbusCommander()) << "Connections state changed" << thing->name() << status; thing->setStateValue(modbusTCPClientConnectedStateTypeId, status); @@ -439,20 +413,7 @@ void IntegrationPluginModbusCommander::onRequestError(QUuid requestId, const QSt void IntegrationPluginModbusCommander::onReceivedCoil(quint32 slaveAddress, quint32 modbusRegister, const QVector &values) { auto modbus = sender(); - - if (m_modbusRTUMasters.values().contains(static_cast(modbus))) { - Thing *parent = m_modbusRTUMasters.key(static_cast(modbus)); - foreach (Thing *thing, myThings().filterByParentId(parent->id())) { - if (thing->thingClassId() == coilThingClassId) { - if ((thing->paramValue(m_slaveAddressParamTypeId.value(thing->thingClassId())) == slaveAddress) - && (thing->paramValue(m_registerAddressParamTypeId.value(thing->thingClassId())) == modbusRegister)) { - thing->setStateValue(m_valueStateTypeId.value(thing->thingClassId()), values[0]); - thing->setStateValue(m_connectedStateTypeId.value(thing->thingClassId()), true); - return; - } - } - } - } else if (m_modbusTCPMasters.values().contains(static_cast(modbus))) { + if (m_modbusTCPMasters.values().contains(static_cast(modbus))) { Thing *parent = m_modbusTCPMasters.key(static_cast(modbus)); foreach (Thing *thing, myThings().filterByParentId(parent->id())) { if (thing->thingClassId() == coilThingClassId) { @@ -471,19 +432,7 @@ void IntegrationPluginModbusCommander::onReceivedDiscreteInput(quint32 slaveAddr { auto modbus = sender(); - if (m_modbusRTUMasters.values().contains(static_cast(modbus))) { - Thing *parent = m_modbusRTUMasters.key(static_cast(modbus)); - foreach (Thing *thing, myThings().filterByParentId(parent->id())) { - if (thing->thingClassId() == discreteInputThingClassId) { - if ((thing->paramValue(m_slaveAddressParamTypeId.value(thing->thingClassId())) == slaveAddress) - && (thing->paramValue(m_registerAddressParamTypeId.value(thing->thingClassId())) == modbusRegister)) { - thing->setStateValue(m_valueStateTypeId.value(thing->thingClassId()), values[0]); - thing->setStateValue(m_connectedStateTypeId.value(thing->thingClassId()), true); - return; - } - } - } - } else if (m_modbusTCPMasters.values().contains(static_cast(modbus))) { + if (m_modbusTCPMasters.values().contains(static_cast(modbus))) { Thing *parent = m_modbusTCPMasters.key(static_cast(modbus)); foreach (Thing *thing, myThings().filterByParentId(parent->id())) { if (thing->thingClassId() == discreteInputThingClassId) { @@ -502,19 +451,7 @@ void IntegrationPluginModbusCommander::onReceivedHoldingRegister(uint slaveAddre { auto modbus = sender(); - if (m_modbusRTUMasters.values().contains(static_cast(modbus))) { - Thing *parent = m_modbusRTUMasters.key(static_cast(modbus)); - foreach (Thing *thing, myThings().filterByParentId(parent->id())) { - if (thing->thingClassId() == holdingRegisterThingClassId) { - if ((thing->paramValue(m_slaveAddressParamTypeId.value(thing->thingClassId())) == slaveAddress) - && (thing->paramValue(m_registerAddressParamTypeId.value(thing->thingClassId())) == modbusRegister)) { - thing->setStateValue(m_valueStateTypeId.value(thing->thingClassId()), values[0]); - thing->setStateValue(m_connectedStateTypeId.value(thing->thingClassId()), true); - return; - } - } - } - } else if (m_modbusTCPMasters.values().contains(static_cast(modbus))) { + if (m_modbusTCPMasters.values().contains(static_cast(modbus))) { Thing *parent = m_modbusTCPMasters.key(static_cast(modbus)); foreach (Thing *thing, myThings().filterByParentId(parent->id())) { if (thing->thingClassId() == holdingRegisterThingClassId) { @@ -533,19 +470,7 @@ void IntegrationPluginModbusCommander::onReceivedInputRegister(uint slaveAddress { auto modbus = sender(); - if (m_modbusRTUMasters.values().contains(static_cast(modbus))) { - Thing *parent = m_modbusRTUMasters.key(static_cast(modbus)); - foreach (Thing *thing, myThings().filterByParentId(parent->id())) { - if (thing->thingClassId() == inputRegisterThingClassId) { - if ((thing->paramValue(m_slaveAddressParamTypeId.value(thing->thingClassId())) == slaveAddress) - && (thing->paramValue(m_registerAddressParamTypeId.value(thing->thingClassId())) == modbusRegister)) { - thing->setStateValue(m_valueStateTypeId.value(thing->thingClassId()), values[0]); - thing->setStateValue(m_connectedStateTypeId.value(thing->thingClassId()), true); - return; - } - } - } - } else if (m_modbusTCPMasters.values().contains(static_cast(modbus))) { + if (m_modbusTCPMasters.values().contains(static_cast(modbus))) { Thing *parent = m_modbusTCPMasters.key(static_cast(modbus)); foreach (Thing *thing, myThings().filterByParentId(parent->id())) { if (thing->thingClassId() == inputRegisterThingClassId) { @@ -592,23 +517,76 @@ void IntegrationPluginModbusCommander::readRegister(Thing *thing) } } else if (parent->thingClassId() == modbusRTUClientThingClassId) { - ModbusRTUMaster *modbus = m_modbusRTUMasters.value(parent); - if (!modbus) + ModbusRtuMaster *modbusMaster = m_modbusRtuMasters.value(parent); + if (!modbusMaster) return; - if (!modbus->connected()) + if (!modbusMaster->connected()) return; // Send requests only if the modbus interface is connected if (thing->thingClassId() == coilThingClassId) { - requestId = modbus->readCoil(slaveAddress, registerAddress); + ModbusRtuReply *reply = modbusMaster->readCoil(slaveAddress, registerAddress); + connect(reply, &ModbusRtuReply::finished, modbusMaster, [=](){ + if (reply->error() != ModbusRtuReply::NoError) { + qCWarning(dcModbusCommander()) << "Failed to read coil from" << modbusMaster << "slave:" << slaveAddress << "register:" << registerAddress; + thing->setStateValue(m_connectedStateTypeId[thing->thingClassId()], false); + return; + } + + if (!reply->result().isEmpty()) { + thing->setStateValue(m_valueStateTypeId.value(thing->thingClassId()), reply->result().at(0)); + } + thing->setStateValue(m_connectedStateTypeId.value(thing->thingClassId()), true); + }); } else if (thing->thingClassId() == discreteInputThingClassId) { - requestId = modbus->readDiscreteInput(slaveAddress, registerAddress); + ModbusRtuReply *reply = modbusMaster->readDiscreteInput(slaveAddress, registerAddress); + connect(reply, &ModbusRtuReply::finished, modbusMaster, [=](){ + if (reply->error() != ModbusRtuReply::NoError) { + qCWarning(dcModbusCommander()) << "Failed to read discrete input from" << modbusMaster << "slave:" << slaveAddress << "register:" << registerAddress; + thing->setStateValue(m_connectedStateTypeId[thing->thingClassId()], false); + return; + } + + if (!reply->result().isEmpty()) { + thing->setStateValue(m_valueStateTypeId.value(thing->thingClassId()), reply->result().at(0)); + } + thing->setStateValue(m_connectedStateTypeId.value(thing->thingClassId()), true); + }); } else if (thing->thingClassId() == holdingRegisterThingClassId) { - requestId = modbus->readHoldingRegister(slaveAddress, registerAddress); + ModbusRtuReply *reply = modbusMaster->readHoldingRegister(slaveAddress, registerAddress); + connect(reply, &ModbusRtuReply::finished, modbusMaster, [=](){ + if (reply->error() != ModbusRtuReply::NoError) { + qCWarning(dcModbusCommander()) << "Failed to read holding register from" << modbusMaster << "slave:" << slaveAddress << "register:" << registerAddress; + thing->setStateValue(m_connectedStateTypeId[thing->thingClassId()], false); + return; + } + + if (!reply->result().isEmpty()) { + thing->setStateValue(m_valueStateTypeId.value(thing->thingClassId()), reply->result().at(0)); + } + thing->setStateValue(m_connectedStateTypeId.value(thing->thingClassId()), true); + }); } else if (thing->thingClassId() == inputRegisterThingClassId) { - requestId = modbus->readInputRegister(slaveAddress, registerAddress); + ModbusRtuReply *reply = modbusMaster->readInputRegister(slaveAddress, registerAddress); + connect(reply, &ModbusRtuReply::finished, modbusMaster, [=](){ + if (reply->error() != ModbusRtuReply::NoError) { + qCWarning(dcModbusCommander()) << "Failed to read input register from" << modbusMaster << "slave:" << slaveAddress << "register:" << registerAddress; + thing->setStateValue(m_connectedStateTypeId[thing->thingClassId()], false); + return; + } + + if (!reply->result().isEmpty()) { + thing->setStateValue(m_valueStateTypeId.value(thing->thingClassId()), reply->result().at(0)); + } + thing->setStateValue(m_connectedStateTypeId.value(thing->thingClassId()), true); + }); } + + // Note: we don't want proceed with the method here, since we are not + // working with the requestId any more on RTU + return; } + if (!requestId.isNull()) { m_readRequests.insert(requestId, thing); QTimer::singleShot(5000, this, [requestId, this] {m_readRequests.remove(requestId);}); @@ -623,8 +601,10 @@ void IntegrationPluginModbusCommander::writeRegister(Thing *thing, ThingActionIn Thing *parent = myThings().findById(thing->parentId()); if (!parent) { qCWarning(dcModbusCommander()) << "Could not find parent device" << thing->name(); + info->finish(Thing::ThingErrorHardwareNotAvailable); return; } + uint registerAddress = thing->paramValue(m_registerAddressParamTypeId.value(thing->thingClassId())).toUInt();; uint slaveAddress = thing->paramValue(m_slaveAddressParamTypeId.value(thing->thingClassId())).toUInt(); @@ -633,8 +613,11 @@ void IntegrationPluginModbusCommander::writeRegister(Thing *thing, ThingActionIn if (parent->thingClassId() == modbusTCPClientThingClassId) { ModbusTCPMaster *modbus = m_modbusTCPMasters.value(parent); - if (!modbus) + if (!modbus) { + qCWarning(dcModbusCommander()) << "Could not find modbus TCP master for" << thing; + info->finish(Thing::ThingErrorHardwareNotAvailable); return; + } if (thing->thingClassId() == coilThingClassId) { requestId = modbus->writeCoil(slaveAddress, registerAddress, action.param(coilValueActionValueParamTypeId).value().toBool()); @@ -643,15 +626,48 @@ void IntegrationPluginModbusCommander::writeRegister(Thing *thing, ThingActionIn } } else if (parent->thingClassId() == modbusRTUClientThingClassId) { - ModbusRTUMaster *modbus = m_modbusRTUMasters.value(parent); - if (!modbus) + ModbusRtuMaster *modbusMaster = m_modbusRtuMasters.value(parent); + if (!modbusMaster) { + qCWarning(dcModbusCommander()) << "Could not find modbus RTU master for" << thing; + info->finish(Thing::ThingErrorHardwareNotAvailable); return; + } if (thing->thingClassId() == coilThingClassId) { - requestId = modbus->writeCoil(slaveAddress, registerAddress, action.param(coilValueActionValueParamTypeId).value().toBool()); + QVector values; + values.append(static_cast(action.param(coilValueActionValueParamTypeId).value().toBool())); + + ModbusRtuReply *reply = modbusMaster->writeCoils(slaveAddress, registerAddress, values); + connect(info, &ThingActionInfo::aborted, reply, &ModbusRtuReply::deleteLater); + connect(reply, &ModbusRtuReply::finished, modbusMaster, [=](){ + if (reply->error() != ModbusRtuReply::NoError) { + qCWarning(dcModbusCommander()) << "Failed to write coils from" << modbusMaster << "slave:" << slaveAddress << "register:" << registerAddress << values << reply->errorString(); + info->finish(Thing::ThingErrorHardwareFailure); + return; + } + + info->finish(Thing::ThingErrorNoError); + }); } else if (thing->thingClassId() == holdingRegisterThingClassId) { - requestId = modbus->writeHoldingRegister(slaveAddress, registerAddress, action.param(holdingRegisterValueActionValueParamTypeId).value().toUInt()); + QVector values; + values.append(static_cast(action.param(holdingRegisterValueActionValueParamTypeId).value().toUInt())); + + ModbusRtuReply *reply = modbusMaster->writeHoldingRegisters(slaveAddress, registerAddress, values); + connect(info, &ThingActionInfo::aborted, reply, &ModbusRtuReply::deleteLater); + connect(reply, &ModbusRtuReply::finished, modbusMaster, [=](){ + if (reply->error() != ModbusRtuReply::NoError) { + qCWarning(dcModbusCommander()) << "Failed to write holding registers from" << modbusMaster << "slave:" << slaveAddress << "register:" << registerAddress << values << reply->errorString(); + info->finish(Thing::ThingErrorHardwareFailure); + return; + } + + info->finish(Thing::ThingErrorNoError); + }); } + + // Note: we don't want proceed with the method here, since we are not + // working with the requestId any more on RTU + return; } if (requestId.toString().isNull()){ diff --git a/modbuscommander/integrationpluginmodbuscommander.h b/modbuscommander/integrationpluginmodbuscommander.h index 4c7b5c0..54f6906 100644 --- a/modbuscommander/integrationpluginmodbuscommander.h +++ b/modbuscommander/integrationpluginmodbuscommander.h @@ -31,11 +31,11 @@ #ifndef INTEGRATIONPLUGINMODBUSCOMMANDER_H #define INTEGRATIONPLUGINMODBUSCOMMANDER_H -#include "integrations/integrationplugin.h" #include "plugintimer.h" +#include "integrations/integrationplugin.h" +#include "hardware/modbus/modbusrtumaster.h" #include "../modbus/modbustcpmaster.h" -#include "../modbus/modbusrtumaster.h" #include #include @@ -60,8 +60,9 @@ public: private: PluginTimer *m_refreshTimer = nullptr; - QHash m_modbusRTUMasters; + //QHash m_modbusRTUMasters; QHash m_modbusTCPMasters; + QHash m_modbusRtuMasters; QHash m_asyncActions; QHash m_readRequests; diff --git a/modbuscommander/integrationpluginmodbuscommander.json b/modbuscommander/integrationpluginmodbuscommander.json index 15bfd37..14f3162 100644 --- a/modbuscommander/integrationpluginmodbuscommander.json +++ b/modbuscommander/integrationpluginmodbuscommander.json @@ -72,74 +72,15 @@ "id": "776df314-6186-4eb5-b824-f0d916f6d9c3", "name": "modbusRTUClient", "displayName": "Modbus RTU client", - "createMethods": ["discovery", "user"], + "createMethods": ["discovery"], "interfaces": ["connectable"], - "settingsTypes": [ - { - "id": "b0af32f0-b8cc-4642-af5a-576732522b2c", - "name": "timeout", - "displayName": "Timeout", - "type": "uint", - "minValue": 10, - "defaultValue": 100 - }, - { - "id": "c4f16d6c-c1f2-4862-b0bd-6fae7193eaa8", - "name": "numberOfRetries", - "displayName": "Number of retries", - "type": "uint", - "defaultValue": 3 - } - ], "paramTypes": [ { "id": "ed49f7d8-ab18-4c37-9b80-1004b75dcb91", - "name": "serialPort", - "displayName": "Serial port", - "type": "QString", - "inputType": "TextLine", - "defaultValue": "ttyAMA0" - }, - { - "id": "9908b01f-a76b-4b21-8242-b507c9252254", - "name": "serialnumber", - "displayName": "Serial number", - "type": "QString", + "name": "modbusMasterUuid", + "displayName": "Modbus RTU master", + "type": "QUuid", "defaultValue": "" - }, - { - "id": "45dfc828-f238-4263-89a3-9b35cf5dea39", - "name": "baudRate", - "displayName": "Baud rate", - "type": "uint", - "defaultValue": 9600 - }, - { - "id": "a27c664b-9f43-4573-a2cc-f65a8fa1a069", - "name": "dataBits", - "displayName": "Data bits", - "type": "uint", - "defaultValue": 8 - }, - { - "id": "4ea8bcdf-d4c5-45a4-a54f-f10ac3f08a78", - "name": "stopBits", - "displayName": "Stop bits", - "type": "uint", - "defaultValue": 1 - }, - { - "id": "72de1b08-2a27-49c5-90e0-8788c3ea1da3", - "name": "parity", - "displayName": "Parity", - "type": "QString", - "inputType": "TextLine", - "allowedValues": [ - "No Parity", - "Even Parity", - "Odd Parity" - ], - "defaultValue": "No Parity" } ], "stateTypes": [ diff --git a/modbuscommander/modbuscommander.pro b/modbuscommander/modbuscommander.pro index 9c7a28e..ab4dfc1 100644 --- a/modbuscommander/modbuscommander.pro +++ b/modbuscommander/modbuscommander.pro @@ -7,11 +7,9 @@ QT += \ SOURCES += \ integrationpluginmodbuscommander.cpp \ - ../modbus/modbustcpmaster.cpp \ - ../modbus/modbusrtumaster.cpp \ + ../modbus/modbustcpmaster.cpp HEADERS += \ integrationpluginmodbuscommander.h \ - ../modbus/modbustcpmaster.h \ - ../modbus/modbusrtumaster.h \ + ../modbus/modbustcpmaster.h