6#include "ndef/qnfctagtype4ndeffsm_p.h"
8#include <QtCore/QLoggingCategory>
9#include <QtCore/QTimer>
11#if defined(Q_OS_DARWIN)
12# define SCARD_ATTR_MAXINPUT 0x0007A007
13#elif !defined(Q_OS_WIN)
19Q_DECLARE_LOGGING_CATEGORY(QT_NFC_PCSC)
22
23
24
25
26
27
28
29
30
31
32static constexpr int KeepAliveIntervalMs = 2500;
35
36
37
38
39
40
43 qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
44 if (!m_card
->isValid() || m_card->m_inAutoTransaction)
47 auto ret = SCardBeginTransaction(m_card->m_handle);
48 if (ret != SCARD_S_SUCCESS) {
49 qCWarning(QT_NFC_PCSC) <<
"SCardBeginTransaction failed:" << QPcsc::errorMessage(ret);
59 qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
63 auto ret = SCardEndTransaction(m_card->m_handle, SCARD_LEAVE_CARD);
65 if (ret != SCARD_S_SUCCESS) {
66 qCWarning(QT_NFC_PCSC) <<
"SCardEndTransaction failed:" << QPcsc::errorMessage(ret);
71QPcscCard::QPcscCard(SCARDHANDLE handle, DWORD protocol, QObject *parent)
72 : QObject(parent), m_handle(handle)
74 qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
76 m_keepAliveTimer =
new QTimer(
this);
77 m_keepAliveTimer->setInterval(KeepAliveIntervalMs);
78 connect(m_keepAliveTimer, &QTimer::timeout,
this, &QPcscCard::onKeepAliveTimeout);
80 m_ioPci.dwProtocol = protocol;
81 m_ioPci.cbPciLength =
sizeof(m_ioPci);
84 m_tagDetectionFsm = std::make_unique<QNfcTagType4NdefFsm>();
86 performNdefDetection();
91 qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
97 qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
102 Transaction transaction(
this);
104 auto action = m_tagDetectionFsm->detectNdefSupport();
106 while (action == QNdefAccessFsm::SendCommand) {
107 auto command = m_tagDetectionFsm->getCommand(action);
109 if (action == QNdefAccessFsm::ProvideResponse) {
110 auto result = sendCommand(command, NoAutoTransaction);
111 action = m_tagDetectionFsm->provideResponse(result.response);
115 qCDebug(QT_NFC_PCSC) <<
"NDEF detection result" << action;
117 m_supportsNdef = action == QNdefAccessFsm::Done;
118 qCDebug(QT_NFC_PCSC) <<
"NDEF supported:" << m_supportsNdef;
122
123
124
130 SCardDisconnect(m_handle, m_inAutoTransaction ? SCARD_RESET_CARD : SCARD_LEAVE_CARD);
133 m_inAutoTransaction =
false;
135 Q_EMIT disconnected();
136 Q_EMIT invalidated();
143
144
145
146
147
148
149
150
151
152
153
154
155
157 QPcscCard::AutoTransaction autoTransaction)
162 if (!m_inAutoTransaction && autoTransaction == StartAutoTransaction) {
163 qCDebug(QT_NFC_PCSC) <<
"Starting transaction";
166 auto ret = SCardBeginTransaction(m_handle);
167 if (ret != SCARD_S_SUCCESS) {
168 qCWarning(QT_NFC_PCSC) <<
"SCardBeginTransaction failed:" << QPcsc::errorMessage(ret);
172 m_inAutoTransaction =
true;
173 m_keepAliveTimer->start();
177 result.response.resize(0xFFFF + 2);
178 DWORD recvLength = result.response.size();
180 qCDebug(QT_NFC_PCSC) <<
"TX:" << command.toHex(
':');
182 result.ret = SCardTransmit(m_handle, &m_ioPci,
reinterpret_cast<LPCBYTE>(command.constData()),
183 command.size(),
nullptr,
184 reinterpret_cast<LPBYTE>(result.response.data()), &recvLength);
185 if (result.ret != SCARD_S_SUCCESS) {
186 qCWarning(QT_NFC_PCSC) <<
"SCardTransmit failed:" << QPcsc::errorMessage(result.ret);
187 result.response.clear();
190 result.response.resize(recvLength);
191 qCDebug(QT_NFC_PCSC) <<
"RX:" << result.response.toHex(
':');
199 if (!m_isValid || !m_inAutoTransaction) {
200 m_keepAliveTimer->stop();
209 QByteArray command = QCommandApdu::build(0xFF, QCommandApdu::GetData, 0x00, 0x00, {}, 256);
212 QResponseApdu res(sendCommand(command, NoAutoTransaction).response);
221 Q_EMIT requestCompleted(request, QNearFieldTarget::ConnectionError, {});
225 if (!m_supportsNdef) {
226 Q_EMIT requestCompleted(request, QNearFieldTarget::UnsupportedError, {});
230 Transaction transaction(
this);
232 auto nextState = m_tagDetectionFsm->readMessages();
235 if (nextState == QNdefAccessFsm::SendCommand) {
236 auto command = m_tagDetectionFsm->getCommand(nextState);
238 if (nextState == QNdefAccessFsm::ProvideResponse) {
239 auto result = sendCommand(command, NoAutoTransaction);
240 nextState = m_tagDetectionFsm->provideResponse(result.response);
242 }
else if (nextState == QNdefAccessFsm::GetMessage) {
243 auto message = m_tagDetectionFsm->getMessage(nextState);
244 Q_EMIT ndefMessageRead(message);
250 qCDebug(QT_NFC_PCSC) <<
"Final state:" << nextState;
251 auto errorCode = (nextState == QNdefAccessFsm::Done) ? QNearFieldTarget::NoError
252 : QNearFieldTarget::NdefReadError;
253 Q_EMIT requestCompleted(request, errorCode, {});
257
258
259
260
261
262
265 qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
271 if (m_inAutoTransaction) {
274 ret = SCardEndTransaction(m_handle, SCARD_RESET_CARD);
275 if (ret != SCARD_S_SUCCESS) {
276 qCWarning(QT_NFC_PCSC) <<
"SCardEndTransaction failed:" << QPcsc::errorMessage(ret);
281 m_inAutoTransaction =
false;
284 DWORD activeProtocol;
285 ret = SCardReconnect(m_handle, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
286 SCARD_LEAVE_CARD, &activeProtocol);
287 if (ret != SCARD_S_SUCCESS) {
288 qCWarning(QT_NFC_PCSC) <<
"SCardReconnect failed:" << QPcsc::errorMessage(ret);
293 Q_EMIT disconnected();
298 qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
303 const QByteArray &command)
305 qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
308 Q_EMIT requestCompleted(request, QNearFieldTarget::ConnectionError, {});
312 auto result = sendCommand(command, StartAutoTransaction);
314 Q_EMIT requestCompleted(request, QNearFieldTarget::NoError, result.response);
316 Q_EMIT requestCompleted(request, QNearFieldTarget::CommandError, {});
320 const QList<QNdefMessage> &messages)
322 qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
325 Q_EMIT requestCompleted(request, QNearFieldTarget::ConnectionError, {});
329 if (!m_supportsNdef) {
330 Q_EMIT requestCompleted(request, QNearFieldTarget::UnsupportedError, {});
334 Transaction transaction(
this);
336 auto nextState = m_tagDetectionFsm->writeMessages(messages);
338 while (nextState == QNdefAccessFsm::SendCommand) {
339 auto command = m_tagDetectionFsm->getCommand(nextState);
340 if (nextState == QNdefAccessFsm::ProvideResponse) {
341 auto result = sendCommand(command, NoAutoTransaction);
342 nextState = m_tagDetectionFsm->provideResponse(result.response);
346 auto errorCode = (nextState == QNdefAccessFsm::Done) ? QNearFieldTarget::NoError
347 : QNearFieldTarget::NdefWriteError;
348 Q_EMIT requestCompleted(request, errorCode, {});
352
353
354
355
356
357
358
361 qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
369
370
371
372
375 qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
381 auto ret = SCardStatus(m_handle,
nullptr,
nullptr, &state,
nullptr,
nullptr,
nullptr);
382 if (ret != SCARD_S_SUCCESS) {
383 qCWarning(QT_NFC_PCSC) <<
"SCardStatus failed:" << QPcsc::errorMessage(ret);
388 qCDebug(QT_NFC_PCSC) <<
"State:" << Qt::hex << state;
390 return (state & SCARD_PRESENT) != 0;
399 static constexpr int DefaultMaxInputLength = 261;
402 DWORD attrSize =
sizeof(maxInput);
403 auto ret = SCardGetAttrib(m_handle, SCARD_ATTR_MAXINPUT,
reinterpret_cast<LPBYTE>(&maxInput),
405 if (ret != SCARD_S_SUCCESS) {
406 qCDebug(QT_NFC_PCSC) <<
"SCardGetAttrib failed:" << QPcsc::errorMessage(ret);
407 return DefaultMaxInputLength;
410 if (attrSize !=
sizeof(maxInput)) {
411 qCWarning(QT_NFC_PCSC) <<
"Unexpected attribute size for SCARD_ATTR_MAXINPUT:" << attrSize;
412 return DefaultMaxInputLength;
415 return static_cast<
int>(maxInput);
void onReadNdefMessagesRequest(const QNearFieldTarget::RequestId &request)
void onWriteNdefMessagesRequest(const QNearFieldTarget::RequestId &request, const QList< QNdefMessage > &messages)
void onSendCommandRequest(const QNearFieldTarget::RequestId &request, const QByteArray &command)
Q_INVOKABLE void enableAutodelete()