1 year ago

#75305

test-img

Baldorius

How to send peripheral commands to an ACS smart card reader with python and pyscard

I would like to programmatically control the buzzer of a smart card reader ACS ACR1281U-C1 but I am not sure to understand correctly how to use ESCAPE command for this.

I use python 3.9.6 + pyscard 2.0.1. Windows 10 (x64).

I have installed the ACS drivers (version 4.2.8.0).

The documentation from ACS (Application Programming Interface V1.11) states:

The reader’s peripherals control commands are implemented by using PC_to_RDR_Escape. Note: The driver will add the Class, INS and P1 automatically.

And in appendix C, the escape command is shown as 2079.

However, the sdk provides examples (in Java) where the escape command is shown as 3500, and the Class, INS and P1 fields are transmitted explicitly.

I can replicate both ways to send this peripheral control, but I am not sure which is the best approach and the documentation is not extensive.

1) SCARD_CTL_CODE(2079) Calculating the ESCAPE command with 2079, the driver adds the Class, INS and P1 [0xE0, 0x00, 0x00] automatically so I do not need to put them in the command. This seems more aligned with API documentation:

IOCTL_CCID_ESCAPE = SCARD_CTL_CODE(2079)
BUZZER_LONG = [0x28, 0x01, 0xB0]
response = cardservice.connection.control(IOCTL_CCID_ESCAPE, BUZZER_LONG)

SCARD_CTL_CODE(3500) Calculating the ESCAPE command with 3500, I must explicitly add the Class, INS and P1 in the command. This is more aligned with Java examples in SDK:

IOCTL_CCID_ESCAPE3500 = SCARD_CTL_CODE(3500)
BUZZER_LONG3500 = [0xE0, 0x00, 0x00, 0x28, 0x01, 0xB0]
response = cardservice.connection.control(IOCTL_CCID_ESCAPE3500, BUZZER_LONG3500)

Why this difference? What is the correct approach?

from smartcard.CardType import ATRCardType
from smartcard.CardRequest import CardRequest
from smartcard.Exceptions import CardRequestTimeoutException, SmartcardException
from smartcard.util import toHexString, toBytes, BinStringToHexList, PACK
from time import sleep
from smartcard.scard import SCARD_CTL_CODE

# prepare escape command
IOCTL_CCID_ESCAPE3500 = SCARD_CTL_CODE(3500)
IOCTL_CCID_ESCAPE = SCARD_CTL_CODE(2079)

# reader commands
READ_UID = [0xFF,0xCA,0x00,0x00,0x00]
BUZZER_LONG = [0x28, 0x01, 0xB0]
BUZZER_LONG3500 = [0xE0, 0x00, 0x00, 0x28, 0x01, 0xB0]

# card centric approach - could be any card type    
cardtype = ATRCardType( toBytes('3B 8F 80 01 80 4F 0C A0 00 00 03 06 03 00 07 00 00 00 00 6C') )

cardrequest = CardRequest( timeout=15, cardType=cardtype )

while True:
    choice = input('Put a card on the reader and press ENTER...').upper()
    if choice == 'Q':
        break
    try:
        cardservice = cardrequest.waitforcard()
    except CardRequestTimeoutException:
        print('Timeout')
        continue
    cardservice.connection.connect()
    # read/write ... do stuff with the card.
    try:
        # beeps with 2079 control code without Class, INS and P1 
        response = cardservice.connection.control(IOCTL_CCID_ESCAPE, BUZZER_LONG)
        sleep(1)
        # beeps with 3500 control code and command including Class, INS and P1 
        response = cardservice.connection.control(IOCTL_CCID_ESCAPE3500, BUZZER_LONG3500)
    except SmartcardException as err:
        print(f"{err=}, {type(err)=}")

python

escaping

smartcard-reader

pcsc

pyscard

0 Answers

Your Answer

Accepted video resources