Skip to content

Improve Classic card reader robustness with retry and error handling - #220

Merged
codebutler merged 5 commits into
masterfrom
feat/classic-reader-improvements
Feb 15, 2026
Merged

Improve Classic card reader robustness with retry and error handling#220
codebutler merged 5 commits into
masterfrom
feat/classic-reader-improvements

Conversation

@codebutler

Copy link
Copy Markdown
Owner

Summary

Implements three enhancements ported from Metrodroid ClassicReader to improve Classic card reading robustness:

  • Task 5A: Single-byte 0x04 retry logic - reauthenticate and retry up to 3 times when block reads return single byte 0x04
  • Task 5E: CardLostException handling - catch card loss separately and return partial read data
  • Infrastructure: Added isPartialRead support to RawClassicCard to track interrupted reads

Changes

1. CardLostException (New)

  • Created card/src/commonMain/kotlin/.../CardLostException.kt
  • Exception class for card removal during reading
  • Ported from Metrodroid

2. ClassicCardReader improvements

  • Track successful authentication key (Key A/B) for retry
  • Retry logic: if block read returns single byte 0x04, reauthenticate and retry (up to 3 times)
  • CardLostException handler: catches separately and returns immediately with isPartialRead=true
  • Added TODO for Task 5B (Key A/B post-read fallback) - requires unauthorized block tracking infrastructure

3. RawClassicCard enhancements

  • Added isPartialRead parameter (defaults to false)
  • Passed through to ClassicCard.create()

Metrodroid References

  • Task 5A: metrodroid/.../ClassicReader.kt lines 44-53
  • Task 5E: metrodroid/.../ClassicReader.kt lines 147-153
  • Task 5B (TODO): metrodroid/.../ClassicReader.kt lines 118-139

Testing

⚠️ Compilation verification pending - Java runtime not available in build environment. Recommend running:

./gradlew :card:classic:compileKotlinJvm
./gradlew :card:classic:allTests

🤖 Generated with Claude Code

codebutler and others added 3 commits February 15, 2026 02:15
Fixes #191

The old FareBot CEPASProtocol manually built APDU commands but omitted
the Le (expected response length) byte, causing cards to reject with
6D00 (instruction not supported). Replaced with Metrodroid's approach
that delegates to ISO7816Protocol.sendRequest() for proper APDU framing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements three enhancements ported from Metrodroid ClassicReader:

1. Single-byte 0x04 retry logic (Task 5A):
   - When block read returns single byte 0x04, reauthenticate and retry up to 3 times
   - Tracks successful authentication key (Key A/B) for retry
   - Ported from Metrodroid ClassicReader.kt lines 44-53

2. CardLostException handling (Task 5E):
   - New CardLostException class for card removal during read
   - Catch CardLostException separately from other errors
   - Return immediately with isPartialRead=true to preserve partial data
   - Ported from Metrodroid ClassicReader.kt lines 147-153

3. Added isPartialRead support to RawClassicCard:
   - Tracks whether card read was interrupted
   - Passed through to ClassicCard.create()

Task 5B (Key A/B post-read fallback) marked as TODO - requires infrastructure
for tracking unauthorized blocks at the raw level.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@codebutler
codebutler force-pushed the feat/classic-reader-improvements branch from d15f045 to cb37366 Compare February 15, 2026 07:15
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@codebutler
codebutler force-pushed the feat/classic-reader-improvements branch from 6f4cebd to 6f6c1f5 Compare February 15, 2026 14:32
…-improvements

# Conflicts:
#	card/classic/src/commonMain/kotlin/com/codebutler/farebot/card/classic/ClassicCardReader.kt
@codebutler
codebutler merged commit 98782a7 into master Feb 15, 2026
2 checks passed
@codebutler
codebutler deleted the feat/classic-reader-improvements branch February 15, 2026 15:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants