Commit cb678a0f authored by David Adam's avatar David Adam
Browse files

MIFARE: compatibility with PySerial 3

parent b728c696
......@@ -11,7 +11,7 @@ import serial, logging
xor = lambda x, y: x ^ y
def checksum(string):
return chr(reduce(xor, [ord(i) for i in string]))
return chr(reduce(xor, [ord(i) for i in string]))
class MIFAREException(Exception):
......@@ -28,15 +28,15 @@ class MIFAREAuthenticationException(MIFAREException):
class MIFAREReader:
'''An interface to a particular MIFARE reader.'''
def __init__(self, io):
'''Returns an interface to a MIFARE reader given a file-like object.
The file-like object is generally a pyserial Serial object.'''
self.io = io
if isinstance(self.io, serial.Serial):
self.io.setTimeout(2)
self.io.setTimeout = 2
self.address = '\x00\x00'
def get_absolute_block(self, vector):
if vector[0] < 32:
return vector[0] * 4 + vector[1]
......@@ -45,17 +45,17 @@ class MIFAREReader:
# Sectors above are 16 blocks
# Thus, sector 32 starts at block 128, 33 at 144, and so on
return 128 + (vector[0] - 32) * 16 + vector[1]
def send_packet(self, data):
'''Constructs a packet for the supplied data string, sends it to the
MIFARE reader, then returns the response (if any) to the commmand.'''
# Occasionally the reader inserts extra trailing characters into its
# responses, so flush the buffers if possible beforehand.
if isinstance(self.io, serial.Serial):
self.io.flushInput()
self.io.flushOutput()
# XXX - Needs more error checking.
data = '\x00' + self.address + data
packet = '\xAA\xBB' + chr(len(data)) + data + checksum(data)
......@@ -71,7 +71,7 @@ class MIFAREReader:
return data[3:]
else:
raise MIFARECommunicationException, "Invalid response received"
def set_antenna(self, state = True):
"""Turn the card reader's antenna on or off (no return value)"""
command = '\x0C\x01' + chr(int(state))
......@@ -80,36 +80,36 @@ class MIFAREReader:
return None
else:
raise MIFAREException, 'command failed: set_antenna (%s)' % state
def select_card(self, include_halted = False):
"""Selects a card and returns a tuple of (serial number, capacity).
If include_halted is set, may select a card that halt() has previously
been called on."""
# Request type of card available
command = command = '\x01\x02'
if include_halted:
command += '\x52'
else:
command += '\x26'
card_type_response = self.send_packet(command)
if card_type_response == None or card_type_response[2] == '\x14':
raise MIFAREException, "select_card: no card available"
card_type = card_type_response[3:5]
if card_type == '\x44\x00': # MIFARE UltraLight
raise NotImplementedError, "UltraLight card selected - no functions available"
else:
# Otherwise, must be a standard MIFARE card.
# Anticollision
command = '\x02\x02\x04'
# No error handling on this command
serial = self.send_packet(command)[3:]
# Select the card for use
try:
select_response = self.send_packet('\x03\x02' + serial)
......@@ -118,58 +118,58 @@ class MIFAREReader:
logging.warning('Tried to select card but failed: card_type %s, serial %s, select_response %s' % (card_type.__repr__(), serial.__repr__(), select_response.__repr__()))
capacity = 0
return (serial, capacity)
def sector_login(self, blockvect, key, keytype=0):
"""Log in to a block using the six-byte key.
Use a keytype of 1 to use key B."""
sector = self.get_absolute_block((blockvect[0], 0))
if len(key) != 6:
raise ValueError, 'key must be a six-byte string'
keytype = 96 + keytype
data = chr(keytype) + chr(sector) + key
result = self.send_packet('\x07\x02' + data)
if ord(result[2]) == 22:
raise MIFAREAuthenticationException, "incorrect key provided"
return
def read_block(self, blockvect):
"Read the 16-byte block at vector (sector, block)."
block = self.get_absolute_block(blockvect)
result = self.send_packet('\x08\x02' + chr(block))
return result[3:19]
def write_block(self, blockvect, data):
"""Write the 16 bytes in data to the block at vector (sector, block)."""
block = self.get_absolute_block(blockvect)
if len(data) != 16:
raise ValueError, "invalid data length - must be 16 bytes"
result = self.send_packet('\x09\x02' + chr(block) + data)
return
def write_key(self, key):
pass
def value_block_increment(self, blocknum, increment):
pass
def value_block_decrement(self, blocknum, decrement):
pass
def copy_block(self, source, dest):
pass
def halt(self):
"""Halt the current card - no further transactions will be performed with it."""
self.send_packet('\x04\x02')
def set_led(self, red = False, green = False):
led_state = 0
if red:
......@@ -177,13 +177,13 @@ class MIFAREReader:
if green:
led_state += 2
self.send_packet('\x07\x01' + chr(led_state))
def beep(self, length):
'''Beep for a specified length of milliseconds.'''
length = int(round(length / 10.))
if length > 255:
length = 255
self.send_packet('\x06\x01' + chr(length))
def reset(self):
pass
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment