Warning: That file was not part of the compilation database. It may have many parsing errors.
1 | /**************************************************************************** |
---|---|
2 | ** |
3 | ** Copyright (C) 2017 The Qt Company Ltd. |
4 | ** Contact: http://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtSerialBus module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL3$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see http://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at http://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or later as published by the Free |
28 | ** Software Foundation and appearing in the file LICENSE.GPL included in |
29 | ** the packaging of this file. Please review the following information to |
30 | ** ensure the GNU General Public License version 2.0 requirements will be |
31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. |
32 | ** |
33 | ** $QT_END_LICENSE$ |
34 | ** |
35 | ****************************************************************************/ |
36 | #ifndef QMODBUSPDU_H |
37 | #define QMODBUSPDU_H |
38 | |
39 | #include <QtCore/qdatastream.h> |
40 | #include <QtCore/qmetatype.h> |
41 | #include <QtCore/qvector.h> |
42 | #include <QtSerialBus/qtserialbusglobal.h> |
43 | |
44 | QT_BEGIN_NAMESPACE |
45 | |
46 | class QModbusPdu |
47 | { |
48 | public: |
49 | enum ExceptionCode { |
50 | IllegalFunction = 0x01, |
51 | IllegalDataAddress = 0x02, |
52 | IllegalDataValue = 0x03, |
53 | ServerDeviceFailure = 0x04, |
54 | Acknowledge = 0x05, |
55 | ServerDeviceBusy = 0x06, |
56 | NegativeAcknowledge = 0x07, |
57 | MemoryParityError = 0x08, |
58 | GatewayPathUnavailable = 0x0A, |
59 | GatewayTargetDeviceFailedToRespond = 0x0B, |
60 | ExtendedException = 0xFF, |
61 | }; |
62 | |
63 | enum FunctionCode { |
64 | Invalid = 0x00, |
65 | ReadCoils = 0x01, |
66 | ReadDiscreteInputs = 0x02, |
67 | ReadHoldingRegisters = 0x03, |
68 | ReadInputRegisters = 0x04, |
69 | WriteSingleCoil = 0x05, |
70 | WriteSingleRegister = 0x06, |
71 | ReadExceptionStatus = 0x07, |
72 | Diagnostics = 0x08, |
73 | GetCommEventCounter = 0x0B, |
74 | GetCommEventLog = 0x0C, |
75 | WriteMultipleCoils = 0x0F, |
76 | WriteMultipleRegisters = 0x10, |
77 | ReportServerId = 0x11, |
78 | ReadFileRecord = 0x14, |
79 | WriteFileRecord = 0x15, |
80 | MaskWriteRegister = 0x16, |
81 | ReadWriteMultipleRegisters = 0x17, |
82 | ReadFifoQueue = 0x18, |
83 | EncapsulatedInterfaceTransport = 0x2B, |
84 | UndefinedFunctionCode = 0x100 |
85 | }; |
86 | |
87 | QModbusPdu() = default; |
88 | virtual ~QModbusPdu() = default; |
89 | |
90 | bool isValid() const { |
91 | return (m_code >= ReadCoils && m_code < UndefinedFunctionCode) |
92 | && (m_data.size() < 253); |
93 | } |
94 | |
95 | static const quint8 ExceptionByte = 0x80; |
96 | ExceptionCode exceptionCode() const { |
97 | if (!m_data.size() || !isException()) |
98 | return ExtendedException; |
99 | return static_cast<ExceptionCode>(m_data.at(i: 0)); |
100 | } |
101 | bool isException() const { return m_code & ExceptionByte; } |
102 | |
103 | qint16 size() const { return dataSize() + 1; } |
104 | qint16 dataSize() const { return qint16(m_data.size()); } |
105 | |
106 | FunctionCode functionCode() const { |
107 | return FunctionCode(quint8(m_code) &~ ExceptionByte); |
108 | } |
109 | virtual void setFunctionCode(FunctionCode code) { m_code = code; } |
110 | |
111 | QByteArray data() const { return m_data; } |
112 | void setData(const QByteArray &newData) { m_data = newData; } |
113 | |
114 | template <typename ... Args> void encodeData(Args ... newData) { |
115 | encode(std::forward<Args>(newData)...); |
116 | } |
117 | |
118 | template <typename ... Args> void decodeData(Args && ... newData) const { |
119 | decode(std::forward<Args>(newData)...); |
120 | } |
121 | |
122 | protected: |
123 | QModbusPdu(FunctionCode code, const QByteArray &newData) |
124 | : m_code(code) |
125 | , m_data(newData) |
126 | {} |
127 | |
128 | QModbusPdu(const QModbusPdu &) = default; |
129 | QModbusPdu &operator=(const QModbusPdu &) = default; |
130 | |
131 | template <typename ... Args> |
132 | QModbusPdu(FunctionCode code, Args ... newData) |
133 | : m_code(code) |
134 | { |
135 | encode(std::forward<Args>(newData)...); |
136 | } |
137 | |
138 | private: |
139 | template <typename T, typename ... Ts> struct IsType { enum { value = false }; }; |
140 | template <typename T, typename T1, typename ... Ts> struct IsType<T, T1, Ts...> { |
141 | enum { value = std::is_same<T, T1>::value || IsType<T, Ts...>::value }; |
142 | }; |
143 | |
144 | template <typename T> |
145 | using is_pod = std::integral_constant<bool, std::is_trivial<T>::value && std::is_standard_layout<T>::value>; |
146 | |
147 | template <typename T> void encode(QDataStream *stream, const T &t) { |
148 | static_assert(is_pod<T>::value, "Only POD types supported."); |
149 | static_assert(IsType<T, quint8, quint16>::value, "Only quint8 and quint16 supported."); |
150 | (*stream) << t; |
151 | } |
152 | template <typename T> void decode(QDataStream *stream, T &t) const { |
153 | static_assert(is_pod<T>::value, "Only POD types supported."); |
154 | static_assert(IsType<T, quint8 *, quint16 *>::value, "Only quint8* and quint16* supported."); |
155 | (*stream) >> *t; |
156 | } |
157 | template <typename T> void encode(QDataStream *stream, const QVector<T> &vector) { |
158 | static_assert(is_pod<T>::value, "Only POD types supported."); |
159 | static_assert(IsType<T, quint8, quint16>::value, "Only quint8 and quint16 supported."); |
160 | for (int i = 0; i < vector.count(); ++i) |
161 | (*stream) << vector[i]; |
162 | } |
163 | |
164 | template<typename ... Args> void encode(Args ... newData) { |
165 | m_data.clear(); |
166 | Q_CONSTEXPR quint32 argCount = sizeof...(Args); |
167 | if (argCount > 0) { |
168 | QDataStream stream(&m_data, QIODevice::WriteOnly); |
169 | char tmp[argCount] = { (encode(&stream, newData), void(), '0')... }; |
170 | Q_UNUSED(tmp) |
171 | } |
172 | } |
173 | template<typename ... Args> void decode(Args ... newData) const { |
174 | Q_CONSTEXPR quint32 argCount = sizeof...(Args); |
175 | if (argCount > 0 && !m_data.isEmpty()) { |
176 | QDataStream stream(m_data); |
177 | char tmp[argCount] = { (decode(&stream, newData), void(), '0')... }; |
178 | Q_UNUSED(tmp) |
179 | } |
180 | } |
181 | |
182 | private: |
183 | FunctionCode m_code = Invalid; |
184 | QByteArray m_data; |
185 | friend class QModbusSerialAdu; |
186 | friend struct QModbusPduPrivate; |
187 | }; |
188 | Q_SERIALBUS_EXPORT QDebug operator<<(QDebug debug, const QModbusPdu &pdu); |
189 | Q_SERIALBUS_EXPORT QDataStream &operator<<(QDataStream &stream, const QModbusPdu &pdu); |
190 | |
191 | class QModbusRequest : public QModbusPdu |
192 | { |
193 | public: |
194 | QModbusRequest() = default; |
195 | QModbusRequest(const QModbusPdu &pdu) |
196 | : QModbusPdu(pdu) |
197 | {} |
198 | |
199 | explicit QModbusRequest(FunctionCode code, const QByteArray &newData = QByteArray()) |
200 | : QModbusPdu(code, newData) |
201 | {} |
202 | |
203 | Q_SERIALBUS_EXPORT static int minimumDataSize(const QModbusRequest &pdu); |
204 | Q_SERIALBUS_EXPORT static int calculateDataSize(const QModbusRequest &pdu); |
205 | |
206 | using CalcFuncPtr = decltype(&calculateDataSize); |
207 | Q_SERIALBUS_EXPORT static void registerDataSizeCalculator(FunctionCode fc, CalcFuncPtr func); |
208 | |
209 | template <typename ... Args> |
210 | QModbusRequest(FunctionCode code, Args ... newData) |
211 | : QModbusPdu(code, newData...) |
212 | {} |
213 | }; |
214 | Q_SERIALBUS_EXPORT QDataStream &operator>>(QDataStream &stream, QModbusRequest &pdu); |
215 | inline QDataStream &operator<<(QDataStream &stream, const QModbusRequest &pdu) |
216 | { return stream << static_cast<const QModbusPdu &>(pdu); } |
217 | |
218 | class QModbusResponse : public QModbusPdu |
219 | { |
220 | public: |
221 | QModbusResponse() = default; |
222 | QModbusResponse(const QModbusPdu &pdu) |
223 | : QModbusPdu(pdu) |
224 | {} |
225 | |
226 | explicit QModbusResponse(FunctionCode code, const QByteArray &newData = QByteArray()) |
227 | : QModbusPdu(code, newData) |
228 | {} |
229 | |
230 | Q_SERIALBUS_EXPORT static int minimumDataSize(const QModbusResponse &pdu); |
231 | Q_SERIALBUS_EXPORT static int calculateDataSize(const QModbusResponse &pdu); |
232 | |
233 | using CalcFuncPtr = decltype(&calculateDataSize); |
234 | Q_SERIALBUS_EXPORT static void registerDataSizeCalculator(FunctionCode fc, CalcFuncPtr func); |
235 | |
236 | template <typename ... Args> |
237 | QModbusResponse(FunctionCode code, Args ... newData) |
238 | : QModbusPdu(code, newData...) |
239 | {} |
240 | }; |
241 | |
242 | class QModbusExceptionResponse : public QModbusResponse |
243 | { |
244 | public: |
245 | QModbusExceptionResponse() = default; |
246 | QModbusExceptionResponse(const QModbusPdu &pdu) |
247 | : QModbusResponse(pdu) |
248 | {} |
249 | QModbusExceptionResponse(FunctionCode fc, ExceptionCode ec) |
250 | : QModbusResponse(FunctionCode(quint8(fc) | ExceptionByte), static_cast<quint8> (ec)) |
251 | {} |
252 | |
253 | void setFunctionCode(FunctionCode c) { |
254 | QModbusPdu::setFunctionCode(FunctionCode(quint8(c) | ExceptionByte)); |
255 | } |
256 | void setExceptionCode(ExceptionCode ec) { QModbusPdu::encodeData(newData: quint8(ec)); } |
257 | }; |
258 | Q_SERIALBUS_EXPORT QDataStream &operator>>(QDataStream &stream, QModbusResponse &pdu); |
259 | inline QDataStream &operator<<(QDataStream &stream, const QModbusResponse &pdu) |
260 | { return stream << static_cast<const QModbusPdu &>(pdu); } |
261 | |
262 | Q_DECLARE_TYPEINFO(QModbusPdu, Q_MOVABLE_TYPE); |
263 | Q_DECLARE_TYPEINFO(QModbusPdu::ExceptionCode, Q_PRIMITIVE_TYPE); |
264 | Q_DECLARE_TYPEINFO(QModbusPdu::FunctionCode, Q_PRIMITIVE_TYPE); |
265 | |
266 | Q_DECLARE_TYPEINFO(QModbusRequest, Q_MOVABLE_TYPE); |
267 | Q_DECLARE_TYPEINFO(QModbusResponse, Q_MOVABLE_TYPE); |
268 | Q_DECLARE_TYPEINFO(QModbusExceptionResponse, Q_MOVABLE_TYPE); |
269 | |
270 | QT_END_NAMESPACE |
271 | |
272 | Q_DECLARE_METATYPE(QModbusPdu::ExceptionCode) |
273 | Q_DECLARE_METATYPE(QModbusPdu::FunctionCode) |
274 | |
275 | #endif // QMODBUSPDU_H |
276 |
Warning: That file was not part of the compilation database. It may have many parsing errors.