7#include <QtCore/QLoggingCategory>
8#include <QtCore/QThread>
9#include <QtCore/QTimer>
24 if (!intervalEnv.isEmpty()) {
25 if (
int intervalFromEnv = intervalEnv.toInt(); intervalFromEnv > 0)
26 pollInterval = intervalFromEnv;
31 m_stateUpdateTimer =
new QTimer(
this);
32 m_stateUpdateTimer->setInterval(pollInterval);
41 for (
auto slot : std::as_const(m_slots))
42 slot->invalidateInsertedCard();
43 SCardReleaseContext(m_context);
50void QPcscManager::processSlotUpdates()
52 for (
auto &
state : m_slotStates) {
56 if ((
state.dwEventState & SCARD_STATE_UNKNOWN) != 0)
59 if (
state.dwEventState ==
state.dwCurrentState)
66 slot->processStateChange(
state.dwEventState, m_targetDetectionRunning);
73void QPcscManager::removeSlots()
75 for (
auto &
state : m_slotStates) {
81 if ((
state.dwEventState & SCARD_STATE_UNKNOWN) != 0
82 || !(m_targetDetectionRunning || slot->hasCard())) {
83 qCDebug(QT_NFC_PCSC) <<
"Removing slot:" << slot;
84 state.dwEventState = SCARD_STATE_UNKNOWN;
85 slot->invalidateInsertedCard();
86 m_slots.
remove(slot->name());
88 state.pvUserData =
nullptr;
94 [](
const auto &
state) {
return (
state.dwEventState & SCARD_STATE_UNKNOWN) != 0; });
101void QPcscManager::updateSlotList()
105#ifndef SCARD_AUTOALLOCATE
108#define LIST_READER_BUFFER_EXTRA 1024
111 buf.resize(listSize);
114 auto ret = SCardListReaders(m_context,
nullptr,
list, &listSize);
117 DWORD listSize = SCARD_AUTOALLOCATE;
122 if (
ret == LONG(SCARD_E_NO_READERS_AVAILABLE)) {
124 ret = SCARD_S_SUCCESS;
126#ifndef SCARD_AUTOALLOCATE
127 else if (
ret == LONG(SCARD_E_INSUFFICIENT_BUFFER)) {
132 buf.resize(listSize);
135 ret = SCardListReaders(m_context,
nullptr,
list, &listSize);
136 if (
ret == LONG(SCARD_E_NO_READERS_AVAILABLE)) {
138 ret = SCARD_S_SUCCESS;
141#undef LIST_READER_BUFFER_EXTRA
144 if (
ret != SCARD_S_SUCCESS) {
149#ifdef SCARD_AUTOALLOCATE
153 SCardFreeMemory(m_context,
list);
158 QSet<QPcscSlotName> presentSlots;
160 if (
list !=
nullptr) {
167 for (
auto &
state : m_slotStates) {
171 if (presentSlots.contains(slot->name()))
172 presentSlots.remove(slot->name());
174 state.dwEventState = SCARD_STATE_UNKNOWN;
177 if (!m_targetDetectionRunning)
181 for (
auto &&slotName :
std::as_const(presentSlots)) {
183 qCDebug(QT_NFC_PCSC) <<
"New slot:" << slot;
185 m_slots[slotName] = slot;
187 SCARD_READERSTATE
state {};
188 state.pvUserData = slot;
190 state.dwCurrentState = SCARD_STATE_UNAWARE;
196bool QPcscManager::establishContext()
202 LONG
ret = SCardEstablishContext(SCARD_SCOPE_USER,
nullptr,
nullptr, &m_context);
203 if (
ret != SCARD_S_SUCCESS) {
212void QPcscManager::onStateUpdate()
215 if (!m_targetDetectionRunning) {
216 m_stateUpdateTimer->
stop();
220 if (!establishContext())
228 if (!m_targetDetectionRunning) {
230 SCardReleaseContext(m_context);
231 m_hasContext =
false;
233 m_stateUpdateTimer->
stop();
248 LONG
ret = SCardGetStatusChange(m_context, 0, m_slotStates.
data(), m_slotStates.
size());
250 if (
ret == SCARD_S_SUCCESS ||
ret == LONG(SCARD_E_UNKNOWN_READER)) {
251 processSlotUpdates();
253 }
else if (
ret == LONG(SCARD_E_CANCELLED) ||
ret == LONG(SCARD_E_UNKNOWN_READER)
254 ||
ret == LONG(SCARD_E_TIMEOUT)) {
263 m_hasContext =
false;
264 for (
auto slot :
std::as_const(m_slots)) {
268 SCardReleaseContext(m_context);
270 m_slotStates.
clear();
278 m_requestedMethod = accessMethod;
280 if (m_targetDetectionRunning)
283 m_targetDetectionRunning =
true;
284 m_stateUpdateTimer->
start();
290 m_targetDetectionRunning =
false;
299 SCARDHANDLE cardHandle;
300 DWORD activeProtocol;
302 LONG
ret = SCardConnect(m_context, slot->
name().
ptr(), SCARD_SHARE_SHARED,
303 SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &cardHandle, &activeProtocol);
304 if (
ret != SCARD_S_SUCCESS) {
306 retryCardDetection(slot);
310 auto card =
new QPcscCard(cardHandle, activeProtocol,
this);
311 auto uid = card->readUid();
312 auto maxInputLength = card->readMaxInputLength();
315 if (card->supportsNdef())
319 && (accessMethods & m_requestedMethod) == 0) {
320 qCDebug(QT_NFC_PCSC) <<
"Dropping card without required access support";
325 if (!card->isValid()) {
326 qCDebug(QT_NFC_PCSC) <<
"Card became invalid";
329 retryCardDetection(slot);
345void QPcscManager::retryCardDetection(
const QPcscSlot *slot)
349 for (
auto &
state : m_slotStates) {
350 if (
state.pvUserData == slot) {
351 state.dwCurrentState = SCARD_STATE_UNAWARE;
qsizetype size() const noexcept
bool isEmpty() const noexcept
qsizetype removeIf(Predicate pred)
void append(parameter_type t)
size_type remove(const Key &key)
AccessMethod
This enum describes the access methods a near field target supports.
QThread * thread() const
Returns the thread in which the object lives.
void deleteLater()
\threadsafe
void onStartTargetDetectionRequest(QNearFieldTarget::AccessMethod accessMethod)
void onStopTargetDetectionRequest()
void cardInserted(QPcscCard *card, const QByteArray &uid, QNearFieldTarget::AccessMethods accessMethods, int maxInputLength)
QPcscCard * connectToCard(QPcscSlot *slot)
CPtr ptr() const noexcept
static qsizetype nameSize(CPtr p)
void invalidateInsertedCard()
const QPcscSlotName & name() const
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
void stop()
Stops the timer.
void timeout(QPrivateSignal)
This signal is emitted when the timer times out.
QString errorMessage(LONG error)
Combined button and popup list for selecting options.
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
#define qCWarning(category,...)
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
GLenum GLuint GLenum GLsizei const GLchar * buf
static constexpr int DefaultPollIntervalMs
static QT_BEGIN_NAMESPACE constexpr auto PollIntervalEnvVar
#define LIST_READER_BUFFER_EXTRA
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)