5#include <QtCore/QtEndian>
6#include <QtCore/QLoggingCategory>
21 static constexpr uint8_t NtagApplicationIdV2[] { 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01 };
23 static constexpr uint8_t CapabilityContainerId[] { 0xE1, 0x03 };
25 static constexpr uint8_t ZeroLength[] { 0x00, 0x00 };
27 nextAction = ProvideResponse;
29 switch (m_currentState) {
30 case SelectApplicationForProbe:
31 case SelectApplicationForRead:
32 case SelectApplicationForWrite:
40 case SelectNdefFileForRead:
41 case SelectNdefFileForWrite:
43 case ReadNdefMessageLength:
45 case ReadNdefMessage: {
46 uint16_t readSize =
qMin(m_fileSize, m_maxReadSize);
49 m_fileOffset & 0xFF, {}, readSize);
53 m_fileSize = m_ndefData.
size();
57 uint16_t updateSize =
qMin(m_fileSize, m_maxUpdateSize);
58 uint16_t fileOffset = m_fileOffset;
60 m_fileOffset += updateSize;
61 m_fileSize -= updateSize;
64 fileOffset & 0xFF, m_ndefData.mid(fileOffset - 2, updateSize));
66 case WriteNdefLength: {
73 nextAction = Unexpected;
80 if (m_currentState == NdefMessageRead) {
83 m_currentState = NdefSupportDetected;
94 switch (m_currentState) {
95 case SelectApplicationForProbe:
96 m_targetState = NdefSupportDetected;
98 case NdefSupportDetected:
100 case NdefNotSupported:
109 switch (m_currentState) {
110 case SelectApplicationForProbe:
111 m_targetState = NdefMessageRead;
113 case NdefSupportDetected:
114 m_currentState = SelectApplicationForRead;
115 m_targetState = NdefMessageRead;
117 case NdefNotSupported:
127 if (messages.isEmpty() || messages.size() > 1)
130 auto messageData = messages.first().toByteArray();
131 if (messageData.size() > m_maxNdefSize - 2)
134 m_ndefData = messageData;
136 m_targetState = NdefMessageWritten;
138 switch (m_currentState) {
139 case SelectApplicationForProbe:
142 case NdefNotSupported:
145 case NdefSupportDetected:
149 m_currentState = SelectApplicationForWrite;
161 switch (m_currentState) {
162 case SelectApplicationForProbe:
163 return handleSimpleResponse(apdu, SelectCCFile, NdefNotSupported);
165 return handleSimpleResponse(apdu, ReadCCFile, NdefNotSupported);
167 return handleReadCCResponse(apdu);
169 case SelectApplicationForRead:
170 return handleSimpleResponse(apdu, SelectNdefFileForRead, NdefSupportDetected);
171 case SelectNdefFileForRead:
172 return handleSimpleResponse(apdu, ReadNdefMessageLength, NdefSupportDetected);
173 case ReadNdefMessageLength:
174 return handleReadFileLengthResponse(apdu);
175 case ReadNdefMessage:
176 return handleReadFileResponse(apdu);
178 case SelectApplicationForWrite:
179 return handleSimpleResponse(apdu, SelectNdefFileForWrite, NdefSupportDetected);
180 case SelectNdefFileForWrite:
181 return handleSimpleResponse(apdu, ClearNdefLength, NdefSupportDetected);
182 case ClearNdefLength:
183 return handleSimpleResponse(apdu, WriteNdefFile, NdefSupportDetected);
185 return handleWriteNdefFileResponse(apdu);
186 case WriteNdefLength:
187 return handleSimpleResponse(apdu, NdefSupportDetected, NdefSupportDetected,
Done);
195 const QResponseApdu &response, QNfcTagType4NdefFsm::State okState,
198 if (!response.
isOk()) {
199 m_currentState = failedState;
203 m_currentState = okState;
209 m_currentState = NdefNotSupported;
211 if (!response.
isOk())
215 qCDebug(QT_NFC_T4T) <<
"Invalid response size";
220 auto readU8 = [&
data = response.
data(), &idx]() {
221 return static_cast<uint8_t
>(
data.at(idx++));
223 auto readU16 = [&
data = response.
data(), &idx]() {
234 auto ccLen = readU16();
236 qCDebug(QT_NFC_T4T) <<
"CC length is too small";
240 if ((
mapping & 0xF0) != 0x20) {
244 m_maxReadSize = readU16();
245 if (m_maxReadSize < 0xF) {
246 qCDebug(QT_NFC_T4T) <<
"Invalid maxReadSize" << m_maxReadSize;
250 m_maxUpdateSize = readU16();
251 auto tlvTag = readU8();
252 if (tlvTag != 0x04) {
253 qCDebug(QT_NFC_T4T) <<
"Invalid TLV tag";
256 auto tlvSize = readU8();
257 if (tlvSize == 0xFF || tlvSize < 6) {
258 qCDebug(QT_NFC_T4T) <<
"Invalid TLV size";
261 m_ndefFileId = readBytes(2);
263 m_maxNdefSize = readU16();
264 if (m_maxNdefSize < 2) {
265 qCDebug(QT_NFC_T4T) <<
"No space for NDEF file length";
276 auto readAccess = readU8();
277 if (readAccess != 0) {
278 qCDebug(QT_NFC_T4T) <<
"No read access";
281 auto writeAccess = readU8();
286 m_writable = writeAccess == 0 && m_maxUpdateSize >= 2;
288 m_currentState = NdefSupportDetected;
290 if (m_targetState == NdefSupportDetected) {
292 }
else if (m_targetState == NdefMessageRead) {
294 m_currentState = SelectNdefFileForRead;
296 }
else if (m_targetState == NdefMessageWritten) {
298 if (m_ndefData.
size() > m_maxNdefSize - 2) {
299 qCDebug(QT_NFC_T4T) <<
"Message is too large";
304 m_currentState = SelectNdefFileForWrite;
315QNfcTagType4NdefFsm::handleReadFileLengthResponse(
const QResponseApdu &response)
318 m_currentState = NdefSupportDetected;
323 if (m_fileSize > m_maxNdefSize - 2) {
324 m_currentState = NdefSupportDetected;
331 if (m_fileSize == 0) {
332 m_currentState = NdefMessageRead;
336 m_currentState = ReadNdefMessage;
343 m_currentState = NdefSupportDetected;
347 auto readSize = qMin<qsizetype>(m_fileSize, response.
data().
size());
349 m_fileOffset += readSize;
350 m_fileSize -= readSize;
352 if (m_fileSize == 0) {
353 m_currentState = NdefMessageRead;
361QNfcTagType4NdefFsm::handleWriteNdefFileResponse(
const QResponseApdu &response)
363 if (!response.
isOk()) {
364 m_currentState = NdefSupportDetected;
369 m_currentState = WriteNdefLength;
static constexpr QByteArrayView fromArray(const Byte(&data)[Size]) noexcept
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
void clear()
Clears the contents of the byte array and makes it null.
QByteArray & append(char c)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QByteArray first(qsizetype n) const &
The QNdefMessage class provides an NFC NDEF message.
static Q_NFC_EXPORT QNdefMessage fromByteArray(const QByteArray &message)
Returns an NDEF message parsed from the contents of message.
Action provideResponse(const QByteArray &response) override
Action writeMessages(const QList< QNdefMessage > &messages) override
Action readMessages() override
QNdefMessage getMessage(Action &nextAction) override
Action detectNdefSupport() override
const QByteArray & data() const
QByteArray build(uint8_t cla, uint8_t ins, uint8_t p1, uint8_t p2, QByteArrayView data, uint16_t ne=0)
constexpr uint8_t ReadBinary
constexpr uint8_t UpdateBinary
Combined button and popup list for selecting options.
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
constexpr Initialization Uninitialized
constexpr T qFromBigEndian(T source)
QT_BEGIN_NAMESPACE Q_ALWAYS_INLINE void qToUnaligned(const T src, void *dest)
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
constexpr const T & qMin(const T &a, const T &b)
GLenum GLenum GLsizei count
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint GLsizei const GLchar * message
GLenum GLenum GLenum GLenum mapping