14#include "keyple/plugin/pcsc/PcscReaderAdapter.hpp"
16#if defined(WIN32) || defined(__MINGW32__) || defined(__MINGW64__)
19#include <PCSC/wintypes.h>
20#include <PCSC/winscard.h>
23#include "keyple/core/plugin/CardIOException.hpp"
24#include "keyple/core/plugin/ReaderIOException.hpp"
25#include "keyple/core/plugin/TaskCanceledException.hpp"
26#include "keyple/core/util/HexUtil.hpp"
27#include "keyple/core/util/cpp/Thread.hpp"
28#include "keyple/core/util/cpp/exception/Exception.hpp"
29#include "keyple/core/util/cpp/exception/IllegalArgumentException.hpp"
30#include "keyple/core/util/cpp/exception/IllegalStateException.hpp"
31#include "keyple/core/util/cpp/exception/InterruptedException.hpp"
32#include "keyple/plugin/pcsc/PcscPluginAdapter.hpp"
33#include "keyple/plugin/pcsc/cpp/exception/CardException.hpp"
34#include "keyple/plugin/pcsc/cpp/exception/CardNotPresentException.hpp"
40using keyple::core::plugin::CardIOException;
41using keyple::core::plugin::ReaderIOException;
42using keyple::core::plugin::TaskCanceledException;
43using keyple::core::util::HexUtil;
44using keyple::core::util::cpp::Thread;
45using keyple::core::util::cpp::exception::Exception;
46using keyple::core::util::cpp::exception::IllegalArgumentException;
47using keyple::core::util::cpp::exception::IllegalStateException;
48using keyple::core::util::cpp::exception::InterruptedException;
49using keyple::plugin::pcsc::cpp::exception::CardException;
50using keyple::plugin::pcsc::cpp::exception::CardNotPresentException;
52PcscReaderAdapter::PcscReaderAdapter(
53 std::shared_ptr<CardTerminal> terminal,
54 std::shared_ptr<PcscPluginAdapter> pluginAdapter,
55 const int cardMonitoringCycleDuration)
56: mIsInitialized(false)
57, mIsPhysicalChannelOpen(false)
59, mName(terminal->getName())
60, mPluginAdapter(pluginAdapter)
61, mCardMonitoringCycleDuration(cardMonitoringCycleDuration)
62, mPingApdu(HexUtil::toByteArray(
"00C0000000"))
63, mIsContactless(false)
64, mProtocol(IsoProtocol::ANY.getValue())
65, mIsModeExclusive(false)
68, mLoopWaitCardRemoval(false)
69, mIsObservationActive(false)
71#if defined(WIN32) || defined(__MINGW32__) || defined(__MINGW64__)
79PcscReaderAdapter::waitForCardInsertion()
82 "Reader [%]: start waiting card insertion (loop latency: % ms)\n",
84 mCardMonitoringCycleDuration);
90 while (mLoopWaitCard) {
91 if (mTerminal->waitForCardPresent(mCardMonitoringCycleDuration)) {
93 mLogger->trace(
"Reader [%]: card inserted\n", getName());
103 "Reader [%]: waiting card insertion stopped\n", getName());
105 }
catch (
const CardException& e) {
107 throw ReaderIOException(
108 mName +
": an error occurred while waiting for a card insertion.",
112 throw TaskCanceledException(
113 mName +
": the wait for a card insertion task has been cancelled.");
117PcscReaderAdapter::stopWaitForCardInsertion()
119 mLoopWaitCard =
false;
123PcscReaderAdapter::isProtocolSupported(
const std::string& readerProtocol)
const
128 const std::string rulmIsPhysicalChannelOpen
129 = mPluginAdapter->getProtocolRule(readerProtocol);
133 }
catch (
const IllegalArgumentException&) {
141PcscReaderAdapter::activateProtocol(
const std::string& readerProtocol)
144 "%: stop waiting for card insertion requested.\n", getName());
146 "Reader [%]: activating protocol [%] takes no action\n",
150 mLoopWaitCard =
false;
154PcscReaderAdapter::deactivateProtocol(
const std::string& readerProtocol)
157 "Reader [%]: de-activating protocol [%] takes no action\n",
163PcscReaderAdapter::isCurrentProtocol(
const std::string& readerProtocol)
const
170 bool isCurrentProtocol =
false;
172 const std::string protocolRule
173 = mPluginAdapter->getProtocolRule(readerProtocol);
174 if (!protocolRule.empty()) {
175 const std::string atr = HexUtil::toHex(mCard->getATR());
177 = Pattern::compile(protocolRule)->matcher(atr)->matches();
180 return isCurrentProtocol;
182 }
catch (
const IllegalArgumentException&) {
190PcscReaderAdapter::onStartDetection()
192 mIsObservationActive =
true;
196PcscReaderAdapter::onStopDetection()
198 mIsObservationActive =
false;
202PcscReaderAdapter::getName()
const
208PcscReaderAdapter::openPhysicalChannel()
210 if (mCard !=
nullptr) {
220 "Reader [%]: open card physical channel for protocol [%]\n",
224 mCard = mTerminal->connect(mProtocol);
225 if (mIsModeExclusive) {
226 mCard->beginExclusive();
228 "Reader [%]: open card physical channel in exclusive mode\n",
233 "%: opening of a card physical channel in shared mode\n",
237 mChannel = mCard->getBasicChannel();
239 }
catch (
const CardNotPresentException& e) {
240 throw CardIOException(
"Card removed", e);
242 }
catch (
const CardException& e) {
243 throw ReaderIOException(
244 getName() +
": Error while opening Physical Channel", e);
249PcscReaderAdapter::closePhysicalChannel()
255 if (!mIsObservationActive) {
260void PcscReaderAdapter::disconnect()
263 if (mCard !=
nullptr) {
265 mCard->disconnect(getDisposition(mDisconnectionMode));
270 }
catch (
const CardNotPresentException& e) {
271 throw CardIOException(
"Card removed", e);
273 }
catch (
const CardException& e) {
274 throw ReaderIOException(
"Error while closing physical channel", e);
283 case DisconnectionMode::RESET:
284 return SCARD_RESET_CARD;
285 case DisconnectionMode::LEAVE:
286 return SCARD_LEAVE_CARD;
287 case DisconnectionMode::UNPOWER:
288 return SCARD_UNPOWER_CARD;
289 case DisconnectionMode::EJECT:
290 return SCARD_EJECT_CARD;
292 throw IllegalArgumentException(std::string(
"Unknown DisconnectionMode: ") + mode);
296void PcscReaderAdapter::resetReaderState()
299 if (mDisconnectionMode == DisconnectionMode::UNPOWER) {
300 mTerminal->connect(
"*")->disconnect(
false);
303 }
catch (
const CardException& ) {
309PcscReaderAdapter::isPhysicalChannelOpen()
const
311 return mIsPhysicalChannelOpen;
315PcscReaderAdapter::checkCardPresence()
318 const bool isCardPresent = mTerminal->isCardPresent();
319 closePhysicalChannelSafely();
321 return isCardPresent;
323 }
catch (
const CardException& e) {
324 throw ReaderIOException(
"Exception occurred in isCardPresent", e);
329PcscReaderAdapter::closePhysicalChannelSafely()
334 }
catch (
const Exception&) {
340PcscReaderAdapter::resetContext()
343 mIsPhysicalChannelOpen =
false;
347PcscReaderAdapter::getPowerOnData()
const
349 return HexUtil::toHex(mCard->getATR());
352const std::vector<uint8_t>
353PcscReaderAdapter::transmitApdu(
const std::vector<uint8_t>& apduCommandData)
355 std::vector<uint8_t> apduResponseData;
359 apduResponseData = mChannel->transmit(apduCommandData);
361 }
catch (
const CardNotPresentException& e) {
362 throw CardIOException(mName +
": " + e.getMessage(), e);
364 }
catch (
const CardException& e) {
365 if (e.getMessage().find(
"CARD") != std::string::npos ||
366 e.getMessage().find(
"NOT_TRANSACTED") != std::string::npos ||
367 e.getMessage().find(
"INVALID_ATR") != std::string::npos) {
368 throw CardIOException(getName() +
":" + e.getMessage(), e);
371 throw ReaderIOException(getName() +
":" + e.getMessage(), e);
374 }
catch (
const IllegalStateException& e) {
376 throw CardIOException(
377 getName() +
":" + e.getMessage(), e);
379 }
catch (
const IllegalArgumentException& e) {
381 throw CardIOException(
382 getName() +
":" + e.getMessage(), e);
387 throw CardIOException(getName() +
": null channel.");
390 return apduResponseData;
394PcscReaderAdapter::isContactless()
396 if (!mIsInitialized) {
402 mIsContactless = mPluginAdapter->isContactless(getName());
405 return mIsContactless;
409PcscReaderAdapter::onUnregister()
415PcscReaderAdapter::monitorCardPresenceDuringProcessing()
417 waitForCardRemoval();
421PcscReaderAdapter::stopCardPresenceMonitoringDuringProcessing()
423 stopWaitForCardRemoval();
427PcscReaderAdapter::waitForCardRemoval()
429 mLogger->trace(
"Reader [%]: start waiting card removal\n", mName);
431 mLoopWaitCardRemoval =
true;
434 if (mDisconnectionMode == DisconnectionMode::UNPOWER) {
435 waitForCardRemovalByPolling();
437 waitForCardRemovalStandard();
440 }
catch (
const Exception&) {
447 }
catch (
const Exception& e) {
449 "Error while disconnecting card during card removal: %\n",
454 if (!mLoopWaitCardRemoval) {
455 mLogger->trace(
"Reader [%]: waiting card removal stopped\n", mName);
457 mLogger->trace(
"Reader [%]: card removed\n", mName);
460 if (!mLoopWaitCardRemoval) {
461 throw TaskCanceledException(
462 mName +
": the wait for the card removal task has been cancelled.");
467PcscReaderAdapter::waitForCardRemovalByPolling()
470 while (mLoopWaitCardRemoval) {
471 transmitApdu(mPingApdu);
478 }
catch (
const CardIOException& e) {
480 "Expected IOException while waiting for card removal: %\n",
483 }
catch (
const ReaderIOException& e) {
485 "Expected IOException while waiting for card removal: %\n",
488 }
catch (
const InterruptedException& e) {
490 "InterruptedException while waiting for card removal: %\n",
496void PcscReaderAdapter::waitForCardRemovalStandard()
499 while (mLoopWaitCardRemoval) {
500 if (mTerminal->waitForCardAbsent(mCardMonitoringCycleDuration)) {
508 }
catch (
const CardException& e) {
510 "Expected CardException while waiting for card removal: %\n",
513 throw ReaderIOException(
514 mName +
": an error occurred while waiting for the card removal.",
520PcscReaderAdapter::stopWaitForCardRemoval()
522 mLoopWaitCardRemoval =
false;
526PcscReaderAdapter::setSharingMode(
const SharingMode sharingMode)
529 "Reader [%]: set sharing mode to [%]\n", getName(), sharingMode);
531 if (sharingMode == SharingMode::SHARED) {
533 if (mCard !=
nullptr) {
535 mCard->endExclusive();
537 }
catch (
const CardException& e) {
538 throw IllegalStateException(
539 "Couldn't disable exclusive mode", e);
543 mIsModeExclusive =
false;
545 }
else if (sharingMode == SharingMode::EXCLUSIVE) {
546 mIsModeExclusive =
true;
553PcscReaderAdapter::setContactless(
const bool contactless)
556 "Reader [%]: set contactless type to [%]\n", getName(), contactless);
558 mIsContactless = contactless;
559 mIsInitialized =
true;
565PcscReaderAdapter::setIsoProtocol(
const IsoProtocol& isoProtocol)
568 "Reader [%]: set ISO protocol to [%] (%)\n",
571 isoProtocol.getValue());
573 mProtocol = isoProtocol.getValue();
579PcscReaderAdapter::setDisconnectionMode(
583 "Reader [%]: set disconnection mode to [%]\n",
587 mDisconnectionMode = disconnectionMode;
592const std::vector<uint8_t>
593PcscReaderAdapter::transmitControlCommand(
594 const int commandId,
const std::vector<uint8_t>& command)
596 std::vector<uint8_t> response;
597 const int controlCode
598 = mIsWindows ? 0x00310000 | (commandId << 2) : 0x42000000 | commandId;
601 if (mCard !=
nullptr) {
603 response = mCard->transmitControlCommand(controlCode, command);
605 std::shared_ptr<Card> virtualCard = mTerminal->connect(
"DIRECT");
606 response = virtualCard->transmitControlCommand(controlCode, command);
607 virtualCard->disconnect(
false);
610 }
catch (
const CardException& e) {
611 throw IllegalStateException(
"Reader failure.", e);
618PcscReaderAdapter::getIoctlCcidEscapeCommandId()
const
620 return mIsWindows ? 3500 : 1;
PcscReader::DisconnectionMode DisconnectionMode