Skip to content

Commit 605fab6

Browse files
fix: ensure proper disconnection and card removal handling for INNOVATRON_B_PRIME cards during processing (#34)
1 parent fd019c0 commit 605fab6

File tree

3 files changed

+33
-12
lines changed

3 files changed

+33
-12
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

77
## [Unreleased]
8+
### Fixed
9+
- Fixed card removal wait for `INNOVATRON_B_PRIME` protocol cards: APDU polling is now bypassed in favor of the
10+
standard PC/SC absence detection, and disconnection is unconditionally performed with `UNPOWER` regardless of the
11+
configured disconnection mode.
812

913
## [2.6.2] - 2026-02-20
1014
### Changed

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
group = org.eclipse.keyple
33
title = Keyple Plugin PCSC Java Lib
44
description = Keyple add-on to manage PC/SC readers
5-
version = 2.6.2-SNAPSHOT
5+
version = 2.6.3-SNAPSHOT
66

77
# Java Configuration
88
javaSourceLevel = 1.8

src/main/java/org/eclipse/keyple/plugin/pcsc/PcscReaderAdapter.java

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -322,10 +322,12 @@ public void closePhysicalChannel() throws ReaderIOException {
322322
* Disconnects the current card and resets the context and reader state.
323323
*
324324
* <p>This method handles the disconnection of a card, taking into account the specific
325-
* disconnection mode. If the card is an instance of {@link Smartcardio.JnaCard}, it disconnects
325+
* disconnection mode. If the card uses the {@code INNOVATRON_B_PRIME} protocol, the disconnection
326+
* mode is unconditionally overridden to {@link DisconnectionMode#UNPOWER}, regardless of the
327+
* configured mode. If the card is an instance of {@link Smartcardio.JnaCard}, it disconnects
326328
* using the extended mode specified by {@link #getDisposition(DisconnectionMode)} and resets the
327329
* reader state to avoid incorrect card detection in subsequent operations. For other card types,
328-
* it disconnects using the specified disconnection mode directly.
330+
* it disconnects using the effective disconnection mode directly.
329331
*
330332
* <p>If a {@link CardException} occurs during the operation, a {@link ReaderIOException} is
331333
* thrown with the associated error message.
@@ -337,13 +339,17 @@ public void closePhysicalChannel() throws ReaderIOException {
337339
private void disconnect() throws ReaderIOException {
338340
try {
339341
if (card != null) {
342+
DisconnectionMode effectiveMode =
343+
isCurrentProtocol(PcscCardCommunicationProtocol.INNOVATRON_B_PRIME.name())
344+
? DisconnectionMode.UNPOWER
345+
: disconnectionMode;
340346
if (card instanceof Smartcardio.JnaCard) {
341347
// disconnect using the extended mode allowing UNPOWER
342-
((Smartcardio.JnaCard) card).disconnect(getDisposition(disconnectionMode));
348+
((Smartcardio.JnaCard) card).disconnect(getDisposition(effectiveMode));
343349
// reset the reader state to avoid bad card detection next time
344-
resetReaderState();
350+
resetReaderState(effectiveMode);
345351
} else {
346-
card.disconnect(disconnectionMode == DisconnectionMode.RESET);
352+
card.disconnect(effectiveMode == DisconnectionMode.RESET);
347353
}
348354
}
349355
} catch (CardException e) {
@@ -377,14 +383,19 @@ private static int getDisposition(DisconnectionMode mode) {
377383
/**
378384
* Resets the state of the card reader.
379385
*
380-
* <p>This method attempts to reset the reader state based on the current disconnection mode. If
381-
* the disconnection mode is set to UNPOWER, it reconnects to the terminal and then disconnects
386+
* <p>This method attempts to reset the reader state based on the effective disconnection mode. If
387+
* the effective mode is {@link DisconnectionMode#UNPOWER} (either configured or forced by the
388+
* {@code INNOVATRON_B_PRIME} protocol), it reconnects to the terminal and then disconnects
382389
* without powering off the reader. If any {@link CardException} occurs during this process, it is
383390
* handled silently.
391+
*
392+
* @param effectiveMode The disconnection mode actually applied, which may differ from the
393+
* configured {@link #disconnectionMode} when the card uses the {@code INNOVATRON_B_PRIME}
394+
* protocol.
384395
*/
385-
private void resetReaderState() {
396+
private void resetReaderState(DisconnectionMode effectiveMode) {
386397
try {
387-
if (disconnectionMode == DisconnectionMode.UNPOWER) {
398+
if (effectiveMode == DisconnectionMode.UNPOWER) {
388399
communicationTerminal.connect("*").disconnect(false);
389400
}
390401
} catch (CardException e) {
@@ -512,7 +523,8 @@ public void onUnregister() {
512523
@Override
513524
public void monitorCardPresenceDuringProcessing()
514525
throws ReaderIOException, TaskCanceledException {
515-
waitForCardRemoval();
526+
doWaitForCardRemoval(
527+
!isCurrentProtocol(PcscCardCommunicationProtocol.INNOVATRON_B_PRIME.name()));
516528
}
517529

518530
/**
@@ -532,12 +544,17 @@ public void stopCardPresenceMonitoringDuringProcessing() {
532544
*/
533545
@Override
534546
public void waitForCardRemoval() throws ReaderIOException, TaskCanceledException {
547+
doWaitForCardRemoval(true);
548+
}
549+
550+
private void doWaitForCardRemoval(boolean allowPolling)
551+
throws ReaderIOException, TaskCanceledException {
535552
if (logger.isTraceEnabled()) {
536553
logger.trace("[readerExt={}] Starting waiting card removal", name);
537554
}
538555
loopWaitCardRemoval.set(true);
539556
try {
540-
if (disconnectionMode == DisconnectionMode.UNPOWER) {
557+
if (allowPolling && disconnectionMode == DisconnectionMode.UNPOWER) {
541558
waitForCardRemovalByPolling();
542559
} else {
543560
waitForCardRemovalStandard();

0 commit comments

Comments
 (0)