Add class infrastructure for PN532 commands

This commit is contained in:
Henryk Plötz 2010-03-03 00:58:30 +01:00
parent bc07262d80
commit b27a1e034f
2 changed files with 74 additions and 2 deletions

View File

@ -8,7 +8,7 @@ pycsc you'll need to downgrade to SVN revision 246.
"""
raise
import sys, utils, getopt
import sys, utils, getopt, binascii
class Smartcard_Reader(object):
def list_readers(cls):

View File

@ -1,4 +1,4 @@
import string, binascii, sys, re
import string, binascii, sys, re, inspect
def represent_binary_fancy(len, value, mask = 0):
result = []
@ -454,7 +454,79 @@ class R_APDU(APDU):
def render(self):
"Return this APDU as a binary string"
return self.data + self.sw
class PN532_Frame(APDU):
"""This is not really an ISO 7816 APDU, but close enough to use the same
class infrastructure."""
def __init__(self, *args, **kwargs):
"""If applicable: redirect instance creation to a subclass"""
super(PN532_Frame, self).__init__(*args, **kwargs)
self._autosubclass()
def _autosubclass(self):
"""If a more appropriate subclass is known about, change __class__ to
point to that class."""
# Find all global classes that are a (possibly indirect) subclass of the current class
candidates = [ e for e in globals().values()
if inspect.isclass(e) and issubclass(e, self.__class__)
and not e == self.__class__ ]
# For each candidate: Find if it specifies any matching rules
# through class variables called MATCH_BY_* where * may be any field
# and if so, remove those classes that don't match. Also count the number
# of matches, to determine the best match
matches = {}
for candidate in candidates:
m = 0
for var in dir(candidate):
if var.startswith("MATCH_BY_"):
fieldname = var[len("MATCH_BY_"):]
if getattr(self, fieldname) == getattr(candidate, var):
m = m + 1
else:
m = -1
break
if m != -1:
matches[candidate] = m
# Remove all candidates that don't have maximal score
max_score = max(matches.values())
candidates = [ k for k,v in matches.items() if v == max_score ]
# If there is still more than one candidate remaining, randomly choose
# the first one.
if len(candidates) > 0:
c = candidates[0]
if c != self.__class__:
self.__class__ = c
DIR = _make_byte_property("DIR"); dir = DIR
CMD = _make_byte_property("CMD"); cmd = CMD
def parse(self, data):
self.dir = data[0]
self.cmd = data[1]
self.data = data[2:]
def _format_fields(self):
fields = ["DIR", "CMD"]
return self._format_parts(fields)
def render(self):
return chr(self.cmd) + chr(self.dir) + self.data
class PN532_Command(PN532_Frame):
MATCH_BY_dir = 0xd4
class PN532_Response(PN532_Frame):
MATCH_BY_dir = 0xd5
class PN532_Response_InListPassiveTarget(PN532_Frame):
MATCH_BY_cmd = 0x4b
if __name__ == "__main__":
response = """
0000: 07 A0 00 00 00 03 00 00 07 00 07 A0 00 00 00 62 ...............b