-
-
Save AxizY/ace631bd5eb6f4eedf281c6366acfe4f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf8 -*- | |
# | |
# Copyright 2014,2018 Mario Gomez <mario.gomez@teubi.co> | |
# | |
# This file is part of MFRC522-Python | |
# MFRC522-Python is a simple Python implementation for | |
# the MFRC522 NFC Card Reader for the Raspberry Pi. | |
# | |
# MFRC522-Python is free software: you can redistribute it and/or modify | |
# it under the terms of the GNU Lesser General Public License as published by | |
# the Free Software Foundation, either version 3 of the License, or | |
# (at your option) any later version. | |
# | |
# MFRC522-Python is distributed in the hope that it will be useful, | |
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
# GNU Lesser General Public License for more details. | |
# | |
# You should have received a copy of the GNU Lesser General Public License | |
# along with MFRC522-Python. If not, see <http://www.gnu.org/licenses/>. | |
# | |
import spidev | |
import signal | |
import time | |
import logging | |
import os | |
def writePin(pin, value): | |
os.system(f"sudo lgpio set {pin}={value}") | |
class MFRC522: | |
MAX_LEN = 16 | |
PCD_IDLE = 0x00 | |
PCD_AUTHENT = 0x0E | |
PCD_RECEIVE = 0x08 | |
PCD_TRANSMIT = 0x04 | |
PCD_TRANSCEIVE = 0x0C | |
PCD_RESETPHASE = 0x0F | |
PCD_CALCCRC = 0x03 | |
PICC_REQIDL = 0x26 | |
PICC_REQALL = 0x52 | |
PICC_ANTICOLL = 0x93 | |
PICC_SElECTTAG = 0x93 | |
PICC_AUTHENT1A = 0x60 | |
PICC_AUTHENT1B = 0x61 | |
PICC_READ = 0x30 | |
PICC_WRITE = 0xA0 | |
PICC_DECREMENT = 0xC0 | |
PICC_INCREMENT = 0xC1 | |
PICC_RESTORE = 0xC2 | |
PICC_TRANSFER = 0xB0 | |
PICC_HALT = 0x50 | |
MI_OK = 0 | |
MI_NOTAGERR = 1 | |
MI_ERR = 2 | |
Reserved00 = 0x00 | |
CommandReg = 0x01 | |
CommIEnReg = 0x02 | |
DivlEnReg = 0x03 | |
CommIrqReg = 0x04 | |
DivIrqReg = 0x05 | |
ErrorReg = 0x06 | |
Status1Reg = 0x07 | |
Status2Reg = 0x08 | |
FIFODataReg = 0x09 | |
FIFOLevelReg = 0x0A | |
WaterLevelReg = 0x0B | |
ControlReg = 0x0C | |
BitFramingReg = 0x0D | |
CollReg = 0x0E | |
Reserved01 = 0x0F | |
Reserved10 = 0x10 | |
ModeReg = 0x11 | |
TxModeReg = 0x12 | |
RxModeReg = 0x13 | |
TxControlReg = 0x14 | |
TxAutoReg = 0x15 | |
TxSelReg = 0x16 | |
RxSelReg = 0x17 | |
RxThresholdReg = 0x18 | |
DemodReg = 0x19 | |
Reserved11 = 0x1A | |
Reserved12 = 0x1B | |
MifareReg = 0x1C | |
Reserved13 = 0x1D | |
Reserved14 = 0x1E | |
SerialSpeedReg = 0x1F | |
Reserved20 = 0x20 | |
CRCResultRegM = 0x21 | |
CRCResultRegL = 0x22 | |
Reserved21 = 0x23 | |
ModWidthReg = 0x24 | |
Reserved22 = 0x25 | |
RFCfgReg = 0x26 | |
GsNReg = 0x27 | |
CWGsPReg = 0x28 | |
ModGsPReg = 0x29 | |
TModeReg = 0x2A | |
TPrescalerReg = 0x2B | |
TReloadRegH = 0x2C | |
TReloadRegL = 0x2D | |
TCounterValueRegH = 0x2E | |
TCounterValueRegL = 0x2F | |
Reserved30 = 0x30 | |
TestSel1Reg = 0x31 | |
TestSel2Reg = 0x32 | |
TestPinEnReg = 0x33 | |
TestPinValueReg = 0x34 | |
TestBusReg = 0x35 | |
AutoTestReg = 0x36 | |
VersionReg = 0x37 | |
AnalogTestReg = 0x38 | |
TestDAC1Reg = 0x39 | |
TestDAC2Reg = 0x3A | |
TestADCReg = 0x3B | |
Reserved31 = 0x3C | |
Reserved32 = 0x3D | |
Reserved33 = 0x3E | |
Reserved34 = 0x3F | |
serNum = [] | |
def __init__(self, bus=0, device=0, spd=1000000, pin_mode=10, pin_rst=-1, debugLevel='WARNING'): | |
self.spi = spidev.SpiDev() | |
self.spi.open(bus, device) | |
self.spi.max_speed_hz = spd | |
self.logger = logging.getLogger('mfrc522Logger') | |
self.logger.addHandler(logging.StreamHandler()) | |
level = logging.getLevelName(debugLevel) | |
self.logger.setLevel(level) | |
writePin(22, 1) | |
self.MFRC522_Init() | |
def MFRC522_Reset(self): | |
self.Write_MFRC522(self.CommandReg, self.PCD_RESETPHASE) | |
def Write_MFRC522(self, addr, val): | |
val = self.spi.xfer2([(addr << 1) & 0x7E, val]) | |
def Read_MFRC522(self, addr): | |
val = self.spi.xfer2([((addr << 1) & 0x7E) | 0x80, 0]) | |
return val[1] | |
def Close_MFRC522(self): | |
self.spi.close() | |
def SetBitMask(self, reg, mask): | |
tmp = self.Read_MFRC522(reg) | |
self.Write_MFRC522(reg, tmp | mask) | |
def ClearBitMask(self, reg, mask): | |
tmp = self.Read_MFRC522(reg) | |
self.Write_MFRC522(reg, tmp & (~mask)) | |
def AntennaOn(self): | |
temp = self.Read_MFRC522(self.TxControlReg) | |
if (~(temp & 0x03)): | |
self.SetBitMask(self.TxControlReg, 0x03) | |
def AntennaOff(self): | |
self.ClearBitMask(self.TxControlReg, 0x03) | |
def MFRC522_ToCard(self, command, sendData): | |
backData = [] | |
backLen = 0 | |
status = self.MI_ERR | |
irqEn = 0x00 | |
waitIRq = 0x00 | |
lastBits = None | |
n = 0 | |
if command == self.PCD_AUTHENT: | |
irqEn = 0x12 | |
waitIRq = 0x10 | |
if command == self.PCD_TRANSCEIVE: | |
irqEn = 0x77 | |
waitIRq = 0x30 | |
self.Write_MFRC522(self.CommIEnReg, irqEn | 0x80) | |
self.ClearBitMask(self.CommIrqReg, 0x80) | |
self.SetBitMask(self.FIFOLevelReg, 0x80) | |
self.Write_MFRC522(self.CommandReg, self.PCD_IDLE) | |
for i in range(len(sendData)): | |
self.Write_MFRC522(self.FIFODataReg, sendData[i]) | |
self.Write_MFRC522(self.CommandReg, command) | |
if command == self.PCD_TRANSCEIVE: | |
self.SetBitMask(self.BitFramingReg, 0x80) | |
i = 2000 | |
while True: | |
n = self.Read_MFRC522(self.CommIrqReg) | |
i -= 1 | |
if ~((i != 0) and ~(n & 0x01) and ~(n & waitIRq)): | |
break | |
self.ClearBitMask(self.BitFramingReg, 0x80) | |
if i != 0: | |
if (self.Read_MFRC522(self.ErrorReg) & 0x1B) == 0x00: | |
status = self.MI_OK | |
if n & irqEn & 0x01: | |
status = self.MI_NOTAGERR | |
if command == self.PCD_TRANSCEIVE: | |
n = self.Read_MFRC522(self.FIFOLevelReg) | |
lastBits = self.Read_MFRC522(self.ControlReg) & 0x07 | |
if lastBits != 0: | |
backLen = (n - 1) * 8 + lastBits | |
else: | |
backLen = n * 8 | |
if n == 0: | |
n = 1 | |
if n > self.MAX_LEN: | |
n = self.MAX_LEN | |
for i in range(n): | |
backData.append(self.Read_MFRC522(self.FIFODataReg)) | |
else: | |
status = self.MI_ERR | |
return (status, backData, backLen) | |
def MFRC522_Request(self, reqMode): | |
status = None | |
backBits = None | |
TagType = [] | |
self.Write_MFRC522(self.BitFramingReg, 0x07) | |
TagType.append(reqMode) | |
(status, backData, backBits) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, TagType) | |
if ((status != self.MI_OK) | (backBits != 0x10)): | |
status = self.MI_ERR | |
return (status, backBits) | |
def MFRC522_Anticoll(self): | |
backData = [] | |
serNumCheck = 0 | |
serNum = [] | |
self.Write_MFRC522(self.BitFramingReg, 0x00) | |
serNum.append(self.PICC_ANTICOLL) | |
serNum.append(0x20) | |
(status, backData, backBits) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, serNum) | |
if (status == self.MI_OK): | |
i = 0 | |
if len(backData) == 5: | |
for i in range(4): | |
serNumCheck = serNumCheck ^ backData[i] | |
if serNumCheck != backData[4]: | |
status = self.MI_ERR | |
else: | |
status = self.MI_ERR | |
return (status, backData) | |
def CalulateCRC(self, pIndata): | |
self.ClearBitMask(self.DivIrqReg, 0x04) | |
self.SetBitMask(self.FIFOLevelReg, 0x80) | |
for i in range(len(pIndata)): | |
self.Write_MFRC522(self.FIFODataReg, pIndata[i]) | |
self.Write_MFRC522(self.CommandReg, self.PCD_CALCCRC) | |
i = 0xFF | |
while True: | |
n = self.Read_MFRC522(self.DivIrqReg) | |
i -= 1 | |
if not ((i != 0) and not (n & 0x04)): | |
break | |
pOutData = [] | |
pOutData.append(self.Read_MFRC522(self.CRCResultRegL)) | |
pOutData.append(self.Read_MFRC522(self.CRCResultRegM)) | |
return pOutData | |
def MFRC522_SelectTag(self, serNum): | |
backData = [] | |
buf = [] | |
buf.append(self.PICC_SElECTTAG) | |
buf.append(0x70) | |
for i in range(5): | |
buf.append(serNum[i]) | |
pOut = self.CalulateCRC(buf) | |
buf.append(pOut[0]) | |
buf.append(pOut[1]) | |
(status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, buf) | |
if (status == self.MI_OK) and (backLen == 0x18): | |
self.logger.debug("Size: " + str(backData[0])) | |
return backData[0] | |
else: | |
return 0 | |
def MFRC522_Auth(self, authMode, BlockAddr, Sectorkey, serNum): | |
buff = [] | |
# First byte should be the authMode (A or B) | |
buff.append(authMode) | |
# Second byte is the trailerBlock (usually 7) | |
buff.append(BlockAddr) | |
# Now we need to append the authKey which usually is 6 bytes of 0xFF | |
for i in range(len(Sectorkey)): | |
buff.append(Sectorkey[i]) | |
# Next we append the first 4 bytes of the UID | |
for i in range(4): | |
buff.append(serNum[i]) | |
# Now we start the authentication itself | |
(status, backData, backLen) = self.MFRC522_ToCard(self.PCD_AUTHENT, buff) | |
# Check if an error occurred | |
if not (status == self.MI_OK): | |
self.logger.error("AUTH ERROR!!") | |
if not (self.Read_MFRC522(self.Status2Reg) & 0x08) != 0: | |
self.logger.error("AUTH ERROR(status2reg & 0x08) != 0") | |
# Return the status | |
return status | |
def MFRC522_StopCrypto1(self): | |
self.ClearBitMask(self.Status2Reg, 0x08) | |
def MFRC522_Read(self, blockAddr): | |
recvData = [] | |
recvData.append(self.PICC_READ) | |
recvData.append(blockAddr) | |
pOut = self.CalulateCRC(recvData) | |
recvData.append(pOut[0]) | |
recvData.append(pOut[1]) | |
(status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, recvData) | |
if not (status == self.MI_OK): | |
self.logger.error("Error while reading!") | |
if len(backData) == 16: | |
self.logger.debug("Sector " + str(blockAddr) + " " + str(backData)) | |
return backData | |
else: | |
return None | |
def MFRC522_Write(self, blockAddr, writeData): | |
buff = [] | |
buff.append(self.PICC_WRITE) | |
buff.append(blockAddr) | |
crc = self.CalulateCRC(buff) | |
buff.append(crc[0]) | |
buff.append(crc[1]) | |
(status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, buff) | |
if not (status == self.MI_OK) or not (backLen == 4) or not ((backData[0] & 0x0F) == 0x0A): | |
status = self.MI_ERR | |
self.logger.debug("%s backdata &0x0F == 0x0A %s" % (backLen, backData[0] & 0x0F)) | |
if status == self.MI_OK: | |
buf = [] | |
for i in range(16): | |
buf.append(writeData[i]) | |
crc = self.CalulateCRC(buf) | |
buf.append(crc[0]) | |
buf.append(crc[1]) | |
(status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, buf) | |
if not (status == self.MI_OK) or not (backLen == 4) or not ((backData[0] & 0x0F) == 0x0A): | |
self.logger.error("Error while writing") | |
if status == self.MI_OK: | |
self.logger.debug("Data written") | |
def MFRC522_DumpClassic1K(self, key, uid): | |
for i in range(64): | |
status = self.MFRC522_Auth(self.PICC_AUTHENT1A, i, key, uid) | |
# Check if authenticated | |
if status == self.MI_OK: | |
self.MFRC522_Read(i) | |
else: | |
self.logger.error("Authentication error") | |
def MFRC522_Init(self): | |
self.MFRC522_Reset() | |
self.Write_MFRC522(self.TModeReg, 0x8D) | |
self.Write_MFRC522(self.TPrescalerReg, 0x3E) | |
self.Write_MFRC522(self.TReloadRegL, 30) | |
self.Write_MFRC522(self.TReloadRegH, 0) | |
self.Write_MFRC522(self.TxAutoReg, 0x40) | |
self.Write_MFRC522(self.ModeReg, 0x3D) | |
self.AntennaOn() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment