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_emulator_p.h"
41#include "qnearfieldtarget_p.h"
42
43#include <QtCore/QByteArray>
44#include <QtCore/QCoreApplication>
45#include <QtCore/QDateTime>
46#include <QtCore/QDirIterator>
47#include <QtCore/QMutex>
48#include <QtCore/QSettings>
49
50QT_BEGIN_NAMESPACE
51
52static QMutex tagMutex;
53static QMap<TagBase *, bool> tagMap;
54
55Q_GLOBAL_STATIC(TagActivator, globalTagActivator);
56
57TagType1::TagType1(TagBase *tag, QObject *parent)
58: QNearFieldTagType1(parent), m_tag(tag)
59{
60}
61
62TagType1::~TagType1()
63{
64}
65
66QByteArray TagType1::uid() const
67{
68 QMutexLocker locker(&tagMutex);
69
70 return m_tag->uid();
71}
72
73QNearFieldTarget::AccessMethods TagType1::accessMethods() const
74{
75 return NdefAccess | TagTypeSpecificAccess;
76}
77
78QNearFieldTarget::RequestId TagType1::sendCommand(const QByteArray &command)
79{
80 QMutexLocker locker(&tagMutex);
81
82 RequestId id(new RequestIdPrivate);
83
84 // tag not in proximity
85 if (!tagMap.value(akey: m_tag)) {
86 reportError(error: QNearFieldTarget::TargetOutOfRangeError, id);
87 return id;
88 }
89
90 quint16 crc = qChecksum(s: command.constData(), len: command.length(), standard: Qt::ChecksumItuV41);
91
92 QByteArray response = m_tag->processCommand(command: command + char(crc & 0xff) + char(crc >> 8));
93
94 if (response.isEmpty()) {
95 reportError(error: QNearFieldTarget::NoResponseError, id);
96 return id;
97 }
98
99 // check crc
100 if (qChecksum(s: response.constData(), len: response.length(), standard: Qt::ChecksumItuV41) != 0) {
101 reportError(error: QNearFieldTarget::ChecksumMismatchError, id);
102 return id;
103 }
104
105 response.chop(n: 2);
106
107 QMetaObject::invokeMethod(obj: this, member: "handleResponse", type: Qt::QueuedConnection,
108 Q_ARG(QNearFieldTarget::RequestId, id), Q_ARG(QByteArray, response));
109
110 return id;
111}
112
113bool TagType1::waitForRequestCompleted(const RequestId &id, int msecs)
114{
115 QCoreApplication::sendPostedEvents(receiver: this, event_type: QEvent::MetaCall);
116
117 return QNearFieldTagType1::waitForRequestCompleted(id, msecs);
118}
119
120
121TagType2::TagType2(TagBase *tag, QObject *parent)
122: QNearFieldTagType2(parent), m_tag(tag)
123{
124}
125
126TagType2::~TagType2()
127{
128}
129
130QByteArray TagType2::uid() const
131{
132 QMutexLocker locker(&tagMutex);
133
134 return m_tag->uid();
135}
136
137QNearFieldTarget::AccessMethods TagType2::accessMethods() const
138{
139 return NdefAccess | TagTypeSpecificAccess;
140}
141
142QNearFieldTarget::RequestId TagType2::sendCommand(const QByteArray &command)
143{
144 QMutexLocker locker(&tagMutex);
145
146 RequestId id(new RequestIdPrivate);
147
148 // tag not in proximity
149 if (!tagMap.value(akey: m_tag)) {
150 reportError(error: QNearFieldTarget::TargetOutOfRangeError, id);
151 return id;
152 }
153
154 quint16 crc = qChecksum(s: command.constData(), len: command.length(), standard: Qt::ChecksumItuV41);
155
156 QByteArray response = m_tag->processCommand(command: command + char(crc & 0xff) + char(crc >> 8));
157
158 if (response.isEmpty())
159 return id;
160
161 if (response.length() > 1) {
162 // check crc
163 if (qChecksum(s: response.constData(), len: response.length(), standard: Qt::ChecksumItuV41) != 0) {
164 reportError(error: QNearFieldTarget::ChecksumMismatchError, id);
165 return id;
166 }
167
168 response.chop(n: 2);
169 }
170
171 QMetaObject::invokeMethod(obj: this, member: "handleResponse", type: Qt::QueuedConnection,
172 Q_ARG(QNearFieldTarget::RequestId, id), Q_ARG(QByteArray, response));
173
174 return id;
175}
176
177bool TagType2::waitForRequestCompleted(const RequestId &id, int msecs)
178{
179 QCoreApplication::sendPostedEvents(receiver: this, event_type: QEvent::MetaCall);
180
181 return QNearFieldTagType2::waitForRequestCompleted(id, msecs);
182}
183
184
185TagActivator::TagActivator()
186: timerId(-1)
187{
188 qRegisterMetaType<QNearFieldTarget::Error>();
189}
190
191TagActivator::~TagActivator()
192{
193 QMutexLocker locker(&tagMutex);
194 qDeleteAll(c: tagMap.keys());
195 tagMap.clear();
196}
197
198void TagActivator::initialize()
199{
200 QMutexLocker locker(&tagMutex);
201
202 if (!tagMap.isEmpty())
203 return;
204
205#ifndef BUILTIN_TESTDATA
206 QDirIterator nfcTargets(QDir::currentPath(), QStringList(QStringLiteral("*.nfc")), QDir::Files);
207#else
208 QDirIterator nfcTargets(":/nfcdata", QStringList(QStringLiteral("*.nfc")), QDir::Files);
209#endif
210 while (nfcTargets.hasNext()) {
211 const QString targetFilename = nfcTargets.next();
212
213 QSettings target(targetFilename, QSettings::IniFormat);
214
215 target.beginGroup(QStringLiteral("Target"));
216
217 const QString tagType = target.value(QStringLiteral("Type")).toString();
218
219 target.endGroup();
220
221 if (tagType == QLatin1String("TagType1")) {
222 NfcTagType1 *tag = new NfcTagType1;
223 tag->load(settings: &target);
224
225 tagMap.insert(akey: tag, avalue: false);
226 } else if (tagType == QLatin1String("TagType2")) {
227 NfcTagType2 *tag = new NfcTagType2;
228 tag->load(settings: &target);
229
230 tagMap.insert(akey: tag, avalue: false);
231 } else {
232 qWarning(msg: "Unknown tag type %s\n", qPrintable(tagType));
233 }
234 }
235
236 m_current = tagMap.end();
237
238 timerId = startTimer(interval: 1000);
239}
240
241void TagActivator::reset()
242{
243 QMutexLocker locker(&tagMutex);
244
245 killTimer(id: timerId);
246 timerId = -1;
247
248 qDeleteAll(c: tagMap.keys());
249 tagMap.clear();
250}
251
252TagActivator *TagActivator::instance()
253{
254 return globalTagActivator();
255}
256
257void TagActivator::timerEvent(QTimerEvent *e)
258{
259 Q_UNUSED(e);
260
261 tagMutex.lock();
262
263 if (m_current != tagMap.end()) {
264 if (m_current.key()->lastAccessTime() + 1500 > QDateTime::currentMSecsSinceEpoch()) {
265 tagMutex.unlock();
266 return;
267 }
268
269 *m_current = false;
270
271 TagBase *tag = m_current.key();
272
273 tagMutex.unlock();
274 emit tagDeactivated(tag);
275 tagMutex.lock();
276 }
277
278 if (m_current != tagMap.end())
279 ++m_current;
280
281 if (m_current == tagMap.end())
282 m_current = tagMap.begin();
283
284 if (m_current != tagMap.end()) {
285 *m_current = true;
286
287 TagBase *tag = m_current.key();
288
289 tagMutex.unlock();
290 emit tagActivated(tag);
291 tagMutex.lock();
292 }
293
294 tagMutex.unlock();
295}
296
297QT_END_NAMESPACE
298

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