diff options
author | Ivan Solovev <ivan.solovev@qt.io> | 2021-05-26 12:04:46 +0200 |
---|---|---|
committer | Ivan Solovev <ivan.solovev@qt.io> | 2021-05-27 16:56:15 +0200 |
commit | cda030a863aff344b4124f114da32e0c5cbc0640 (patch) | |
tree | 0b396b590baccf99e5a6acef9542627ddf63a456 /tests | |
parent | a1aa294733c91881aee0f4416a888d0d269cfcbd (diff) | |
download | qtconnectivity-cda030a863aff344b4124f114da32e0c5cbc0640.tar.gz |
QtNFC: refactor directory structure
A lot of test-related files were actually located in the src directory.
This patch moves them to tests/auto/nfccommons and adjusts the build
files accordingly.
Task-number: QTBUG-93854
Change-Id: I05641d849f4f07cd39d12ea136b4e7453d6aa883
Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
Diffstat (limited to 'tests')
18 files changed, 3095 insertions, 26 deletions
diff --git a/tests/auto/nfccommons/qnearfieldmanager_emulator.cpp b/tests/auto/nfccommons/qnearfieldmanager_emulator.cpp new file mode 100644 index 00000000..986658a6 --- /dev/null +++ b/tests/auto/nfccommons/qnearfieldmanager_emulator.cpp @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtNfc module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnearfieldmanager_emulator_p.h" +#include "qnearfieldtarget_emulator_p.h" + +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +QNearFieldManagerPrivateImpl::QNearFieldManagerPrivateImpl() +{ + TagActivator *activator = TagActivator::instance(); + activator->initialize(); + + connect(activator, &TagActivator::tagActivated, this, &QNearFieldManagerPrivateImpl::tagActivated); + connect(activator, &TagActivator::tagDeactivated, this, &QNearFieldManagerPrivateImpl::tagDeactivated); +} + +QNearFieldManagerPrivateImpl::~QNearFieldManagerPrivateImpl() +{ +} + +bool QNearFieldManagerPrivateImpl::isEnabled() const +{ + return true; +} + +bool QNearFieldManagerPrivateImpl::startTargetDetection(QNearFieldTarget::AccessMethod) +{ + return true; +} + +void QNearFieldManagerPrivateImpl::reset() +{ + TagActivator::instance()->reset(); +} + +void QNearFieldManagerPrivateImpl::tagActivated(TagBase *tag) +{ + QNearFieldTargetPrivate *target = targets.value(tag).data(); + if (!target) { + if (dynamic_cast<NfcTagType1 *>(tag)) + target = new TagType1(tag, this); + else if (dynamic_cast<NfcTagType2 *>(tag)) + target = new TagType2(tag, this); + else + qFatal("Unknown emulator tag type"); + + targets.insert(tag, target); + } + + Q_EMIT targetDetected(new NearFieldTarget(target, this)); +} + +void QNearFieldManagerPrivateImpl::tagDeactivated(TagBase *tag) +{ + QNearFieldTargetPrivate *target = targets.value(tag).data(); + if (!target) { + targets.remove(tag); + return; + } + + Q_EMIT targetLost(target->q_ptr); + QMetaObject::invokeMethod(target->q_ptr, &QNearFieldTarget::disconnected); +} + +QT_END_NAMESPACE diff --git a/tests/auto/nfccommons/qnearfieldmanager_emulator_p.h b/tests/auto/nfccommons/qnearfieldmanager_emulator_p.h new file mode 100644 index 00000000..50e23895 --- /dev/null +++ b/tests/auto/nfccommons/qnearfieldmanager_emulator_p.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtNfc module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNEARFIELDMANAGER_EMULATOR_H +#define QNEARFIELDMANAGER_EMULATOR_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtNfc/private/qnearfieldmanager_p.h> +#include <QtNfc/private/qnearfieldtarget_p.h> +#include <QtNfc/qndeffilter.h> + +#include <QtCore/QMetaMethod> +#include <QtCore/QObject> +#include <QtCore/QPointer> + +QT_BEGIN_NAMESPACE + +class TagBase; +class QNearFieldManagerPrivateImpl : public QNearFieldManagerPrivate +{ + Q_OBJECT + +public: + QNearFieldManagerPrivateImpl(); + ~QNearFieldManagerPrivateImpl() override; + + bool isEnabled() const override; + + bool startTargetDetection(QNearFieldTarget::AccessMethod accessMethod) override; + + void reset(); + +private slots: + void tagActivated(TagBase *tag); + void tagDeactivated(TagBase *tag); + +private: + QMap<TagBase *, QPointer<QNearFieldTargetPrivate> > targets; + +}; + +QT_END_NAMESPACE + +#endif // QNEARFIELDMANAGER_EMULATOR_H diff --git a/tests/auto/nfccommons/qnearfieldtagtype1.cpp b/tests/auto/nfccommons/qnearfieldtagtype1.cpp new file mode 100644 index 00000000..3d1a9b0d --- /dev/null +++ b/tests/auto/nfccommons/qnearfieldtagtype1.cpp @@ -0,0 +1,733 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtNfc module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnearfieldtagtype1_p.h" +#include "qtlv_p.h" + +#include <QtNfc/private/qnearfieldtarget_p.h> +#include <QtNfc/qndefmessage.h> + +#include <QtCore/QByteArray> +#include <QtCore/QVariant> + +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +/*! + \class QNearFieldTagType1 + \brief The QNearFieldTagType1 class provides an interface for communicating with an NFC Tag + Type 1 tag. + + \ingroup connectivity-nfc + \inmodule QtNfc + \internal +*/ + +/*! + \enum QNearFieldTagType1::WriteMode + \brief This enum describes the write modes that are supported. + + \value EraseAndWrite The memory is erased before the new value is written. + \value WriteOnly The memory is not erased before the new value is written. The effect of + this mode is that the final value store is the bitwise or of the data + to be written and the original data value. +*/ + +/*! + \fn Type QNearFieldTagType1::type() const + \reimp +*/ + +class QNearFieldTagType1Private +{ + Q_DECLARE_PUBLIC(QNearFieldTagType1) + +public: + QNearFieldTagType1Private(QNearFieldTagType1 *q) + : q_ptr(q), m_readNdefMessageState(NotReadingNdefMessage), + m_tlvReader(nullptr), + m_writeNdefMessageState(NotWritingNdefMessage), + m_tlvWriter(nullptr) + { } + + QNearFieldTagType1 *q_ptr; + + QMap<QNearFieldTarget::RequestId, QByteArray> m_pendingInternalCommands; + + enum ReadNdefMessageState { + NotReadingNdefMessage, + NdefReadCheckingIdentification, + NdefReadCheckingNdefMagicNumber, + NdefReadReadingTlv + }; + + void progressToNextNdefReadMessageState(); + ReadNdefMessageState m_readNdefMessageState; + QNearFieldTarget::RequestId m_readNdefRequestId; + + QTlvReader *m_tlvReader; + QNearFieldTarget::RequestId m_nextExpectedRequestId; + + enum WriteNdefMessageState { + NotWritingNdefMessage, + NdefWriteCheckingIdentification, + NdefWriteCheckingNdefMagicNumber, + NdefWriteReadingTlv, + NdefWriteWritingTlv, + NdefWriteWritingTlvFlush + }; + + void progressToNextNdefWriteMessageState(); + WriteNdefMessageState m_writeNdefMessageState; + QNearFieldTarget::RequestId m_writeNdefRequestId; + QList<QNdefMessage> m_ndefWriteMessages; + + QTlvWriter *m_tlvWriter; + + typedef QPair<quint8, QByteArray> Tlv; + QList<Tlv> m_tlvs; +}; + +void QNearFieldTagType1Private::progressToNextNdefReadMessageState() +{ + Q_Q(QNearFieldTagType1); + + switch (m_readNdefMessageState) { + case NotReadingNdefMessage: + m_readNdefMessageState = NdefReadCheckingIdentification; + m_nextExpectedRequestId = q->readIdentification(); + break; + case NdefReadCheckingIdentification: { + const QByteArray data = q->requestResponse(m_nextExpectedRequestId).toByteArray(); + + if (data.isEmpty()) { + m_readNdefMessageState = NotReadingNdefMessage; + m_nextExpectedRequestId = QNearFieldTarget::RequestId(); + Q_EMIT q->error(QNearFieldTarget::NdefReadError, m_readNdefRequestId); + m_readNdefRequestId = QNearFieldTarget::RequestId(); + break; + } + + quint8 hr0 = data.at(0); + + // Check if target is a NFC TagType1 tag + if (!(hr0 & 0x10)) { + m_readNdefMessageState = NotReadingNdefMessage; + m_nextExpectedRequestId = QNearFieldTarget::RequestId(); + Q_EMIT q->error(QNearFieldTarget::NdefReadError, m_readNdefRequestId); + m_readNdefRequestId = QNearFieldTarget::RequestId(); + break; + } + + m_readNdefMessageState = NdefReadCheckingNdefMagicNumber; + m_nextExpectedRequestId = q->readByte(8); + break; + } + case NdefReadCheckingNdefMagicNumber: { + quint8 ndefMagicNumber = q->requestResponse(m_nextExpectedRequestId).toUInt(); + m_nextExpectedRequestId = QNearFieldTarget::RequestId(); + + if (ndefMagicNumber != 0xe1) { + m_readNdefMessageState = NotReadingNdefMessage; + Q_EMIT q->error(QNearFieldTarget::NdefReadError, m_readNdefRequestId); + m_readNdefRequestId = QNearFieldTarget::RequestId(); + break; + } + + m_readNdefMessageState = NdefReadReadingTlv; + delete m_tlvReader; + m_tlvReader = new QTlvReader(q); + + Q_FALLTHROUGH(); // fall through + } + case NdefReadReadingTlv: + Q_ASSERT(m_tlvReader); + while (!m_tlvReader->atEnd()) { + if (!m_tlvReader->readNext()) + break; + + // NDEF Message TLV + if (m_tlvReader->tag() == 0x03) { + Q_Q(QNearFieldTagType1); + + Q_EMIT q->ndefMessageRead(QNdefMessage::fromByteArray(m_tlvReader->data())); + } + } + + m_nextExpectedRequestId = m_tlvReader->requestId(); + if (!m_nextExpectedRequestId.isValid()) { + delete m_tlvReader; + m_tlvReader = nullptr; + m_readNdefMessageState = NotReadingNdefMessage; + Q_EMIT q->requestCompleted(m_readNdefRequestId); + m_readNdefRequestId = QNearFieldTarget::RequestId(); + } + break; + } +} + +void QNearFieldTagType1Private::progressToNextNdefWriteMessageState() +{ + Q_Q(QNearFieldTagType1); + + switch (m_writeNdefMessageState) { + case NotWritingNdefMessage: + m_writeNdefMessageState = NdefWriteCheckingIdentification; + m_nextExpectedRequestId = q->readIdentification(); + break; + case NdefWriteCheckingIdentification: { + const QByteArray data = q->requestResponse(m_nextExpectedRequestId).toByteArray(); + + if (data.isEmpty()) { + m_writeNdefMessageState = NotWritingNdefMessage; + m_nextExpectedRequestId = QNearFieldTarget::RequestId(); + Q_EMIT q->error(QNearFieldTarget::NdefWriteError, m_writeNdefRequestId); + m_writeNdefRequestId = QNearFieldTarget::RequestId(); + break; + } + + quint8 hr0 = data.at(0); + + // Check if target is a NFC TagType1 tag + if (!(hr0 & 0x10)) { + m_writeNdefMessageState = NotWritingNdefMessage; + m_nextExpectedRequestId = QNearFieldTarget::RequestId(); + Q_EMIT q->error(QNearFieldTarget::NdefWriteError, m_writeNdefRequestId); + m_writeNdefRequestId = QNearFieldTarget::RequestId(); + break; + } + + m_writeNdefMessageState = NdefWriteCheckingNdefMagicNumber; + m_nextExpectedRequestId = q->readByte(8); + break; + } + case NdefWriteCheckingNdefMagicNumber: { + quint8 ndefMagicNumber = q->requestResponse(m_nextExpectedRequestId).toUInt(); + m_nextExpectedRequestId = QNearFieldTarget::RequestId(); + + if (ndefMagicNumber != 0xe1) { + m_writeNdefMessageState = NotWritingNdefMessage; + Q_EMIT q->error(QNearFieldTarget::NdefWriteError, m_writeNdefRequestId); + m_writeNdefRequestId = QNearFieldTarget::RequestId(); + break; + } + + m_writeNdefMessageState = NdefWriteReadingTlv; + delete m_tlvReader; + m_tlvReader = new QTlvReader(q); + + Q_FALLTHROUGH(); // fall through + } + case NdefWriteReadingTlv: + Q_ASSERT(m_tlvReader); + while (!m_tlvReader->atEnd()) { + if (!m_tlvReader->readNext()) + break; + + quint8 tag = m_tlvReader->tag(); + if (tag == 0x01 || tag == 0x02 || tag == 0xfd) + m_tlvs.append(qMakePair(tag, m_tlvReader->data())); + } + + m_nextExpectedRequestId = m_tlvReader->requestId(); + if (m_nextExpectedRequestId.isValid()) + break; + + delete m_tlvReader; + m_tlvReader = nullptr; + m_writeNdefMessageState = NdefWriteWritingTlv; + + // fall through + case NdefWriteWritingTlv: + delete m_tlvWriter; + m_tlvWriter = new QTlvWriter(q); + + // write old TLVs + for (const Tlv &tlv : qAsConst(m_tlvs)) + m_tlvWriter->writeTlv(tlv.first, tlv.second); + + // write new NDEF message TLVs + for (const QNdefMessage &message : qAsConst(m_ndefWriteMessages)) + m_tlvWriter->writeTlv(0x03, message.toByteArray()); + + // write terminator TLV + m_tlvWriter->writeTlv(0xfe); + + m_writeNdefMessageState = NdefWriteWritingTlvFlush; + + // fall through + case NdefWriteWritingTlvFlush: + // flush the writer + Q_ASSERT(m_tlvWriter); + if (m_tlvWriter->process(true)) { + m_nextExpectedRequestId = QNearFieldTarget::RequestId(); + m_writeNdefMessageState = NotWritingNdefMessage; + delete m_tlvWriter; + m_tlvWriter = nullptr; + Q_EMIT q->requestCompleted(m_writeNdefRequestId); + m_writeNdefRequestId = QNearFieldTarget::RequestId(); + } else { + m_nextExpectedRequestId = m_tlvWriter->requestId(); + if (!m_nextExpectedRequestId.isValid()) { + m_writeNdefMessageState = NotWritingNdefMessage; + delete m_tlvWriter; + m_tlvWriter = nullptr; + Q_EMIT q->error(QNearFieldTarget::NdefWriteError, m_writeNdefRequestId); + m_writeNdefRequestId = QNearFieldTarget::RequestId(); + } + } + break; + } +} + +static QVariant decodeResponse(const QByteArray &command, const QByteArray &response) +{ + switch (command.at(0)) { + case 0x01: // READ + if (command.at(1) == response.at(0)) + return quint8(response.at(1)); + break; + case 0x53: { // WRITE-E + quint8 address = command.at(1); + quint8 data = command.at(2); + quint8 writeAddress = response.at(0); + quint8 writeData = response.at(1); + + return ((writeAddress == address) && (writeData == data)); + } + case 0x1a: { // WRITE-NE + quint8 address = command.at(1); + quint8 data = command.at(2); + quint8 writeAddress = response.at(0); + quint8 writeData = response.at(1); + + return ((writeAddress == address) && ((writeData & data) == data)); + } + case 0x10: { // RSEG + quint8 segmentAddress = quint8(command.at(1)) >> 4; + quint8 readSegmentAddress = quint8(response.at(0)) >> 4; + if (readSegmentAddress == segmentAddress) + return response.mid(1); + break; + } + case 0x02: { // READ8 + quint8 blockAddress = command.at(1); + quint8 readBlockAddress = response.at(0); + if (readBlockAddress == blockAddress) + return response.mid(1); + break; + } + case 0x54: { // WRITE-E8 + quint8 blockAddress = command.at(1); + QByteArray data = command.mid(2, 8); + quint8 writeBlockAddress = response.at(0); + QByteArray writeData = response.mid(1); + + return ((writeBlockAddress == blockAddress) && (writeData == data)); + } + case 0x1b: { // WRITE-NE8 + quint8 blockAddress = command.at(1); + QByteArray data = command.mid(2, 8); + quint8 writeBlockAddress = response.at(0); + QByteArray writeData = response.mid(1); + + if (writeBlockAddress != blockAddress) + return false; + + for (int i = 0; i < writeData.length(); ++i) { + if ((writeData.at(i) & data.at(i)) != data.at(i)) + return false; + } + + return true; + } + } + + return QVariant(); +} + +/*! + Constructs a new tag type 1 near field target with \a parent. +*/ +QNearFieldTagType1::QNearFieldTagType1(QObject *parent) +: QNearFieldTargetPrivate(parent), d_ptr(new QNearFieldTagType1Private(this)) +{ +} + +/*! + Destroys the tag type 1 near field target. +*/ +QNearFieldTagType1::~QNearFieldTagType1() +{ + delete d_ptr; +} + +/*! + \reimp +*/ +bool QNearFieldTagType1::hasNdefMessage() +{ + QNearFieldTarget::RequestId id = readAll(); + if (!waitForRequestCompleted(id)) + return false; + + const QByteArray data = requestResponse(id).toByteArray(); + + if (data.isEmpty()) + return false; + + quint8 hr0 = data.at(0); + + // Check if target is a NFC TagType1 tag + if (!(hr0 & 0x10)) + return false; + + // Check if NDEF Message Magic number is present + quint8 nmn = data.at(10); + if (nmn != 0xe1) + return false; + + // Check if TLV contains NDEF Message + return true; +} + +/*! + \reimp +*/ +QNearFieldTarget::RequestId QNearFieldTagType1::readNdefMessages() +{ + Q_D(QNearFieldTagType1); + + d->m_readNdefRequestId = QNearFieldTarget::RequestId(new QNearFieldTarget::RequestIdPrivate); + + if (d->m_readNdefMessageState == QNearFieldTagType1Private::NotReadingNdefMessage) { + d->progressToNextNdefReadMessageState(); + } else { + reportError(QNearFieldTarget::NdefReadError, d->m_readNdefRequestId); + } + + return d->m_readNdefRequestId; +} + +/*! + \reimp +*/ +QNearFieldTarget::RequestId QNearFieldTagType1::writeNdefMessages(const QList<QNdefMessage> &messages) +{ + Q_D(QNearFieldTagType1); + + d->m_writeNdefRequestId = QNearFieldTarget::RequestId(new QNearFieldTarget::RequestIdPrivate); + + if (d->m_readNdefMessageState == QNearFieldTagType1Private::NotReadingNdefMessage && + d->m_writeNdefMessageState == QNearFieldTagType1Private::NotWritingNdefMessage) { + d->m_ndefWriteMessages = messages; + d->progressToNextNdefWriteMessageState(); + } else { + reportError(QNearFieldTarget::NdefWriteError, d->m_readNdefRequestId); + } + + return d->m_writeNdefRequestId; +} + +/*! + Returns the NFC Tag Type 1 specification version number that the tag supports. +*/ +quint8 QNearFieldTagType1::version() +{ + QNearFieldTarget::RequestId id = readByte(9); + if (!waitForRequestCompleted(id)) + return 0; + + quint8 versionNumber = requestResponse(id).toUInt(); + return versionNumber; +} + +/*! + Returns the memory size in bytes of the tag. +*/ +int QNearFieldTagType1::memorySize() +{ + QNearFieldTarget::RequestId id = readByte(10); + if (!waitForRequestCompleted(id)) + return 0; + + quint8 tms = requestResponse(id).toUInt(); + + return 8 * (tms + 1); +} + +/*! + Requests the identification bytes from the target. Returns a request id which can be used to + track the completion status of the request. + + Once the request completes successfully the response can be retrieved from the + requestResponse() function. The response of this request will be a QByteArray containing: HR0, + HR1, UID0, UID1, UID2 and UID3 in order. + + \sa requestCompleted(), waitForRequestCompleted() +*/ +QNearFieldTarget::RequestId QNearFieldTagType1::readIdentification() +{ + QByteArray command; + command.append(char(0x78)); // RID + command.append(char(0x00)); // Address (unused) + command.append(char(0x00)); // Data (unused) + command.append(uid().left(4)); // 4 bytes of UID + + return sendCommand(command); +} + +/*! + Requests all data in the static memory area of the target. Returns a request id which can be + used to track the completion status of the request. + + Once the request completes successfully the response can be retrieved from the + requestResponse() function. The response of this request will be a QByteArray containing: HR0 + and HR1 followed by the 120 bytes of data stored in the static memory area of the target. + + \sa requestCompleted(), waitForRequestCompleted() +*/ +QNearFieldTarget::RequestId QNearFieldTagType1::readAll() +{ + QByteArray command; + command.append(char(0x00)); // RALL + command.append(char(0x00)); // Address (unused) + command.append(char(0x00)); // Data (unused) + command.append(uid().left(4));// 4 bytes of UID + + return sendCommand(command); +} + +/*! + Requests a single byte from the static memory area of the tag. The \a address parameter + specifices the linear byte address to read. Returns a request id which can be used to track + the completion status of the request. + + Once the request completes successfully the response can be retrieved from the + requestResponse() function. The response of this request will be a quint8. + + \sa requestCompleted(), waitForRequestCompleted() +*/ +QNearFieldTarget::RequestId QNearFieldTagType1::readByte(quint8 address) +{ + if (address & 0x80) + return QNearFieldTarget::RequestId(); + + QByteArray command; + command.append(char(0x01)); // READ + command.append(char(address)); // Address + command.append(char(0x00)); // Data (unused) + command.append(uid().left(4)); // 4 bytes of UID + + QNearFieldTarget::RequestId id = sendCommand(command); + + Q_D(QNearFieldTagType1); + + d->m_pendingInternalCommands.insert(id, command); + + return id; +} + +/*! + Writes a single \a data byte to the linear byte \a address on the tag. If \a mode is + EraseAndWrite the byte will be erased before writing. If \a mode is WriteOnly the contents will + not be erased before writing. This is equivelant to writing the result of the bitwise OR of + \a data and the original value. + + Returns a request id which can be used to track the completion status of the request. + + Once the request completes the response can be retrieved from the requestResponse() function. + The response of this request will be a boolean value, true for success; otherwise false. + + \sa requestCompleted(), waitForRequestCompleted() +*/ +QNearFieldTarget::RequestId QNearFieldTagType1::writeByte(quint8 address, quint8 data, + WriteMode mode) +{ + if (address & 0x80) + return QNearFieldTarget::RequestId(); + + QByteArray command; + + if (mode == EraseAndWrite) + command.append(char(0x53)); // WRITE-E + else if (mode == WriteOnly) + command.append(char(0x1a)); // WRITE-NE + else + return QNearFieldTarget::RequestId(); + + command.append(char(address)); // Address + command.append(char(data)); // Data + command.append(uid().left(4)); // 4 bytes of UID + + QNearFieldTarget::RequestId id = sendCommand(command); + + Q_D(QNearFieldTagType1); + + d->m_pendingInternalCommands.insert(id, command); + + return id; +} + +/*! + Requests 128 bytes of data from the segment specified by \a segmentAddress. Returns a request + id which can be used to track the completion status of the request. + + Once the request completes successfully the response can be retrieved from the + requestResponse() function. The response of this request will be a QByteArray. + + \sa requestCompleted(), waitForRequestCompleted() +*/ +QNearFieldTarget::RequestId QNearFieldTagType1::readSegment(quint8 segmentAddress) +{ + if (segmentAddress & 0xf0) + return QNearFieldTarget::RequestId(); + + QByteArray command; + command.append(char(0x10)); // RSEG + command.append(char(segmentAddress << 4)); // Segment address + command.append(QByteArray(8, char(0x00))); // Data (unused) + command.append(uid().left(4)); // 4 bytes of UID + + QNearFieldTarget::RequestId id = sendCommand(command); + + Q_D(QNearFieldTagType1); + + d->m_pendingInternalCommands.insert(id, command); + + return id; +} + +/*! + Requests 8 bytes of data from the block specified by \a blockAddress. Returns a request id + which can be used to track the completion status of the request. + + Once the request completes successfully the response can be retrieved from the + requestResponse() function. The response of this request will be a QByteArray. + + \sa requestCompleted(), waitForRequestCompleted() +*/ +QNearFieldTarget::RequestId QNearFieldTagType1::readBlock(quint8 blockAddress) +{ + QByteArray command; + command.append(char(0x02)); // READ8 + command.append(char(blockAddress)); // Block address + command.append(QByteArray(8, char(0x00))); // Data (unused) + command.append(uid().left(4)); // 4 bytes of UID + + QNearFieldTarget::RequestId id = sendCommand(command); + + Q_D(QNearFieldTagType1); + + d->m_pendingInternalCommands.insert(id, command); + + return id; +} + +/*! + Writes 8 bytes of \a data to the block specified by \a blockAddress. If \a mode is + EraseAndWrite the bytes will be erased before writing. If \a mode is WriteOnly the contents + will not be erased before writing. This is equivelant to writing the result of the bitwise OR + of \a data and the original value. + + Returns a request id which can be used to track the completion status of the request. + + Once the request completes the response can be retrieved from the requestResponse() function. + The response of this request will be a boolean value, true for success; otherwise false. + + \sa requestCompleted(), waitForRequestCompleted() +*/ +QNearFieldTarget::RequestId QNearFieldTagType1::writeBlock(quint8 blockAddress, + const QByteArray &data, + WriteMode mode) +{ + if (data.length() != 8) + return QNearFieldTarget::RequestId(); + + QByteArray command; + + if (mode == EraseAndWrite) + command.append(char(0x54)); // WRITE-E8 + else if (mode == WriteOnly) + command.append(char(0x1b)); // WRITE-NE8 + else + return QNearFieldTarget::RequestId(); + + command.append(char(blockAddress)); // Block address + command.append(data); // Data + command.append(uid().left(4)); // 4 bytes of UID + + QNearFieldTarget::RequestId id = sendCommand(command); + + Q_D(QNearFieldTagType1); + + d->m_pendingInternalCommands.insert(id, command); + + return id; +} + +/*! + \reimp +*/ +void QNearFieldTagType1::setResponseForRequest(const QNearFieldTarget::RequestId &id, + const QVariant &response, + bool emitRequestCompleted) +{ + Q_D(QNearFieldTagType1); + + if (d->m_pendingInternalCommands.contains(id)) { + const QByteArray command = d->m_pendingInternalCommands.take(id); + + QVariant decodedResponse = decodeResponse(command, response.toByteArray()); + QNearFieldTargetPrivate::setResponseForRequest(id, decodedResponse, emitRequestCompleted); + } else { + QNearFieldTargetPrivate::setResponseForRequest(id, response, emitRequestCompleted); + } + + // continue reading / writing NDEF message + if (d->m_nextExpectedRequestId == id) { + if (d->m_readNdefMessageState != QNearFieldTagType1Private::NotReadingNdefMessage) + d->progressToNextNdefReadMessageState(); + else if (d->m_writeNdefMessageState != QNearFieldTagType1Private::NotWritingNdefMessage) + d->progressToNextNdefWriteMessageState(); + } +} + +QT_END_NAMESPACE diff --git a/tests/auto/nfccommons/qnearfieldtagtype1_p.h b/tests/auto/nfccommons/qnearfieldtagtype1_p.h new file mode 100644 index 00000000..3e170572 --- /dev/null +++ b/tests/auto/nfccommons/qnearfieldtagtype1_p.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtNfc module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNEARFIELDTAGTYPE1_H +#define QNEARFIELDTAGTYPE1_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtNfc/private/qnearfieldtarget_p.h> + +QT_BEGIN_NAMESPACE + +class QNearFieldTagType1Private; + +class QNearFieldTagType1 : public QNearFieldTargetPrivate +{ + Q_OBJECT + + Q_DECLARE_PRIVATE(QNearFieldTagType1) + +public: + enum WriteMode { + EraseAndWrite, + WriteOnly + }; + Q_ENUM(WriteMode) + + explicit QNearFieldTagType1(QObject *parent = nullptr); + ~QNearFieldTagType1(); + + QNearFieldTarget::Type type() const override { return QNearFieldTarget::NfcTagType1; } + + bool hasNdefMessage() override; + QNearFieldTarget::RequestId readNdefMessages() override; + QNearFieldTarget::RequestId writeNdefMessages(const QList<QNdefMessage> &messages) override; + + quint8 version(); + virtual int memorySize(); + + // DIGPROTO + virtual QNearFieldTarget::RequestId readIdentification(); + + // static memory functions + virtual QNearFieldTarget::RequestId readAll(); + virtual QNearFieldTarget::RequestId readByte(quint8 address); + virtual QNearFieldTarget::RequestId writeByte(quint8 address, quint8 data, WriteMode mode = EraseAndWrite); + + // dynamic memory functions + virtual QNearFieldTarget::RequestId readSegment(quint8 segmentAddress); + virtual QNearFieldTarget::RequestId readBlock(quint8 blockAddress); + virtual QNearFieldTarget::RequestId writeBlock(quint8 blockAddress, const QByteArray &data, + WriteMode mode = EraseAndWrite); + +protected: + void setResponseForRequest(const QNearFieldTarget::RequestId &id, const QVariant &response, bool emitRequestCompleted = true) override; + +private: + QNearFieldTagType1Private *d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QNEARFIELDTAGTYPE1_H diff --git a/tests/auto/nfccommons/qnearfieldtagtype2.cpp b/tests/auto/nfccommons/qnearfieldtagtype2.cpp new file mode 100644 index 00000000..02297892 --- /dev/null +++ b/tests/auto/nfccommons/qnearfieldtagtype2.cpp @@ -0,0 +1,328 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtNfc module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnearfieldtagtype2_p.h" +#include <QtNfc/private/qnearfieldtarget_p.h> + +#include <QtCore/QVariant> +#include <QtCore/QCoreApplication> +#include <QtCore/QTime> + +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +/*! + \class QNearFieldTagType2 + \brief The QNearFieldTagType2 class provides an interface for communicating with an NFC Tag + Type 2 tag. + + \ingroup connectivity-nfc + \inmodule QtNfc + \internal +*/ + +/*! + \fn Type QNearFieldTagType2::type() const + \reimp +*/ + +struct SectorSelectState { + int timerId; // id of timer used for passive ack + quint8 sector; // sector being selected +}; + +class QNearFieldTagType2Private +{ +public: + QNearFieldTagType2Private() : m_currentSector(0) { } + + QMap<QNearFieldTarget::RequestId, QByteArray> m_pendingInternalCommands; + + quint8 m_currentSector; + + QMap<QNearFieldTarget::RequestId, SectorSelectState> m_pendingSectorSelectCommands; +}; + +static QVariant decodeResponse(const QByteArray &command, const QByteArray &response) +{ + quint8 opcode = command.at(0); + + switch (opcode) { + case 0xa2: // WRITE + return quint8(response.at(0)) == 0x0a; + case 0xc2: // SECTOR SELECT (Command Packet 1) + return quint8(response.at(0)) == 0x0a; + } + + return QVariant(); +} + +/*! + Constructs a new tag type 2 near field target with \a parent. +*/ +QNearFieldTagType2::QNearFieldTagType2(QObject *parent) +: QNearFieldTargetPrivate(parent), d_ptr(new QNearFieldTagType2Private) +{ +} + +/*! + Destroys the tag type 2 near field target. +*/ +QNearFieldTagType2::~QNearFieldTagType2() +{ + delete d_ptr; +} + +/*! + \reimp +*/ +bool QNearFieldTagType2::hasNdefMessage() +{ + qWarning() << Q_FUNC_INFO << "is unimplemeted"; + return false; +} + +/*! + \reimp +*/ +QNearFieldTarget::RequestId QNearFieldTagType2::readNdefMessages() +{ + return QNearFieldTarget::RequestId(); +} + +/*! + \reimp +*/ +QNearFieldTarget::RequestId QNearFieldTagType2::writeNdefMessages(const QList<QNdefMessage> &messages) +{ + Q_UNUSED(messages); + + return QNearFieldTarget::RequestId(); +} + +/*! + Returns the NFC Tag Type 2 specification version number that the tag supports. +*/ +quint8 QNearFieldTagType2::version() +{ + Q_D(QNearFieldTagType2); + if (d->m_currentSector != 0) { + QNearFieldTarget::RequestId id = selectSector(0); + if (!waitForRequestCompleted(id)) + return 0; + } + + QNearFieldTarget::RequestId id = readBlock(0); + if (!waitForRequestCompleted(id)) + return 0; + + const QByteArray data = requestResponse(id).toByteArray(); + return data.at(13); +} + +/*! + Returns the memory size in bytes of the tag. +*/ +int QNearFieldTagType2::memorySize() +{ + Q_D(QNearFieldTagType2); + if (d->m_currentSector != 0) { + QNearFieldTarget::RequestId id = selectSector(0); + if (!waitForRequestCompleted(id)) + return 0; + } + + QNearFieldTarget::RequestId id = readBlock(0); + if (!waitForRequestCompleted(id)) + return 0; + + const QByteArray data = requestResponse(id).toByteArray(); + return 8 * quint8(data.at(14)); +} + +/*! + Requests 16 bytes of data starting at \a blockAddress. Returns a request id which can be used + to track the completion status of the request. + + Once the request completes successfully the response can be retrieved from the + requestResponse() function. The response of this request will be a QByteArray. + + \sa requestCompleted(), waitForRequestCompleted() +*/ +QNearFieldTarget::RequestId QNearFieldTagType2::readBlock(quint8 blockAddress) +{ + QByteArray command; + command.append(char(0x30)); // READ + command.append(char(blockAddress)); // Block address + + return sendCommand(command); +} + +/*! + Writes 4 bytes of \a data to the block at \a blockAddress. Returns a request id which can be + used to track the completion status of the request. + + Once the request completes the response can be retrieved from the requestResponse() function. + The response of this request will be a boolean value, true for success; otherwise false. + + Returns true on success; otherwise returns false. +*/ +QNearFieldTarget::RequestId QNearFieldTagType2::writeBlock(quint8 blockAddress, + const QByteArray &data) +{ + if (data.length() != 4) + return QNearFieldTarget::RequestId(); + + QByteArray command; + command.append(char(0xa2)); // WRITE + command.append(char(blockAddress)); // Block address + command.append(data); // Data + + QNearFieldTarget::RequestId id = sendCommand(command); + + Q_D(QNearFieldTagType2); + + d->m_pendingInternalCommands.insert(id, command); + + return id; +} + +/*! + Selects the \a sector upon which subsequent readBlock() and writeBlock() operations will act. + + Returns a request id which can be used to track the completion status of the request. + + Once the request completes the response can be retrieved from the requestResponse() function. + The response of this request will be a boolean value, true for success; otherwise false. + + \note this request has a passive acknowledgement mechanism. The operation is deemed successful + if no response is received within 1ms. It will therefore take a minimum of 1 millisecond for + the requestCompleted() signal to be emitted and calling waitForRequestCompleted() on the + returned request id may cause the current thread to block for up to 1 millisecond. +*/ +QNearFieldTarget::RequestId QNearFieldTagType2::selectSector(quint8 sector) +{ + QByteArray command; + command.append(char(0xc2)); // SECTOR SELECT (Command Packet 1) + command.append(char(0xff)); + + QNearFieldTarget::RequestId id = sendCommand(command); + + Q_D(QNearFieldTagType2); + + d->m_pendingInternalCommands.insert(id, command); + + SectorSelectState state; + state.timerId = -1; + state.sector = sector; + + d->m_pendingSectorSelectCommands.insert(id, state); + + return id; +} + +/*! + \reimp +*/ +void QNearFieldTagType2::setResponseForRequest(const QNearFieldTarget::RequestId &id, + const QVariant &response, + bool emitRequestCompleted) +{ + Q_D(QNearFieldTagType2); + + if (d->m_pendingInternalCommands.contains(id)) { + const QByteArray command = d->m_pendingInternalCommands.take(id); + + QVariant decodedResponse = decodeResponse(command, response.toByteArray()); + if (quint8(command.at(0)) == 0xc2 && decodedResponse.toBool()) { + // SECTOR SELECT (Command Packet 2) + SectorSelectState &state = d->m_pendingSectorSelectCommands[id]; + + QByteArray packet2; + packet2.append(char(state.sector)); + packet2.append(QByteArray(3, 0x00)); + + sendCommand(packet2); + + state.timerId = startTimer(1); + } else { + QNearFieldTargetPrivate::setResponseForRequest(id, decodedResponse, emitRequestCompleted); + } + + return; + } + + if (d->m_pendingSectorSelectCommands.contains(id)) { + if (!response.toByteArray().isEmpty()) { + d->m_pendingSectorSelectCommands.remove(id); + QNearFieldTargetPrivate::setResponseForRequest(id, false, emitRequestCompleted); + + return; + } + } + + QNearFieldTargetPrivate::setResponseForRequest(id, response, emitRequestCompleted); +} + +/*! + \internal +*/ +void QNearFieldTagType2::timerEvent(QTimerEvent *event) +{ + Q_D(QNearFieldTagType2); + + killTimer(event->timerId()); + + for (auto i = d->m_pendingSectorSelectCommands.begin(), end = d->m_pendingSectorSelectCommands.end(); i != end; ++i) { + + SectorSelectState &state = i.value(); + + if (state.timerId == event->timerId()) { + d->m_currentSector = state.sector; + + QNearFieldTargetPrivate::setResponseForRequest(i.key(), true); + + d->m_pendingSectorSelectCommands.erase(i); + break; + } + } +} + +QT_END_NAMESPACE diff --git a/tests/auto/nfccommons/qnearfieldtagtype2_p.h b/tests/auto/nfccommons/qnearfieldtagtype2_p.h new file mode 100644 index 00000000..5bc49158 --- /dev/null +++ b/tests/auto/nfccommons/qnearfieldtagtype2_p.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtNfc module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNEARFIELDTAGTYPE2_H +#define QNEARFIELDTAGTYPE2_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtNfc/private/qnearfieldtarget_p.h> + +QT_BEGIN_NAMESPACE + +class QNearFieldTagType2Private; + +class QNearFieldTagType2 : public QNearFieldTargetPrivate +{ + Q_OBJECT + + Q_DECLARE_PRIVATE(QNearFieldTagType2) + +public: + explicit QNearFieldTagType2(QObject *parent = nullptr); + ~QNearFieldTagType2(); + + QNearFieldTarget::Type type() const override { return QNearFieldTarget::NfcTagType2; } + + bool hasNdefMessage() override; + QNearFieldTarget::RequestId readNdefMessages() override; + QNearFieldTarget::RequestId writeNdefMessages(const QList<QNdefMessage> &messages) override; + + quint8 version(); + int memorySize(); + + virtual QNearFieldTarget::RequestId readBlock(quint8 blockAddress); + virtual QNearFieldTarget::RequestId writeBlock(quint8 blockAddress, const QByteArray &data); + virtual QNearFieldTarget::RequestId selectSector(quint8 sector); + + void timerEvent(QTimerEvent *event) override; + +protected: + void setResponseForRequest(const QNearFieldTarget::RequestId &id, const QVariant &response, bool emitRequestCompleted = true) override; + +private: + QNearFieldTagType2Private *d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QNEARFIELDTAGTYPE2_H diff --git a/tests/auto/nfccommons/qnearfieldtarget_emulator.cpp b/tests/auto/nfccommons/qnearfieldtarget_emulator.cpp new file mode 100644 index 00000000..8f969592 --- /dev/null +++ b/tests/auto/nfccommons/qnearfieldtarget_emulator.cpp @@ -0,0 +1,300 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtNfc module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnearfieldtarget_emulator_p.h" +#include <QtNfc/private/qnearfieldtarget_p.h> + +#include <QtCore/QByteArray> +#include <QtCore/QByteArrayView> +#include <QtCore/QCoreApplication> +#include <QtCore/QDateTime> +#include <QtCore/QDirIterator> +#include <QtCore/QMutex> +#include <QtCore/QSettings> + +QT_BEGIN_NAMESPACE + +static QMutex tagMutex; +static QMap<TagBase *, bool> tagMap; + +Q_GLOBAL_STATIC(TagActivator, globalTagActivator) + +TagType1::TagType1(TagBase *tag, QObject *parent) +: QNearFieldTagType1(parent), tag(tag) +{ +} + +TagType1::~TagType1() +{ +} + +QByteArray TagType1::uid() const +{ + QMutexLocker locker(&tagMutex); + + return tag->uid(); +} + +QNearFieldTarget::AccessMethods TagType1::accessMethods() const +{ + return QNearFieldTarget::NdefAccess | QNearFieldTarget::TagTypeSpecificAccess; +} + +QNearFieldTarget::RequestId TagType1::sendCommand(const QByteArray &command) +{ + QMutexLocker locker(&tagMutex); + + QNearFieldTarget::RequestId id(new QNearFieldTarget::RequestIdPrivate); + + // tag not in proximity + if (!tagMap.value(tag)) { + reportError(QNearFieldTarget::TargetOutOfRangeError, id); + return id; + } + + quint16 crc = qChecksum(QByteArrayView(command.constData(), command.length()), Qt::ChecksumItuV41); + + QByteArray response = tag->processCommand(command + char(crc & 0xff) + char(crc >> 8)); + + if (response.isEmpty()) { + reportError(QNearFieldTarget::NoResponseError, id); + return id; + } + + // check crc + if (qChecksum(QByteArrayView(response.constData(), response.length()), Qt::ChecksumItuV41) != 0) { + reportError(QNearFieldTarget::ChecksumMismatchError, id); + return id; + } + + response.chop(2); + + QMetaObject::invokeMethod(this, [this, id, response] { + this->setResponseForRequest(id, response); + }, Qt::QueuedConnection); + + return id; +} + +bool TagType1::waitForRequestCompleted(const QNearFieldTarget::RequestId &id, int msecs) +{ + QCoreApplication::sendPostedEvents(this, QEvent::MetaCall); + + return QNearFieldTagType1::waitForRequestCompleted(id, msecs); +} + + +TagType2::TagType2(TagBase *tag, QObject *parent) +: QNearFieldTagType2(parent), tag(tag) +{ +} + +TagType2::~TagType2() +{ +} + +QByteArray TagType2::uid() const +{ + QMutexLocker locker(&tagMutex); + + return tag->uid(); +} + +QNearFieldTarget::AccessMethods TagType2::accessMethods() const +{ + return QNearFieldTarget::NdefAccess | QNearFieldTarget::TagTypeSpecificAccess; +} + +QNearFieldTarget::RequestId TagType2::sendCommand(const QByteArray &command) +{ + QMutexLocker locker(&tagMutex); + + QNearFieldTarget::RequestId id(new QNearFieldTarget::RequestIdPrivate); + + // tag not in proximity + if (!tagMap.value(tag)) { + reportError(QNearFieldTarget::TargetOutOfRangeError, id); + return id; + } + + quint16 crc = qChecksum(QByteArrayView(command.constData(), command.length()), Qt::ChecksumItuV41); + + QByteArray response = tag->processCommand(command + char(crc & 0xff) + char(crc >> 8)); + + if (response.isEmpty()) + return id; + + if (response.length() > 1) { + // check crc + if (qChecksum(QByteArrayView(response.constData(), response.length()), Qt::ChecksumItuV41) != 0) { + reportError(QNearFieldTarget::ChecksumMismatchError, id); + return id; + } + + response.chop(2); + } + + QMetaObject::invokeMethod(this, [this, id, response] { + this->setResponseForRequest(id, response); + }, Qt::QueuedConnection); + + return id; +} + +bool TagType2::waitForRequestCompleted(const QNearFieldTarget::RequestId &id, int msecs) +{ + QCoreApplication::sendPostedEvents(this, QEvent::MetaCall); + + return QNearFieldTagType2::waitForRequestCompleted(id, msecs); +} + + +TagActivator::TagActivator() +: timerId(-1) +{ + qRegisterMetaType<QNearFieldTarget::Error>(); +} + +TagActivator::~TagActivator() +{ + QMutexLocker locker(&tagMutex); + qDeleteAll(tagMap.keys()); + tagMap.clear(); +} + +void TagActivator::initialize() +{ + QMutexLocker locker(&tagMutex); + + if (!tagMap.isEmpty()) + return; + +#ifndef BUILTIN_TESTDATA + QDirIterator nfcTargets(QDir::currentPath(), QStringList(QStringLiteral("*.nfc")), QDir::Files); +#else + QDirIterator nfcTargets(":/nfcdata", QStringList(QStringLiteral("*.nfc")), QDir::Files); +#endif + while (nfcTargets.hasNext()) { + const QString targetFilename = nfcTargets.next(); + + QSettings target(targetFilename, QSettings::IniFormat); + + target.beginGroup(QStringLiteral("Target")); + + const QString tagType = target.value(QStringLiteral("Type")).toString(); + + target.endGroup(); + + if (tagType == QLatin1String("TagType1")) { + NfcTagType1 *tag = new NfcTagType1; + tag->load(&target); + + tagMap.insert(tag, false); + } else if (tagType == QLatin1String("TagType2")) { + NfcTagType2 *tag = new NfcTagType2; + tag->load(&target); + + tagMap.insert(tag, false); + } else { + qWarning("Unknown tag type %s\n", qPrintable(tagType)); + } + } + + current = tagMap.end(); + + timerId = startTimer(1000); +} + +void TagActivator::reset() +{ + QMutexLocker locker(&tagMutex); + + killTimer(timerId); + timerId = -1; + + qDeleteAll(tagMap.keys()); + tagMap.clear(); +} + +TagActivator *TagActivator::instance() +{ + return globalTagActivator(); +} + +void TagActivator::timerEvent(QTimerEvent *e) +{ + Q_UNUSED(e); + + tagMutex.lock(); + + if (current != tagMap.end()) { + if (current.key()->lastAccessTime() + 1500 > QDateTime::currentMSecsSinceEpoch()) { + tagMutex.unlock(); + return; + } + + *current = false; + + TagBase *tag = current.key(); + + tagMutex.unlock(); + Q_EMIT tagDeactivated(tag); + tagMutex.lock(); + } + + if (current != tagMap.end()) + ++current; + + if (current == tagMap.end()) + current = tagMap.begin(); + + if (current != tagMap.end()) { + *current = true; + + TagBase *tag = current.key(); + + tagMutex.unlock(); + Q_EMIT tagActivated(tag); + tagMutex.lock(); + } + + tagMutex.unlock(); +} + +QT_END_NAMESPACE diff --git a/tests/auto/nfccommons/qnearfieldtarget_emulator_p.h b/tests/auto/nfccommons/qnearfieldtarget_emulator_p.h new file mode 100644 index 00000000..cb1e70a7 --- /dev/null +++ b/tests/auto/nfccommons/qnearfieldtarget_emulator_p.h @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtNfc module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNEARFIELDTARGET_EMULATOR_P_H +#define QNEARFIELDTARGET_EMULATOR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qnearfieldtagtype1_p.h" +#include "qnearfieldtagtype2_p.h" +#include "targetemulator_p.h" + +#include <QtCore/QMap> + +QT_BEGIN_NAMESPACE + +class TagType1 : public QNearFieldTagType1 +{ + Q_OBJECT + +public: + TagType1(TagBase *tag, QObject *parent = nullptr); + ~TagType1(); + + QByteArray uid() const override; + + QNearFieldTarget::AccessMethods accessMethods() const override; + + QNearFieldTarget::RequestId sendCommand(const QByteArray &command) override; + bool waitForRequestCompleted(const QNearFieldTarget::RequestId &id, int msecs); + +private: + TagBase *tag; +}; + +class TagType2 : public QNearFieldTagType2 +{ + Q_OBJECT + +public: + TagType2(TagBase *tag, QObject *parent = nullptr); + ~TagType2(); + + QByteArray uid() const override; + + QNearFieldTarget::AccessMethods accessMethods() const override; + + QNearFieldTarget::RequestId sendCommand(const QByteArray &command) override; + bool waitForRequestCompleted(const QNearFieldTarget::RequestId &id, int msecs); + +private: + TagBase *tag; +}; + +class TagActivator : public QObject +{ + Q_OBJECT + +public: + TagActivator(); + ~TagActivator(); + + void initialize(); + void reset(); + + static TagActivator *instance(); + +protected: + void timerEvent(QTimerEvent *e) override; + +signals: + void tagActivated(TagBase *tag); + void tagDeactivated(TagBase *tag); + +private: + QMap<TagBase *, bool>::Iterator current; + int timerId; +}; + +QT_END_NAMESPACE + +#endif // QNEARFIELDTARGET_EMULATOR_P_H diff --git a/tests/auto/nfccommons/qtlv.cpp b/tests/auto/nfccommons/qtlv.cpp new file mode 100644 index 00000000..03c3b022 --- /dev/null +++ b/tests/auto/nfccommons/qtlv.cpp @@ -0,0 +1,532 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtNfc module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtlv_p.h" + +#include "qnearfieldtagtype1_p.h" + +#include <QtCore/QVariant> + +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +QPair<int, int> qParseReservedMemoryControlTlv(const QByteArray &tlvData) +{ + quint8 position = tlvData.at(0); + int pageAddr = position >> 4; + int byteOffset = position & 0x0f; + + int size = quint8(tlvData.at(1)); + if (size == 0) + size = 256; + + quint8 pageControl = tlvData.at(2); + int bytesPerPage = pageControl & 0x0f; + + if (!bytesPerPage) + return qMakePair(0, 0); + + int byteAddress = pageAddr * (1 << bytesPerPage) + byteOffset; + return qMakePair(byteAddress, size); +} + +QPair<int, int> qParseLockControlTlv(const QByteArray &tlvData) +{ + quint8 position = tlvData.at(0); + int pageAddr = position >> 4; + int byteOffset = position & 0x0f; + + int size = quint8(tlvData.at(1)); + if (size == 0) + size = 256; + size = size / 8; + + quint8 pageControl = tlvData.at(2); + int bytesPerPage = pageControl & 0x0f; + + if (!bytesPerPage) + return qMakePair(0, 0); + + int byteAddress = pageAddr * (1 << bytesPerPage) + byteOffset; + return qMakePair(byteAddress, size); +} + +QTlvReader::QTlvReader(QNearFieldTargetPrivate *target) +: m_target(target), m_index(-1) +{ + if (qobject_cast<QNearFieldTagType1 *>(m_target)) { + addReservedMemory(0, 12); // skip uid, cc + addReservedMemory(104, 16); // skip reserved block D, lock block E + + addReservedMemory(120, 8); // skip reserved block F + } +} + +QTlvReader::QTlvReader(const QByteArray &data) +: m_target(0), m_rawData(data), m_index(-1) +{ +} + +void QTlvReader::addReservedMemory(int offset, int length) +{ + m_reservedMemory.insert(offset, length); +} + +/*! + Returns the number of bytes of reserved memory found so far. The actual number of reserved + bytes will not be known until atEnd() returns true. +*/ +int QTlvReader::reservedMemorySize() const +{ + int total = 0; + + QMap<int, int>::ConstIterator i; + for (i = m_reservedMemory.constBegin(); i != m_reservedMemory.constEnd(); ++i) + total += i.value(); + + return total; +} + +/*! + Returns the request id that the TLV reader is currently waiting on. +*/ +QNearFieldTarget::RequestId QTlvReader::requestId() const +{ + return m_requestId; +} + +bool QTlvReader::atEnd() const +{ + if (m_index == -1) + return false; + + if (m_requestId.isValid()) + return false; + + return (m_index == m_tlvData.length()) || (tag() == 0xfe); +} + +/*! + Moves to the next TLV. Returns true on success; otherwise returns false. +*/ +bool QTlvReader::readNext() +{ + if (atEnd()) + return false; + + // Move to next TLV + if (m_index == -1) { + m_index = 0; + } else if (m_requestId.isValid()) { + // do nothing + } else if (tag() == 0x00 || tag() == 0xfe) { + ++m_index; + } else { + int tlvLength = length(); + m_index += (tlvLength < 0xff) ? tlvLength + 2 : tlvLength + 4; + } + + // Ensure that tag byte is available + if (!readMoreData(m_index)) + return false; + + // Ensure that length byte(s) are available + if (length() == -1) + return false; + + // Ensure that data bytes are available + int tlvLength = length(); + + int dataOffset = (tlvLength < 0xff) ? m_index + 2 : m_index + 4; + + if (!readMoreData(dataOffset + tlvLength - 1)) + return false; + + switch (tag()) { + case 0x01: { // Lock Control TLV + QPair<int, int> locked = qParseLockControlTlv(data()); + addReservedMemory(locked.first, locked.second); + break; + } + case 0x02: { // Reserved Memory Control TLV + QPair<int, int> reserved = qParseReservedMemoryControlTlv(data()); + addReservedMemory(reserved.first, reserved.second); + break; + } + } + + return true; +} + +quint8 QTlvReader::tag() const +{ + return m_tlvData.at(m_index); +} + +int QTlvReader::length() +{ + if (tag() == 0x00 || tag() == 0xfe) + return 0; + + if (!readMoreData(m_index + 1)) + return -1; + + quint8 shortLength = m_tlvData.at(m_index + 1); + if (shortLength != 0xff) + return shortLength; + + if (!readMoreData(m_index + 3)) + return -1; + + quint16 longLength = (quint8(m_tlvData.at(m_index + 2)) << 8) | + quint8(m_tlvData.at(m_index + 3)); + + if (longLength < 0xff || longLength == 0xffff) { + qWarning("Invalid 3 byte length"); + return 0; + } + + return longLength; +} + +QByteArray QTlvReader::data() +{ + int tlvLength = length(); + + int dataOffset = (tlvLength < 0xff) ? m_index + 2 : m_index + 4; + + if (!readMoreData(dataOffset + tlvLength - 1)) + return QByteArray(); + + return m_tlvData.mid(dataOffset, tlvLength); +} + +bool QTlvReader::readMoreData(int sparseOffset) +{ + while (sparseOffset >= m_tlvData.length()) { + int absOffset = absoluteOffset(m_tlvData.length()); + + QByteArray data; + + if (!m_rawData.isEmpty()) { + data = m_rawData.mid(absOffset, dataLength(absOffset)); + } else if (QNearFieldTagType1 *tag = qobject_cast<QNearFieldTagType1 *>(m_target)) { + quint8 segment = absOffset / 128; + + if (m_requestId.isValid()) { + QVariant v = m_target->requestResponse(m_requestId); + if (!v.isValid()) + return false; + + m_requestId = QNearFieldTarget::RequestId(); + + data = v.toByteArray(); + + if (absOffset < 120) + data = data.mid(2); + + int length = dataLength(absOffset); + + data = data.mid(absOffset - (segment * 128), length); + } else { + m_requestId = (absOffset < 120) ? tag->readAll() : tag->readSegment(segment); + + return false; + } + } + + if (data.isEmpty() && sparseOffset >= m_tlvData.length()) + return false; + + m_tlvData.append(data); + } + + return true; +} + +int QTlvReader::absoluteOffset(int sparseOffset) const +{ + int absoluteOffset = sparseOffset; + const QList<int> offsets = m_reservedMemory.keys(); + for (const int offset : offsets) { + if (offset <= absoluteOffset) + absoluteOffset += m_reservedMemory.value(offset); + } + + return absoluteOffset; +} + +/*! + Returns the length of the contiguous non-reserved data block starting from absolute offset + \a startOffset. -1 is return as the length of the last contiguous data block. +*/ +int QTlvReader::dataLength(int startOffset) const +{ + const QList<int> offsets = m_reservedMemory.keys(); + for (const int offset : offsets) { + if (offset <= startOffset) + continue; + + return offset - startOffset; + } + + return -1; +} + + +QTlvWriter::QTlvWriter(QNearFieldTargetPrivate *target) +: m_target(target), m_rawData(0), m_index(0), m_tagMemorySize(-1) +{ + if (qobject_cast<QNearFieldTagType1 *>(m_target)) { + addReservedMemory(0, 12); // skip uid, cc + addReservedMemory(104, 16); // skip reserved block D, lock block E + + addReservedMemory(120, 8); // skip reserved block F + } +} + +QTlvWriter::QTlvWriter(QByteArray *data) +: m_target(0), m_rawData(data), m_index(0), m_tagMemorySize(-1) +{ +} + +QTlvWriter::~QTlvWriter() +{ + if (m_rawData) + process(true); +} + +void QTlvWriter::addReservedMemory(int offset, int length) +{ + m_reservedMemory.insert(offset, length); +} + +void QTlvWriter::writeTlv(quint8 tagType, const QByteArray &data) +{ + m_buffer.append(tagType); + + if (tagType != 0x00 && tagType != 0xfe) { + int length = data.length(); + if (length < 0xff) { + m_buffer.append(quint8(length)); + } else { + m_buffer.append(char(0xff)); + m_buffer.append(quint16(length) >> 8); + m_buffer.append(quint16(length) & 0x00ff); + } + + m_buffer.append(data); + } + + process(); + + switch (tagType) { + case 0x01: { // Lock Control TLV + QPair<int, int> locked = qParseLockControlTlv(data); + addReservedMemory(locked.first, locked.second); + break; + } + case 0x02: { // Reserved Memory Control TLV + QPair<int, int> reserved = qParseReservedMemoryControlTlv(data); + addReservedMemory(reserved.first, reserved.second); + break; + } + } +} + +/*! + Processes more of the TLV writer process. Returns true if the TLVs have been successfully + written to the target or buffer; otherwise returns false. + + A false return value indicates that an NFC request is pending (if requestId() returns a valid + request identifier) or the write process has failed (requestId() returns an invalid request + identifier). +*/ +bool QTlvWriter::process(bool all) +{ + if (m_requestId.isValid()) { + QVariant v = m_target->requestResponse(m_requestId); + if (!v.isValid()) + return false; + } + + if (m_tagMemorySize == -1) { + if (m_rawData) + m_tagMemorySize = m_rawData->length(); + else if (QNearFieldTagType1 *tag = qobject_cast<QNearFieldTagType1 *>(m_target)) { + if (m_requestId.isValid()) { + m_tagMemorySize = 8 * (tag->requestResponse(m_requestId).toUInt() + 1); + m_requestId = QNearFieldTarget::RequestId(); + } else { + m_requestId = tag->readByte(10); + return false; + } + } + } + + while (!m_buffer.isEmpty()) { + int spaceRemaining = moveToNextAvailable(); + if (spaceRemaining < 1) + return false; + + int length = qMin(spaceRemaining, m_buffer.length()); + + if (m_rawData) { + m_rawData->replace(m_index, length, m_buffer); + m_index += length; + m_buffer = m_buffer.mid(length); + } else if (QNearFieldTagType1 *tag = qobject_cast<QNearFieldTagType1 *>(m_target)) { + int bufferIndex = 0; + + // static memory - can only use writeByte() + while (m_index < 120 && bufferIndex < length) { + if (m_requestId.isValid()) { + if (!m_target->requestResponse(m_requestId).toBool()) + return false; + + m_requestId = QNearFieldTarget::RequestId(); + + ++m_index; + ++bufferIndex; + } else { + m_requestId = tag->writeByte(m_index, m_buffer.at(bufferIndex)); + m_buffer = m_buffer.mid(bufferIndex); + return false; + } + } + + + // dynamic memory - writeBlock() full + while (m_index >= 120 && (m_index % 8 == 0) && bufferIndex + 8 < length) { + if (m_requestId.isValid()) { + if (!m_target->requestResponse(m_requestId).toBool()) + return false; + + m_requestId = QNearFieldTarget::RequestId(); + + m_index += 8; + bufferIndex += 8; + } else { + m_requestId = tag->writeBlock(m_index / 8, m_buffer.mid(bufferIndex, 8)); + m_buffer = m_buffer.mid(bufferIndex); + return false; + } + } + + // partial block + int currentBlock = m_index / 8; + int nextBlock = currentBlock + 1; + int currentBlockStart = currentBlock * 8; + int nextBlockStart = nextBlock * 8; + + int fillLength = qMin(nextBlockStart - m_index, spaceRemaining - bufferIndex); + + if (fillLength && (all || m_buffer.length() - bufferIndex >= fillLength) && + (m_buffer.length() != bufferIndex)) { + // sufficient data available + if (m_requestId.isValid()) { + const QVariant v = tag->requestResponse(m_requestId); + if (v.typeId() == QMetaType::QByteArray) { + // read in block + QByteArray block = v.toByteArray(); + + int fill = qMin(fillLength, m_buffer.length() - bufferIndex); + + for (int i = m_index - currentBlockStart; i < fill; ++i) + block[i] = m_buffer.at(bufferIndex++); + + // now write block + m_requestId = tag->writeBlock(currentBlock, block); + return false; + } else if (v.typeId() == QMetaType::Bool) { + m_requestId = QNearFieldTarget::RequestId(); + int fill = qMin(fillLength, m_buffer.length() - bufferIndex); + bufferIndex = fill - (m_index - currentBlockStart); + + // write complete + if (!v.toBool()) + return false; + } + } else { + // read in block + m_requestId = tag->readBlock(currentBlock); + m_buffer = m_buffer.mid(bufferIndex); + return false; + } + } + + m_buffer = m_buffer.mid(bufferIndex); + } + } + + return true; +} + +QNearFieldTarget::RequestId QTlvWriter::requestId() const +{ + return m_requestId; +} + +int QTlvWriter::moveToNextAvailable() +{ + int length = -1; + + // move index to next available byte + QMap<int, int>::ConstIterator i; + for (i = m_reservedMemory.constBegin(); i != m_reservedMemory.constEnd(); ++i) { + if (m_index < i.key()) { + length = i.key() - m_index; + break; + } else if (m_index == i.key()) { + m_index += i.value(); + } else if (m_index > i.key() && m_index < (i.key() + i.value())) { + m_index = i.key() + i.value(); + } + } + + if (length == -1) + return m_tagMemorySize - m_index; + + Q_ASSERT(length != -1); + + return length; +} + +QT_END_NAMESPACE diff --git a/tests/auto/nfccommons/qtlv_p.h b/tests/auto/nfccommons/qtlv_p.h new file mode 100644 index 00000000..6c5e6bdd --- /dev/null +++ b/tests/auto/nfccommons/qtlv_p.h @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtNfc module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTLV_P_H +#define QTLV_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtNfc/qnearfieldtarget.h> +#include <QtNfc/private/qnearfieldtarget_p.h> + +#include <QtCore/QByteArray> +#include <QtCore/QMap> +#include <QtCore/QPair> + +QT_BEGIN_NAMESPACE + +class QNearFieldTarget; +class QTlvReader +{ +public: + explicit QTlvReader(QNearFieldTargetPrivate *target); + explicit QTlvReader(const QByteArray &data); + + void addReservedMemory(int offset, int length); + int reservedMemorySize() const; + + QNearFieldTarget::RequestId requestId() const; + + bool atEnd() const; + + bool readNext(); + + quint8 tag() const; + int length(); + QByteArray data(); + +private: + bool readMoreData(int sparseOffset); + int absoluteOffset(int sparseOffset) const; + int dataLength(int startOffset) const; + + QNearFieldTargetPrivate *m_target; + QByteArray m_rawData; + QNearFieldTarget::RequestId m_requestId; + + QByteArray m_tlvData; + int m_index; + QMap<int, int> m_reservedMemory; +}; + +class QTlvWriter +{ +public: + explicit QTlvWriter(QNearFieldTargetPrivate *target); + explicit QTlvWriter(QByteArray *data); + ~QTlvWriter(); + + void addReservedMemory(int offset, int length); + + void writeTlv(quint8 tag, const QByteArray &data = QByteArray()); + + bool process(bool all = false); + + QNearFieldTarget::RequestId requestId() const; + +private: + int moveToNextAvailable(); + + QNearFieldTargetPrivate *m_target; + QByteArray *m_rawData; + + int m_index; + int m_tagMemorySize; + QMap<int, int> m_reservedMemory; + + QByteArray m_buffer; + + QNearFieldTarget::RequestId m_requestId; +}; + +QPair<int, int> qParseReservedMemoryControlTlv(const QByteArray &tlvData); +QPair<int, int> qParseLockControlTlv(const QByteArray &tlvData); + +QT_END_NAMESPACE + +#endif // QTLV_P_H diff --git a/tests/auto/nfccommons/targetemulator.cpp b/tests/auto/nfccommons/targetemulator.cpp new file mode 100644 index 00000000..697fec4b --- /dev/null +++ b/tests/auto/nfccommons/targetemulator.cpp @@ -0,0 +1,389 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtNfc module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "targetemulator_p.h" + +#include <QtCore/QSettings> +#include <QtCore/QDateTime> + +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +TagBase::TagBase() +: lastAccess(0) +{ +} + +TagBase::~TagBase() +{ +} + +static inline quint8 blockByteToAddress(quint8 block, quint8 byte) +{ + return ((block & 0x0f) << 3) | (byte & 0x07); +} + +NfcTagType1::NfcTagType1() +: hr0(0x11), hr1(0x00), memory(120, '\0') +{ + // Locked blocks + memory[(0x0e << 3) | 0x00] = 0x01; + memory[(0x0e << 3) | 0x01] = 0x60; +} + +NfcTagType1::~NfcTagType1() +{ +} + +void NfcTagType1::load(QSettings *settings) +{ + settings->beginGroup(QStringLiteral("TagType1")); + + hr0 = settings->value(QStringLiteral("HR0"), 0x11).toUInt(); + + if (!(hr0 & 0x10)) { + settings->endGroup(); + return; + } + + hr1 = settings->value(QStringLiteral("HR1"), 0x00).toUInt(); + + memory = settings->value(QStringLiteral("Data")).toByteArray(); + + //quint8 nmn = memory.at(8); + + quint8 vno = memory.at(9); + if (vno != 0x10) + qWarning("Only NFC TagType1 v1.0 behavior is supported."); + + quint8 tms = memory.at(10); + if (memory.length() != 8 * (tms + 1)) + qWarning("Static memory size does not match TMS value."); + + quint8 rwa = memory.at(11); + switch (rwa >> 4) { + case 0: + // Unrestricted read access tag + break; + default: + // tag with unknown read attributes + ; + } + + switch (rwa & 0x0f) { + case 0: + // Unrestricted write access tag + break; + case 0x0f: + // Read only tag + break; + default: + // tag with unknown write attributes + ; + } + + //quint16 lock = (quint8(memory[blockByteToAddress(0x0e, 1)]) << 8) | + // quint8(memory[blockByteToAddress(0x0e, 0)]); + + settings->endGroup(); +} + +QByteArray NfcTagType1::uid() const +{ + lastAccess = QDateTime::currentMSecsSinceEpoch(); + + return memory.left(7); +} + +quint8 NfcTagType1::readData(quint8 block, quint8 byte) +{ + return memory.at((block << 3) | byte); +} + +QByteArray NfcTagType1::processCommand(const QByteArray &command) +{ + lastAccess = QDateTime::currentMSecsSinceEpoch(); + + QByteArray response; + + bool tagType1 = (hr0 & 0xf0) == 0x10; + bool dynamic = (hr0 & 0x0f) != 0x01; + + if (command.length() == 9) { + // static memory model command + quint8 opcode = command.at(0); + quint8 address = command.at(1); + quint8 data = command.at(2); + QByteArray uid = command.mid(3, 4); + + // check checksum + if (qChecksum(QByteArrayView(command.constData(), command.length()), Qt::ChecksumItuV41) != 0) + return QByteArray(); + + // check UID + if (uid != memory.left(4)) + return QByteArray(); + + switch (opcode) { + case 0x00: // RALL + response.append(hr0); + response.append(hr1); + response.append(memory.left(120)); + break; + case 0x01: // READ + response.append(address); + if (address & 0x80) + response.append(char(0x00)); + else + response.append(memory.at(address)); + break; + case 0x53: { // WRITE-E + quint8 block = address >> 3; + if (block == 0x00 || block == 0x0d || block == 0x0e) // locked blocks + break; + + quint16 lock = (readData(0x0e, 0x01) << 8) | readData(0x0e, 0x00); + if ((0x01 << block) & lock) // locked blocks + break; + + // FIXME: Test dynamic lock bytes + + memory[address] = data; + + response.append(address); + response.append(data); + break; + } + case 0x1a: { // WRITE-NE + quint8 block = address >> 3; + if (block == 0x00 || block == 0x0d) // locked blocks + break; + + quint16 lock = (readData(0x0e, 0x01) << 8) | readData(0x0e, 0x00); + if ((0x01 << block) & lock) // locked blocks + break; + + + // FIXME: Test dynamic lock bytes + + memory[address] = memory.at(address) | data; + + response.append(address); + response.append(memory.at(address)); + break; + } + case 0x78: // RID + response.append(hr0); + response.append(hr1); + response.append(memory.left(4)); + break; + } + } else if (tagType1 && dynamic && command.length() == 16) { + // dynamic memory model command + quint8 opcode = command.at(0); + quint8 address = command.at(1); + QByteArray data = command.mid(2, 8); + QByteArray uid = command.mid(10, 4); + + // check checksum + if (qChecksum(QByteArrayView(command.constData(), command.length()), Qt::ChecksumItuV41) != 0) + return QByteArray(); + + // check UID + if (uid != memory.left(4)) + return QByteArray(); + + switch (opcode) { + case 0x10: // RSEG + response.append(address); + response.append(memory.mid(128 * (address >> 4), 128)); + break; + case 0x02: // READ8 + response.append(address); + response.append(memory.mid(8 * address, 8)); + break; + case 0x54: { // WRITE-E8 + // locked blocks + if (address == 0x00 || address == 0x0d || address == 0x0e || address == 0x0f) + break; + + quint16 lock = (readData(0x0e, 0x01) << 8) | readData(0x0e, 0x00); + if (address <= 0x0e && ((0x01 << address) & lock)) // locked blocks + break; + + // FIXME: Test dynamic lock bytes + + memory.replace(address * 8, 8, data); + + response.append(address); + response.append(memory.mid(address * 8, 8)); + break; + } + case 0x1b: // WRITE-NE8 + // locked blocks + if (address == 0x00 || address == 0x0d || address == 0x0e || address == 0x0f) + break; + + quint16 lock = (readData(0x0e, 0x01) << 8) | readData(0x0e, 0x00); + if (address <= 0x0e && ((0x01 << address) & lock)) // locked blocks + break; + + // FIXME: Test dynamic lock bytes + + for (int i = 0; i < 8; ++i) + memory[address * 8 + i] = memory.at(address * 8 + i) | data.at(i); + + response.append(address); + response.append(memory.mid(address * 8, 8)); + break; + } + } + + if (!response.isEmpty()) { + quint16 crc = qChecksum(QByteArrayView(response.constData(), response.length()), Qt::ChecksumItuV41); + response.append(quint8(crc & 0xff)); + response.append(quint8(crc >> 8)); + } + + return response; +} + + +NfcTagType2::NfcTagType2() +: memory(64, 0x00), currentSector(0), expectPacket2(false) +{ +} + +NfcTagType2::~NfcTagType2() +{ +} + +void NfcTagType2::load(QSettings *settings) +{ + settings->beginGroup(QStringLiteral("TagType2")); + + memory = settings->value(QStringLiteral("Data")).toByteArray(); + + settings->endGroup(); +} + +QByteArray NfcTagType2::uid() const +{ + lastAccess = QDateTime::currentMSecsSinceEpoch(); + + return memory.left(3) + memory.mid(4, 4); +} + +#define NACK QByteArray("\x05") +#define ACK QByteArray("\x0a") + +QByteArray NfcTagType2::processCommand(const QByteArray &command) +{ + lastAccess = QDateTime::currentMSecsSinceEpoch(); + + QByteArray response; + + // check checksum + if (qChecksum(QByteArrayView(command.constData(), command.length()), Qt::ChecksumItuV41) != 0) + return QByteArray(); + + if (expectPacket2) { + expectPacket2 = false; + quint8 sector = command.at(0); + if (sector * 1024 > memory.length()) + return NACK; + else { + currentSector = sector; + return QByteArray(); + } + } + + quint8 opcode = command.at(0); + + switch (opcode) { + case 0x30: { // READ BLOCK + quint8 block = command.at(1); + int absoluteBlock = currentSector * 256 + block; + + response.append(memory.mid(absoluteBlock * 4, 16)); + if (response.length() != 16) + response.append(QByteArray(16 - response.length(), '\0')); + + break; + } + case 0xa2: { // WRITE BLOCK + quint8 block = command.at(1); + int absoluteBlock = currentSector * 256 + block; + + // locked blocks + if (absoluteBlock == 0 || absoluteBlock == 1) + return NACK; + + const QByteArray data = command.mid(2, 4); + + memory.replace(absoluteBlock * 4, 4, data); + + return ACK; + } + case 0xc2: // SECTOR SELECT - Packet 1 + if (memory.length() > 1024) { + expectPacket2 = true; + return ACK; + } + + return NACK; + default: + qDebug() << "Unknown opcode for Tag Type 2" << Qt::hex << opcode; + qDebug() << "command:" << command.toHex(); + + return NACK; + ; + } + + if (!response.isEmpty()) { + quint16 crc = qChecksum(QByteArrayView(response.constData(), response.length()), Qt::ChecksumItuV41); + response.append(quint8(crc & 0xff)); + response.append(quint8(crc >> 8)); + } + + return response; +} + +QT_END_NAMESPACE diff --git a/tests/auto/nfccommons/targetemulator_p.h b/tests/auto/nfccommons/targetemulator_p.h new file mode 100644 index 00000000..cd35e036 --- /dev/null +++ b/tests/auto/nfccommons/targetemulator_p.h @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtNfc module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TARGETEMULATOR_P_H +#define TARGETEMULATOR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/QtGlobal> +#include <QtCore/QByteArray> +#include <QtNfc/qtnfcglobal.h> +#include <QMetaType> + +QT_FORWARD_DECLARE_CLASS(QSettings) + +QT_BEGIN_NAMESPACE + +class TagBase +{ +public: + TagBase(); + virtual ~TagBase(); + + virtual void load(QSettings *settings) = 0; + + virtual QByteArray processCommand(const QByteArray &command) = 0; + + virtual QByteArray uid() const = 0; + + qint64 lastAccessTime() const { return lastAccess; } + +protected: + mutable qint64 lastAccess; +}; + +class NfcTagType1 : public TagBase +{ +public: + NfcTagType1(); + ~NfcTagType1(); + + void load(QSettings *settings) override; + + QByteArray processCommand(const QByteArray &command) override; + + QByteArray uid() const override; + +private: + quint8 readData(quint8 block, quint8 byte); + + quint8 hr0; + quint8 hr1; + + QByteArray memory; +}; + +class NfcTagType2 : public TagBase +{ +public: + NfcTagType2(); + ~NfcTagType2(); + + void load(QSettings *settings) override; + + QByteArray processCommand(const QByteArray &command) override; + + QByteArray uid() const override; + +private: + QByteArray memory; + quint8 currentSector; + bool expectPacket2; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(TagBase *) + +#endif // TARGETEMULATOR_P_H diff --git a/tests/auto/qnearfieldmanager/CMakeLists.txt b/tests/auto/qnearfieldmanager/CMakeLists.txt index 14bb41f2..af94db09 100644 --- a/tests/auto/qnearfieldmanager/CMakeLists.txt +++ b/tests/auto/qnearfieldmanager/CMakeLists.txt @@ -12,14 +12,17 @@ list(APPEND test_data "../nfcdata/Qt Website Tag Type1.nfc") qt_internal_add_test(tst_qnearfieldmanager SOURCES - ../../../src/nfc/qnearfieldmanager_emulator.cpp ../../../src/nfc/qnearfieldmanager_emulator_p.h - ../../../src/nfc/qnearfieldtarget_emulator.cpp ../../../src/nfc/qnearfieldtarget_emulator_p.h - ../../../src/nfc/targetemulator.cpp ../../../src/nfc/targetemulator_p.h + ../nfccommons/qnearfieldmanager_emulator.cpp ../nfccommons/qnearfieldmanager_emulator_p.h + ../nfccommons/qnearfieldtarget_emulator.cpp ../nfccommons/qnearfieldtarget_emulator_p.h + ../nfccommons/targetemulator.cpp ../nfccommons/targetemulator_p.h + ../nfccommons/qnearfieldtagtype1.cpp ../nfccommons/qnearfieldtagtype1_p.h + ../nfccommons/qnearfieldtagtype2.cpp ../nfccommons/qnearfieldtagtype2_p.h + ../nfccommons/qtlv.cpp ../nfccommons/qtlv_p.h tst_qnearfieldmanager.cpp DEFINES SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../nfcdata\\\" INCLUDE_DIRECTORIES - ../../../src/nfc + ../nfccommons PUBLIC_LIBRARIES Qt::NfcPrivate TESTDATA ${test_data} diff --git a/tests/auto/qnearfieldmanager/tst_qnearfieldmanager.cpp b/tests/auto/qnearfieldmanager/tst_qnearfieldmanager.cpp index ce8224ef..09bda66a 100644 --- a/tests/auto/qnearfieldmanager/tst_qnearfieldmanager.cpp +++ b/tests/auto/qnearfieldmanager/tst_qnearfieldmanager.cpp @@ -28,12 +28,12 @@ #include <QtTest/QtTest> -#include <private/qnearfieldmanager_emulator_p.h> -#include <qnearfieldmanager.h> -#include <qndefnfctextrecord.h> -#include <qndefnfcurirecord.h> -#include <qndefmessage.h> -#include <qndefrecord.h> +#include <qnearfieldmanager_emulator_p.h> +#include <QtNfc/qnearfieldmanager.h> +#include <QtNfc/qndefnfctextrecord.h> +#include <QtNfc/qndefnfcurirecord.h> +#include <QtNfc/qndefmessage.h> +#include <QtNfc/qndefrecord.h> QT_USE_NAMESPACE diff --git a/tests/auto/qnearfieldtagtype1/CMakeLists.txt b/tests/auto/qnearfieldtagtype1/CMakeLists.txt index 00254f70..744a9504 100644 --- a/tests/auto/qnearfieldtagtype1/CMakeLists.txt +++ b/tests/auto/qnearfieldtagtype1/CMakeLists.txt @@ -12,14 +12,16 @@ list(APPEND test_data "../nfcdata/Qt Website Tag Type1.nfc") qt_internal_add_test(tst_qnearfieldtagtype1 SOURCES - ../../../src/nfc/qnearfieldmanager_emulator.cpp ../../../src/nfc/qnearfieldmanager_emulator_p.h - ../../../src/nfc/qnearfieldtarget_emulator.cpp ../../../src/nfc/qnearfieldtarget_emulator_p.h - ../../../src/nfc/targetemulator.cpp ../../../src/nfc/targetemulator_p.h + ../nfccommons/qnearfieldtarget_emulator.cpp ../nfccommons/qnearfieldtarget_emulator_p.h + ../nfccommons/targetemulator.cpp ../nfccommons/targetemulator_p.h + ../nfccommons/qnearfieldtagtype1.cpp ../nfccommons/qnearfieldtagtype1_p.h + ../nfccommons/qnearfieldtagtype2.cpp ../nfccommons/qnearfieldtagtype2_p.h + ../nfccommons/qtlv.cpp ../nfccommons/qtlv_p.h tst_qnearfieldtagtype1.cpp DEFINES SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../nfcdata\\\" INCLUDE_DIRECTORIES - ../../../src/nfc + ../nfccommons PUBLIC_LIBRARIES Qt::NfcPrivate TESTDATA ${test_data} diff --git a/tests/auto/qnearfieldtagtype1/tst_qnearfieldtagtype1.cpp b/tests/auto/qnearfieldtagtype1/tst_qnearfieldtagtype1.cpp index 42a62b7a..1fff7574 100644 --- a/tests/auto/qnearfieldtagtype1/tst_qnearfieldtagtype1.cpp +++ b/tests/auto/qnearfieldtagtype1/tst_qnearfieldtagtype1.cpp @@ -28,10 +28,11 @@ #include <QtTest/QtTest> -#include <private/qnearfieldtarget_emulator_p.h> -#include <qndefmessage.h> -#include <private/qnearfieldtagtype1_p.h> -#include <qndefnfctextrecord.h> +#include <qnearfieldtarget_emulator_p.h> +#include <qnearfieldtagtype1_p.h> + +#include <QtNfc/qndefmessage.h> +#include <QtNfc/qndefnfctextrecord.h> QT_USE_NAMESPACE diff --git a/tests/auto/qnearfieldtagtype2/CMakeLists.txt b/tests/auto/qnearfieldtagtype2/CMakeLists.txt index c07238ef..63f28de7 100644 --- a/tests/auto/qnearfieldtagtype2/CMakeLists.txt +++ b/tests/auto/qnearfieldtagtype2/CMakeLists.txt @@ -12,14 +12,16 @@ list(APPEND test_data "nfcdata/Empty Tag.nfc") qt_internal_add_test(tst_qnearfieldtagtype2 SOURCES - ../../../src/nfc/qnearfieldmanager_emulator.cpp ../../../src/nfc/qnearfieldmanager_emulator_p.h - ../../../src/nfc/qnearfieldtarget_emulator.cpp ../../../src/nfc/qnearfieldtarget_emulator_p.h - ../../../src/nfc/targetemulator.cpp ../../../src/nfc/targetemulator_p.h + ../nfccommons/qnearfieldtarget_emulator.cpp ../nfccommons/qnearfieldtarget_emulator_p.h + ../nfccommons/targetemulator.cpp ../nfccommons/targetemulator_p.h + ../nfccommons/qnearfieldtagtype1.cpp ../nfccommons/qnearfieldtagtype1_p.h + ../nfccommons/qnearfieldtagtype2.cpp ../nfccommons/qnearfieldtagtype2_p.h + ../nfccommons/qtlv.cpp ../nfccommons/qtlv_p.h tst_qnearfieldtagtype2.cpp DEFINES SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/nfcdata\\\" INCLUDE_DIRECTORIES - ../../../src/nfc + ../nfccommons PUBLIC_LIBRARIES Qt::NfcPrivate TESTDATA ${test_data} diff --git a/tests/auto/qnearfieldtagtype2/tst_qnearfieldtagtype2.cpp b/tests/auto/qnearfieldtagtype2/tst_qnearfieldtagtype2.cpp index 4ea9bc42..2147763c 100644 --- a/tests/auto/qnearfieldtagtype2/tst_qnearfieldtagtype2.cpp +++ b/tests/auto/qnearfieldtagtype2/tst_qnearfieldtagtype2.cpp @@ -28,10 +28,10 @@ #include <QtTest/QtTest> -#include <private/qnearfieldtarget_emulator_p.h> -#include <qndefmessage.h> -#include <private/qnearfieldtagtype2_p.h> -#include <qndefnfctextrecord.h> +#include <qnearfieldtarget_emulator_p.h> +#include <qnearfieldtagtype2_p.h> +#include <QtNfc/qndefmessage.h> +#include <QtNfc/qndefnfctextrecord.h> QT_USE_NAMESPACE |