1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtNfc module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
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 https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qnearfieldtarget.h"
41#include "qnearfieldtarget_p.h"
42#include "qndefmessage.h"
43
44#include <QtCore/QString>
45#include <QtCore/QUrl>
46#include <QtCore/QVariant>
47
48#include <QtCore/QDebug>
49
50#include <QElapsedTimer>
51#include <QCoreApplication>
52
53QT_BEGIN_NAMESPACE
54
55/*!
56 \class QNearFieldTarget
57 \brief The QNearFieldTarget class provides an interface for communicating with a target
58 device.
59
60 \ingroup connectivity-nfc
61 \inmodule QtNfc
62 \since 5.2
63
64 QNearFieldTarget provides a generic interface for communicating with an NFC target device.
65 Both NFC Forum devices and NFC Forum Tag targets are supported by this class. All target
66 specific classes subclass this class.
67
68 The type() function can be used to get the type of the target device. The uid() function
69 returns the unique identifier of the target. The AccessMethods flags returns from the
70 accessMethods() function can be tested to determine which access methods are supported by the
71 target.
72
73 If the target supports NdefAccess, hasNdefMessage() can be called to test if the target has a
74 stored NDEF message, readNdefMessages() and writeNdefMessages() functions can be used to get
75 and set the NDEF message.
76
77 If the target supports TagTypeSpecificAccess, sendCommand() can be used to send a single
78 proprietary command to the target and retrieve the response. sendCommands() can be used to
79 send multiple proprietary commands to the target and retrieve all of the responses.
80
81 If the target supports LlcpAccess, the QLlcpSocket class can be used to connected to a
82 service provided by the target.
83*/
84
85/*!
86 \enum QNearFieldTarget::Type
87
88 This enum describes the type of tag the target is detected as.
89
90 \value ProprietaryTag An unidentified proprietary target tag.
91 \value NfcTagType1 An NFC tag type 1 target.
92 \value NfcTagType2 An NFC tag type 2 target.
93 \value NfcTagType3 An NFC tag type 3 target.
94 \value NfcTagType4 An NFC tag type 4 target.
95 \value MifareTag A Mifare target.
96*/
97
98/*!
99 \enum QNearFieldTarget::AccessMethod
100
101 This enum describes the access methods a near field target supports.
102
103 \value UnknownAccess The target supports an unknown access type.
104 \value NdefAccess The target supports reading and writing NDEF messages using
105 readNdefMessages() and writeNdefMessages().
106 \value TagTypeSpecificAccess The target supports sending tag type specific commands using
107 sendCommand() and sendCommands().
108 \value LlcpAccess The target supports peer-to-peer LLCP communication.
109*/
110
111/*!
112 \enum QNearFieldTarget::Error
113
114 This enum describes the error codes that a near field target reports.
115
116 \value NoError No error has occurred.
117 \value UnknownError An unidentified error occurred.
118 \value UnsupportedError The requested operation is unsupported by this near field
119 target.
120 \value TargetOutOfRangeError The target is no longer within range.
121 \value NoResponseError The target did not respond.
122 \value ChecksumMismatchError The checksum has detected a corrupted response.
123 \value InvalidParametersError Invalid parameters were passed to a tag type specific function.
124 \value NdefReadError Failed to read NDEF messages from the target.
125 \value NdefWriteError Failed to write NDEF messages to the target.
126 \value CommandError Failed to send a command to the target.
127*/
128
129#if QT_DEPRECATED_SINCE(5, 9)
130/*!
131 \relates QNearFieldTarget
132
133 Returns the NFC checksum of the first \a len bytes of \a data.
134*/
135quint16 qNfcChecksum(const char *data, uint len)
136{
137 return qChecksum(s: data, len, standard: Qt::ChecksumItuV41);
138}
139#endif
140
141/*!
142 \fn void QNearFieldTarget::disconnected()
143
144 This signal is emitted when the near field target moves out of proximity.
145*/
146
147/*!
148 \fn void QNearFieldTarget::ndefMessageRead(const QNdefMessage &message)
149
150 This signal is emitted when a complete NDEF \a message has been read from the target.
151
152 \sa readNdefMessages()
153*/
154
155/*!
156 \fn void QNearFieldTarget::ndefMessagesWritten()
157
158 This signal is emitted when NDEF messages have been successfully written to the target.
159
160 \sa writeNdefMessages()
161*/
162
163/*!
164 \fn void QNearFieldTarget::requestCompleted(const QNearFieldTarget::RequestId &id)
165
166 This signal is emitted when a request \a id completes.
167
168 \sa sendCommand()
169*/
170
171/*!
172 \fn void QNearFieldTarget::error(QNearFieldTarget::Error error, const QNearFieldTarget::RequestId &id)
173
174 This signal is emitted when an error occurs while processing request \a id. The \a error
175 parameter describes the error.
176*/
177
178/*!
179 \class QNearFieldTarget::RequestId
180 \inmodule QtHfc
181 \inheaderfile QNearFieldTarget
182 \brief A request id handle.
183*/
184
185/*!
186 Constructs a new invalid request id handle.
187*/
188QNearFieldTarget::RequestId::RequestId()
189{
190}
191
192/*!
193 Constructs a new request id handle that is a copy of \a other.
194*/
195QNearFieldTarget::RequestId::RequestId(const RequestId &other)
196: d(other.d)
197{
198}
199
200/*!
201 \internal
202*/
203QNearFieldTarget::RequestId::RequestId(RequestIdPrivate *p)
204: d(p)
205{
206}
207
208/*!
209 Destroys the request id handle.
210*/
211QNearFieldTarget::RequestId::~RequestId()
212{
213}
214
215/*!
216 Returns true if this is a valid request id; otherwise returns false.
217*/
218bool QNearFieldTarget::RequestId::isValid() const
219{
220 return d;
221}
222
223/*!
224 Returns the current reference count of the request id.
225*/
226int QNearFieldTarget::RequestId::refCount() const
227{
228 if (d)
229 return d->ref.loadRelaxed();
230
231 return 0;
232}
233
234/*!
235 \internal
236*/
237bool QNearFieldTarget::RequestId::operator<(const RequestId &other) const
238{
239 return d < other.d;
240}
241
242/*!
243 \internal
244*/
245bool QNearFieldTarget::RequestId::operator==(const RequestId &other) const
246{
247 return d == other.d;
248}
249
250/*!
251 \internal
252*/
253bool QNearFieldTarget::RequestId::operator!=(const RequestId &other) const
254{
255 return d != other.d;
256}
257
258/*!
259 Assigns a copy of \a other to this request id and returns a reference to this request id.
260*/
261QNearFieldTarget::RequestId &QNearFieldTarget::RequestId::operator=(const RequestId &other)
262{
263 d = other.d;
264 return *this;
265}
266
267/*!
268 Constructs a new near field target with \a parent.
269*/
270QNearFieldTarget::QNearFieldTarget(QObject *parent)
271: QObject(parent), d_ptr(new QNearFieldTargetPrivate(this))
272{
273 qRegisterMetaType<QNearFieldTarget::RequestId>();
274 qRegisterMetaType<QNearFieldTarget::Error>();
275 qRegisterMetaType<QNdefMessage>();
276}
277
278/*!
279 Destroys the near field target.
280*/
281QNearFieldTarget::~QNearFieldTarget()
282{
283 delete d_ptr;
284}
285
286/*!
287 \fn QByteArray QNearFieldTarget::uid() const = 0
288
289 Returns the UID of the near field target.
290*/
291
292/*!
293 Returns the URL of the near field target.
294*/
295QUrl QNearFieldTarget::url() const
296{
297 return QUrl();
298}
299
300/*!
301 \fn QNearFieldTarget::Type QNearFieldTarget::type() const = 0
302
303 Returns the type of tag type of this near field target.
304*/
305
306/*!
307 \fn QNearFieldTarget::AccessMethods QNearFieldTarget::accessMethods() const = 0
308
309 Returns the access methods support by this near field target.
310*/
311
312/*!
313 \since 5.9
314
315 Returns true if this feature is enabled.
316
317 \sa setKeepConnection(), disconnect()
318*/
319bool QNearFieldTarget::keepConnection() const
320{
321 return d_ptr->keepConnection();
322}
323
324/*!
325 \since 5.9
326
327 Preserves the connection to the target device after processing a command or
328 reading/writing NDEF messages if \a isPersistent is \c true.
329 By default, this behavior is not enabled.
330
331 Returns \c true if enabling this feature was successful. A possible
332 reason for a failure is the lack of support on the used platform.
333
334 Enabling this feature requires to use the disconnect() function too, to close the
335 connection manually and enable communication with the target from a different instance.
336 Disabling this feature will also close an open connection.
337
338 \sa keepConnection(), disconnect()
339*/
340bool QNearFieldTarget::setKeepConnection(bool isPersistent)
341{
342 return d_ptr->setKeepConnection(isPersistent);
343}
344
345/*!
346 \since 5.9
347
348 Closes the connection to the target.
349
350 Returns true only if an existing connection was successfully closed.
351
352 \sa keepConnection(), setKeepConnection()
353*/
354bool QNearFieldTarget::disconnect()
355{
356 return d_ptr->disconnect();
357}
358
359/*!
360 Returns true if the target is processing commands; otherwise returns false.
361*/
362bool QNearFieldTarget::isProcessingCommand() const
363{
364 return false;
365}
366
367/*!
368 Returns true if at least one NDEF message is stored on the near field target; otherwise returns
369 false.
370*/
371bool QNearFieldTarget::hasNdefMessage()
372{
373 return false;
374}
375
376/*!
377 Starts reading NDEF messages stored on the near field target. Returns a request id which can
378 be used to track the completion status of the request. An invalid request id will be returned
379 if the target does not support reading NDEF messages.
380
381 An ndefMessageRead() signal will be emitted for each NDEF message. The requestCompleted()
382 signal will be emitted was all NDEF messages have been read. The error() signal is emitted if
383 an error occurs.
384*/
385QNearFieldTarget::RequestId QNearFieldTarget::readNdefMessages()
386{
387 return RequestId();
388}
389
390/*!
391 Writes the NDEF messages in \a messages to the target. Returns a request id which can be used
392 to track the completion status of the request. An invalid request id will be returned if the
393 target does not support reading NDEF messages.
394
395 The ndefMessagesWritten() signal will be emitted when the write operation completes
396 successfully; otherwise the error() signal is emitted.
397*/
398QNearFieldTarget::RequestId QNearFieldTarget::writeNdefMessages(const QList<QNdefMessage> &messages)
399{
400 Q_UNUSED(messages);
401
402 return RequestId();
403}
404
405/*!
406 \since 5.9
407
408 Returns the maximum number of bytes that can be sent with sendCommand. 0 will
409 be returned if the target does not support sending tag type specific commands.
410
411 \sa sendCommand(), sendCommands()
412*/
413int QNearFieldTarget::maxCommandLength() const
414{
415 return d_ptr->maxCommandLength();
416}
417
418/*!
419 Sends \a command to the near field target. Returns a request id which can be used to track the
420 completion status of the request. An invalid request id will be returned if the target does not
421 support sending tag type specific commands.
422
423 The requestCompleted() signal will be emitted on successful completion of the request;
424 otherwise the error() signal will be emitted.
425
426 Once the request completes successfully the response can be retrieved from the
427 requestResponse() function. The response of this request will be a QByteArray.
428
429 \sa requestCompleted(), waitForRequestCompleted()
430*/
431QNearFieldTarget::RequestId QNearFieldTarget::sendCommand(const QByteArray &command)
432{
433 Q_UNUSED(command);
434
435 emit error(error: UnsupportedError, id: RequestId());
436
437 return RequestId();
438}
439
440/*!
441 Sends multiple \a commands to the near field target. Returns a request id which can be used to
442 track the completion status of the request. An invalid request id will be returned if the
443 target does not support sending tag type specific commands.
444
445 If all commands complete successfully the requestCompleted() signal will be emitted; otherwise
446 the error() signal will be emitted. If a command fails succeeding commands from this call will
447 not be processed.
448
449 Once the request completes the response for successfully completed requests can be retrieved
450 from the requestResponse() function. The response of this request will be a QList<QByteArray>.
451
452 \sa requestCompleted(), waitForRequestCompleted()
453*/
454QNearFieldTarget::RequestId QNearFieldTarget::sendCommands(const QList<QByteArray> &commands)
455{
456 Q_UNUSED(commands);
457
458 emit error(error: UnsupportedError, id: RequestId());
459
460 return RequestId();
461}
462
463/*!
464 Waits up to \a msecs milliseconds for the request \a id to complete. Returns true if the
465 request completes successfully and the requestCompeted() signal is emitted; otherwise returns
466 false.
467*/
468bool QNearFieldTarget::waitForRequestCompleted(const RequestId &id, int msecs)
469{
470 Q_D(QNearFieldTarget);
471
472 QElapsedTimer timer;
473 timer.start();
474
475 do {
476 if (d->m_decodedResponses.contains(akey: id))
477 return true;
478 else
479 QCoreApplication::processEvents(flags: QEventLoop::WaitForMoreEvents, maxtime: 1);
480 } while (timer.elapsed() <= msecs);
481
482 return false;
483}
484
485/*!
486 Returns the decoded response for request \a id. If the request is unknown or has not yet been
487 completed an invalid QVariant is returned.
488*/
489QVariant QNearFieldTarget::requestResponse(const RequestId &id)
490{
491 Q_D(QNearFieldTarget);
492
493 return d->m_decodedResponses.value(akey: id);
494}
495
496/*!
497 Sets the decoded response for request \a id to \a response. If \a emitRequestCompleted is true
498 the requestCompleted() signal will be emitted for \a id; otherwise no signal will be emitted.
499
500 \sa requestResponse()
501*/
502void QNearFieldTarget::setResponseForRequest(const QNearFieldTarget::RequestId &id,
503 const QVariant &response, bool emitRequestCompleted)
504{
505 Q_D(QNearFieldTarget);
506
507 for (auto i = d->m_decodedResponses.begin(), end = d->m_decodedResponses.end(); i != end; /* erasing */) {
508 // no more external references
509 if (i.key().refCount() == 1)
510 i = d->m_decodedResponses.erase(it: i);
511 else
512 ++i;
513 }
514
515 d->m_decodedResponses.insert(akey: id, avalue: response);
516
517 if (emitRequestCompleted)
518 emit requestCompleted(id);
519}
520
521/*!
522 Handles the \a response received for the request \a id. Returns true if the response is
523 handled; otherwise returns false.
524
525 Classes reimplementing this virtual function should call the base class implementation to
526 ensure that requests initiated by those classes are handled correctly.
527
528 The default implementation stores the response such that it can be retrieved by
529 requestResponse().
530*/
531bool QNearFieldTarget::handleResponse(const QNearFieldTarget::RequestId &id,
532 const QByteArray &response)
533{
534 setResponseForRequest(id, response);
535
536 return true;
537}
538
539/*!
540 \since 5.12
541
542 Reports the \a error for the request \a id by appending the signal emission to the event queue.
543*/
544void QNearFieldTarget::reportError(QNearFieldTarget::Error error,
545 const QNearFieldTarget::RequestId &id)
546{
547 setResponseForRequest(id, response: QVariant(), emitRequestCompleted: false);
548 QMetaObject::invokeMethod(context: this, function: [this, error, id]() {
549 Q_EMIT this->error(error, id);
550 }, type: Qt::QueuedConnection);
551}
552
553QT_END_NAMESPACE
554

source code of qtconnectivity/src/nfc/qnearfieldtarget.cpp