class NFCInterface: def __init__(self, logger=None): # Member variables self.running = False self.writing = False self.write_data = [0] # 16bytes self.nfc = Pn532_i2c() self.db = None self.logger = logger or logging.getLogger(__name__) GPIO.setmode(GPIO.BOARD) GPIO.setup(12, GPIO.OUT, initial=0) # Red GPIO.setup(15, GPIO.OUT, initial=0) # Green # GPIO.cleanup() # Initiate the PN532 module self.logger.info('Initializing PN532 ...') # Send a FirmwareVersion command frame = Pn532Frame(frame_type=PN532_FRAME_TYPE_DATA, data=bytearray([PN532_COMMAND_GETFIRMWAREVERSION])) self.nfc.send_command_check_ack(frame) response = self.nfc.read_response() # Ensure the SAM (Security Access Module) is basically off self.nfc.SAMconfigure() def red(self, state): GPIO.output(12, state) def green(self, state): GPIO.output(15, state) def blink(self, id, number, initial=0): for x in range(0, number): GPIO.output(id, initial) sleep(0.2) GPIO.output(id, not initial) sleep(0.2) def start(self): self.logger.info('Starting NFCInterface ...') self.db = DBInterface(self.logger) self.running = True while (self.running): # Block waiting for a swipe uuid = self.get_uuid() # What we really want here is a callback interface, to abstract away the # specifics of this particular project. For now, we make it work. if (self.writing): # If we're in writing mode self.logger.info('In writing mode') success = 1 # Populate the database with the UUID, if it's not already available, # so at least this card is registered. card_id = self.db.register_card(uuid) if card_id is None: success = 0 # Authenticate for reading/writing self.mifare_auth(uuid, 0x04) ids = [ self.write_data[0], card_id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] self.mifare_write(0x04, ids) self.mifare_auth(uuid, 0x05) md5hash = self.write_data[2:] self.mifare_write(0x05, md5hash) #binprint.print_r_t(self.write_data, "Data to be written") # Need a check here to determine if the card has written correctly, # then we can trust the success check below. if (success): self.db.update_card(card_id, self.write_data[0]) self.writing = False self.logger.info('Success beep.') self.red(0) self.blink(15, 3, 0) else: self.logger.info("Failure beep.") self.green(0) self.blink(12, 3, 0) else: # If we're not in writing mode, we're in default reading mode self.mifare_auth(uuid, 0x04) response_A = self.mifare_read(0x04) self.mifare_auth(uuid, 0x04) response_B = self.mifare_read(0x05) user_id = self.db.check_hash(uuid, response_A, response_B) if (user_id): logged_in = self.db.toggle_status(user_id) # 1 in, 0 out if (logged_in): self.logger.info("Success in beep.") self.green(1) else: self.logger.info("Success out beep.") self.blink(15, 2, 1) else: self.logger.info("Failure beep.") self.red(1) sleep(0.5) self.logger.info("LED reset") self.green(0) self.red(0) # Delay the loop reset for a bit of time # to prevent someone from leaning on the # login/logout button. sleep(3) def stop(self): self.logger.info('Stopping NFCInterface ...') self.running = False self.nfc.stop() def set_writing(self, write_data): self.logger.info('Received data to write') self.red(1) self.green(1) #binprint.print_r_t(write_data, "Received: ") self.writing = True self.write_data = write_data def get_uuid(self): uuid_frame = self.nfc.read_mifare() if uuid_frame is None: return else: return uuid_frame.get_data()[-4:] def mifare_auth(self, uuid, block): if uuid is None: return # Apparently, before we can do anything at all, we must authenticate against the block. # Arduino calls MifareAuthenticate, which wraps the command PN532_COMMAND_INDATAEXCHANGE # (0x40) issued to pn532 with payload MIFARE_CMD_AUTH_A (0x60) on block. auth_data = bytearray([0x40, 0x01, 0x60, block]) # PN532 + MiFare command auth_data += bytearray([0xff, 0xff, 0xff, 0xff, 0xff, 0xff]) # default auth KeyA auth_data += uuid frame = Pn532Frame(frame_type=PN532_FRAME_TYPE_DATA, data=auth_data) self.nfc.send_command_check_ack(frame) def mifare_read(self, block): # Let's try and read a particular block, shall we? # So, the Arduino code uses MifareReadBlock, which is a wrapper around the command # PN532_COMMAND_INDATAEXCHANGE (0x40) issued to the pn532 controller logical relevant # target 0x01, with the payload of MIFARE_CMD_READ (0x30) on block. # Build the frame frame = Pn532Frame(frame_type=PN532_FRAME_TYPE_DATA, data=bytearray([0x40, 0x01, 0x30, block])) # Issue the command self.nfc.send_command_check_ack(frame) response = self.nfc.read_response() return response.get_data() def mifare_write(self, block, data): # Write write write! What a risk. # Arduino uses MifareWriteBlock; a wrapper around PN532_COMMAND_INDATAEXCHANGE (0x40) # issued to pn532, logical relevant target 0x01, with a payload of MIFARE_CMD_WRITE # (0xA0) on block. # Then you've got 16 bytes you can fill with stuff and/or things. write_data = bytearray([0x40, 0x01, 0xA0, block]) write_data += bytearray(data) frame = Pn532Frame(frame_type=PN532_FRAME_TYPE_DATA, data=write_data) self.nfc.send_command_check_ack(frame)
class NFCInterface: def __init__(self, logger=None): # Member variables self.running = False self.writing = False self.write_data = [0] # 16bytes self.nfc = Pn532_i2c() self.db = None self.logger = logger or logging.getLogger(__name__) GPIO.setmode(GPIO.BOARD) GPIO.setup(12,GPIO.OUT, initial=0) # Red GPIO.setup(15,GPIO.OUT, initial=0) # Green # GPIO.cleanup() # Initiate the PN532 module self.logger.info('Initializing PN532 ...') # Send a FirmwareVersion command frame = Pn532Frame(frame_type=PN532_FRAME_TYPE_DATA, data=bytearray([PN532_COMMAND_GETFIRMWAREVERSION])) self.nfc.send_command_check_ack(frame) response = self.nfc.read_response() # Ensure the SAM (Security Access Module) is basically off self.nfc.SAMconfigure() def red(self, state): GPIO.output(12,state) def green(self, state): GPIO.output(15,state) def blink(self, id, number, initial=0): for x in range(0,number): GPIO.output(id, initial) sleep(0.2) GPIO.output(id, not initial) sleep(0.2) def start(self): self.logger.info('Starting NFCInterface ...') self.db = DBInterface(self.logger) self.running = True while (self.running): # Block waiting for a swipe uuid = self.get_uuid() # What we really want here is a callback interface, to abstract away the # specifics of this particular project. For now, we make it work. if (self.writing): # If we're in writing mode self.logger.info('In writing mode') success = 1 # Populate the database with the UUID, if it's not already available, # so at least this card is registered. card_id = self.db.register_card(uuid) if card_id is None: success = 0 # Authenticate for reading/writing self.mifare_auth(uuid, 0x04) ids = [self.write_data[0], card_id, 0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0] self.mifare_write(0x04, ids) self.mifare_auth(uuid, 0x05) md5hash = self.write_data[2:] self.mifare_write(0x05, md5hash) #binprint.print_r_t(self.write_data, "Data to be written") # Need a check here to determine if the card has written correctly, # then we can trust the success check below. if (success): self.db.update_card(card_id, self.write_data[0]) self.writing = False self.logger.info('Success beep.') self.red(0) self.blink(15,3,0) else: self.logger.info("Failure beep.") self.green(0) self.blink(12,3,0) else: # If we're not in writing mode, we're in default reading mode self.mifare_auth(uuid, 0x04) response_A = self.mifare_read(0x04) self.mifare_auth(uuid, 0x04) response_B = self.mifare_read(0x05) user_id = self.db.check_hash(uuid, response_A, response_B) if (user_id): logged_in = self.db.toggle_status(user_id) # 1 in, 0 out if (logged_in): self.logger.info("Success in beep.") self.green(1) else: self.logger.info("Success out beep.") self.blink(15,2,1) else: self.logger.info("Failure beep.") self.red(1) sleep(0.5) self.logger.info("LED reset") self.green(0) self.red(0) # Delay the loop reset for a bit of time # to prevent someone from leaning on the # login/logout button. sleep(3) def stop(self): self.logger.info('Stopping NFCInterface ...') self.running = False self.nfc.stop() def set_writing(self, write_data): self.logger.info('Received data to write') self.red(1) self.green(1) #binprint.print_r_t(write_data, "Received: ") self.writing = True self.write_data = write_data def get_uuid(self): uuid_frame = self.nfc.read_mifare() if uuid_frame is None: return else: return uuid_frame.get_data()[-4:] def mifare_auth(self, uuid, block): if uuid is None: return # Apparently, before we can do anything at all, we must authenticate against the block. # Arduino calls MifareAuthenticate, which wraps the command PN532_COMMAND_INDATAEXCHANGE # (0x40) issued to pn532 with payload MIFARE_CMD_AUTH_A (0x60) on block. auth_data = bytearray([0x40,0x01,0x60,block]) # PN532 + MiFare command auth_data += bytearray([0xff,0xff,0xff,0xff,0xff,0xff]) # default auth KeyA auth_data += uuid frame = Pn532Frame(frame_type=PN532_FRAME_TYPE_DATA, data=auth_data) self.nfc.send_command_check_ack(frame) def mifare_read(self, block): # Let's try and read a particular block, shall we? # So, the Arduino code uses MifareReadBlock, which is a wrapper around the command # PN532_COMMAND_INDATAEXCHANGE (0x40) issued to the pn532 controller logical relevant # target 0x01, with the payload of MIFARE_CMD_READ (0x30) on block. # Build the frame frame = Pn532Frame(frame_type=PN532_FRAME_TYPE_DATA, data=bytearray([0x40,0x01,0x30,block])) # Issue the command self.nfc.send_command_check_ack(frame) response = self.nfc.read_response() return response.get_data() def mifare_write(self, block, data): # Write write write! What a risk. # Arduino uses MifareWriteBlock; a wrapper around PN532_COMMAND_INDATAEXCHANGE (0x40) # issued to pn532, logical relevant target 0x01, with a payload of MIFARE_CMD_WRITE # (0xA0) on block. # Then you've got 16 bytes you can fill with stuff and/or things. write_data = bytearray([0x40,0x01,0xA0,block]) write_data += bytearray(data) frame = Pn532Frame(frame_type=PN532_FRAME_TYPE_DATA, data=write_data) self.nfc.send_command_check_ack(frame)