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:GPL-EXCEPT$
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 General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include <QtTest/QtTest>
30
31#include <private/qnearfieldmanager_emulator_p.h>
32#include <qnearfieldmanager.h>
33#include <qndefmessage.h>
34#include <private/qnearfieldtagtype1_p.h>
35#include <qndefnfctextrecord.h>
36
37QT_USE_NAMESPACE
38
39Q_DECLARE_METATYPE(QNearFieldTarget*)
40
41class tst_QNearFieldTagType1 : public QObject
42{
43 Q_OBJECT
44
45public:
46 tst_QNearFieldTagType1();
47
48private slots:
49 void init();
50 void cleanup();
51
52 void staticMemoryModel();
53 void dynamicMemoryModel();
54
55 void ndefMessages();
56
57private:
58 void waitForMatchingTarget();
59
60 QNearFieldManagerPrivateImpl *emulatorBackend;
61 QNearFieldManager *manager;
62 QNearFieldTagType1 *target;
63};
64
65tst_QNearFieldTagType1::tst_QNearFieldTagType1()
66: emulatorBackend(0), manager(0), target(0)
67{
68 QDir::setCurrent(QLatin1String(SRCDIR));
69
70 qRegisterMetaType<QNdefMessage>();
71 qRegisterMetaType<QNearFieldTarget *>();
72}
73
74void tst_QNearFieldTagType1::init()
75{
76 emulatorBackend = new QNearFieldManagerPrivateImpl;
77 manager = new QNearFieldManager(emulatorBackend, 0);
78}
79
80void tst_QNearFieldTagType1::cleanup()
81{
82 emulatorBackend->reset();
83
84 delete manager;
85 manager = 0;
86 emulatorBackend = 0;
87 target = 0;
88}
89
90void tst_QNearFieldTagType1::waitForMatchingTarget()
91{
92 QSignalSpy targetDetectedSpy(manager, SIGNAL(targetDetected(QNearFieldTarget*)));
93
94 manager->startTargetDetection();
95
96 QTRY_VERIFY(!targetDetectedSpy.isEmpty());
97
98 target =
99 qobject_cast<QNearFieldTagType1 *>(object: targetDetectedSpy.first().at(i: 0).value<QNearFieldTarget *>());
100
101 manager->stopTargetDetection();
102
103 QVERIFY(target);
104
105 QCOMPARE(target->type(), QNearFieldTarget::NfcTagType1);
106}
107
108void tst_QNearFieldTagType1::staticMemoryModel()
109{
110 waitForMatchingTarget();
111
112 QVERIFY(target->accessMethods() & QNearFieldTarget::TagTypeSpecificAccess);
113
114 QCOMPARE(target->version(), quint8(0x10));
115
116 // readIdentification()
117 {
118 QNearFieldTarget::RequestId id = target->readIdentification();
119 QVERIFY(target->waitForRequestCompleted(id));
120
121 const QByteArray data = target->requestResponse(id).toByteArray();
122
123 QCOMPARE(data.length(), 6);
124
125 quint8 hr0 = data.at(i: 0);
126 //quint8 hr1 = data.at(1);
127 const QByteArray uid4 = data.mid(index: 2, len: 4);
128
129 // verify NfcTagType1
130 QVERIFY(hr0 & 0x10);
131
132 QCOMPARE(uid4, target->uid().left(4));
133 }
134
135 // readAll()
136 {
137 // read all reads the first 120 bytes, prepended with HR0 and HR1.
138 QNearFieldTarget::RequestId id = target->readAll();
139 QVERIFY(target->waitForRequestCompleted(id));
140
141 const QByteArray data = target->requestResponse(id).toByteArray();
142 QCOMPARE(data.length(), 122);
143
144 // verify NfcTagType1.
145 QVERIFY(data.at(0) & 0x10);
146
147 // NFC Magic Number means NDEF message present.
148 QCOMPARE(quint8(data.at(10)) == 0xe1, target->hasNdefMessage());
149 }
150
151 // readByte()
152 {
153 QNearFieldTarget::RequestId id = target->readAll();
154 QVERIFY(target->waitForRequestCompleted(id));
155
156 const QByteArray data = target->requestResponse(id).toByteArray();
157
158 for (int i = 0; i < 120; ++i) {
159 id = target->readByte(address: i);
160 QVERIFY(target->waitForRequestCompleted(id));
161
162 quint8 byte = target->requestResponse(id).toUInt();
163
164 QCOMPARE(byte, quint8(data.at(i + 2)));
165 }
166 }
167
168 // writeByte()
169 {
170 for (int i = 0; i < 8; ++i) {
171 QNearFieldTarget::RequestId id = target->readByte(address: i);
172 QVERIFY(target->waitForRequestCompleted(id));
173
174 quint8 byte = target->requestResponse(id).toUInt();
175
176 id = target->writeByte(address: i, data: 0x55);
177 QVERIFY(target->waitForRequestCompleted(id));
178 QVERIFY(!target->requestResponse(id).isValid());
179
180 id = target->readByte(address: i);
181 QVERIFY(target->waitForRequestCompleted(id));
182
183 quint8 readByte = target->requestResponse(id).toUInt();
184 QCOMPARE(readByte, byte);
185 }
186
187 for (int i = 8; i < 104; ++i) {
188 // Write 0x55
189 QNearFieldTarget::RequestId id = target->writeByte(address: i, data: 0x55);
190 QVERIFY(target->waitForRequestCompleted(id));
191 QVERIFY(target->requestResponse(id).toBool());
192
193 id = target->readByte(address: i);
194 QVERIFY(target->waitForRequestCompleted(id));
195 quint8 readByte = target->requestResponse(id).toUInt();
196 QCOMPARE(readByte, quint8(0x55));
197
198 // Write 0xaa
199 id = target->writeByte(address: i, data: 0xaa);
200 QVERIFY(target->waitForRequestCompleted(id));
201 QVERIFY(target->requestResponse(id).toBool());
202
203 id = target->readByte(address: i);
204 QVERIFY(target->waitForRequestCompleted(id));
205 readByte = target->requestResponse(id).toUInt();
206 QCOMPARE(readByte, quint8(0xaa));
207
208 // Write 0x55 without erase, result should be 0xff
209 id = target->writeByte(address: i, data: 0x55, mode: QNearFieldTagType1::WriteOnly);
210 QVERIFY(target->waitForRequestCompleted(id));
211 QVERIFY(target->requestResponse(id).toBool());
212
213 id = target->readByte(address: i);
214 QVERIFY(target->waitForRequestCompleted(id));
215 readByte = target->requestResponse(id).toUInt();
216 QCOMPARE(readByte, quint8(0xff));
217 }
218
219 for (int i = 104; i < 120; ++i) {
220 QNearFieldTarget::RequestId id = target->readByte(address: i);
221 QVERIFY(target->waitForRequestCompleted(id));
222
223 quint8 byte = target->requestResponse(id).toUInt();
224
225 id = target->writeByte(address: i, data: 0x55);
226 QVERIFY(target->waitForRequestCompleted(id));
227 QVERIFY(!target->requestResponse(id).isValid());
228
229 id = target->readByte(address: i);
230 QVERIFY(target->waitForRequestCompleted(id));
231
232 quint8 readByte = target->requestResponse(id).toUInt();
233 QCOMPARE(readByte, byte);
234 }
235 }
236}
237
238void tst_QNearFieldTagType1::dynamicMemoryModel()
239{
240 bool testedStatic = false;
241 bool testedDynamic = false;
242
243 QList<QByteArray> seenIds;
244 forever {
245 waitForMatchingTarget();
246
247 QNearFieldTarget::RequestId id = target->readIdentification();
248 QVERIFY(target->waitForRequestCompleted(id));
249
250 const QByteArray data = target->requestResponse(id).toByteArray();
251 if (seenIds.contains(t: data))
252 break;
253 else
254 seenIds.append(t: data);
255
256 quint8 hr0 = data.at(i: 0);
257 bool dynamic = (((hr0 & 0xf0) == 0x10) && ((hr0 & 0x0f) != 0x01));
258
259 if (dynamic) {
260 testedDynamic = true;
261
262 // block 0, UID is locked
263 {
264 QNearFieldTarget::RequestId id = target->readBlock(blockAddress: 0x00);
265 QVERIFY(target->waitForRequestCompleted(id));
266
267 const QByteArray block = target->requestResponse(id).toByteArray();
268
269 QCOMPARE(target->uid(), block.left(7));
270 QCOMPARE(quint8(block.at(7)), quint8(0x00));
271
272 id = target->writeBlock(blockAddress: 0x00, data: QByteArray(8, quint8(0x55)));
273 QVERIFY(target->waitForRequestCompleted(id));
274 QVERIFY(!target->requestResponse(id).isValid());
275
276 QCOMPARE(target->uid(), block.left(7));
277 QCOMPARE(quint8(block.at(7)), quint8(0x00));
278 }
279
280 // static data area
281 QNearFieldTarget::RequestId id = target->readSegment(segmentAddress: 0);
282 QVERIFY(target->waitForRequestCompleted(id));
283 QByteArray segment = target->requestResponse(id).toByteArray();
284 for (int i = 1; i < 0x0d; ++i) {
285 // Write 0x55
286 id = target->writeBlock(blockAddress: i, data: QByteArray(8, quint8(0x55)));
287 QVERIFY(target->waitForRequestCompleted(id));
288 QVERIFY(target->requestResponse(id).toBool());
289
290 id = target->readBlock(blockAddress: i);
291 QVERIFY(target->waitForRequestCompleted(id));
292 QCOMPARE(target->requestResponse(id).toByteArray(), QByteArray(8, quint8(0x55)));
293
294 segment.replace(index: i * 8, len: 8, s: QByteArray(8, quint8(0x55)));
295
296 id = target->readSegment(segmentAddress: 0);
297 QVERIFY(target->waitForRequestCompleted(id));
298 QCOMPARE(target->requestResponse(id).toByteArray(), segment);
299
300 // Write 0xaa
301 id = target->writeBlock(blockAddress: i, data: QByteArray(8, quint8(0xaa)));
302 QVERIFY(target->waitForRequestCompleted(id));
303 QVERIFY(target->requestResponse(id).toBool());
304
305 id = target->readBlock(blockAddress: i);
306 QVERIFY(target->waitForRequestCompleted(id));
307 QCOMPARE(target->requestResponse(id).toByteArray(), QByteArray(8, quint8(0xaa)));
308
309 segment.replace(index: i * 8, len: 8, s: QByteArray(8, quint8(0xaa)));
310
311 id = target->readSegment(segmentAddress: 0);
312 QVERIFY(target->waitForRequestCompleted(id));
313 QCOMPARE(target->requestResponse(id).toByteArray(), segment);
314
315 // Write 0x55 without erase, result should be 0xff
316 id = target->writeBlock(blockAddress: i, data: QByteArray(8, quint8(0x55)),
317 mode: QNearFieldTagType1::WriteOnly);
318 QVERIFY(target->waitForRequestCompleted(id));
319 QVERIFY(target->requestResponse(id).toBool());
320
321 id = target->readBlock(blockAddress: i);
322 QVERIFY(target->waitForRequestCompleted(id));
323 QCOMPARE(target->requestResponse(id).toByteArray(), QByteArray(8, quint8(0xff)));
324
325 segment.replace(index: i * 8, len: 8, s: QByteArray(8, quint8(0xff)));
326
327 id = target->readSegment(segmentAddress: 0);
328 QVERIFY(target->waitForRequestCompleted(id));
329 QCOMPARE(target->requestResponse(id).toByteArray(), segment);
330 }
331
332 // static / dynamic reserved lock area
333 for (int i = 0x0d; i < 0x10; ++i) {
334 id = target->readBlock(blockAddress: i);
335 QVERIFY(target->waitForRequestCompleted(id));
336 QByteArray block = target->requestResponse(id).toByteArray();
337
338 id = target->writeBlock(blockAddress: i, data: QByteArray(8, quint8(0x55)));
339 QVERIFY(target->waitForRequestCompleted(id));
340 QVERIFY(!target->requestResponse(id).isValid());
341
342 id = target->readBlock(blockAddress: i);
343 QVERIFY(target->waitForRequestCompleted(id));
344 QCOMPARE(target->requestResponse(id).toByteArray(), block);
345 }
346 } else {
347 testedStatic = true;
348
349 for (int i = 0; i < 256; ++i) {
350 QNearFieldTarget::RequestId id = target->readBlock(blockAddress: i);
351 QVERIFY(target->waitForRequestCompleted(id));
352 QVERIFY(!target->requestResponse(id).isValid());
353
354 id = target->writeBlock(blockAddress: i, data: QByteArray(8, quint8(0x55)));
355 QVERIFY(target->waitForRequestCompleted(id));
356 QVERIFY(!target->requestResponse(id).isValid());
357 }
358 for (int i = 0; i < 16; ++i) {
359 QNearFieldTarget::RequestId id = target->readSegment(segmentAddress: i);
360 QVERIFY(target->waitForRequestCompleted(id));
361 QVERIFY(!target->requestResponse(id).isValid());
362 }
363 }
364 }
365
366 QVERIFY(testedStatic);
367 QVERIFY(testedDynamic);
368}
369
370void tst_QNearFieldTagType1::ndefMessages()
371{
372 QByteArray firstId;
373 forever {
374 waitForMatchingTarget();
375
376 QNearFieldTarget::RequestId id = target->readIdentification();
377 QVERIFY(target->waitForRequestCompleted(id));
378
379 const QByteArray uid = target->requestResponse(id).toByteArray();
380 if (firstId.isEmpty())
381 firstId = uid;
382 else if (firstId == uid)
383 break;
384
385 QVERIFY(target->hasNdefMessage());
386
387 QSignalSpy ndefMessageReadSpy(target, SIGNAL(ndefMessageRead(QNdefMessage)));
388 QSignalSpy requestCompletedSpy(target,
389 SIGNAL(requestCompleted(QNearFieldTarget::RequestId)));
390 QSignalSpy errorSpy(target,
391 SIGNAL(error(QNearFieldTarget::Error,QNearFieldTarget::RequestId)));
392
393 QNearFieldTarget::RequestId readId = target->readNdefMessages();
394
395 QVERIFY(readId.isValid());
396
397 QNearFieldTarget::RequestId completedId;
398
399 while (completedId != readId) {
400 QTRY_VERIFY(!requestCompletedSpy.isEmpty() && errorSpy.isEmpty());
401
402 completedId =
403 requestCompletedSpy.takeFirst().first().value<QNearFieldTarget::RequestId>();
404 }
405
406 QList<QNdefMessage> ndefMessages;
407 for (int i = 0; i < ndefMessageReadSpy.count(); ++i)
408 ndefMessages.append(t: ndefMessageReadSpy.at(i).first().value<QNdefMessage>());
409
410 QList<QNdefMessage> messages;
411 QNdefNfcTextRecord textRecord;
412 textRecord.setText(QStringLiteral("tst_QNearFieldTagType1::ndefMessages"));
413
414 QNdefMessage message;
415 message.append(t: textRecord);
416
417 if (target->memorySize() > 120) {
418 QNdefRecord record;
419 record.setTypeNameFormat(QNdefRecord::ExternalRtd);
420 record.setType("org.qt-project:ndefMessagesTest");
421 record.setPayload(QByteArray(120, quint8(0x55)));
422 message.append(t: record);
423 }
424
425 messages.append(t: message);
426
427 requestCompletedSpy.clear();
428 errorSpy.clear();
429
430 QSignalSpy ndefMessageWriteSpy(target, SIGNAL(ndefMessagesWritten()));
431 QNearFieldTarget::RequestId writeId = target->writeNdefMessages(messages);
432
433 QVERIFY(writeId.isValid());
434
435 completedId = QNearFieldTarget::RequestId();
436
437 while (completedId != writeId) {
438 QTRY_VERIFY(!requestCompletedSpy.isEmpty() && errorSpy.isEmpty());
439
440 completedId =
441 requestCompletedSpy.takeFirst().first().value<QNearFieldTarget::RequestId>();
442 }
443
444 QVERIFY(!ndefMessageWriteSpy.isEmpty());
445
446 QVERIFY(target->hasNdefMessage());
447
448 ndefMessageReadSpy.clear();
449 requestCompletedSpy.clear();
450 errorSpy.clear();
451
452 readId = target->readNdefMessages();
453
454 QVERIFY(readId.isValid());
455
456 completedId = QNearFieldTarget::RequestId();
457
458 while (completedId != readId) {
459 QTRY_VERIFY(!requestCompletedSpy.isEmpty() && errorSpy.isEmpty());
460
461 completedId =
462 requestCompletedSpy.takeFirst().first().value<QNearFieldTarget::RequestId>();
463 }
464
465 QList<QNdefMessage> storedMessages;
466 for (int i = 0; i < ndefMessageReadSpy.count(); ++i)
467 storedMessages.append(t: ndefMessageReadSpy.at(i).first().value<QNdefMessage>());
468
469 QVERIFY(ndefMessages != storedMessages);
470
471 QCOMPARE(messages, storedMessages);
472 }
473}
474
475QTEST_MAIN(tst_QNearFieldTagType1)
476
477// Unset the moc namespace which is not required for the following include.
478#undef QT_BEGIN_MOC_NAMESPACE
479#define QT_BEGIN_MOC_NAMESPACE
480#undef QT_END_MOC_NAMESPACE
481#define QT_END_MOC_NAMESPACE
482
483#include "tst_qnearfieldtagtype1.moc"
484

source code of qtconnectivity/tests/auto/qnearfieldtagtype1/tst_qnearfieldtagtype1.cpp