CuteHMI - Modbus (CuteHMI.Modbus.2)
QtServerMixin.hpp
1 #ifndef H_EXTENSIONS_CUTEHMI_MODBUS_2_INCLUDE_CUTEHMI_MODBUS_INTERNAL_QTSERVERMIXIN_HPP
2 #define H_EXTENSIONS_CUTEHMI_MODBUS_2_INCLUDE_CUTEHMI_MODBUS_INTERNAL_QTSERVERMIXIN_HPP
3 
4 #include "common.hpp"
5 
6 #include <QtGlobal>
7 
8 #include <QModbusDataUnitMap>
9 
10 namespace cutehmi {
11 namespace modbus {
12 namespace internal {
13 
14 template <typename DERIVED>
16 {
17  protected:
18  bool setMap(const QModbusDataUnitMap & map);
19 
20  bool readData(QModbusDataUnit * newData) const;
21 
22  bool writeData(const QModbusDataUnit & newData);
23 
24  private:
25  const DERIVED & derived() const;
26 
27  DERIVED & derived();
28 };
29 
30 template <typename DERIVED>
31 bool QtServerMixin<DERIVED>::setMap(const QModbusDataUnitMap & map)
32 {
33  Q_UNUSED(map)
34 
35  // Data containers cover whole address range.
36 
37  return true;
38 }
39 
40 template<typename DERIVED>
42 {
43  //<CuteHMI.Modbus-6.unsolved target="Qt" cause="design">
44  // QModbusDataUnit::startAddress() returns `int` value. On systems, where `int` is 16 bit wide it will fail to cover whole
45  // Modbus address range (0 - 65535).
46  static_assert(std::numeric_limits<quint16>::max() <= static_cast<quint16>(std::numeric_limits<int>::max()), "can not safely use startAddress() function on this system");
47 
48  switch (newData->registerType()) {
49  case QModbusDataUnit::Coils:
50  for (quint16 index = 0, address = static_cast<quint16>(newData->startAddress()); index < static_cast<quint16>(newData->valueCount()); index++, address++) { // Note: `uint` returned by valueCount() is guaranteed to be at least 16 bit wide.
51  //<CuteHMI.Modbus-7.workaround target="Qt" cause="design">
52  // QModbusDataUnit::setValue() function accepts `int` type as its `index` parameter. It should be however safe to
53  // cast `quint16` to `int` here, even if `int` is 16 bit wide, because of @ref cutehmi-modbus-AbstractDevice-query_limits.
54  newData->setValue(static_cast<int>(index), derived().m->coilData->value(address)->value());
55  //</CuteHMI.Modbus-7.workaround>
56  }
57  break;
58  case QModbusDataUnit::DiscreteInputs:
59  for (quint16 index = 0, address = static_cast<quint16>(newData->startAddress()); index < static_cast<quint16>(newData->valueCount()); index++, address++) { // Note: `uint` returned by valueCount() is guaranteed to be at least 16 bit wide.
60  //<CuteHMI.Modbus-7.workaround target="Qt" cause="design">
61  // QModbusDataUnit::setValue() function accepts `int` type as its `index` parameter. It should be however safe to
62  // cast `quint16` to `int` here, even if `int` is 16 bit wide, because of @ref cutehmi-modbus-AbstractDevice-query_limits.
63  newData->setValue(static_cast<int>(index), derived().m->discreteInputData->value(address)->value());
64  //</CuteHMI.Modbus-7.workaround>
65  }
66  break;
67  case QModbusDataUnit::HoldingRegisters:
68  for (quint16 index = 0, address = static_cast<quint16>(newData->startAddress()); index < static_cast<quint16>(newData->valueCount()); index++, address++) { // Note: `uint` returned by valueCount() is guaranteed to be at least 16 bit wide.
69  //<CuteHMI.Modbus-7.workaround target="Qt" cause="design">
70  // QModbusDataUnit::setValue() function accepts `int` type as its `index` parameter. It should be however safe to
71  // cast `quint16` to `int` here, even if `int` is 16 bit wide, because of @ref cutehmi-modbus-AbstractDevice-query_limits.
72  newData->setValue(static_cast<int>(index), derived().m->holdingRegisterData->value(address)->value());
73  //</CuteHMI.Modbus-7.workaround>
74  }
75  break;
76  case QModbusDataUnit::InputRegisters:
77  for (quint16 index = 0, address = static_cast<quint16>(newData->startAddress()); index < static_cast<quint16>(newData->valueCount()); index++, address++) { // Note: `uint` returned by valueCount() is guaranteed to be at least 16 bit wide.
78  //<CuteHMI.Modbus-7.workaround target="Qt" cause="design">
79  // QModbusDataUnit::setValue() function accepts `int` type as its `index` parameter. It should be however safe to
80  // cast `quint16` to `int` here, even if `int` is 16 bit wide, because of @ref cutehmi-modbus-AbstractDevice-query_limits.
81  newData->setValue(static_cast<int>(index), derived().m->inputRegisterData->value(address)->value());
82  //</CuteHMI.Modbus-7.workaround>
83  }
84  break;
85  default:
86  CUTEHMI_WARNING("Unrecognized register type '" << newData->registerType() << "'.");
87  }
88  return true;
89 
90  //</CuteHMI.Modbus-6.unsolved>
91 }
92 
93 template<typename DERIVED>
95 {
96  //<CuteHMI.Modbus-6.unsolved target="Qt" cause="design">
97  // QModbusDataUnit::startAddress() returns `int` value. On systems, where `int` is 16 bit wide it will fail to cover
98  // whole Modbus address range (0 - 65535).
99  static_assert(std::numeric_limits<quint16>::max() <= static_cast<quint16>(std::numeric_limits<int>::max()), "can not safely use startAddress() function on this system");
100 
101  switch (newData.registerType()) {
102  case QModbusDataUnit::Coils:
103  for (quint16 index = 0, address = static_cast<quint16>(newData.startAddress()); index < static_cast<quint16>(newData.valueCount()); index++, address++) { // Note: `uint` returned by valueCount() is guaranteed to be at least 16 bit wide.
104  //<CuteHMI.Modbus-3.workaround target="Qt" cause="design">
105  // QModbusDataUnit::value() function accepts `int` type as its `index` parameter. It should be however safe to cast `quint16` to
106  // `int` here, even if `int` is 16 bit wide, because of @ref cutehmi-modbus-AbstractDevice-query_limits.
107  derived().m->coilData->value(address)->setValue(static_cast<bool>(newData.value(static_cast<int>(index))));
108  //</CuteHMI.Modbus-3.workaround>
109  }
110  break;
111  case QModbusDataUnit::DiscreteInputs:
112  for (quint16 index = 0, address = static_cast<quint16>(newData.startAddress()); index < static_cast<quint16>(newData.valueCount()); index++, address++) { // Note: `uint` returned by valueCount() is guaranteed to be at least 16 bit wide.
113  //<CuteHMI.Modbus-3.workaround target="Qt" cause="design">
114  // QModbusDataUnit::value() function accepts `int` type as its `index` parameter. It should be however safe to cast `quint16` to
115  // `int` here, even if `int` is 16 bit wide, because of @ref cutehmi-modbus-AbstractDevice-query_limits.
116  derived().m->discreteInputData->value(address)->setValue(static_cast<bool>(newData.value(static_cast<int>(index))));
117  //</CuteHMI.Modbus-3.workaround>
118  }
119  break;
120  case QModbusDataUnit::HoldingRegisters:
121  for (quint16 index = 0, address = static_cast<quint16>(newData.startAddress()); index < static_cast<quint16>(newData.valueCount()); index++, address++) { // Note: `uint` returned by valueCount() is guaranteed to be at least 16 bit wide.
122  //<CuteHMI.Modbus-3.workaround target="Qt" cause="design">
123  // QModbusDataUnit::value() function accepts `int` type as its `index` parameter. It should be however safe to cast `quint16` to
124  // `int` here, even if `int` is 16 bit wide, because of @ref cutehmi-modbus-AbstractDevice-query_limits.
125  derived().m->holdingRegisterData->value(address)->setValue(newData.value(static_cast<int>(index)));
126  //</CuteHMI.Modbus-3.workaround>
127  }
128  break;
129  case QModbusDataUnit::InputRegisters:
130  for (quint16 index = 0, address = static_cast<quint16>(newData.startAddress()); index < static_cast<quint16>(newData.valueCount()); index++, address++) { // Note: `uint` returned by valueCount() is guaranteed to be at least 16 bit wide.
131  //<CuteHMI.Modbus-3.workaround target="Qt" cause="design">
132  // QModbusDataUnit::value() function accepts `int` type as its `index` parameter. It should be however safe to cast `quint16` to
133  // `int` here, even if `int` is 16 bit wide, because of @ref cutehmi-modbus-AbstractDevice-query_limits.
134  derived().m->inputRegisterData->value(address)->setValue(newData.value(static_cast<int>(index)));
135  //</CuteHMI.Modbus-3.workaround>
136  }
137  break;
138  default:
139  CUTEHMI_WARNING("Unrecognized register type '" << newData.registerType() << "'.");
140  }
141 
142  //</CuteHMI.Modbus-6.unsolved>
143 
144  //<CuteHMI.Modbus-5.unsolved target="Qt" cause="design">
145  // Signal QModbusServer::dataWritten() uses `int` for `address` type. On systems, where `int` is 16 bit wide it will fail to
146  // cover whole Modbus address range (0-65535).
147  static_assert(std::numeric_limits<quint16>::max() <= static_cast<quint16>(std::numeric_limits<int>::max()), "can not safely use dataWritten() signal on this system");
148 
149  //<CuteHMI.Modbus-9.workaround target="Qt" cause="design">
150  // QModbusDataUnit::dataWritten() signal accepts `int` type as its `size` parameter, while QModbusDataUnit::valueCount() uses
151  // `uint` as return type. As such it is incompatible with `size` parameter, which might not be able to represent all returned
152  // values. It should be safe however to cas it to `int`, because of @ref cutehmi-modbus-AbstractDevice-query_limits.
153  emit derived().dataWritten(newData.registerType(), newData.startAddress(), static_cast<int>(newData.valueCount()));
154  //</CuteHMI.Modbus-9.workaround>
155 
156  //</CuteHMI.Modbus-5.unsolved>
157 
158  return true;
159 }
160 
161 template <typename DERIVED>
162 const DERIVED & QtServerMixin<DERIVED>::derived() const
163 {
164  return static_cast<const DERIVED &>(*this);
165 }
166 
167 template <typename DERIVED>
168 DERIVED & QtServerMixin<DERIVED>::derived()
169 {
170  return static_cast<DERIVED &>(*this);
171 }
172 
173 
174 }
175 }
176 }
177 
178 #endif
179 
180 //(c)C: Copyright © 2019, Michał Policht <michal@policht.pl>. All rights reserved.
181 //(c)C: This file is a part of CuteHMI.
182 //(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.
183 //(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.
184 //(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/>.
QModbusDataUnit::valueCount
uint valueCount() const const
cutehmi::modbus::internal::QtServerMixin::readData
bool readData(QModbusDataUnit *newData) const
Definition: QtServerMixin.hpp:41
QModbusDataUnit::registerType
QModbusDataUnit::RegisterType registerType() const const
cutehmi::modbus::internal::QtServerMixin
Definition: QtServerMixin.hpp:15
cutehmi::modbus::internal::QtServerMixin::writeData
bool writeData(const QModbusDataUnit &newData)
Definition: QtServerMixin.hpp:94
cutehmi
QModbusDataUnit
std::internal
T internal(T... args)
CUTEHMI_WARNING
#define CUTEHMI_WARNING(EXPR)
cutehmi::modbus::internal::QtServerMixin::setMap
bool setMap(const QModbusDataUnitMap &map)
Definition: QtServerMixin.hpp:31
QModbusDataUnit::setValue
void setValue(int index, quint16 value)
std::numeric_limits
QModbusDataUnit::value
quint16 value(int index) const const
QModbusDataUnit::startAddress
int startAddress() const const