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 "qnearfieldtagtype1_p.h"
41#include "qnearfieldtarget_p.h"
42#include "qndefmessage.h"
43#include "qtlv_p.h"
44
45#include <QtCore/QByteArray>
46#include <QtCore/QVariant>
47
48#include <QtCore/QDebug>
49
50QT_BEGIN_NAMESPACE
51
52/*!
53 \class QNearFieldTagType1
54 \brief The QNearFieldTagType1 class provides an interface for communicating with an NFC Tag
55 Type 1 tag.
56
57 \ingroup connectivity-nfc
58 \inmodule QtNfc
59 \internal
60*/
61
62/*!
63 \enum QNearFieldTagType1::WriteMode
64 \brief This enum describes the write modes that are supported.
65
66 \value EraseAndWrite The memory is erased before the new value is written.
67 \value WriteOnly The memory is not erased before the new value is written. The effect of
68 this mode is that the final value store is the bitwise or of the data
69 to be written and the original data value.
70*/
71
72/*!
73 \fn Type QNearFieldTagType1::type() const
74 \reimp
75*/
76
77class QNearFieldTagType1Private
78{
79 Q_DECLARE_PUBLIC(QNearFieldTagType1)
80
81public:
82 QNearFieldTagType1Private(QNearFieldTagType1 *q)
83 : q_ptr(q), m_readNdefMessageState(NotReadingNdefMessage),
84 m_tlvReader(0),
85 m_writeNdefMessageState(NotWritingNdefMessage),
86 m_tlvWriter(0)
87 { }
88
89 QNearFieldTagType1 *q_ptr;
90
91 QMap<QNearFieldTarget::RequestId, QByteArray> m_pendingInternalCommands;
92
93 enum ReadNdefMessageState {
94 NotReadingNdefMessage,
95 NdefReadCheckingIdentification,
96 NdefReadCheckingNdefMagicNumber,
97 NdefReadReadingTlv
98 };
99
100 void progressToNextNdefReadMessageState();
101 ReadNdefMessageState m_readNdefMessageState;
102 QNearFieldTarget::RequestId m_readNdefRequestId;
103
104 QTlvReader *m_tlvReader;
105 QNearFieldTarget::RequestId m_nextExpectedRequestId;
106
107 enum WriteNdefMessageState {
108 NotWritingNdefMessage,
109 NdefWriteCheckingIdentification,
110 NdefWriteCheckingNdefMagicNumber,
111 NdefWriteReadingTlv,
112 NdefWriteWritingTlv,
113 NdefWriteWritingTlvFlush
114 };
115
116 void progressToNextNdefWriteMessageState();
117 WriteNdefMessageState m_writeNdefMessageState;
118 QNearFieldTarget::RequestId m_writeNdefRequestId;
119 QList<QNdefMessage> m_ndefWriteMessages;
120
121 QTlvWriter *m_tlvWriter;
122
123 typedef QPair<quint8, QByteArray> Tlv;
124 QList<Tlv> m_tlvs;
125};
126
127void QNearFieldTagType1Private::progressToNextNdefReadMessageState()
128{
129 Q_Q(QNearFieldTagType1);
130
131 switch (m_readNdefMessageState) {
132 case NotReadingNdefMessage:
133 m_readNdefMessageState = NdefReadCheckingIdentification;
134 m_nextExpectedRequestId = q->readIdentification();
135 break;
136 case NdefReadCheckingIdentification: {
137 const QByteArray data = q->requestResponse(id: m_nextExpectedRequestId).toByteArray();
138
139 if (data.isEmpty()) {
140 m_readNdefMessageState = NotReadingNdefMessage;
141 m_nextExpectedRequestId = QNearFieldTarget::RequestId();
142 emit q->error(error: QNearFieldTarget::NdefReadError, id: m_readNdefRequestId);
143 m_readNdefRequestId = QNearFieldTarget::RequestId();
144 break;
145 }
146
147 quint8 hr0 = data.at(i: 0);
148
149 // Check if target is a NFC TagType1 tag
150 if (!(hr0 & 0x10)) {
151 m_readNdefMessageState = NotReadingNdefMessage;
152 m_nextExpectedRequestId = QNearFieldTarget::RequestId();
153 emit q->error(error: QNearFieldTarget::NdefReadError, id: m_readNdefRequestId);
154 m_readNdefRequestId = QNearFieldTarget::RequestId();
155 break;
156 }
157
158 m_readNdefMessageState = NdefReadCheckingNdefMagicNumber;
159 m_nextExpectedRequestId = q->readByte(address: 8);
160 break;
161 }
162 case NdefReadCheckingNdefMagicNumber: {
163 quint8 ndefMagicNumber = q->requestResponse(id: m_nextExpectedRequestId).toUInt();
164 m_nextExpectedRequestId = QNearFieldTarget::RequestId();
165
166 if (ndefMagicNumber != 0xe1) {
167 m_readNdefMessageState = NotReadingNdefMessage;
168 emit q->error(error: QNearFieldTarget::NdefReadError, id: m_readNdefRequestId);
169 m_readNdefRequestId = QNearFieldTarget::RequestId();
170 break;
171 }
172
173 m_readNdefMessageState = NdefReadReadingTlv;
174 delete m_tlvReader;
175 m_tlvReader = new QTlvReader(q);
176
177 Q_FALLTHROUGH(); // fall through
178 }
179 case NdefReadReadingTlv:
180 Q_ASSERT(m_tlvReader);
181 while (!m_tlvReader->atEnd()) {
182 if (!m_tlvReader->readNext())
183 break;
184
185 // NDEF Message TLV
186 if (m_tlvReader->tag() == 0x03) {
187 Q_Q(QNearFieldTagType1);
188
189 emit q->ndefMessageRead(message: QNdefMessage::fromByteArray(message: m_tlvReader->data()));
190 }
191 }
192
193 m_nextExpectedRequestId = m_tlvReader->requestId();
194 if (!m_nextExpectedRequestId.isValid()) {
195 delete m_tlvReader;
196 m_tlvReader = 0;
197 m_readNdefMessageState = NotReadingNdefMessage;
198 emit q->requestCompleted(id: m_readNdefRequestId);
199 m_readNdefRequestId = QNearFieldTarget::RequestId();
200 }
201 break;
202 }
203}
204
205void QNearFieldTagType1Private::progressToNextNdefWriteMessageState()
206{
207 Q_Q(QNearFieldTagType1);
208
209 switch (m_writeNdefMessageState) {
210 case NotWritingNdefMessage:
211 m_writeNdefMessageState = NdefWriteCheckingIdentification;
212 m_nextExpectedRequestId = q->readIdentification();
213 break;
214 case NdefWriteCheckingIdentification: {
215 const QByteArray data = q->requestResponse(id: m_nextExpectedRequestId).toByteArray();
216
217 if (data.isEmpty()) {
218 m_writeNdefMessageState = NotWritingNdefMessage;
219 m_nextExpectedRequestId = QNearFieldTarget::RequestId();
220 emit q->error(error: QNearFieldTarget::NdefWriteError, id: m_writeNdefRequestId);
221 m_writeNdefRequestId = QNearFieldTarget::RequestId();
222 break;
223 }
224
225 quint8 hr0 = data.at(i: 0);
226
227 // Check if target is a NFC TagType1 tag
228 if (!(hr0 & 0x10)) {
229 m_writeNdefMessageState = NotWritingNdefMessage;
230 m_nextExpectedRequestId = QNearFieldTarget::RequestId();
231 emit q->error(error: QNearFieldTarget::NdefWriteError, id: m_writeNdefRequestId);
232 m_writeNdefRequestId = QNearFieldTarget::RequestId();
233 break;
234 }
235
236 m_writeNdefMessageState = NdefWriteCheckingNdefMagicNumber;
237 m_nextExpectedRequestId = q->readByte(address: 8);
238 break;
239 }
240 case NdefWriteCheckingNdefMagicNumber: {
241 quint8 ndefMagicNumber = q->requestResponse(id: m_nextExpectedRequestId).toUInt();
242 m_nextExpectedRequestId = QNearFieldTarget::RequestId();
243
244 if (ndefMagicNumber != 0xe1) {
245 m_writeNdefMessageState = NotWritingNdefMessage;
246 emit q->error(error: QNearFieldTarget::NdefWriteError, id: m_writeNdefRequestId);
247 m_writeNdefRequestId = QNearFieldTarget::RequestId();
248 break;
249 }
250
251 m_writeNdefMessageState = NdefWriteReadingTlv;
252 delete m_tlvReader;
253 m_tlvReader = new QTlvReader(q);
254
255 Q_FALLTHROUGH(); // fall through
256 }
257 case NdefWriteReadingTlv:
258 Q_ASSERT(m_tlvReader);
259 while (!m_tlvReader->atEnd()) {
260 if (!m_tlvReader->readNext())
261 break;
262
263 quint8 tag = m_tlvReader->tag();
264 if (tag == 0x01 || tag == 0x02 || tag == 0xfd)
265 m_tlvs.append(t: qMakePair(x: tag, y: m_tlvReader->data()));
266 }
267
268 m_nextExpectedRequestId = m_tlvReader->requestId();
269 if (m_nextExpectedRequestId.isValid())
270 break;
271
272 delete m_tlvReader;
273 m_tlvReader = 0;
274 m_writeNdefMessageState = NdefWriteWritingTlv;
275
276 // fall through
277 case NdefWriteWritingTlv:
278 delete m_tlvWriter;
279 m_tlvWriter = new QTlvWriter(q);
280
281 // write old TLVs
282 for (const Tlv &tlv : qAsConst(t&: m_tlvs))
283 m_tlvWriter->writeTlv(tag: tlv.first, data: tlv.second);
284
285 // write new NDEF message TLVs
286 for (const QNdefMessage &message : qAsConst(t&: m_ndefWriteMessages))
287 m_tlvWriter->writeTlv(tag: 0x03, data: message.toByteArray());
288
289 // write terminator TLV
290 m_tlvWriter->writeTlv(tag: 0xfe);
291
292 m_writeNdefMessageState = NdefWriteWritingTlvFlush;
293
294 // fall through
295 case NdefWriteWritingTlvFlush:
296 // flush the writer
297 Q_ASSERT(m_tlvWriter);
298 if (m_tlvWriter->process(all: true)) {
299 m_nextExpectedRequestId = QNearFieldTarget::RequestId();
300 m_writeNdefMessageState = NotWritingNdefMessage;
301 delete m_tlvWriter;
302 m_tlvWriter = 0;
303 emit q->ndefMessagesWritten();
304 emit q->requestCompleted(id: m_writeNdefRequestId);
305 m_writeNdefRequestId = QNearFieldTarget::RequestId();
306 } else {
307 m_nextExpectedRequestId = m_tlvWriter->requestId();
308 if (!m_nextExpectedRequestId.isValid()) {
309 m_writeNdefMessageState = NotWritingNdefMessage;
310 delete m_tlvWriter;
311 m_tlvWriter = 0;
312 emit q->error(error: QNearFieldTarget::NdefWriteError, id: m_writeNdefRequestId);
313 m_writeNdefRequestId = QNearFieldTarget::RequestId();
314 }
315 }
316 break;
317 }
318}
319
320static QVariant decodeResponse(const QByteArray &command, const QByteArray &response)
321{
322 switch (command.at(i: 0)) {
323 case 0x01: // READ
324 if (command.at(i: 1) == response.at(i: 0))
325 return quint8(response.at(i: 1));
326 break;
327 case 0x53: { // WRITE-E
328 quint8 address = command.at(i: 1);
329 quint8 data = command.at(i: 2);
330 quint8 writeAddress = response.at(i: 0);
331 quint8 writeData = response.at(i: 1);
332
333 return ((writeAddress == address) && (writeData == data));
334 }
335 case 0x1a: { // WRITE-NE
336 quint8 address = command.at(i: 1);
337 quint8 data = command.at(i: 2);
338 quint8 writeAddress = response.at(i: 0);
339 quint8 writeData = response.at(i: 1);
340
341 return ((writeAddress == address) && ((writeData & data) == data));
342 }
343 case 0x10: { // RSEG
344 quint8 segmentAddress = quint8(command.at(i: 1)) >> 4;
345 quint8 readSegmentAddress = quint8(response.at(i: 0)) >> 4;
346 if (readSegmentAddress == segmentAddress)
347 return response.mid(index: 1);
348 break;
349 }
350 case 0x02: { // READ8
351 quint8 blockAddress = command.at(i: 1);
352 quint8 readBlockAddress = response.at(i: 0);
353 if (readBlockAddress == blockAddress)
354 return response.mid(index: 1);
355 break;
356 }
357 case 0x54: { // WRITE-E8
358 quint8 blockAddress = command.at(i: 1);
359 QByteArray data = command.mid(index: 2, len: 8);
360 quint8 writeBlockAddress = response.at(i: 0);
361 QByteArray writeData = response.mid(index: 1);
362
363 return ((writeBlockAddress == blockAddress) && (writeData == data));
364 }
365 case 0x1b: { // WRITE-NE8
366 quint8 blockAddress = command.at(i: 1);
367 QByteArray data = command.mid(index: 2, len: 8);
368 quint8 writeBlockAddress = response.at(i: 0);
369 QByteArray writeData = response.mid(index: 1);
370
371 if (writeBlockAddress != blockAddress)
372 return false;
373
374 for (int i = 0; i < writeData.length(); ++i) {
375 if ((writeData.at(i) & data.at(i)) != data.at(i))
376 return false;
377 }
378
379 return true;
380 }
381 }
382
383 return QVariant();
384}
385
386/*!
387 Constructs a new tag type 1 near field target with \a parent.
388*/
389QNearFieldTagType1::QNearFieldTagType1(QObject *parent)
390: QNearFieldTarget(parent), d_ptr(new QNearFieldTagType1Private(this))
391{
392}
393
394/*!
395 Destroys the tag type 1 near field target.
396*/
397QNearFieldTagType1::~QNearFieldTagType1()
398{
399 delete d_ptr;
400}
401
402/*!
403 \reimp
404*/
405bool QNearFieldTagType1::hasNdefMessage()
406{
407 RequestId id = readAll();
408 if (!waitForRequestCompleted(id))
409 return false;
410
411 const QByteArray data = requestResponse(id).toByteArray();
412
413 if (data.isEmpty())
414 return false;
415
416 quint8 hr0 = data.at(i: 0);
417
418 // Check if target is a NFC TagType1 tag
419 if (!(hr0 & 0x10))
420 return false;
421
422 // Check if NDEF Message Magic number is present
423 quint8 nmn = data.at(i: 10);
424 if (nmn != 0xe1)
425 return false;
426
427 // Check if TLV contains NDEF Message
428 return true;
429}
430
431/*!
432 \reimp
433*/
434QNearFieldTarget::RequestId QNearFieldTagType1::readNdefMessages()
435{
436 Q_D(QNearFieldTagType1);
437
438 d->m_readNdefRequestId = RequestId(new RequestIdPrivate);
439
440 if (d->m_readNdefMessageState == QNearFieldTagType1Private::NotReadingNdefMessage) {
441 d->progressToNextNdefReadMessageState();
442 } else {
443 reportError(error: QNearFieldTarget::NdefReadError, id: d->m_readNdefRequestId);
444 }
445
446 return d->m_readNdefRequestId;
447}
448
449/*!
450 \reimp
451*/
452QNearFieldTarget::RequestId QNearFieldTagType1::writeNdefMessages(const QList<QNdefMessage> &messages)
453{
454 Q_D(QNearFieldTagType1);
455
456 d->m_writeNdefRequestId = RequestId(new RequestIdPrivate);
457
458 if (d->m_readNdefMessageState == QNearFieldTagType1Private::NotReadingNdefMessage &&
459 d->m_writeNdefMessageState == QNearFieldTagType1Private::NotWritingNdefMessage) {
460 d->m_ndefWriteMessages = messages;
461 d->progressToNextNdefWriteMessageState();
462 } else {
463 reportError(error: QNearFieldTarget::NdefWriteError, id: d->m_readNdefRequestId);
464 }
465
466 return d->m_writeNdefRequestId;
467}
468
469/*!
470 Returns the NFC Tag Type 1 specification version number that the tag supports.
471*/
472quint8 QNearFieldTagType1::version()
473{
474 RequestId id = readByte(address: 9);
475 if (!waitForRequestCompleted(id))
476 return 0;
477
478 quint8 versionNumber = requestResponse(id).toUInt();
479 return versionNumber;
480}
481
482/*!
483 Returns the memory size in bytes of the tag.
484*/
485int QNearFieldTagType1::memorySize()
486{
487 RequestId id = readByte(address: 10);
488 if (!waitForRequestCompleted(id))
489 return 0;
490
491 quint8 tms = requestResponse(id).toUInt();
492
493 return 8 * (tms + 1);
494}
495
496/*!
497 Requests the identification bytes from the target. Returns a request id which can be used to
498 track the completion status of the request.
499
500 Once the request completes successfully the response can be retrieved from the
501 requestResponse() function. The response of this request will be a QByteArray containing: HR0,
502 HR1, UID0, UID1, UID2 and UID3 in order.
503
504 \sa requestCompleted(), waitForRequestCompleted()
505*/
506QNearFieldTarget::RequestId QNearFieldTagType1::readIdentification()
507{
508 QByteArray command;
509 command.append(c: char(0x78)); // RID
510 command.append(c: char(0x00)); // Address (unused)
511 command.append(c: char(0x00)); // Data (unused)
512 command.append(a: uid().left(len: 4)); // 4 bytes of UID
513
514 return sendCommand(command);
515}
516
517/*!
518 Requests all data in the static memory area of the target. Returns a request id which can be
519 used to track the completion status of the request.
520
521 Once the request completes successfully the response can be retrieved from the
522 requestResponse() function. The response of this request will be a QByteArray containing: HR0
523 and HR1 followed by the 120 bytes of data stored in the static memory area of the target.
524
525 \sa requestCompleted(), waitForRequestCompleted()
526*/
527QNearFieldTarget::RequestId QNearFieldTagType1::readAll()
528{
529 QByteArray command;
530 command.append(c: char(0x00)); // RALL
531 command.append(c: char(0x00)); // Address (unused)
532 command.append(c: char(0x00)); // Data (unused)
533 command.append(a: uid().left(len: 4));// 4 bytes of UID
534
535 return sendCommand(command);
536}
537
538/*!
539 Requests a single byte from the static memory area of the tag. The \a address parameter
540 specifices the linear byte address to read. Returns a request id which can be used to track
541 the completion status of the request.
542
543 Once the request completes successfully the response can be retrieved from the
544 requestResponse() function. The response of this request will be a quint8.
545
546 \sa requestCompleted(), waitForRequestCompleted()
547*/
548QNearFieldTarget::RequestId QNearFieldTagType1::readByte(quint8 address)
549{
550 if (address & 0x80)
551 return RequestId();
552
553 QByteArray command;
554 command.append(c: char(0x01)); // READ
555 command.append(c: char(address)); // Address
556 command.append(c: char(0x00)); // Data (unused)
557 command.append(a: uid().left(len: 4)); // 4 bytes of UID
558
559 RequestId id = sendCommand(command);
560
561 Q_D(QNearFieldTagType1);
562
563 d->m_pendingInternalCommands.insert(akey: id, avalue: command);
564
565 return id;
566}
567
568/*!
569 Writes a single \a data byte to the linear byte \a address on the tag. If \a mode is
570 EraseAndWrite the byte will be erased before writing. If \a mode is WriteOnly the contents will
571 not be erased before writing. This is equivelant to writing the result of the bitwise OR of
572 \a data and the original value.
573
574 Returns a request id which can be used to track the completion status of the request.
575
576 Once the request completes the response can be retrieved from the requestResponse() function.
577 The response of this request will be a boolean value, true for success; otherwise false.
578
579 \sa requestCompleted(), waitForRequestCompleted()
580*/
581QNearFieldTarget::RequestId QNearFieldTagType1::writeByte(quint8 address, quint8 data,
582 WriteMode mode)
583{
584 if (address & 0x80)
585 return RequestId();
586
587 QByteArray command;
588
589 if (mode == EraseAndWrite)
590 command.append(c: char(0x53)); // WRITE-E
591 else if (mode == WriteOnly)
592 command.append(c: char(0x1a)); // WRITE-NE
593 else
594 return RequestId();
595
596 command.append(c: char(address)); // Address
597 command.append(c: char(data)); // Data
598 command.append(a: uid().left(len: 4)); // 4 bytes of UID
599
600 RequestId id = sendCommand(command);
601
602 Q_D(QNearFieldTagType1);
603
604 d->m_pendingInternalCommands.insert(akey: id, avalue: command);
605
606 return id;
607}
608
609/*!
610 Requests 128 bytes of data from the segment specified by \a segmentAddress. Returns a request
611 id which can be used to track the completion status of the request.
612
613 Once the request completes successfully the response can be retrieved from the
614 requestResponse() function. The response of this request will be a QByteArray.
615
616 \sa requestCompleted(), waitForRequestCompleted()
617*/
618QNearFieldTarget::RequestId QNearFieldTagType1::readSegment(quint8 segmentAddress)
619{
620 if (segmentAddress & 0xf0)
621 return RequestId();
622
623 QByteArray command;
624 command.append(c: char(0x10)); // RSEG
625 command.append(c: char(segmentAddress << 4)); // Segment address
626 command.append(a: QByteArray(8, char(0x00))); // Data (unused)
627 command.append(a: uid().left(len: 4)); // 4 bytes of UID
628
629 RequestId id = sendCommand(command);
630
631 Q_D(QNearFieldTagType1);
632
633 d->m_pendingInternalCommands.insert(akey: id, avalue: command);
634
635 return id;
636}
637
638/*!
639 Requests 8 bytes of data from the block specified by \a blockAddress. Returns a request id
640 which can be used to track the completion status of the request.
641
642 Once the request completes successfully the response can be retrieved from the
643 requestResponse() function. The response of this request will be a QByteArray.
644
645 \sa requestCompleted(), waitForRequestCompleted()
646*/
647QNearFieldTarget::RequestId QNearFieldTagType1::readBlock(quint8 blockAddress)
648{
649 QByteArray command;
650 command.append(c: char(0x02)); // READ8
651 command.append(c: char(blockAddress)); // Block address
652 command.append(a: QByteArray(8, char(0x00))); // Data (unused)
653 command.append(a: uid().left(len: 4)); // 4 bytes of UID
654
655 RequestId id = sendCommand(command);
656
657 Q_D(QNearFieldTagType1);
658
659 d->m_pendingInternalCommands.insert(akey: id, avalue: command);
660
661 return id;
662}
663
664/*!
665 Writes 8 bytes of \a data to the block specified by \a blockAddress. If \a mode is
666 EraseAndWrite the bytes will be erased before writing. If \a mode is WriteOnly the contents
667 will not be erased before writing. This is equivelant to writing the result of the bitwise OR
668 of \a data and the original value.
669
670 Returns a request id which can be used to track the completion status of the request.
671
672 Once the request completes the response can be retrieved from the requestResponse() function.
673 The response of this request will be a boolean value, true for success; otherwise false.
674
675 \sa requestCompleted(), waitForRequestCompleted()
676*/
677QNearFieldTarget::RequestId QNearFieldTagType1::writeBlock(quint8 blockAddress,
678 const QByteArray &data,
679 WriteMode mode)
680{
681 if (data.length() != 8)
682 return RequestId();
683
684 QByteArray command;
685
686 if (mode == EraseAndWrite)
687 command.append(c: char(0x54)); // WRITE-E8
688 else if (mode == WriteOnly)
689 command.append(c: char(0x1b)); // WRITE-NE8
690 else
691 return RequestId();
692
693 command.append(c: char(blockAddress)); // Block address
694 command.append(a: data); // Data
695 command.append(a: uid().left(len: 4)); // 4 bytes of UID
696
697 RequestId id = sendCommand(command);
698
699 Q_D(QNearFieldTagType1);
700
701 d->m_pendingInternalCommands.insert(akey: id, avalue: command);
702
703 return id;
704}
705
706/*!
707 \reimp
708*/
709bool QNearFieldTagType1::handleResponse(const QNearFieldTarget::RequestId &id,
710 const QByteArray &response)
711{
712 Q_D(QNearFieldTagType1);
713
714 bool handled;
715
716 if (d->m_pendingInternalCommands.contains(akey: id)) {
717 const QByteArray command = d->m_pendingInternalCommands.take(akey: id);
718
719 QVariant decodedResponse = decodeResponse(command, response);
720 setResponseForRequest(id, response: decodedResponse);
721
722 handled = true;
723 } else {
724 handled = QNearFieldTarget::handleResponse(id, response);
725 }
726
727 // continue reading / writing NDEF message
728 if (d->m_nextExpectedRequestId == id) {
729 if (d->m_readNdefMessageState != QNearFieldTagType1Private::NotReadingNdefMessage)
730 d->progressToNextNdefReadMessageState();
731 else if (d->m_writeNdefMessageState != QNearFieldTagType1Private::NotWritingNdefMessage)
732 d->progressToNextNdefWriteMessageState();
733 }
734
735 return handled;
736}
737
738QT_END_NAMESPACE
739

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