aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHenryk Plötz <henryk@ploetzli.ch>2010-02-25 19:50:25 +0100
committerHenryk Plötz <henryk@ploetzli.ch>2010-02-26 02:27:26 +0100
commite960c92fbd19181661c6a315aa8666599bbda252 (patch)
tree8b547cdd647dde7a96bdba11790976c139077179
parent8f5ec36f7afbdd2e170d03bff5e42658b076e813 (diff)
Initial and very minimal support for ISO 14443-4 over PN532 over ISO 7816-3 T=0 on the ACR122 firmware 1.x
-rw-r--r--cards/pn532_card.py9
-rw-r--r--readers.py77
2 files changed, 82 insertions, 4 deletions
diff --git a/cards/pn532_card.py b/cards/pn532_card.py
index 6c34324..464ee42 100644
--- a/cards/pn532_card.py
+++ b/cards/pn532_card.py
@@ -25,9 +25,12 @@ class PN532_Virtual_Card(Card):
self.cmd_pn532("d4 4a 01 00")
def pn532_transceive(self, cmd):
- apdu = C_APDU(self.APDU_TRANSCEIVE_PN532, lc=len(cmd), data=cmd)
- response = self.send_apdu(apdu)
- return response
+ if hasattr(self.reader, "pn532_transceive_raw"):
+ return R_APDU(self.reader.pn532_transceive_raw(cmd))
+ else:
+ apdu = C_APDU(self.APDU_TRANSCEIVE_PN532, lc=len(cmd), data=cmd)
+ response = self.send_apdu(apdu)
+ return response
def pn532_parse(self, response):
result = []
diff --git a/readers.py b/readers.py
index 5086afa..c37e17c 100644
--- a/readers.py
+++ b/readers.py
@@ -8,9 +8,10 @@ pycsc you'll need to downgrade to SVN revision 246.
"""
raise
class Smartcard_Reader(object):
- def list_readers():
+ def list_readers(cls):
"Return a list of tuples: (reader name, implementing object)"
return []
+ list_readers = classmethod(list_readers)
def connect(self):
"Create a connection to this reader"
@@ -93,10 +94,84 @@ class PCSC_Reader(Smartcard_Reader):
self._cardservice.connection.disconnect()
del self._cardservice
self._cardservice = None
+
+class ACR122_Reader(Smartcard_Reader):
+ """This class implements ISO 14443-4 access through the
+ PN532 in an ACR122 reader with firmware version 1.x"""
+ def list_readers(cls):
+ pcsc_readers = PCSC_Reader.list_readers()
+ readers = []
+ for name, obj in pcsc_readers:
+ if name.startswith("ACS ACR 38U-CCID"):
+ reader = cls(obj)
+ readers.append( (reader.name, reader) )
+ return readers
+ list_readers = classmethod(list_readers)
+
+ name = property(lambda self: self._name, None, None, "The human readable name of the reader")
+
+ def __init__(self, parent):
+ self._parent = parent
+ self._name = self._parent.name+"-RFID"
+
+ def pn532_transceive_raw(self, command):
+ c_apdu = "\xff\x00\x00\x00" + chr(len(command)) + command
+ r_apdu = self._parent.transceive(c_apdu)
+
+ if len(r_apdu) == 2 and r_apdu[0] == "\x61":
+ c_apdu = "\xff\xc0\x00\x00" + r_apdu[1]
+ r_apdu = self._parent.transceive(c_apdu)
+
+ return r_apdu
+
+ def pn532_transceive(self, command):
+ response = self.pn532_transceive_raw(command)
+
+ if len(response) < 2 or response[-2:] != ["\x90", "\x00"]:
+ raise IOError, "Couldn't communicate with PN532"
+
+ if not (response[0] == "\xd5" and ord(response[1]) == ord(command[1])+1 ):
+ raise IOError, "Wrong response from PN532"
+
+ return "".join(response[:-2])
+
+ def pn532_acquire_card(self):
+ response = self.pn532_transceive("\xd4\x04")
+ if ord(response[4]) > 0:
+ return True
+ else:
+ response = self.pn532_transceive("\xd4\x4a\x01\x00")
+ if ord(response[2]) > 0:
+ return True
+ else:
+ response = self.pn532_transceive("\xd4\x4a\x01\x03")
+ if ord(response[2]) > 0:
+ return True
+
+ def connect(self):
+ # FIXME Add loop or something similar to PCSC_Reader.connect
+ self._parent.connect()
+ self.pn532_acquire_card()
+
+ def get_ATR(self):
+ # FIXME Properly implement for PC/SC version 2
+ return "\x3b\x80\x80\x01\x01"
+
+ def transceive(self, data):
+ # FIXME Properly determine target number
+ response = self.pn532_transceive("\xd4\x40\x01" + data)
+ if response[2] != "\x00":
+ # FIXME Proper error processing
+ raise IOError, "Error while transceiving"
+ return response[3:]
+
+ def disconnect(self):
+ self._parent.disconnect()
def list_readers():
"Collect readers from all known drivers"
readers = PCSC_Reader.list_readers()
+ readers.extend( ACR122_Reader.list_readers() )
return readers
def connect_to(reader):