// SPDX-License-Identifier: LGPL-3.0-or-later /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright (C) 2013 - 2024, nymea GmbH * Copyright (C) 2024 - 2025, chargebyte austria GmbH * * This file is part of libnymea-sunspec. * * libnymea-sunspec is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * libnymea-sunspec 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 libnymea-sunspec. If not, see . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef SUNSPECCONNECTION_H #define SUNSPECCONNECTION_H #include #include #include #include #include #include "sunspecdatapoint.h" Q_DECLARE_LOGGING_CATEGORY(dcSunSpec) class SunSpecModel; class SunSpecConnection : public QObject { Q_OBJECT public: explicit SunSpecConnection(const QHostAddress &hostAddress, uint port = 502, uint slaveId = 1, QObject *parent = nullptr); explicit SunSpecConnection(const QHostAddress &hostAddress, uint port = 502, uint slaveId = 1, SunSpecDataPoint::ByteOrder byteOrder = SunSpecDataPoint::ByteOrderLittleEndian, QObject *parent = nullptr); ~SunSpecConnection() = default; QModbusTcpClient *modbusTcpClient() const; QHostAddress hostAddress() const; void setHostAddress(const QHostAddress &hostAddress); uint port() const; void setPort(uint port); uint slaveId() const; void setSlaveId(uint slaveId); SunSpecDataPoint::ByteOrder byteOrder() const; int timeout() const; void setTimeout(int milliSeconds); uint numberOfRetries() const; void setNumberOfRetries(uint retries); bool connected() const; bool discoveryRunning() const; quint16 baseRegister() const; QList models() const; // Helper methods for internal queue handling if enabled QModbusReply *sendReadRequest(const QModbusDataUnit &read, int serverAddress); QModbusReply *sendWriteRequest(const QModbusDataUnit &write, int serverAddress); QModbusReply *sendRawRequest(const QModbusRequest &request, int serverAddress); public slots: bool startDiscovery(); bool connectDevice(); void disconnectDevice(); bool reconnectDevice(); signals: void connectedChanged(bool connected); void discoveryRunningChanged(bool discoveryRunning); void sunspecBaseRegisterFound(quint16 baseRegister); void discoveryFinished(bool success); private: QModbusTcpClient *m_modbusTcpClient = nullptr; QHostAddress m_hostAddress; uint m_port; int m_slaveId = 1; QTimer m_reconnectTimer; bool m_connected = false; quint16 m_baseRegister = 40000; QQueue m_baseRegisterQueue; // SunSpec discovery typedef struct ModuleDiscoveryResult { quint16 modbusStartRegister; quint16 modelId; quint16 modelLength; } ModuleDiscoveryResult; bool m_discoveryRunning = false; QList m_modelDiscoveryResult; QList m_models; QList m_uninitializedModels; SunSpecDataPoint::ByteOrder m_byteOrder = SunSpecDataPoint::ByteOrderLittleEndian; int m_timoutReplyCounter = 0; int m_timoutReplyCounterLimit = 16; void createConnection(); void processDiscoveryResult(); void setDiscoveryRunning(bool discoveryRunning); bool modelAlreadyAdded(SunSpecModel *model) const; bool scanSunspecBaseRegister(quint16 baseRegister); void scanNextSunspecBaseRegister(); void scanModelsOnBaseRegister(quint16 offset = 2); void monitorTimoutErrors(QModbusReply *reply); }; QDebug operator<<(QDebug debug, SunSpecConnection *connection); #endif // SUNSPECCONNECTION_H