CuteHMI - Modbus (CuteHMI.Modbus.2)
AbstractDevice.hpp
1 #ifndef H_EXTENSIONS_CUTEHMI_MODBUS_2_INCLUDE_CUTEHMI_MODBUS_ABSTRACTDEVICE_HPP
2 #define H_EXTENSIONS_CUTEHMI_MODBUS_2_INCLUDE_CUTEHMI_MODBUS_ABSTRACTDEVICE_HPP
3 
4 #include "internal/common.hpp"
5 #include "internal/RegisterTraits.hpp"
6 #include "InputRegister.hpp"
7 #include "internal/HoldingRegister.hpp"
8 #include "internal/InputRegister.hpp"
9 #include "DiscreteInput.hpp"
10 #include "Coil.hpp"
11 
12 #include <cutehmi/InplaceError.hpp>
13 #include <cutehmi/services/Serviceable.hpp>
14 
15 #include <QObject>
16 #include <QUuid>
17 #include <QJsonObject>
18 #include <QJsonArray>
19 #include <QQmlListProperty>
20 #include <QModbusPdu>
21 #include <QLinkedList>
22 
23 namespace cutehmi {
24 namespace modbus {
25 
26 namespace internal {
27 class IterableTasks;
28 }
29 
33 class CUTEHMI_MODBUS_API AbstractDevice:
34  public QObject,
36 {
37  Q_OBJECT
38 
39  friend class test_AbstractDevice;
40  friend class test_AbstractServer;
42 
43  public:
44  enum State {
48  CLOSED
49  };
50  Q_ENUM(State)
51 
52  enum Function {
53  FUNCTION_INVALID = QModbusPdu::Invalid,
54  FUNCTION_READ_COILS = QModbusPdu::ReadCoils,
55  FUNCTION_READ_DISCRETE_INPUTS = QModbusPdu::ReadDiscreteInputs,
56  FUNCTION_READ_HOLDING_REGISTERS = QModbusPdu::ReadHoldingRegisters,
57  FUNCTION_READ_INPUT_REGISTERS = QModbusPdu::ReadInputRegisters,
58  FUNCTION_WRITE_COIL = QModbusPdu::WriteSingleCoil,
59  FUNCTION_WRITE_HOLDING_REGISTER = QModbusPdu::WriteSingleRegister,
60  FUNCTION_READ_EXCEPTION_STATUS = QModbusPdu::ReadExceptionStatus,
61  FUNCTION_DIAGNOSTICS = QModbusPdu::Diagnostics,
62  FUNCTION_FETCH_COMM_EVENT_COUNTER = QModbusPdu::GetCommEventCounter,
63  FUNCTION_FETCH_COMM_EVENT_LOG = QModbusPdu::GetCommEventLog,
64  FUNCTION_WRITE_MULTIPLE_COILS = QModbusPdu::WriteMultipleCoils,
65  FUNCTION_WRITE_MULTIPLE_HOLDING_REGISTERS = QModbusPdu::WriteMultipleRegisters,
66  FUNCTION_REPORT_SLAVE_ID = QModbusPdu::ReportServerId,
67  FUNCTION_READ_FILE_RECORD = QModbusPdu::ReadFileRecord,
68  FUNCTION_WRITE_FILE_RECORD = QModbusPdu::WriteFileRecord,
69  FUNCTION_MASK_WRITE_HOLDING_REGISTER = QModbusPdu::MaskWriteRegister,
70  FUNCTION_READ_WRITE_MULTIPLE_HOLDING_REGISTERS = QModbusPdu::ReadWriteMultipleRegisters,
71  FUNCTION_READ_FIFO_QUEUE = QModbusPdu::ReadFifoQueue,
72  // FUNCTION_ENCAPSULATED_INTERFACE_TRANSPORT = QModbusPdu::EncapsulatedInterfaceTransport, // Currently not implemented.
73  FUNCTION_UNDEFINED = QModbusPdu::UndefinedFunctionCode,
78  FUNCTION_RAW
79  };
80  Q_ENUM(Function)
81 
82  enum DiagnosticsSubfunction : quint16 {
83  DIAGNOSTICS_RETURN_QUERY_DATA = 0x00,
84  DIAGNOSTICS_RESTART_COMM_OPTION = 0x01,
85  DIAGNOSTICS_RETURN_DIAGNOSTICS_REGISTER = 0x02,
86  DIAGNOSTICS_CHANGE_ASCII_INPUT_DELIMITER = 0x03,
87  DIAGNOSTICS_FORCE_LISTEN_ONLY_MODE = 0x04,
88  DIAGNOSTICS_CLEAR_COUNTERS_AND_DIAGNOSTICS_REGISTER = 0x0A,
89  DIAGNOSTICS_RETURN_BUS_MESSAGE_COUNT = 0x0B,
90  DIAGNOSTICS_RETURN_BUS_COMM_ERROR_COUNT = 0x0C,
91  DIAGNOSTICS_RETURN_BUS_EXCEPTION_ERROR_COUNT = 0x0D,
92  DIAGNOSTICS_RETURN_SLAVE_MESSAGE_COUNT = 0x0E,
93  DIAGNOSTICS_RETURN_SLAVE_NO_RESPONSE_COUNT = 0x0F,
94  DIAGNOSTICS_RETURN_SLAVE_NAK_COUNT = 0x10,
95  DIAGNOSTICS_RETURN_SLAVE_BUSY_COUNT = 0x11,
96  DIAGNOSTICS_RETURN_BUS_CHARACTER_OVERRUN_COUNT = 0x12,
97  DIAGNOSTICS_RETURN_IOP_OVERRUN_COUNT = 0x13,
98  DIAGNOSTICS_CLEAR_OVERRUN_COUNTER_AND_FLAG = 0x14,
99  DIAGNOSTICS_GET_CLEAR_MODBUS_PLUS_STATISTICS = 0x15
100  };
101  Q_ENUM(DiagnosticsSubfunction)
102 
103 
118 
122  static constexpr int MAX_READ_TCP_COILS = 1976;
123 
127  static constexpr int MAX_READ_RTU_COILS = 2008;
128 
132  static constexpr int MAX_WRITE_TCP_COILS = 1944;
133 
137  static constexpr int MAX_WRITE_RTU_COILS = 1976;
138 
142  static constexpr int MAX_READ_TCP_DISCRETE_INPUTS = 1976;
143 
147  static constexpr int MAX_READ_RTU_DISCRETE_INPUTS = 2008;
148 
152  static constexpr int MAX_READ_TCP_HOLDING_REGISTERS = 123;
153 
157  static constexpr int MAX_READ_RTU_HOLDING_REGISTERS = 125;
158 
162  static constexpr int MAX_WRITE_TCP_HOLDING_REGISTERS = 123;
163 
167  static constexpr int MAX_WRITE_RTU_HOLDING_REGISTERS = 125;
168 
172  static constexpr int MAX_READ_TCP_INPUT_REGISTERS = 123;
173 
177  static constexpr int MAX_READ_RTU_INPUT_REGISTERS = 125;
179 
180  static constexpr quint16 MIN_ADDRESS = 0;
181  static constexpr quint16 MAX_ADDRESS = 65535;
182 
183  static constexpr int INITIAL_MAX_READ_COILS = 16; // Max RTU: 2008, Max TCP: 1976
184  static constexpr int INITIAL_MAX_WRITE_COILS = 16; // Max RTU: 1976, Max TCP: 1944
185  static constexpr int INITIAL_MAX_READ_DISCRETE_INPUTS = 16; // Max RTU: 2008, Max TCP: 1976
186  static constexpr int INITIAL_MAX_WRITE_DISCRETE_INPUTS = 16; // Max RTU: N/A, Max TCP: N/A
187  static constexpr int INITIAL_MAX_READ_HOLDING_REGISTERS = 16; // Max RTU: 125, Max TCP: 123
188  static constexpr int INITIAL_MAX_WRITE_HOLDING_REGISTERS = 16; // Max RTU: 123, Max TCP: 121
189  static constexpr int INITIAL_MAX_READ_INPUT_REGISTERS = 16; // Max RTU: 125, Max TCP: 123
190  static constexpr int INITIAL_MAX_WRITE_INPUT_REGISTERS = 16; // Max RTU: N/A, Max TCP: N/A
191  static constexpr int INITIAL_MAX_REQUESTS = 1000;
192  static constexpr State INITIAL_STATE = CLOSED;
193  static constexpr bool INITIAL_READY = false;
194 
195  Q_PROPERTY(State state READ state NOTIFY stateChanged)
196 
197  Q_PROPERTY(bool ready READ ready NOTIFY readyChanged)
198 
199  Q_PROPERTY(int maxReadCoils READ maxReadCoils WRITE setMaxReadCoils NOTIFY maxReadCoilsChanged)
200 
201  Q_PROPERTY(int maxWriteCoils READ maxWriteCoils WRITE setMaxWriteCoils NOTIFY maxWriteCoilsChanged)
202 
203  Q_PROPERTY(int maxReadDiscreteInputs READ maxReadDiscreteInputs WRITE setMaxReadDiscreteInputs NOTIFY maxReadDiscreteInputsChanged)
204 
205  Q_PROPERTY(int maxWriteDiscreteInputs READ maxWriteDiscreteInputs WRITE setMaxWriteDiscreteInputs NOTIFY maxWriteDiscreteInputsChanged)
206 
207  Q_PROPERTY(int maxReadHoldingRegisters READ maxReadHoldingRegisters WRITE setMaxReadHoldingRegisters NOTIFY maxReadHoldingRegistersChanged)
208 
209  Q_PROPERTY(int maxWriteHoldingRegisters READ maxWriteHoldingRegisters WRITE setMaxWriteHoldingRegisters NOTIFY maxWriteHoldingRegistersChanged)
210 
211  Q_PROPERTY(int maxReadInputRegisters READ maxReadInputRegisters WRITE setMaxReadInputRegisters NOTIFY maxReadInputRegistersChanged)
212 
213  Q_PROPERTY(int maxWriteInputRegisters READ maxWriteInputRegisters WRITE setMaxWriteInputRegisters NOTIFY maxWriteInputRegistersChanged)
214 
215  Q_PROPERTY(int maxRequests READ maxRequests WRITE setMaxRequests NOTIFY maxRequestsChanged)
216 
217  State state() const;
218 
223  bool ready() const;
224 
225  int maxReadCoils() const;
226 
227  void setMaxReadCoils(int maxReadCoils);
228 
229  int maxWriteCoils() const;
230 
231  void setMaxWriteCoils(int maxWriteCoils);
232 
233  int maxReadDiscreteInputs() const;
234 
235  void setMaxReadDiscreteInputs(int maxReadDiscreteInputs);
236 
237  int maxWriteDiscreteInputs() const;
238 
239  void setMaxWriteDiscreteInputs(int maxWriteDiscreteInputs);
240 
241  int maxReadHoldingRegisters() const;
242 
243  void setMaxReadHoldingRegisters(int maxReadHoldingRegisters);
244 
245  int maxWriteHoldingRegisters() const;
246 
247  void setMaxWriteHoldingRegisters(int maxWriteHoldingRegisters);
248 
249  int maxReadInputRegisters() const;
250 
251  void setMaxReadInputRegisters(int maxReadInputRegisters);
252 
253  int maxWriteInputRegisters() const;
254 
255  void setMaxWriteInputRegisters(int maxWriteInputRegisters);
256 
257  int maxRequests() const;
258 
259  void setMaxRequests(int maxRequests);
260 
261  Coil * coilAt(quint16 address);
262 
263  DiscreteInput * discreteInputAt(quint16 address);
264 
265  HoldingRegister * holdingRegisterAt(quint16 address);
266 
267  InputRegister * inputRegisterAt(quint16 address);
268 
279  Q_INVOKABLE void requestReadCoils(quint16 address, quint16 amount = 1, QUuid * requestId = nullptr);
280 
288  Q_INVOKABLE void requestWriteCoil(quint16 address, bool value, QUuid * requestId = nullptr);
289 
298  Q_INVOKABLE void requestWriteMultipleCoils(quint16 address, QJsonArray values, QUuid * requestId = nullptr);
299 
310  Q_INVOKABLE void requestReadDiscreteInputs(quint16 address, quint16 amount = 1, QUuid * requestId = nullptr);
311 
320  Q_INVOKABLE void requestWriteDiscreteInput(quint16 address, bool value, QUuid * requestId = nullptr);
321 
330  Q_INVOKABLE void requestWriteMultipleDiscreteInputs(quint16 address, QJsonArray values, QUuid * requestId = nullptr);
331 
343  Q_INVOKABLE void requestReadHoldingRegisters(quint16 address, quint16 amount = 1, QUuid * requestId = nullptr);
344 
353  Q_INVOKABLE void requestWriteHoldingRegister(quint16 address, quint16 value, QUuid * requestId = nullptr);
354 
363  Q_INVOKABLE void requestWriteMultipleHoldingRegisters(quint16 address, QJsonArray values, QUuid * requestId = nullptr);
364 
376  Q_INVOKABLE void requestReadInputRegisters(quint16 address, quint16 amount = 1, QUuid * requestId = nullptr);
377 
386  Q_INVOKABLE void requestWriteInputRegister(quint16 address, quint16 value, QUuid * requestId = nullptr);
387 
396  Q_INVOKABLE void requestWriteMultipleInputRegisters(quint16 address, QJsonArray values, QUuid * requestId = nullptr);
397 
406  Q_INVOKABLE void requestDiagnostics(DiagnosticsSubfunction subfunction, quint16 data, QUuid * requestId = nullptr);
407 
413  Q_INVOKABLE void requestReadExceptionStatus(QUuid * requestId = nullptr);
414 
420  Q_INVOKABLE void requestFetchCommEventCounter(QUuid * requestId = nullptr);
421 
427  Q_INVOKABLE void requestFetchCommEventLog(QUuid * requestId = nullptr);
428 
434  Q_INVOKABLE void requestReportSlaveId(QUuid * requestId = nullptr);
435 
446  Q_INVOKABLE void requestMaskWriteHoldingRegister(quint16 address, quint16 andMask, quint16 orMask, QUuid * requestId = nullptr);
447 
458  Q_INVOKABLE void requestReadWriteMultipleHoldingRegisters(quint16 readAddress, quint16 amount, quint16 writeAddress, QJsonArray values, QUuid * requestId = nullptr);
459 
467  Q_INVOKABLE void requestReadFIFOQueue(quint16 address, QUuid * requestId = nullptr);
468 
478  Q_INVOKABLE QJsonObject readFileRecordSubrequest(quint16 file, quint16 address, quint16 amount);
479 
490  Q_INVOKABLE void requestReadFileRecord(QJsonArray subrequests, QUuid * requestId = nullptr);
491 
501  Q_INVOKABLE QJsonObject writeFileRecordSubrequest(quint16 file, quint16 address, QJsonArray values);
502 
513  Q_INVOKABLE void requestWriteFileRecord(QJsonArray subrequests, QUuid * requestId = nullptr);
514 
529  Q_INVOKABLE void request(Function function, QJsonObject payload, QUuid * requestId = nullptr);
530 
531  public slots:
532  virtual void open() = 0;
533 
534  virtual void close() = 0;
535 
536  signals:
537  void errored(cutehmi::InplaceError error);
538 
539  void stateChanged();
540 
541  void readyChanged();
542 
543  void maxReadCoilsChanged();
544 
545  void maxWriteCoilsChanged();
546 
547  void maxReadDiscreteInputsChanged();
548 
549  void maxWriteDiscreteInputsChanged();
550 
551  void maxReadHoldingRegistersChanged();
552 
553  void maxWriteHoldingRegistersChanged();
554 
555  void maxReadInputRegistersChanged();
556 
557  void maxWriteInputRegistersChanged();
558 
559  void maxRequestsChanged();
560 
561  void requestCompleted(QJsonObject request, QJsonObject reply);
562 
563  protected:
564  typedef typename internal::RegisterTraits<internal::Coil>::Container CoilDataContainer;
565  typedef typename internal::RegisterTraits<internal::DiscreteInput>::Container DiscreteInputDataContainer;
566  typedef typename internal::RegisterTraits<internal::HoldingRegister>::Container HoldingRegisterDataContainer;
567  typedef typename internal::RegisterTraits<internal::InputRegister>::Container InputRegisterDataContainer;
568 
569  AbstractDevice(QObject * parent = nullptr);
570 
577  ~AbstractDevice() override;
578 
589  virtual void handleRequest(const QJsonObject & request) = 0;
590 
591  const CoilDataContainer & coilData() const;
592 
593  CoilDataContainer & coilData();
594 
595  const DiscreteInputDataContainer & discreteInputData() const;
596 
597  DiscreteInputDataContainer & discreteInputData();
598 
599  const HoldingRegisterDataContainer & holdingRegisterData() const;
600 
601  HoldingRegisterDataContainer & holdingRegisterData();
602 
603  const InputRegisterDataContainer & inputRegisterData() const;
604 
605  InputRegisterDataContainer & inputRegisterData();
606 
607  QJsonObject pendingRequest(QUuid requestId) const;
608 
609  QJsonObject takePendingRequest(QUuid requestId);
610 
611  protected slots:
617  virtual void handleReply(QUuid requestId, QJsonObject reply);
618 
619  void setState(State state);
620 
621  void setReady(bool ready);
622 
623  void handleError(cutehmi::InplaceError error);
624 
625  CUTEHMI_PROTECTED_SIGNALS:
626  void broke();
627 
628  void stopped();
629 
630  void started();
631 
632  private:
634 
635  static void ValidatePayloadAddressKey(const QJsonObject & json, const QString & key = "address");
636 
637  static void ValidatePayloadAmountKey(const QJsonObject & json, int max);
638 
639  static void ValidatePayloadValueKeyInt(const QJsonObject & json);
640 
641  static void ValidatetPayloadValueKeyBool(const QJsonObject & json);
642 
643  static void ValidatePayloadReadFileRecordSubrequestsKey(const QJsonObject & json);
644 
645  static void ValidatePayloadWriteFileRecordSubrequestsKey(const QJsonObject & json);
646 
647  static void ValidateBoolKey(const QJsonObject & json, const QString & key, const QString & path = "");
648 
649  static void ValidateNumberKey(const QJsonObject & json, const QString & key, const QString & path = "");
650 
651  static void ValidateArrayKey(const QJsonObject & json, const QString & key, const QString & path = "");
652 
653  static void ValidateNumberArrayKey(const QJsonObject & json, const QString & key, const QString & path = "");
654 
655  static void ValidateBoolArrayKey(const QJsonObject & json, const QString & key, const QString & path = "");
656 
657  static void ValidateObjectArrayKey(const QJsonObject & json, const QString & key, const QString & path = "", std::function<void(const QJsonObject & json, const QString & path)> filter = nullptr);
658 
659  static void ValidateReadFileRecordSubresponsesKey(const QJsonObject & json, const QString & path = "");
660 
661  static void ValidateWriteFileRecordSubresponsesKey(const QJsonObject & json, const QString & path = "");
662 
663  bool validateRequest(const QJsonObject & request);
664 
665  bool validateReply(const QJsonObject & request, const QJsonObject & reply);
666 
667  struct Members
668  {
669  State state;
670  bool ready;
671  int maxReadCoils;
672  int maxWriteCoils;
673  int maxReadDiscreteInputs;
674  int maxWriteDiscreteInputs;
675  int maxReadHoldingRegisters;
676  int maxWriteHoldingRegisters;
677  int maxReadInputRegisters;
678  int maxWriteInputRegisters;
679  int maxRequests;
680  InputRegisterDataContainer inputRegisters;
681  HoldingRegisterDataContainer holdingRegisters;
682  DiscreteInputDataContainer discreteInputs;
683  CoilDataContainer coils;
684  PendingRequestsContainer pendingRequests;
685 
686  Members():
687  state(INITIAL_STATE),
688  ready(INITIAL_READY),
689  maxReadCoils(INITIAL_MAX_READ_COILS),
690  maxWriteCoils(INITIAL_MAX_WRITE_COILS),
691  maxReadDiscreteInputs(INITIAL_MAX_READ_DISCRETE_INPUTS),
692  maxWriteDiscreteInputs(INITIAL_MAX_WRITE_DISCRETE_INPUTS),
693  maxReadHoldingRegisters(INITIAL_MAX_READ_HOLDING_REGISTERS),
694  maxWriteHoldingRegisters(INITIAL_MAX_WRITE_HOLDING_REGISTERS),
695  maxReadInputRegisters(INITIAL_MAX_READ_INPUT_REGISTERS),
696  maxWriteInputRegisters(INITIAL_MAX_WRITE_INPUT_REGISTERS),
697  maxRequests(INITIAL_MAX_REQUESTS)
698  {
699  }
700  };
701 
702  MPtr<Members> m;
703 };
704 
705 }
706 }
707 
708 Q_DECLARE_METATYPE(cutehmi::modbus::AbstractDevice::State) // Must use this macro despite using Q_ENUM to register metatype inside Init.
709 
710 #endif
711 
712 //(c)C: Copyright © 2019-2020, Michał Policht <michal@policht.pl>. All rights reserved.
713 //(c)C: This file is a part of CuteHMI.
714 //(c)C: CuteHMI 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.
715 //(c)C: CuteHMI 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.
716 //(c)C: You should have received a copy of the GNU Lesser General Public License along with CuteHMI. If not, see <https://www.gnu.org/licenses/>.
cutehmi::modbus::AbstractDevice::OPENING
@ OPENING
Definition: AbstractDevice.hpp:45
cutehmi::modbus::AbstractDevice::CoilDataContainer
internal::RegisterTraits< internal::Coil >::Container CoilDataContainer
Definition: AbstractDevice.hpp:564
cutehmi::modbus::AbstractDevice::FUNCTION_WRITE_DISCRETE_INPUT
@ FUNCTION_WRITE_DISCRETE_INPUT
Definition: AbstractDevice.hpp:74
QUuid
cutehmi::modbus::AbstractDevice
Abstract Modbus device.
Definition: AbstractDevice.hpp:33
cutehmi::modbus::Register1
Cached properties of 1 bit register.
Definition: Register1.hpp:14
cutehmi::modbus::AbstractDevice::CLOSING
@ CLOSING
Definition: AbstractDevice.hpp:47
cutehmi::modbus::AbstractDevice::FUNCTION_WRITE_INPUT_REGISTER
@ FUNCTION_WRITE_INPUT_REGISTER
Definition: AbstractDevice.hpp:76
cutehmi::modbus::internal::IterableTasks
Definition: IterableTasks.hpp:16
cutehmi::InplaceError
cutehmi::MPtr< Members >
QObject
QLinkedList
cutehmi::modbus::AbstractDevice::FUNCTION_WRITE_MULTIPLE_INPUT_REGISTERS
@ FUNCTION_WRITE_MULTIPLE_INPUT_REGISTERS
Definition: AbstractDevice.hpp:77
cutehmi
QJsonArray
QString
cutehmi::services::Serviceable
cutehmi::modbus::AbstractDevice::OPENED
@ OPENED
Definition: AbstractDevice.hpp:46
cutehmi::modbus::AbstractDevice::HoldingRegisterDataContainer
internal::RegisterTraits< internal::HoldingRegister >::Container HoldingRegisterDataContainer
Definition: AbstractDevice.hpp:566
cutehmi::modbus::AbstractDevice::State
State
Definition: AbstractDevice.hpp:44
QJsonObject
cutehmi::modbus::AbstractDevice::FUNCTION_WRITE_MULTIPLE_DISCRETE_INPUTS
@ FUNCTION_WRITE_MULTIPLE_DISCRETE_INPUTS
Definition: AbstractDevice.hpp:75
cutehmi::modbus::AbstractDevice::DiscreteInputDataContainer
internal::RegisterTraits< internal::DiscreteInput >::Container DiscreteInputDataContainer
Definition: AbstractDevice.hpp:565
std
cutehmi::modbus::AbstractDevice::Function
Function
Definition: AbstractDevice.hpp:52
cutehmi::modbus::AbstractDevice::DiagnosticsSubfunction
DiagnosticsSubfunction
Definition: AbstractDevice.hpp:82
cutehmi::modbus::Register16
Cached properties of 16 bit register.
Definition: Register16.hpp:14
cutehmi::modbus::AbstractDevice::InputRegisterDataContainer
internal::RegisterTraits< internal::InputRegister >::Container InputRegisterDataContainer
Definition: AbstractDevice.hpp:567