diff --git a/CHANGELOG.md b/CHANGELOG.md index 74f588e..68ec2fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Fixed +- Fixed card removal wait for `INNOVATRON_B_PRIME` protocol cards: APDU polling is now bypassed in favor of the + standard PC/SC absence detection, and disconnection is unconditionally performed with `UNPOWER` regardless of the + configured disconnection mode. ## [2.6.2] - 2026-02-20 ### Changed diff --git a/gradle.properties b/gradle.properties index 2bf642d..c300172 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ group = org.eclipse.keyple title = Keyple Plugin PCSC Java Lib description = Keyple add-on to manage PC/SC readers -version = 2.6.2-SNAPSHOT +version = 2.6.3-SNAPSHOT # Java Configuration javaSourceLevel = 1.8 diff --git a/src/main/java/org/eclipse/keyple/plugin/pcsc/PcscReaderAdapter.java b/src/main/java/org/eclipse/keyple/plugin/pcsc/PcscReaderAdapter.java index 81ed3e7..28f2683 100644 --- a/src/main/java/org/eclipse/keyple/plugin/pcsc/PcscReaderAdapter.java +++ b/src/main/java/org/eclipse/keyple/plugin/pcsc/PcscReaderAdapter.java @@ -322,10 +322,12 @@ public void closePhysicalChannel() throws ReaderIOException { * Disconnects the current card and resets the context and reader state. * *

This method handles the disconnection of a card, taking into account the specific - * disconnection mode. If the card is an instance of {@link Smartcardio.JnaCard}, it disconnects + * disconnection mode. If the card uses the {@code INNOVATRON_B_PRIME} protocol, the disconnection + * mode is unconditionally overridden to {@link DisconnectionMode#UNPOWER}, regardless of the + * configured mode. If the card is an instance of {@link Smartcardio.JnaCard}, it disconnects * using the extended mode specified by {@link #getDisposition(DisconnectionMode)} and resets the * reader state to avoid incorrect card detection in subsequent operations. For other card types, - * it disconnects using the specified disconnection mode directly. + * it disconnects using the effective disconnection mode directly. * *

If a {@link CardException} occurs during the operation, a {@link ReaderIOException} is * thrown with the associated error message. @@ -337,13 +339,17 @@ public void closePhysicalChannel() throws ReaderIOException { private void disconnect() throws ReaderIOException { try { if (card != null) { + DisconnectionMode effectiveMode = + isCurrentProtocol(PcscCardCommunicationProtocol.INNOVATRON_B_PRIME.name()) + ? DisconnectionMode.UNPOWER + : disconnectionMode; if (card instanceof Smartcardio.JnaCard) { // disconnect using the extended mode allowing UNPOWER - ((Smartcardio.JnaCard) card).disconnect(getDisposition(disconnectionMode)); + ((Smartcardio.JnaCard) card).disconnect(getDisposition(effectiveMode)); // reset the reader state to avoid bad card detection next time - resetReaderState(); + resetReaderState(effectiveMode); } else { - card.disconnect(disconnectionMode == DisconnectionMode.RESET); + card.disconnect(effectiveMode == DisconnectionMode.RESET); } } } catch (CardException e) { @@ -377,14 +383,19 @@ private static int getDisposition(DisconnectionMode mode) { /** * Resets the state of the card reader. * - *

This method attempts to reset the reader state based on the current disconnection mode. If - * the disconnection mode is set to UNPOWER, it reconnects to the terminal and then disconnects + *

This method attempts to reset the reader state based on the effective disconnection mode. If + * the effective mode is {@link DisconnectionMode#UNPOWER} (either configured or forced by the + * {@code INNOVATRON_B_PRIME} protocol), it reconnects to the terminal and then disconnects * without powering off the reader. If any {@link CardException} occurs during this process, it is * handled silently. + * + * @param effectiveMode The disconnection mode actually applied, which may differ from the + * configured {@link #disconnectionMode} when the card uses the {@code INNOVATRON_B_PRIME} + * protocol. */ - private void resetReaderState() { + private void resetReaderState(DisconnectionMode effectiveMode) { try { - if (disconnectionMode == DisconnectionMode.UNPOWER) { + if (effectiveMode == DisconnectionMode.UNPOWER) { communicationTerminal.connect("*").disconnect(false); } } catch (CardException e) { @@ -512,7 +523,8 @@ public void onUnregister() { @Override public void monitorCardPresenceDuringProcessing() throws ReaderIOException, TaskCanceledException { - waitForCardRemoval(); + doWaitForCardRemoval( + !isCurrentProtocol(PcscCardCommunicationProtocol.INNOVATRON_B_PRIME.name())); } /** @@ -532,12 +544,17 @@ public void stopCardPresenceMonitoringDuringProcessing() { */ @Override public void waitForCardRemoval() throws ReaderIOException, TaskCanceledException { + doWaitForCardRemoval(true); + } + + private void doWaitForCardRemoval(boolean allowPolling) + throws ReaderIOException, TaskCanceledException { if (logger.isTraceEnabled()) { logger.trace("[readerExt={}] Starting waiting card removal", name); } loopWaitCardRemoval.set(true); try { - if (disconnectionMode == DisconnectionMode.UNPOWER) { + if (allowPolling && disconnectionMode == DisconnectionMode.UNPOWER) { waitForCardRemovalByPolling(); } else { waitForCardRemovalStandard();