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