Python pyscard control the buzzer of an NFC reader

1.1k Views Asked by At

I have two NFC reading devices: ACR12U and ACR1252U

I have a short script in python using pyscard to read the UIDs of NFC tags:

from smartcard.CardMonitoring import CardMonitor, CardObserver
from smartcard.util import toHexString
from smartcard.Exceptions import CardConnectionException

getuid = [0xFF, 0xCA, 0x00, 0x00, 0x00]

class transmitobserver(CardObserver):
    def update(self, observable, actions):
        (addedcards, removedcards) = actions
        for card in addedcards:
            card.connection = card.createConnection()
            try:
                card.connection.connect()
            except CardConnectionException:
                # print("Card was removed too fast!")
                return
            response, sw1, sw2 = card.connection.transmit(
                getuid)
            nfc_id = "{}".format(toHexString(response)).replace(" ", "").lower()
            return nfc_id

if __name__ == '__main__':
    cardmonitor = CardMonitor()
    cardobserver = transmitobserver()
    cardmonitor.addObserver(cardobserver)
    try:
        while True:
            pass
    except KeyboardInterrupt:
        pass

The ACR122U buzzes as soon as I an NFC card is in proximity. The ACR1252U buzzes when an NFC is in proximity and buzzes again when I remove it.

I would like to change this behaviour so they only buzz when I remove the card and the card has been read. I tested it out and the program fails if I remove a card too fast, but the reader still buzzes like it was a success.

This is the first time I am working with things like this so I tried some trial and error methods.

So I figured getuid = [0xFF, 0xCA, 0x00, 0x00, 0x00] is sending the reader a command to read the UID, which I was able to find in both of their manuals:

enter image description here

Now I thought I could use this to control the buzzer. In the manual for the ACR1252U I found this:

enter image description here

So I tried the following:

buzzer = [0xE0, 0x00, 0x00, 0x28, 0x01, 0xFF]
response = card.connection.transmit(buzzer)

But nothing is happening. There is a different instruction for the ACR122U, but same thing happens. Can anyone aid me what am I doing wrong?

EDIT:

I was able to come a little closer to the solution, however I still dont understand what is going on 100%.

I only have a ACR122U when I am writing this, so all testing is done with that one. from the manual I was able to get a bunch of APDUs and I found a code that emulates a card read without an actual card being touched to the device, so I can test it.

from smartcard.System import readers
from smartcard.CardConnection import CardConnection
from smartcard.scard import SCARD_SHARE_DIRECT

reader = readers()[0]
connection = reader.createConnection()
connection.connect(protocol=CardConnection.RAW_protocol, mode=SCARD_SHARE_DIRECT)
turn_off_red = [0xFF, 0x00, 0x40, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00]
r, sw1, sw2 = connection.transmit(turn_off_red)

Now I have this APDU: turn_off_red = [0xFF, 0x00, 0x40, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00]

Which turns of the red led according to the manual, and it works as well, but just for a few seconds. Even if I put a sleep(50) at the end of the code, the red LED only blinks for a second, than turns back.

I think the same thing is happening when I try to use configBuzzer = [0xFF, 0x00, 0x52, 0x00, 0x00]. It turn the buzzer off for a couple of seconds, but turns it back on afterwards.

1

There are 1 best solutions below

5
Andrew On

Two pointers

1)All commands sent using Command APDU's have a standard Response APDU format of Result (If available - most do have a Result), SW1 and SW2

So you should use the code response, sw1, sw2 = card.connection.transmit(buzzer)

You should always check that SW1 = 90h and SW2 = 00h to confirm the command was successful (Other values will indicate an error, see the datasheet for more details of what the codes mean)

2)You say you want it to buzz when it successful read the card, but you don't check the SW1 and SW2 values for success when you read the UID.

3)The command buzzer = [0xE0, 0x00, 0x00, 0x28, 0x01, 0xFF] is to manually turn the buzzer on, great for when you manually want to indicate success after checking in the SW1 and SW2 values of the read but this command does not change the default buzzing behaviour of the reader.

On the ACR1252U configBuzzer = [0xE0, 0x00, 0x00, 0x21, 0x01, 0x67] should be the right bits to turn off buzzing on Card Insertion Events and Card Removal Events, which is what you described you wanted, so you can manually trigger the buzzer on success (Again check SW1 and SW2 for success)

Update for the ACR122U

configBuzzer = [0xFF, 0x00, 0x52, 0x00, 0x00]

then

response, sw1, sw2 = card.connection.transmit(configBuzzer)

This will not cause buzzer to not turn on during Tag detection (the ACR122U has less configuration options than the ACR1252U)