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-2020, Michał Policht <michal@policht.pl>. All rights reserved.
181 //(c)C: SPDX-License-Identifier: LGPL-3.0-or-later OR MIT
182 //(c)C: This file is a part of CuteHMI.
183 //(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.
184 //(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.
185 //(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/>.
186 //(c)C: Additionally, this file is licensed under terms of MIT license as expressed below.
187 //(c)C: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
188 //(c)C: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
189 //(c)C: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
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