From f66992469c5de6ac3f94d33d64a0bdbaedc7f719 Mon Sep 17 00:00:00 2001 From: Stefan Wendler Date: Mon, 30 May 2016 22:27:29 +0200 Subject: [PATCH] First commit --- README.md | 40 +++++++++ examples/read.py | 40 +++++++++ examples/write.py | 44 ++++++++++ mfrc522.py | 215 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 339 insertions(+) create mode 100644 examples/read.py create mode 100644 examples/write.py create mode 100644 mfrc522.py diff --git a/README.md b/README.md index 37d8191..e689871 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,42 @@ # micropython-mfrc522 (Micro)Python class to access the MFRC522 RFID reader + +Basic class to access RFID readers of the type [MFRC522](http://www.nxp.com/documents/data_sheet/MFRC522.pdf). +This is basically a re-write of [this](https://github.com/mxgxw/MFRC522-python) Python port for the MFRC522. I +tried to strip things down and make them more "pythonic" so the result is small enough to run on +[Micropython](https://github.com/micropython/micropython) boards. The only board I tried this so far is the +[ESP8266](https://github.com/micropython/micropython/tree/master/esp8266). + +## Usage + +Put the modules ``mfrc522.py``, ``examples/read.py``, ``examples/write.py`` to the root of the flash FS on your board. +For the ESP8266 there are multiple solutions to do that. E.g. use the +[WebREPL file transfer](https://github.com/micropython/webrepl), or [mpfshell](https://github.com/wendlers/mpfshell). + +The class expects the reader by default to be connected like this: + +| Signal | GPIO | Note | +| --------- | --------- | ------------------------------------- | +| sck | GPIO0 | | +| mosi | GPIO2 | | +| miso | GPIO4 | | +| rst | GPIO5 | | +| cs | GPIO14 | Labeled SDA on most RFID-RC522 boards | + +Now enter the REPL you could run one of the two exmaples: + +For detecting, authenticating and reading from a card: + + import read + read.do_read() + +This will wait for a MifareClasskic 1k card. As soon the card is detected, it is authenticated, and +16 bytes are read from address 0x08. + +For detecting, authenticating and writing to a card: + + import write + write.do_write() + +This will wait for a MifareClasskic 1k card. As soon the card is detected, it is authenticated, and +16 bytes written to address 0x08. diff --git a/examples/read.py b/examples/read.py new file mode 100644 index 0000000..64e6e74 --- /dev/null +++ b/examples/read.py @@ -0,0 +1,40 @@ +import mfrc522 + + +def do_read(): + + rdr = mfrc522.MFRC522() + + print("") + print("Place card before reader to read from address 0x08") + print("") + + try: + while True: + + (stat, tag_type) = rdr.request(0x26) + + if stat == rdr.OK: + + (stat, raw_uid) = rdr.anticoll() + + if stat == rdr.OK: + print("New card detected") + print(" - tag type: 0x%02x" % tag_type) + print(" - uid : 0x%02x%02x%02x%02x" % (raw_uid[0], raw_uid[1], raw_uid[2], raw_uid[3])) + print("") + + if rdr.select_tag(raw_uid) == rdr.OK: + + key = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF] + + if rdr.auth(0x60, 8, key, raw_uid) == rdr.OK: + print("Address 8 data: %s" % rdr.read(8)) + rdr.stop_crypto1() + else: + print("Authentication error") + else: + print("Failed to select tag") + + except KeyboardInterrupt: + print("Bye") \ No newline at end of file diff --git a/examples/write.py b/examples/write.py new file mode 100644 index 0000000..c072319 --- /dev/null +++ b/examples/write.py @@ -0,0 +1,44 @@ +import mfrc522 + + +def do_write(): + + rdr = mfrc522.MFRC522() + + print("") + print("Place card before reader to write address 0x08") + print("") + + try: + while True: + + (stat, tag_type) = rdr.request(0x26) + + if stat == rdr.OK: + + (stat, raw_uid) = rdr.anticoll() + + if stat == rdr.OK: + print("New card detected") + print(" - tag type: 0x%02x" % tag_type) + print(" - uid : 0x%02x%02x%02x%02x" % (raw_uid[0], raw_uid[1], raw_uid[2], raw_uid[3])) + print("") + + if rdr.select_tag(raw_uid) == rdr.OK: + + key = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF] + + if rdr.auth(0x60, 8, key, raw_uid) == rdr.OK: + stat = rdr.write(8, b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f") + rdr.stop_crypto1() + if stat == rdr.OK: + print("Data written to card") + else: + print("Failed to write data to card") + else: + print("Authentication error") + else: + print("Failed to select tag") + + except KeyboardInterrupt: + print("Bye") diff --git a/mfrc522.py b/mfrc522.py new file mode 100644 index 0000000..19ae5d8 --- /dev/null +++ b/mfrc522.py @@ -0,0 +1,215 @@ +from machine import Pin, SPI + + +class MFRC522: + + OK = 0 + NOTAGERR = 1 + ERR = 2 + + def __init__(self): + + self.sck = Pin(0, Pin.OUT) + self.mosi = Pin(2, Pin.OUT) + self.miso = Pin(4) + self.rst = Pin(5, Pin.OUT) + self.cs = Pin(14, Pin.OUT) + + self.rst.value(0) + self.cs.value(1) + + self.spi = SPI(baudrate=100000, polarity=0, phase=0, sck=self.sck, mosi=self.mosi, miso=self.miso) + self.spi.init() + + self.rst.value(1) + self.init() + + def _wreg(self, reg, val): + + self.cs.value(0) + self.spi.write(b'%c' % int(0xff & ((reg << 1) & 0x7e))) + self.spi.write(b'%c' % int(0xff & val)) + self.cs.value(1) + + def _rreg(self, reg): + + self.cs.value(0) + self.spi.write(b'%c' % int(0xff & (((reg << 1) & 0x7e) | 0x80))) + val = self.spi.read(1) + self.cs.value(1) + + return val[0] + + def _sflags(self, reg, mask): + self._wreg(reg, self._rreg(reg) | mask) + + def _cflags(self, reg, mask): + self._wreg(reg, self._rreg(reg) & (~mask)) + + def _tocard(self, cmd, send): + + recv = [] + bits = irq_en = wait_irq = n = 0 + stat = self.ERR + + if cmd == 0x0E: + irq_en = 0x12 + wait_irq = 0x10 + elif cmd == 0x0C: + irq_en = 0x77 + wait_irq = 0x30 + + self._wreg(0x02, irq_en | 0x80) + self._cflags(0x04, 0x80) + self._sflags(0x0A, 0x80) + self._wreg(0x01, 0x00) + + for c in send: + self._wreg(0x09, c) + self._wreg(0x01, cmd) + + if cmd == 0x0C: + self._sflags(0x0D, 0x80) + + i = 2000 + while True: + n = self._rreg(0x04) + i -= 1 + if ~((i != 0) and ~(n & 0x01) and ~(n & wait_irq)): + break + + self._cflags(0x0D, 0x80) + + if i: + if (self._rreg(0x06) & 0x1B) == 0x00: + stat = self.OK + + if n & irq_en & 0x01: + stat = self.NOTAGERR + elif cmd == 0x0C: + n = self._rreg(0x0A) + lbits = self._rreg(0x0C) & 0x07 + if lbits != 0: + bits = (n - 1) * 8 + lbits + else: + bits = n * 8 + + if n == 0: + n = 1 + elif n > 16: + n = 16 + + for _ in range(n): + recv.append(self._rreg(0x09)) + else: + stat = self.ERR + + return stat, recv, bits + + def _crc(self, data): + + self._cflags(0x05, 0x04) + self._sflags(0x0A, 0x80) + + for c in data: + self._wreg(0x09, c) + + self._wreg(0x01, 0x03) + + i = 0xFF + while True: + n = self._rreg(0x05) + i -= 1 + if not ((i != 0) and not (n & 0x04)): + break + + return [self._rreg(0x22), self._rreg(0x21)] + + def init(self): + + self.reset() + self._wreg(0x2A, 0x8D) + self._wreg(0x2B, 0x3E) + self._wreg(0x2D, 30) + self._wreg(0x2C, 0) + self._wreg(0x15, 0x40) + self._wreg(0x11, 0x3D) + self.antenna_on() + + def reset(self): + self._wreg(0x01, 0x0F) + + def antenna_on(self, on=True): + + if on and ~(self._rreg(0x14) & 0x03): + self._sflags(0x14, 0x03) + else: + self._cflags(0x14, 0x03) + + def request(self, mode): + + self._wreg(0x0D, 0x07) + (stat, recv, bits) = self._tocard(0x0C, [mode]) + + if (stat != self.OK) | (bits != 0x10): + stat = self.ERR + + return stat, bits + + def anticoll(self): + + ser_chk = 0 + ser = [0x93, 0x20] + + self._wreg(0x0D, 0x00) + (stat, recv, bits) = self._tocard(0x0C, ser) + + if stat == self.OK: + if len(recv) == 5: + for i in range(4): + ser_chk = ser_chk ^ recv[i] + if ser_chk != recv[4]: + stat = self.ERR + else: + stat = self.ERR + + return stat, recv + + def select_tag(self, ser): + + buf = [0x93, 0x70] + ser[:5] + buf += self._crc(buf) + (stat, recv, bits) = self._tocard(0x0C, buf) + return self.OK if (stat == self.OK) and (bits == 0x18) else self.ERR + + def auth(self, mode, addr, sect, ser): + return self._tocard(0x0E, [mode, addr] + sect + ser[:4])[0] + + def stop_crypto1(self): + self._cflags(0x08, 0x08) + + def read(self, addr): + + data = [0x30, addr] + data += self._crc(data) + (stat, recv, _) = self._tocard(0x0C, data) + return recv if stat == self.OK else None + + def write(self, addr, data): + + buf = [0xA0, addr] + buf += self._crc(buf) + (stat, recv, bits) = self._tocard(0x0C, buf) + + if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A): + stat = self.ERR + else: + buf = [] + for i in range(16): + buf.append(data[i]) + buf += self._crc(buf) + (stat, recv, bits) = self._tocard(0x0C, buf) + if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A): + stat = self.ERR + + return stat