From 571af9c85a6707e111ee4ee85cee80824cd24888 Mon Sep 17 00:00:00 2001 From: Boernsman Date: Thu, 4 Feb 2021 22:20:38 +0100 Subject: [PATCH] refactored neuron code --- unipi/integrationpluginunipi.cpp | 3 +- unipi/neuron.cpp | 191 ++++++++++--------------------- unipi/neuron.h | 47 +------- unipi/neuroncommon.cpp | 111 ++++++++++++++++++ unipi/neuroncommon.h | 106 +++++++++++++++++ unipi/neuronextension.cpp | 168 +++++++++++---------------- unipi/neuronextension.h | 44 +------ unipi/unipi.pro | 2 + 8 files changed, 359 insertions(+), 313 deletions(-) create mode 100644 unipi/neuroncommon.cpp create mode 100644 unipi/neuroncommon.h diff --git a/unipi/integrationpluginunipi.cpp b/unipi/integrationpluginunipi.cpp index dbe2ba4..45a1e69 100644 --- a/unipi/integrationpluginunipi.cpp +++ b/unipi/integrationpluginunipi.cpp @@ -893,10 +893,9 @@ void IntegrationPluginUniPi::onNeuronExtensionConnectionStateChanged(bool state) void IntegrationPluginUniPi::onRequestExecuted(const QUuid &requestId, bool success) { - qCDebug(dcUniPi()) << "Request executed, pending requests:" << m_asyncActions.size(); - if (m_asyncActions.contains(requestId)){ ThingActionInfo *info = m_asyncActions.take(requestId); + qCDebug(dcUniPi()) << "Request executed, pending requests:" << m_asyncActions.count(); if (success){ info->finish(Thing::ThingErrorNoError); } else { diff --git a/unipi/neuron.cpp b/unipi/neuron.cpp index 0e60f82..65bdfb1 100644 --- a/unipi/neuron.cpp +++ b/unipi/neuron.cpp @@ -36,43 +36,11 @@ #include Neuron::Neuron(NeuronTypes neuronType, QModbusTcpClient *modbusInterface, QObject *parent) : - QObject(parent), + NeuronCommon(parent), m_modbusInterface(modbusInterface), m_neuronType(neuronType) { qCDebug(dcUniPi()) << "Neuron: Creating Neuron connection" << neuronType; - m_inputPollingTimer = new QTimer(this); - connect(m_inputPollingTimer, &QTimer::timeout, this, &Neuron::onInputPollingTimer); - m_inputPollingTimer->setTimerType(Qt::TimerType::PreciseTimer); - m_inputPollingTimer->setInterval(200); - - m_outputPollingTimer = new QTimer(this); - connect(m_outputPollingTimer, &QTimer::timeout, this, &Neuron::onOutputPollingTimer); - m_outputPollingTimer->setTimerType(Qt::TimerType::PreciseTimer); - m_outputPollingTimer->setInterval(1000); - - if (m_modbusInterface->state() == QModbusDevice::State::ConnectedState) { - m_inputPollingTimer->start(); - m_outputPollingTimer->start(); - } - - connect(m_modbusInterface, &QModbusDevice::stateChanged, this, [this] (QModbusDevice::State state) { - if (state == QModbusDevice::State::ConnectedState) { - qCDebug(dcUniPi()) << "Neuron: Starting polling timer"; - if (m_inputPollingTimer) - m_inputPollingTimer->start(); - if (m_outputPollingTimer) - m_outputPollingTimer->start(); - emit connectionStateChanged(true); - } else { - qCDebug(dcUniPi()) << "Neuron: Stopping polling timer"; - if (m_inputPollingTimer) - m_inputPollingTimer->stop(); - if (m_outputPollingTimer) - m_outputPollingTimer->stop(); - emit connectionStateChanged(false); - } - }); } Neuron::~Neuron() @@ -134,31 +102,6 @@ QString Neuron::type() return "Unknown"; } -QList Neuron::digitalInputs() -{ - return m_modbusDigitalInputRegisters.keys(); -} - -QList Neuron::digitalOutputs() -{ - return m_modbusDigitalOutputRegisters.keys(); -} - -QList Neuron::analogInputs() -{ - return m_modbusAnalogInputRegisters.keys(); -} - -QList Neuron::analogOutputs() -{ - return m_modbusAnalogOutputRegisters.keys(); -} - -QList Neuron::userLEDs() -{ - return m_modbusUserLEDRegisters.keys(); -} - bool Neuron::loadModbusMap() { @@ -354,13 +297,13 @@ bool Neuron::loadModbusMap() return false; } if (list.last() == "Basic") { - QString circuit = list[5].split(" ").last(); + int modbusAddress = list[0].toInt(); if (list[5].contains("Analog Input Value", Qt::CaseSensitivity::CaseInsensitive)) { - m_modbusAnalogInputRegisters.insert(circuit, list[0].toInt()); - qDebug(dcUniPi()) << "Neuron: Found analog input register" << circuit << list[0].toInt(); + m_modbusAnalogInputRegisters.insert(modbusAddress, registerDescriptorFromStringList(list)); + qDebug(dcUniPi()) << "Neuron: Found analog input register" << modbusAddress; } else if (list[5].contains("Analog Output Value", Qt::CaseSensitivity::CaseInsensitive)) { - m_modbusAnalogOutputRegisters.insert(circuit, list[0].toInt()); - qDebug(dcUniPi()) << "Neuron: Found analog output register" << circuit << list[0].toInt(); + m_modbusAnalogOutputRegisters.insert(modbusAddress, registerDescriptorFromStringList(list)); + qDebug(dcUniPi()) << "Neuron: Found analog output register" << modbusAddress; } } } @@ -392,8 +335,8 @@ bool Neuron::modbusWriteRequest(const Request &request) if(m_modbusDigitalOutputRegisters.values().contains(modbusAddress)){ QString circuit = m_modbusDigitalOutputRegisters.key(modbusAddress); emit digitalOutputStatusChanged(circuit, unit.value(0)); - } else if(m_modbusAnalogOutputRegisters.values().contains(modbusAddress)){ - QString circuit = m_modbusAnalogOutputRegisters.key(modbusAddress); + } else if(m_modbusAnalogOutputRegisters.contains(modbusAddress)){ + QString circuit = m_modbusAnalogOutputRegisters.value(modbusAddress).circuit; emit analogOutputStatusChanged(circuit, unit.value(0)); } else if(m_modbusUserLEDRegisters.values().contains(modbusAddress)){ QString circuit = m_modbusUserLEDRegisters.key(modbusAddress); @@ -458,8 +401,8 @@ bool Neuron::modbusReadRequest(const QModbusDataUnit &request) break; case QModbusDataUnit::RegisterType::HoldingRegisters: - if(m_modbusAnalogOutputRegisters.values().contains(modbusAddress)){ - circuit = m_modbusAnalogOutputRegisters.key(modbusAddress); + if(m_modbusAnalogOutputRegisters.keys().contains(modbusAddress)){ + circuit = m_modbusAnalogOutputRegisters.value(modbusAddress).circuit; if (circuitValueChanged(circuit, unit.value(i))) emit analogOutputStatusChanged(circuit, unit.value(i)); } else { @@ -467,8 +410,8 @@ bool Neuron::modbusReadRequest(const QModbusDataUnit &request) } break; case QModbusDataUnit::RegisterType::InputRegisters: - if(m_modbusAnalogInputRegisters.values().contains(modbusAddress)){ - circuit = m_modbusAnalogInputRegisters.key(modbusAddress); + if(m_modbusAnalogInputRegisters.keys().contains(modbusAddress)){ + circuit = m_modbusAnalogInputRegisters.value(modbusAddress).circuit; quint32 value = (unit.value(i) << 16 | unit.value(i+1)); if (circuitValueChanged(circuit, value)) emit analogInputStatusChanged(circuit, value); @@ -617,23 +560,20 @@ bool Neuron::getCoils(QList registerList) return true; } -bool Neuron::circuitValueChanged(const QString &circuit, quint32 value) +bool Neuron::getAnalogIO(const RegisterDescriptor &descriptor) { - if (m_previousCircuitValue.contains(circuit)) { - if (m_previousCircuitValue.value(circuit) == value) { - // Only emit status change of the circuit value has changed - return false; - } else { - m_previousCircuitValue.insert(circuit, value); //update existing value - return true; - } + QModbusDataUnit request = QModbusDataUnit(descriptor.registerType, descriptor.address, descriptor.count); + if (m_readRequestQueue.isEmpty()) { + return modbusReadRequest(request); + } else if (m_readRequestQueue.length() > 100) { + qCWarning(dcUniPi()) << "Neuron: Too many pending read requests"; + return false; } else { - m_previousCircuitValue.insert(circuit, value); - return true; + m_readRequestQueue.append(request); } + return true; } - bool Neuron::getAllDigitalInputs() { if (!m_modbusInterface) { @@ -658,8 +598,8 @@ bool Neuron::getAllAnalogInputs() qCWarning(dcUniPi()) << "Neuron: Modbus interface not initialized"; return false; } - foreach(QString circuit, m_modbusAnalogInputRegisters.keys()) { - getAnalogInput(circuit); + Q_FOREACH(RegisterDescriptor descriptor, m_modbusAnalogInputRegisters.values()) { + getAnalogIO(descriptor); } return true; } @@ -670,8 +610,8 @@ bool Neuron::getAllAnalogOutputs() qCWarning(dcUniPi()) << "Neuron: Modbus interface not initialized"; return false; } - foreach(QString circuit, m_modbusAnalogOutputRegisters.keys()) { - getAnalogOutput(circuit); + Q_FOREACH(RegisterDescriptor descriptor, m_modbusAnalogOutputRegisters.values()) { + getAnalogIO(descriptor); } return true; } @@ -698,22 +638,13 @@ bool Neuron::getDigitalInput(const QString &circuit) bool Neuron::getAnalogOutput(const QString &circuit) { - int modbusAddress = m_modbusAnalogOutputRegisters.value(circuit); - //qDebug(dcUniPi()) << "Neuron: Reading analog output" << circuit << modbusAddress; - - if (!m_modbusInterface) - return false; - - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, modbusAddress, 1); - if (m_readRequestQueue.isEmpty()) { - return modbusReadRequest(request); - } else if (m_readRequestQueue.length() > 100) { - qCWarning(dcUniPi()) << "Neuron: Too many pending read requests"; - return false; - } else { - m_readRequestQueue.append(request); + //qDebug(dcUniPi()) << "Neuron: Get analog output" << circuit; + Q_FOREACH(RegisterDescriptor descriptor, m_modbusAnalogOutputRegisters.values()) { + if (descriptor.circuit == circuit) { + return getAnalogIO(descriptor); + } } - return true; + return false; } @@ -761,48 +692,46 @@ bool Neuron::getDigitalOutput(const QString &circuit) QUuid Neuron::setAnalogOutput(const QString &circuit, double value) { - int modbusAddress = m_modbusAnalogOutputRegisters.value(circuit); - qDebug(dcUniPi()) << "Neuron: Writing analog Output" << circuit << modbusAddress; - + qDebug(dcUniPi()) << "Neuron: Set analog output" << circuit << value; if (!m_modbusInterface) return ""; - Request request; - request.id = QUuid::createUuid(); - request.data = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, modbusAddress, 2); - request.data.setValue(0, (static_cast(value) >> 16)); //FIXME - request.data.setValue(0, (static_cast(value) & 0xffff)); //FIXME + Q_FOREACH(RegisterDescriptor descriptor, m_modbusAnalogOutputRegisters) { + if (descriptor.circuit == circuit) { + Request request; + request.id = QUuid::createUuid(); + request.data = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, descriptor.address, descriptor.count); + if (descriptor.count == 1) { + request.data.setValue(0, (static_cast(value*400))); // 0 to 4000 = 0 to 10.0 V + } else if (descriptor.count == 2) { + request.data.setValue(0, (static_cast(value) >> 16)); + request.data.setValue(1, (static_cast(value) & 0xffff)); + } - if (m_writeRequestQueue.isEmpty()) { - modbusWriteRequest(request); - } else if (m_writeRequestQueue.length() > 100) { - return ""; - } else { - m_writeRequestQueue.append(request); + if (m_writeRequestQueue.isEmpty()) { + modbusWriteRequest(request); + } else if (m_writeRequestQueue.length() > 100) { + return ""; + } else { + m_writeRequestQueue.append(request); + } + return request.id; + } } - - return request.id; + return ""; } bool Neuron::getAnalogInput(const QString &circuit) { - int modbusAddress = m_modbusAnalogInputRegisters.value(circuit); - //qDebug(dcUniPi()) << "Neuron: Reading analog Input" << circuit << modbusAddress; + //qDebug(dcUniPi()) << "Neuron: Get analog input" << circuit; - if (!m_modbusInterface) - return false; - - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, modbusAddress, 2); - if (m_readRequestQueue.isEmpty()) { - return modbusReadRequest(request); - } else if (m_readRequestQueue.length() > 100) { - qCWarning(dcUniPi()) << "Neuron: Too many pending read requests"; - return false; - } else { - m_readRequestQueue.append(request); + Q_FOREACH(RegisterDescriptor descriptor, m_modbusAnalogOutputRegisters.values()) { + if (descriptor.circuit == circuit) { + return getAnalogIO(descriptor); + } } - return true; + return false; } QUuid Neuron::setUserLED(const QString &circuit, bool value) @@ -834,7 +763,7 @@ QUuid Neuron::setUserLED(const QString &circuit, bool value) bool Neuron::getUserLED(const QString &circuit) { int modbusAddress = m_modbusUserLEDRegisters.value(circuit); - //qDebug(dcUniPi()) << "Neuron: Reading digital Output" << circuit << modbusAddress; + //qDebug(dcUniPi()) << "Neuron: Get user LED" << circuit << modbusAddress; if (!m_modbusInterface) return false; diff --git a/unipi/neuron.h b/unipi/neuron.h index 267ea38..490d24a 100644 --- a/unipi/neuron.h +++ b/unipi/neuron.h @@ -31,22 +31,19 @@ #ifndef NEURON_H #define NEURON_H +#include "neuroncommon.h" + #include #include #include -#include #include -class Neuron : public QObject + +class Neuron : public NeuronCommon { Q_OBJECT public: - struct Request { - QUuid id; - QModbusDataUnit data; - }; - enum NeuronTypes { S103, M103, @@ -71,12 +68,6 @@ public: bool init(); QString type(); - QList digitalInputs(); - QList digitalOutputs(); - QList analogInputs(); - QList analogOutputs(); - QList userLEDs(); - QUuid setDigitalOutput(const QString &circuit, bool value); QUuid setAnalogOutput(const QString &circuit, double value); QUuid setUserLED(const QString &circuit, bool value); @@ -93,27 +84,11 @@ public: bool getAllAnalogOutputs(); bool getUserLED(const QString &circuit); + private: - int m_slaveAddress = 0; - uint m_responseTimeoutTime = 2000; - - QTimer *m_inputPollingTimer = nullptr; - QTimer *m_outputPollingTimer = nullptr; - QModbusTcpClient *m_modbusInterface = nullptr; - - QHash m_modbusDigitalOutputRegisters; - QHash m_modbusDigitalInputRegisters; - QHash m_modbusAnalogInputRegisters; - QHash m_modbusAnalogOutputRegisters; - QHash m_modbusUserLEDRegisters; - QList m_writeRequestQueue; - QList m_readRequestQueue; - NeuronTypes m_neuronType = NeuronTypes::S103; - QHash m_previousCircuitValue; - bool loadModbusMap(); bool modbusReadRequest(const QModbusDataUnit &request); bool modbusWriteRequest(const Request &request); @@ -122,17 +97,7 @@ private: bool getHoldingRegisters(QList registers); bool getCoils(QList registers); - bool circuitValueChanged(const QString &circuit, quint32 value); - -signals: - void requestExecuted(const QUuid &requestId, bool success); - void requestError(const QUuid &requestId, const QString &error); - void digitalInputStatusChanged(const QString &circuit, bool value); - void digitalOutputStatusChanged(const QString &circuit, bool value); - void analogInputStatusChanged(const QString &circuit, double value); - void analogOutputStatusChanged(const QString &circuit, double value); - void userLEDStatusChanged(const QString &circuit, bool value); - void connectionStateChanged(bool state); + bool getAnalogIO(const RegisterDescriptor &descriptor); public slots: void onOutputPollingTimer(); diff --git a/unipi/neuroncommon.cpp b/unipi/neuroncommon.cpp new file mode 100644 index 0000000..a33ef8e --- /dev/null +++ b/unipi/neuroncommon.cpp @@ -0,0 +1,111 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is distributed in the hope that +* it will be useful, but WITHOUT ANY WARRANTY; without even the implied +* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "neuroncommon.h" + +NeuronCommon::NeuronCommon(QObject *parent) : QObject(parent) +{ + +} + +QList NeuronCommon::digitalInputs() +{ + return m_modbusDigitalInputRegisters.keys(); +} + +QList NeuronCommon::digitalOutputs() +{ + return m_modbusDigitalOutputRegisters.keys(); +} + +QList NeuronCommon::analogInputs() +{ + QList circuits; + Q_FOREACH(RegisterDescriptor descriptor, m_modbusAnalogInputRegisters.values()) { + circuits.append(descriptor.circuit); + } + return circuits; +} + +QList NeuronCommon::analogOutputs() +{ + QList circuits; + Q_FOREACH(RegisterDescriptor descriptor, m_modbusAnalogOutputRegisters.values()) { + circuits.append(descriptor.circuit); + } + return circuits; +} + +QList NeuronCommon::userLEDs() +{ + return m_modbusUserLEDRegisters.keys(); +} + +NeuronCommon::RegisterDescriptor NeuronCommon::registerDescriptorFromStringList(const QStringList &data) +{ + RegisterDescriptor descriptor; + if (data.count() < 7) { + return descriptor; + } + descriptor.address = data[0].toInt(); + descriptor.count = data[2].toInt(); + if (data[3] == "RW") { + descriptor.readWrite = RWPermissionReadWrite; + } else if (data[3] == "W") { + descriptor.readWrite = RWPermissionWrite; + } else if (data[3] == "R") { + descriptor.readWrite = RWPermissionRead; + } + descriptor.circuit = data[5].split(" ").last(); + descriptor.category = data.last(); + + if (data[5].contains("Analog Input Value", Qt::CaseSensitivity::CaseInsensitive)) { + descriptor.registerType = QModbusDataUnit::RegisterType::InputRegisters; + } else if (data[5].contains("Analog Output Value", Qt::CaseSensitivity::CaseInsensitive)) { + descriptor.registerType = QModbusDataUnit::RegisterType::HoldingRegisters; + } + return descriptor; +} + +bool NeuronCommon::circuitValueChanged(const QString &circuit, quint32 value) +{ + if (m_previousCircuitValue.contains(circuit)) { + if (m_previousCircuitValue.value(circuit) == value) { + // Only emit status change of the circuit value has changed + return false; + } else { + m_previousCircuitValue.insert(circuit, value); //update existing value + return true; + } + } else { + m_previousCircuitValue.insert(circuit, value); + return true; + } +} diff --git a/unipi/neuroncommon.h b/unipi/neuroncommon.h new file mode 100644 index 0000000..32f1317 --- /dev/null +++ b/unipi/neuroncommon.h @@ -0,0 +1,106 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is distributed in the hope that +* it will be useful, but WITHOUT ANY WARRANTY; without even the implied +* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef NEURONCOMMON_H +#define NEURONCOMMON_H + +#include +#include + +class NeuronCommon : public QObject +{ + Q_OBJECT +public: + explicit NeuronCommon(QObject *parent = nullptr); + + QList digitalInputs(); + QList digitalOutputs(); + QList analogInputs(); + QList analogOutputs(); + QList userLEDs(); + +protected: + enum RWPermission { + RWPermissionNone, + RWPermissionRead, + RWPermissionReadWrite, + RWPermissionWrite + }; + + struct RegisterDescriptor { + int address; + uint count; + QString circuit; + RWPermission readWrite; + QString category; + QModbusDataUnit::RegisterType registerType; + }; + + struct Request { + QUuid id; + QModbusDataUnit data; + }; + + int m_slaveAddress = 0; + uint m_responseTimeoutTime = 2000; + + QTimer *m_inputPollingTimer = nullptr; + QTimer *m_outputPollingTimer = nullptr; + + QList m_writeRequestQueue; + QList m_readRequestQueue; + + QHash m_modbusDigitalOutputRegisters; + QHash m_modbusDigitalInputRegisters; + QHash m_modbusUserLEDRegisters; + QHash m_modbusAnalogInputRegisters; + QHash m_modbusAnalogOutputRegisters; + + QHash m_previousCircuitValue; + + RegisterDescriptor registerDescriptorFromStringList(const QStringList &data); + bool circuitValueChanged(const QString &circuit, quint32 value); + +signals: + void requestExecuted(const QUuid &requestId, bool success); + void requestError(const QUuid &requestId, const QString &error); + void digitalInputStatusChanged(const QString &circuit, bool value); + void digitalOutputStatusChanged(const QString &circuit, bool value); + + void analogInputStatusChanged(const QString &circuit, double value); + void analogOutputStatusChanged(const QString &circuit, double value); + + void userLEDStatusChanged(const QString &circuit, bool value); + + void connectionStateChanged(bool state); + +}; + +#endif // NEURONCOMMON_H diff --git a/unipi/neuronextension.cpp b/unipi/neuronextension.cpp index b493799..3291c4a 100644 --- a/unipi/neuronextension.cpp +++ b/unipi/neuronextension.cpp @@ -37,7 +37,7 @@ #include NeuronExtension::NeuronExtension(ExtensionTypes extensionType, QModbusRtuSerialMaster *modbusInterface, int slaveAddress, QObject *parent) : - QObject(parent), + NeuronCommon(parent), m_modbusInterface(modbusInterface), m_slaveAddress(slaveAddress), m_extensionType(extensionType) @@ -132,31 +132,6 @@ void NeuronExtension::setSlaveAddress(int slaveAddress) m_slaveAddress = slaveAddress; } -QList NeuronExtension::digitalInputs() -{ - return m_modbusDigitalInputRegisters.keys(); -} - -QList NeuronExtension::digitalOutputs() -{ - return m_modbusDigitalOutputRegisters.keys(); -} - -QList NeuronExtension::analogInputs() -{ - return m_modbusAnalogInputRegisters.keys(); -} - -QList NeuronExtension::analogOutputs() -{ - return m_modbusAnalogOutputRegisters.keys(); -} - -QList NeuronExtension::userLEDs() -{ - return m_modbusUserLEDRegisters.keys(); -} - bool NeuronExtension::loadModbusMap() { qCDebug(dcUniPi()) << "Neuron Extension: Load modbus map"; @@ -275,13 +250,13 @@ bool NeuronExtension::loadModbusMap() csvFile->deleteLater(); return false; } - QString circuit = list[5].split(" ").at(3); + int modbusAddress = list[0].toInt(); if (list[5].contains("Analog Input Value", Qt::CaseSensitivity::CaseInsensitive)) { - m_modbusAnalogInputRegisters.insert(circuit, list[0].toInt()); - qDebug(dcUniPi()) << "Neuron Extension: Found analog input register" << circuit << list[0].toInt(); + m_modbusAnalogInputRegisters.insert(modbusAddress, registerDescriptorFromStringList(list)); + qDebug(dcUniPi()) << "Neuron Extension: Found analog input register" << modbusAddress; } else if (list[5].contains("Analog Output Value", Qt::CaseSensitivity::CaseInsensitive)) { - m_modbusAnalogOutputRegisters.insert(circuit, list[0].toInt()); - qDebug(dcUniPi()) << "Neuron Extension: Found analog output register" << circuit << list[0].toInt(); + m_modbusAnalogOutputRegisters.insert(modbusAddress, registerDescriptorFromStringList(list)); + qDebug(dcUniPi()) << "Neuron Extension: Found analog output register" << modbusAddress; } } } @@ -330,28 +305,28 @@ bool NeuronExtension::modbusReadRequest(const QModbusDataUnit &request) if (circuitValueChanged(circuit, unit.value(i))) emit userLEDStatusChanged(circuit, unit.value(i)); } else { - qCWarning(dcUniPi()) << "Neuron Extension: Received unrecorgnised coil register" << modbusAddress; + qCWarning(dcUniPi()) << "Neuron Extension: Received unrecognised coil register" << modbusAddress; } break; case QModbusDataUnit::RegisterType::InputRegisters: - if(m_modbusAnalogInputRegisters.values().contains(modbusAddress)){ - circuit = m_modbusAnalogInputRegisters.key(modbusAddress); + if(m_modbusAnalogInputRegisters.contains(modbusAddress)){ + circuit = m_modbusAnalogInputRegisters.value(modbusAddress).circuit; quint32 value = ((unit.value(i) << 16) | unit.value(i+1)); if (circuitValueChanged(circuit, value)) emit analogInputStatusChanged(circuit, value); i++; } else { - qCWarning(dcUniPi()) << "Neuron Extension: Received unrecorgnised input register" << modbusAddress; + qCWarning(dcUniPi()) << "Neuron Extension: Received unrecognised input register" << modbusAddress; } break; case QModbusDataUnit::RegisterType::HoldingRegisters: - if(m_modbusAnalogOutputRegisters.values().contains(modbusAddress)){ - circuit = m_modbusAnalogOutputRegisters.key(modbusAddress); + if(m_modbusAnalogOutputRegisters.contains(modbusAddress)){ + circuit = m_modbusAnalogOutputRegisters.value(modbusAddress).circuit; if (circuitValueChanged(circuit, unit.value(i))) emit analogOutputStatusChanged(circuit, unit.value(i)); } else { - qCWarning(dcUniPi()) << "Neuron Extension: Received unrecorgnised holding register" << modbusAddress; + qCWarning(dcUniPi()) << "Neuron Extension: Received unrecognised holding register" << modbusAddress; } break; case QModbusDataUnit::RegisterType::DiscreteInputs: @@ -401,8 +376,8 @@ bool NeuronExtension::modbusWriteRequest(const Request &request) if(m_modbusDigitalOutputRegisters.values().contains(modbusAddress)){ QString circuit = m_modbusDigitalOutputRegisters.key(modbusAddress); emit digitalOutputStatusChanged(circuit, unit.value(0)); - } else if(m_modbusAnalogOutputRegisters.values().contains(modbusAddress)){ - QString circuit = m_modbusAnalogOutputRegisters.key(modbusAddress); + } else if(m_modbusAnalogOutputRegisters.contains(modbusAddress)){ + QString circuit = m_modbusAnalogOutputRegisters.value(modbusAddress).circuit; emit analogOutputStatusChanged(circuit, unit.value(0)); } else if(m_modbusUserLEDRegisters.values().contains(modbusAddress)){ QString circuit = m_modbusUserLEDRegisters.key(modbusAddress); @@ -426,20 +401,18 @@ bool NeuronExtension::modbusWriteRequest(const Request &request) return true; } -bool NeuronExtension::circuitValueChanged(const QString &circuit, quint32 value) +bool NeuronExtension::getAnalogIO(const RegisterDescriptor &descriptor) { - if (m_previousCircuitValue.contains(circuit)) { - if (m_previousCircuitValue.value(circuit) == value) { - // Only emit status change of the circuit value has changed - return false; - } else { - m_previousCircuitValue.insert(circuit, value); //update existing value - return true; - } + QModbusDataUnit request = QModbusDataUnit(descriptor.registerType, descriptor.address, descriptor.count); + if (m_readRequestQueue.isEmpty()) { + return modbusReadRequest(request); + } else if (m_readRequestQueue.length() > 100) { + qCWarning(dcUniPi()) << "Neuron: Too many pending read requests"; + return false; } else { - m_previousCircuitValue.insert(circuit, value); - return true; + m_readRequestQueue.append(request); } + return true; } bool NeuronExtension::getDigitalInput(const QString &circuit) @@ -556,22 +529,24 @@ bool NeuronExtension::getAllDigitalInputs() bool NeuronExtension::getAllAnalogOutputs() { - if (!m_modbusInterface) + if (!m_modbusInterface) { + qCWarning(dcUniPi()) << "Neuron: Modbus interface not initialized"; return false; - - foreach (QString circuit, m_modbusAnalogOutputRegisters.keys()) { - getAnalogOutput(circuit); + } + Q_FOREACH(RegisterDescriptor descriptor, m_modbusAnalogOutputRegisters.values()) { + getAnalogIO(descriptor); } return true; } bool NeuronExtension::getAllAnalogInputs() { - if (!m_modbusInterface) + if (!m_modbusInterface) { + qCWarning(dcUniPi()) << "Neuron: Modbus interface not initialized"; return false; - - foreach (QString circuit, m_modbusAnalogInputRegisters.keys()) { - getAnalogInput(circuit); + } + Q_FOREACH(RegisterDescriptor descriptor, m_modbusAnalogInputRegisters.values()) { + getAnalogIO(descriptor); } return true; } @@ -624,64 +599,57 @@ bool NeuronExtension::getAllDigitalOutputs() QUuid NeuronExtension::setAnalogOutput(const QString &circuit, double value) { - int modbusAddress = m_modbusAnalogOutputRegisters.value(circuit); + qDebug(dcUniPi()) << "Neuron Extension: Set analog output" << circuit << value; if (!m_modbusInterface) return ""; - Request request; - request.id = QUuid::createUuid(); - request.data = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, modbusAddress, 1); - request.data.setValue(0, static_cast(value)); + Q_FOREACH(RegisterDescriptor descriptor, m_modbusAnalogOutputRegisters) { + if (descriptor.circuit == circuit) { + Request request; + request.id = QUuid::createUuid(); + request.data = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, descriptor.address, descriptor.count); + if (descriptor.count == 1) { + request.data.setValue(0, (static_cast(value*400))); // 0 to 4000 = 0 to 10.0 V + } else if (descriptor.count == 2) { + request.data.setValue(0, (static_cast(value) >> 16)); + request.data.setValue(1, (static_cast(value) & 0xffff)); + } - if (m_writeRequestQueue.isEmpty()) { - modbusWriteRequest(request); - } else if (m_writeRequestQueue.length() > 100) { - return ""; - } else { - m_writeRequestQueue.append(request); + if (m_writeRequestQueue.isEmpty()) { + modbusWriteRequest(request); + } else if (m_writeRequestQueue.length() > 100) { + return ""; + } else { + m_writeRequestQueue.append(request); + } + return request.id; + } } - - return request.id; + return ""; } bool NeuronExtension::getAnalogOutput(const QString &circuit) { - int modbusAddress = m_modbusAnalogOutputRegisters.value(circuit); - - if (!m_modbusInterface) - return false; - - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, modbusAddress, 1); - if (m_readRequestQueue.isEmpty()) { - return modbusReadRequest(request); - } else if (m_readRequestQueue.length() > 100) { - qCWarning(dcUniPi()) << "Neuron extension: Too many pending read requests"; - return false; - } else { - m_readRequestQueue.append(request); + //qDebug(dcUniPi()) << "Neuron Extension: Get analog output" << circuit; + Q_FOREACH(RegisterDescriptor descriptor, m_modbusAnalogOutputRegisters.values()) { + if (descriptor.circuit == circuit) { + return getAnalogIO(descriptor); + } } - return true; + return false; } bool NeuronExtension::getAnalogInput(const QString &circuit) { - int modbusAddress = m_modbusAnalogInputRegisters.value(circuit); - - if (!m_modbusInterface) - return false; - - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, modbusAddress, 2); - if (m_readRequestQueue.isEmpty()) { - return modbusReadRequest(request); - } else if (m_readRequestQueue.length() > 100) { - qCWarning(dcUniPi()) << "Neuron extension: Too many pending read requests"; - return false; - } else { - m_readRequestQueue.append(request); + //qDebug(dcUniPi()) << "Neuron Extension: Get analog input" << circuit; + Q_FOREACH(RegisterDescriptor descriptor, m_modbusAnalogInputRegisters.values()) { + if (descriptor.circuit == circuit) { + return getAnalogIO(descriptor); + } } - return true; + return false; } QUuid NeuronExtension::setUserLED(const QString &circuit, bool value) diff --git a/unipi/neuronextension.h b/unipi/neuronextension.h index c6aa621..0867957 100644 --- a/unipi/neuronextension.h +++ b/unipi/neuronextension.h @@ -31,22 +31,18 @@ #ifndef NEURONEXTENSION_H #define NEURONEXTENSION_H +#include "neuroncommon.h" + #include #include #include -#include #include -class NeuronExtension : public QObject +class NeuronExtension : public NeuronCommon { Q_OBJECT public: - struct Request { - QUuid id; - QModbusDataUnit data; - }; - enum ExtensionTypes { xS10, xS20, @@ -66,12 +62,6 @@ public: int slaveAddress(); void setSlaveAddress(int slaveAddress); - QList digitalInputs(); - QList digitalOutputs(); - QList analogInputs(); - QList analogOutputs(); - QList userLEDs(); - QUuid setDigitalOutput(const QString &circuit, bool value); bool getDigitalOutput(const QString &circuit); bool getDigitalInput(const QString &circuit); @@ -87,19 +77,8 @@ public: QUuid setUserLED(const QString &circuit, bool value); bool getUserLED(const QString &circuit); + private: - uint m_responseTimeoutTime = 2000; - - QTimer *m_inputPollingTimer = nullptr; - QTimer *m_outputPollingTimer = nullptr; - - QHash m_modbusDigitalOutputRegisters; - QHash m_modbusDigitalInputRegisters; - QHash m_modbusAnalogInputRegisters; - QHash m_modbusAnalogOutputRegisters; - QHash m_modbusUserLEDRegisters; - QList m_writeRequestQueue; - QList m_readRequestQueue; QModbusRtuSerialMaster *m_modbusInterface = nullptr; int m_slaveAddress = 0; @@ -110,20 +89,7 @@ private: bool modbusWriteRequest(const Request &request); bool modbusReadRequest(const QModbusDataUnit &request); - bool circuitValueChanged(const QString &circuit, quint32 value); - -signals: - void requestExecuted(const QUuid &requestId, bool success); - void requestError(const QUuid &requestId, const QString &error); - void digitalInputStatusChanged(const QString &circuit, bool value); - void digitalOutputStatusChanged(const QString &circuit, bool value); - - void analogInputStatusChanged(const QString &circuit, double value); - void analogOutputStatusChanged(const QString &circuit, double value); - - void userLEDStatusChanged(const QString &circuit, bool value); - - void connectionStateChanged(bool state); + bool getAnalogIO(const RegisterDescriptor &descriptor); private slots: void onOutputPollingTimer(); diff --git a/unipi/unipi.pro b/unipi/unipi.pro index 3a68943..28b20a2 100644 --- a/unipi/unipi.pro +++ b/unipi/unipi.pro @@ -11,6 +11,7 @@ QT += \ SOURCES += \ integrationpluginunipi.cpp \ neuron.cpp \ + neuroncommon.cpp \ neuronextension.cpp \ mcp23008.cpp \ i2cport.cpp \ @@ -21,6 +22,7 @@ SOURCES += \ HEADERS += \ integrationpluginunipi.h \ neuron.h \ + neuroncommon.h \ neuronextension.h \ mcp23008.h \ i2cport.h \