1/***************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the QtBluetooth module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#include <QtBluetooth/QLowEnergyService>
42#include "qlowenergyserviceprivate_p.h"
43#include "qlowenergydescriptor.h"
44
45QT_BEGIN_NAMESPACE
46
47/*!
48 \class QLowEnergyDescriptor
49 \inmodule QtBluetooth
50 \brief The QLowEnergyDescriptor class stores information about the Bluetooth
51 Low Energy descriptor.
52 \since 5.4
53
54 QLowEnergyDescriptor provides information about a Bluetooth Low Energy
55 descriptor's \l name(), \l uuid(), \l value() and \l handle(). Descriptors are
56 encapsulated by Bluetooth Low Energy characteristics and provide additional
57 contextual information about the characteristic (data format, notification activation
58 and so on).
59
60 The descriptor value may be written via the \l QLowEnergyService instance
61 that manages the service to which this descriptor belongs. The
62 \l {QLowEnergyService::writeDescriptor()} function writes the new value.
63 The \l {QLowEnergyService::descriptorWritten()} signal
64 is emitted upon success. The cached \l value() of this object is updated accordingly.
65
66 \sa QLowEnergyService, QLowEnergyCharacteristic
67*/
68
69struct QLowEnergyDescriptorPrivate
70{
71 QLowEnergyHandle charHandle;
72 QLowEnergyHandle descHandle;
73};
74
75/*!
76 Construct a new QLowEnergyDescriptor. A default-constructed instance
77 of this class is always invalid.
78*/
79QLowEnergyDescriptor::QLowEnergyDescriptor():
80 d_ptr(nullptr)
81{
82}
83
84/*!
85 Construct a new QLowEnergyDescriptor that is a copy of \a other.
86
87 The two copies continue to share the same underlying data which does not detach
88 upon write.
89*/
90QLowEnergyDescriptor::QLowEnergyDescriptor(const QLowEnergyDescriptor &other):
91 d_ptr(other.d_ptr)
92{
93 if (other.data) {
94 data = new QLowEnergyDescriptorPrivate();
95 data->charHandle = other.data->charHandle;
96 data->descHandle = other.data->descHandle;
97 }
98}
99
100/*!
101 \internal
102
103*/
104QLowEnergyDescriptor::QLowEnergyDescriptor(QSharedPointer<QLowEnergyServicePrivate> p,
105 QLowEnergyHandle charHandle,
106 QLowEnergyHandle descHandle):
107 d_ptr(p)
108{
109 data = new QLowEnergyDescriptorPrivate();
110 data->charHandle = charHandle;
111 data->descHandle = descHandle;
112
113}
114
115/*!
116 Destroys the QLowEnergyDescriptor object.
117*/
118QLowEnergyDescriptor::~QLowEnergyDescriptor()
119{
120 delete data;
121}
122
123/*!
124 Makes a copy of \a other and assigns it to this QLowEnergyDescriptor object.
125 The two copies continue to share the same service and controller details.
126*/
127QLowEnergyDescriptor &QLowEnergyDescriptor::operator=(const QLowEnergyDescriptor &other)
128{
129 d_ptr = other.d_ptr;
130
131 if (!other.data) {
132 if (data) {
133 delete data;
134 data = nullptr;
135 }
136 } else {
137 if (!data)
138 data = new QLowEnergyDescriptorPrivate();
139
140 data->charHandle = other.data->charHandle;
141 data->descHandle = other.data->descHandle;
142 }
143
144 return *this;
145}
146
147/*!
148 Returns \c true if \a other is equal to this QLowEnergyCharacteristic; otherwise \c false.
149
150 Two QLowEnergyDescriptor instances are considered to be equal if they refer to
151 the same descriptor on the same remote Bluetooth Low Energy device or both
152 instances have been default-constructed.
153 */
154bool QLowEnergyDescriptor::operator==(const QLowEnergyDescriptor &other) const
155{
156 if (d_ptr != other.d_ptr)
157 return false;
158
159 if ((data && !other.data) || (!data && other.data))
160 return false;
161
162 if (!data)
163 return true;
164
165 if (data->charHandle != other.data->charHandle
166 || data->descHandle != other.data->descHandle) {
167 return false;
168 }
169
170 return true;
171}
172
173/*!
174 Returns \c true if \a other is not equal to this QLowEnergyCharacteristic; otherwise \c false.
175
176 Two QLowEnergyDescriptor instances are considered to be equal if they refer to
177 the same descriptor on the same remote Bluetooth Low Energy device or both
178 instances have been default-constructed.
179 */
180bool QLowEnergyDescriptor::operator!=(const QLowEnergyDescriptor &other) const
181{
182 return !(*this == other);
183}
184
185/*!
186 Returns \c true if the QLowEnergyDescriptor object is valid, otherwise returns \c false.
187
188 An invalid descriptor instance is not associated with any service (default-constructed)
189 or the associated service is no longer valid due to a disconnect from
190 the underlying Bluetooth Low Energy device, for example. Once the object is invalid
191 it cannot become valid anymore.
192
193 \note If a QLowEnergyDescriptor instance turns invalid due to a disconnect
194 from the underlying device, the information encapsulated by the current
195 instance remains as it was at the time of the disconnect. Therefore it can be
196 retrieved after the disconnect event.
197*/
198bool QLowEnergyDescriptor::isValid() const
199{
200 if (d_ptr.isNull() || !data)
201 return false;
202
203 if (d_ptr->state == QLowEnergyService::InvalidService)
204 return false;
205
206 return true;
207}
208
209/*!
210 Returns the UUID of this descriptor if \l isValid() returns \c true; otherwise a
211 \l {QUuid::isNull()}{null} UUID.
212*/
213QBluetoothUuid QLowEnergyDescriptor::uuid() const
214{
215 if (d_ptr.isNull() || !data
216 || !d_ptr->characteristicList.contains(data->charHandle)
217 || !d_ptr->characteristicList[data->charHandle].
218 descriptorList.contains(data->descHandle)) {
219 return QBluetoothUuid();
220 }
221
222 return d_ptr->characteristicList[data->charHandle].descriptorList[data->descHandle].uuid;
223}
224
225/*!
226 Returns the handle of the descriptor or \c 0 if the handle
227 cannot be accessed on the platform or the descriptor is invalid.
228
229 \note On \macos and iOS handles can differ from 0, but these
230 values have no special meaning outside of internal/private API.
231*/
232QLowEnergyHandle QLowEnergyDescriptor::handle() const
233{
234 if (!data)
235 return 0;
236
237 return data->descHandle;
238}
239
240/*!
241 Returns the cached value of the descriptor.
242
243 The cached descriptor value may be updated using
244 \l QLowEnergyService::writeDescriptor() or \l QLowEnergyService::readDescriptor().
245*/
246QByteArray QLowEnergyDescriptor::value() const
247{
248 if (d_ptr.isNull() || !data
249 || !d_ptr->characteristicList.contains(data->charHandle)
250 || !d_ptr->characteristicList[data->charHandle].
251 descriptorList.contains(data->descHandle)) {
252 return QByteArray();
253 }
254
255 return d_ptr->characteristicList[data->charHandle].descriptorList[data->descHandle].value;
256}
257
258/*!
259 Returns the human-readable name of the descriptor.
260
261 The name is based on the descriptor's \l type(). The complete list
262 of descriptor types can be found under
263 \l {https://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorsHomePage.aspx}{Bluetooth.org Descriptors}.
264
265 The returned string is empty if the \l type() is unknown.
266
267 \sa type(), QBluetoothUuid::descriptorToString()
268*/
269
270QString QLowEnergyDescriptor::name() const
271{
272 return QBluetoothUuid::descriptorToString(type());
273}
274
275/*!
276 Returns the type of the descriptor.
277
278 \sa name()
279 */
280QBluetoothUuid::DescriptorType QLowEnergyDescriptor::type() const
281{
282 const QBluetoothUuid u = uuid();
283 bool ok = false;
284 quint16 shortUuid = u.toUInt16(&ok);
285
286 if (!ok)
287 return QBluetoothUuid::UnknownDescriptorType;
288
289 switch (shortUuid) {
290 case QBluetoothUuid::CharacteristicExtendedProperties:
291 case QBluetoothUuid::CharacteristicUserDescription:
292 case QBluetoothUuid::ClientCharacteristicConfiguration:
293 case QBluetoothUuid::ServerCharacteristicConfiguration:
294 case QBluetoothUuid::CharacteristicPresentationFormat:
295 case QBluetoothUuid::CharacteristicAggregateFormat:
296 case QBluetoothUuid::ValidRange:
297 case QBluetoothUuid::ExternalReportReference:
298 case QBluetoothUuid::ReportReference:
299 return (QBluetoothUuid::DescriptorType) shortUuid;
300 default:
301 break;
302 }
303
304 return QBluetoothUuid::UnknownDescriptorType;
305}
306
307/*!
308 \internal
309
310 Returns the handle of the characteristic to which this descriptor belongs
311 */
312QLowEnergyHandle QLowEnergyDescriptor::characteristicHandle() const
313{
314 if (d_ptr.isNull() || !data)
315 return 0;
316
317 return data->charHandle;
318}
319
320QT_END_NAMESPACE
321