1 | // Copyright (C) 2017 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "qmodbusdeviceidentification.h" |
5 | #include "qmodbus_symbols_p.h" |
6 | |
7 | QT_BEGIN_NAMESPACE |
8 | |
9 | /*! |
10 | \class QModbusDeviceIdentification |
11 | \inmodule QtSerialBus |
12 | \since 5.8 |
13 | |
14 | \brief The QModbusDeviceIdentification is a container class representing |
15 | the physical and functional description of a Modbus server. |
16 | |
17 | The Device Identification interface is modeled as an address space composed |
18 | of a set of addressable data elements. The data elements are called objects |
19 | and an \l ObjectId identifies them. |
20 | */ |
21 | |
22 | /*! |
23 | \enum QModbusDeviceIdentification::ObjectId |
24 | |
25 | This enum describes the possible server objects. The interface consists of |
26 | three categories of objects: |
27 | |
28 | Basic Device Identification. All objects of this category are mandatory. |
29 | |
30 | \value VendorNameObjectId The vendor name of the device. |
31 | \value ProductCodeObjectId The product code of the device. |
32 | \value MajorMinorRevisionObjectId The product version numbering. |
33 | |
34 | Regular Device Identification. All objects of this category are standard |
35 | defined and optional. |
36 | |
37 | \value VendorUrlObjectId The vendor URL of the device. |
38 | \value ProductNameObjectId The product name of the device. |
39 | \value ModelNameObjectId The model name of the device. |
40 | \value UserApplicationNameObjectId The user application name of the device. |
41 | |
42 | Reserved range (i.e., ReservedObjectId >= ObjectId < ProductDependentObjectId). |
43 | Do not use. |
44 | |
45 | \value ReservedObjectId First value of reserved object Ids. |
46 | |
47 | Extended Device Identification. All of these data are device dependent and |
48 | optional. |
49 | |
50 | \value ProductDependentObjectId First possible value of product dependent |
51 | identifiers. |
52 | \value UndefinedObjectId Do not use. |
53 | */ |
54 | |
55 | /*! |
56 | \enum QModbusDeviceIdentification::ReadDeviceIdCode |
57 | |
58 | Defines the access type of the read identification request. |
59 | |
60 | Stream access: |
61 | |
62 | \value BasicReadDeviceIdCode Request to get the basic device |
63 | identification. |
64 | \value RegularReadDeviceIdCode Request to get the regular device |
65 | identification. |
66 | \value ExtendedReadDeviceIdCode Request to get the extended device |
67 | identification. |
68 | |
69 | Individual access: |
70 | |
71 | \value IndividualReadDeviceIdCode Request to get one specific identification |
72 | object. |
73 | */ |
74 | |
75 | /*! |
76 | \enum QModbusDeviceIdentification::ConformityLevel |
77 | |
78 | Defines the identification conformity level of the device and type of |
79 | supported access. |
80 | |
81 | \value BasicConformityLevel Basic identification (stream access). |
82 | \value RegularConformityLevel Regular identification (stream access). |
83 | \value ExtendedConformityLevel Extended identification (stream access). |
84 | \value BasicIndividualConformityLevel Basic identification (stream access and |
85 | individual access). |
86 | \value RegularIndividualConformityLevel Regular identification (stream access |
87 | and individual access). |
88 | \value ExtendedIndividualConformityLevel Extended identification (stream access |
89 | and individual access). |
90 | |
91 | \sa ReadDeviceIdCode |
92 | */ |
93 | |
94 | /*! |
95 | \fn QModbusDeviceIdentification::QModbusDeviceIdentification() |
96 | |
97 | Constructs an invalid QModbusDeviceIdentification object. |
98 | */ |
99 | |
100 | /*! |
101 | \fn bool QModbusDeviceIdentification::isValid() const |
102 | |
103 | Returns \c true if the device identification object is valid; otherwise |
104 | \c false. |
105 | |
106 | A device identification object is considered valid if \l ProductNameObjectId, |
107 | \l ProductCodeObjectId and \l MajorMinorRevisionObjectId are set to a |
108 | non-empty value. Still the object can contain valid object id's and |
109 | associated data. |
110 | |
111 | \note A default constructed device identification object is invalid. |
112 | */ |
113 | |
114 | /*! |
115 | \fn QList<int> QModbusDeviceIdentification::objectIds() const |
116 | |
117 | Returns a list containing all the object id's in the |
118 | \c QModbusDeviceIdentification object in ascending order. |
119 | |
120 | \sa ObjectId |
121 | */ |
122 | |
123 | /*! |
124 | \fn void QModbusDeviceIdentification::remove(uint objectId) |
125 | |
126 | Removes the item for the given \a objectId. |
127 | |
128 | \sa ObjectId |
129 | */ |
130 | |
131 | /*! |
132 | \fn bool QModbusDeviceIdentification::contains(uint objectId) const |
133 | |
134 | Returns \c true if there is an item for the given \a objectId; otherwise \c |
135 | false. |
136 | |
137 | \sa ObjectId |
138 | */ |
139 | |
140 | /*! |
141 | \fn QByteArray QModbusDeviceIdentification::value(uint objectId) const |
142 | |
143 | Returns the value associated with the \a objectId. If there is no item with |
144 | the \a objectId, the function returns a \l{default-constructed value}. |
145 | |
146 | \sa ObjectId |
147 | */ |
148 | |
149 | /*! |
150 | \fn bool QModbusDeviceIdentification::insert(uint objectId, const QByteArray &value) |
151 | |
152 | Inserts a new item with the \a objectId and a value of \a value. If there |
153 | is already an item with the \a objectId, that item's value is replaced with |
154 | \a value. |
155 | |
156 | Returns \c true if the size of \a value is less than 245 bytes and the |
157 | \a objectId is less then \l QModbusDeviceIdentification::UndefinedObjectId. |
158 | |
159 | \sa ObjectId |
160 | */ |
161 | |
162 | /*! |
163 | \fn ConformityLevel QModbusDeviceIdentification::conformityLevel() const |
164 | |
165 | Returns the identification conformity level of the device and type of |
166 | supported access. |
167 | */ |
168 | |
169 | /*! |
170 | \fn void QModbusDeviceIdentification::setConformityLevel(ConformityLevel level) |
171 | |
172 | Sets the identification conformity level of the device and type of |
173 | supported access to \a level. |
174 | */ |
175 | |
176 | /*! |
177 | Converts the byte array \a ba to a QModbusDeviceIdentification object. |
178 | |
179 | \note: The returned object might be empty or even invalid if some error |
180 | occurs while processing the byte array. |
181 | |
182 | \sa isValid() |
183 | */ |
184 | QModbusDeviceIdentification QModbusDeviceIdentification::fromByteArray(const QByteArray &ba) |
185 | { |
186 | QModbusDeviceIdentification qmdi; |
187 | // header 6 bytes: mei type + read device id + conformity level + more follows |
188 | // + next object id + number of object |
189 | // data 2 bytes: + object id + object size of the first object -> 8 |
190 | if (ba.size() >= 8) { |
191 | if (ba[0] != EncapsulatedInterfaceTransport::ReadDeviceIdentification) |
192 | return qmdi; |
193 | if (ba.size() < (8 + quint8(ba[7]))) |
194 | return qmdi; |
195 | } else { |
196 | return qmdi; |
197 | } |
198 | |
199 | ConformityLevel level = ConformityLevel(quint8(ba[2])); |
200 | switch (level) { |
201 | case BasicConformityLevel: |
202 | case RegularConformityLevel: |
203 | case ExtendedConformityLevel: |
204 | case BasicIndividualConformityLevel: |
205 | case RegularIndividualConformityLevel: |
206 | case ExtendedIndividualConformityLevel: |
207 | qmdi.setConformityLevel(level); |
208 | break; |
209 | default: |
210 | return qmdi; |
211 | } |
212 | |
213 | quint8 numOfObjects = ba[5]; |
214 | quint8 objectSize = quint8(ba[7]); |
215 | qmdi.insert(objectId: quint8(ba[6]), data: ba.mid(index: 8, len: objectSize)); |
216 | |
217 | // header + object id + object size + second object id (9 bytes) + first object size |
218 | int nextSizeField = 9 + objectSize; |
219 | for (int i = 1; i < numOfObjects; ++i) { |
220 | if (ba.size() <= nextSizeField) |
221 | break; |
222 | objectSize = ba[nextSizeField]; |
223 | if (ba.size() < (nextSizeField + objectSize)) |
224 | break; |
225 | qmdi.insert(objectId: quint8(ba[nextSizeField - 1]), data: ba.mid(index: nextSizeField + 1, len: objectSize)); |
226 | nextSizeField += objectSize + 2; // object size + object id field + object size field |
227 | } |
228 | return qmdi; |
229 | } |
230 | |
231 | QT_END_NAMESPACE |
232 | |