| /**************************************************************************** |
| ** |
| ** 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 "qnearfieldtarget_p.h" |
| #include "qndefmessage.h" |
| #include "qtlv_p.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(0), |
| m_writeNdefMessageState(NotWritingNdefMessage), |
| m_tlvWriter(0) |
| { } |
| |
| 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(); |
| 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(); |
| 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; |
| 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); |
| |
| emit q->ndefMessageRead(QNdefMessage::fromByteArray(m_tlvReader->data())); |
| } |
| } |
| |
| m_nextExpectedRequestId = m_tlvReader->requestId(); |
| if (!m_nextExpectedRequestId.isValid()) { |
| delete m_tlvReader; |
| m_tlvReader = 0; |
| m_readNdefMessageState = NotReadingNdefMessage; |
| 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(); |
| 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(); |
| 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; |
| 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 = 0; |
| 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 = 0; |
| emit q->ndefMessagesWritten(); |
| 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 = 0; |
| 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) |
| : QNearFieldTarget(parent), d_ptr(new QNearFieldTagType1Private(this)) |
| { |
| } |
| |
| /*! |
| Destroys the tag type 1 near field target. |
| */ |
| QNearFieldTagType1::~QNearFieldTagType1() |
| { |
| delete d_ptr; |
| } |
| |
| /*! |
| \reimp |
| */ |
| bool QNearFieldTagType1::hasNdefMessage() |
| { |
| 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 = RequestId(new 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 = RequestId(new 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() |
| { |
| 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() |
| { |
| 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 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 |
| |
| 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 RequestId(); |
| |
| QByteArray command; |
| |
| if (mode == EraseAndWrite) |
| command.append(char(0x53)); // WRITE-E |
| else if (mode == WriteOnly) |
| command.append(char(0x1a)); // WRITE-NE |
| else |
| return RequestId(); |
| |
| command.append(char(address)); // Address |
| command.append(char(data)); // Data |
| command.append(uid().left(4)); // 4 bytes of UID |
| |
| 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 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 |
| |
| 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 |
| |
| 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 RequestId(); |
| |
| QByteArray command; |
| |
| if (mode == EraseAndWrite) |
| command.append(char(0x54)); // WRITE-E8 |
| else if (mode == WriteOnly) |
| command.append(char(0x1b)); // WRITE-NE8 |
| else |
| return RequestId(); |
| |
| command.append(char(blockAddress)); // Block address |
| command.append(data); // Data |
| command.append(uid().left(4)); // 4 bytes of UID |
| |
| RequestId id = sendCommand(command); |
| |
| Q_D(QNearFieldTagType1); |
| |
| d->m_pendingInternalCommands.insert(id, command); |
| |
| return id; |
| } |
| |
| /*! |
| \reimp |
| */ |
| bool QNearFieldTagType1::handleResponse(const QNearFieldTarget::RequestId &id, |
| const QByteArray &response) |
| { |
| Q_D(QNearFieldTagType1); |
| |
| bool handled; |
| |
| if (d->m_pendingInternalCommands.contains(id)) { |
| const QByteArray command = d->m_pendingInternalCommands.take(id); |
| |
| QVariant decodedResponse = decodeResponse(command, response); |
| setResponseForRequest(id, decodedResponse); |
| |
| handled = true; |
| } else { |
| handled = QNearFieldTarget::handleResponse(id, response); |
| } |
| |
| // 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(); |
| } |
| |
| return handled; |
| } |
| |
| QT_END_NAMESPACE |