summaryrefslogtreecommitdiffstats
path: root/src/nfc/qnearfieldtagtype2.cpp
diff options
context:
space:
mode:
authorMichael Zanetti <michael.zanetti@nokia.com>2011-08-24 14:09:22 +1000
committerRohan McGovern <rohan.mcgovern@nokia.com>2011-08-24 14:10:36 +1000
commit29ba8297443cf76d4f647bde329d62c2a567c709 (patch)
tree88875199053cd88b3b3521c829277f209e815159 /src/nfc/qnearfieldtagtype2.cpp
Initial commit.
From qt5connectivity.tar.gz, md5 317c149d6f8c07d09632353188582834
Diffstat (limited to 'src/nfc/qnearfieldtagtype2.cpp')
-rw-r--r--src/nfc/qnearfieldtagtype2.cpp348
1 files changed, 348 insertions, 0 deletions
diff --git a/src/nfc/qnearfieldtagtype2.cpp b/src/nfc/qnearfieldtagtype2.cpp
new file mode 100644
index 00000000..f54567ec
--- /dev/null
+++ b/src/nfc/qnearfieldtagtype2.cpp
@@ -0,0 +1,348 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qnearfieldtagtype2.h"
+#include "qnearfieldtarget_p.h"
+
+#include <QtCore/QVariant>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QTime>
+
+#include <QtCore/QDebug>
+
+/*!
+ \class QNearFieldTagType2
+ \brief The QNearFieldTagType2 class provides an interface for communicating with an NFC Tag
+ Type 2 tag.
+ \since 5.0
+
+ \ingroup connectivity-nfc
+ \inmodule QtConnectivity
+*/
+
+/*!
+ \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)
+: QNearFieldTarget(parent), d_ptr(new QNearFieldTagType2Private)
+{
+}
+
+/*!
+ Destroys the tag type 2 near field target.
+*/
+QNearFieldTagType2::~QNearFieldTagType2()
+{
+ delete d_ptr;
+}
+
+/*!
+ \reimp
+*/
+bool QNearFieldTagType2::hasNdefMessage()
+{
+ qDebug() << Q_FUNC_INFO << "is unimplemeted";
+ return false;
+}
+
+/*!
+ \reimp
+*/
+QNearFieldTarget::RequestId QNearFieldTagType2::readNdefMessages()
+{
+ return RequestId();
+}
+
+/*!
+ \reimp
+*/
+QNearFieldTarget::RequestId QNearFieldTagType2::writeNdefMessages(const QList<QNdefMessage> &messages)
+{
+ Q_UNUSED(messages);
+
+ return 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) {
+ RequestId id = selectSector(0);
+ if (!waitForRequestCompleted(id))
+ return 0;
+ }
+
+ 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) {
+ RequestId id = selectSector(0);
+ if (!waitForRequestCompleted(id))
+ return 0;
+ }
+
+ 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 RequestId();
+
+ QByteArray command;
+ command.append(char(0xa2)); // WRITE
+ command.append(char(blockAddress)); // Block address
+ command.append(data); // Data
+
+ 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));
+
+ 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
+*/
+bool QNearFieldTagType2::waitForRequestCompleted(const RequestId &id, int msecs)
+{
+ Q_D(QNearFieldTagType2);
+
+ QTime timer;
+ timer.start();
+ while (d->m_pendingSectorSelectCommands.contains(id)) {
+ QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents, 1);
+
+ // detect passive ack
+ if (timer.elapsed() >= 1)
+ break;
+ }
+
+ return QNearFieldTarget::waitForRequestCompleted(id, msecs);
+}
+
+/*!
+ \reimp
+*/
+bool QNearFieldTagType2::handleResponse(const QNearFieldTarget::RequestId &id,
+ const QByteArray &response)
+{
+ Q_D(QNearFieldTagType2);
+
+ if (d->m_pendingInternalCommands.contains(id)) {
+ const QByteArray command = d->m_pendingInternalCommands.take(id);
+
+ QVariant decodedResponse = decodeResponse(command, response);
+ 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 {
+ setResponseForRequest(id, decodedResponse);
+ }
+
+ return true;
+ } else if (d->m_pendingSectorSelectCommands.contains(id)) {
+ if (!response.isEmpty()) {
+ d->m_pendingSectorSelectCommands.remove(id);
+ setResponseForRequest(id, false);
+
+ return true;
+ }
+ }
+
+ return QNearFieldTarget::handleResponse(id, response);
+}
+
+/*!
+ \internal
+*/
+void QNearFieldTagType2::timerEvent(QTimerEvent *event)
+{
+ Q_D(QNearFieldTagType2);
+
+ killTimer(event->timerId());
+
+ QMutableMapIterator<QNearFieldTarget::RequestId, SectorSelectState> i(d->m_pendingSectorSelectCommands);
+ while (i.hasNext()) {
+ i.next();
+
+ SectorSelectState &state = i.value();
+
+ if (state.timerId == event->timerId()) {
+ d->m_currentSector = state.sector;
+
+ setResponseForRequest(i.key(), true);
+
+ i.remove();
+
+ break;
+ }
+ }
+}
+
+#include "moc_qnearfieldtagtype2.cpp"