diff --git a/.gitignore b/.gitignore index 3a49b8e..7262245 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,6 @@ dist/ downloads/ eggs/ .eggs/ -lib/ lib64/ parts/ sdist/ diff --git a/src/api.py b/src/api.py index 30e8a25..d21c6a9 100644 --- a/src/api.py +++ b/src/api.py @@ -25,6 +25,8 @@ def request(self, method: str, url: str, data=None, params=None) -> urequests.Re if query_string: url = f"{url}?{query_string}" + print(f"Requesting {method} {url} {'with data' if data else ''}...") + if method == "GET": if data: raise ValueError("GET requests cannot have data, use params instead") @@ -33,6 +35,8 @@ def request(self, method: str, url: str, data=None, params=None) -> urequests.Re else: resp = urequests.request(method, url, headers=self.__HEADERS, data=json.dumps(data)) + print(f"Response ({resp.status_code}): {resp.text}") + return resp def check_health(self) -> bool: diff --git a/src/lib/__init__.py b/src/lib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/lib/button.py b/src/lib/button.py new file mode 100644 index 0000000..ef13c77 --- /dev/null +++ b/src/lib/button.py @@ -0,0 +1,39 @@ +from machine import Pin + + +class Button(object): + rest_state = False + # pin = None + # pin_number = 0 + RELEASED = 'released' + PRESSED = 'pressed' + + def __init__(self, pin, rest_state=False, callback=None, internal_pullup=False, internal_pulldown=False): + self.pin_number = pin + self.rest_state = rest_state + if internal_pulldown: + self.internal_pull = Pin.PULL_DOWN + self.rest_state = False + elif internal_pullup: + self.internal_pull = Pin.PULL_UP + self.rest_state = True + else: + self.internal_pull = None + + self.pin = Pin(pin, mode=Pin.IN, pull=self.internal_pull) + + self.callback = callback + self.active = False + + def update(self): + # print(self.pin.value()) + if self.pin.value() == (not self.rest_state) and (not self.active): + self.active = True + if self.callback != None: + self.callback(self.pin_number, Button.PRESSED) + return + if self.pin.value() == self.rest_state and self.active: + self.active = False + if self.callback != None: + self.callback(self.pin_number, Button.RELEASED) + return diff --git a/src/lib/buzzer.py b/src/lib/buzzer.py new file mode 100644 index 0000000..99cf022 --- /dev/null +++ b/src/lib/buzzer.py @@ -0,0 +1,64 @@ +# +# MIT License +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +# Сreated by Immersive-programs: +# github: https://github.com/Immersive-programs/micropython-buzzer +from machine import PWM, Timer + + +class Buzzer: + """Tone playback""" + + def __init__(self, pin): + self.buzzer = PWM(pin) + self.beeptimer = Timer() + self.beeps = [] + self.isenabled = True + self.isbeeping = False + + def __beep(self): + """Воспроизводит последовательность звуковых сигналов""" + if self.isenabled: + if len(self.beeps) > 0: + self.isbeeping = True + self.beeptimer.init(mode=Timer.ONE_SHOT, period=self.beeps[0][1], callback=lambda x: self.__beep()) + if self.beeps[0][0] <= 20: + self.buzzer.duty_u16(1) + else: + self.buzzer.duty_u16(32768) + self.buzzer.freq(self.beeps[0][0]) + del self.beeps[0] + else: + self.buzzer.freq(20) + self.buzzer.duty_u16(0) + self.beeptimer.deinit() + self.isbeeping = False + + def beep(self, beeps): + """Добавляет и запускает последовательность звуковых сигналов""" + self.beeps += beeps + if not self.isbeeping: + self.__beep() + + def deinit(self): + self.buzzer.deinit() + self.beeptimer.deinit() diff --git a/src/lib/i2c_lcd.py b/src/lib/i2c_lcd.py new file mode 100644 index 0000000..f923770 --- /dev/null +++ b/src/lib/i2c_lcd.py @@ -0,0 +1,87 @@ +import utime +import gc + +from lcd_api import LcdApi +from machine import I2C + +# PCF8574 pin definitions +MASK_RS = 0x01 # P0 +MASK_RW = 0x02 # P1 +MASK_E = 0x04 # P2 + +SHIFT_BACKLIGHT = 3 # P3 +SHIFT_DATA = 4 # P4-P7 + + +class I2cLcd(LcdApi): + + # Implements a HD44780 character LCD connected via PCF8574 on I2C + + def __init__(self, i2c, i2c_addr, num_lines, num_columns): + self.i2c = i2c + self.i2c_addr = i2c_addr + self.i2c.writeto(self.i2c_addr, bytes([0])) + utime.sleep_ms(20) # Allow LCD time to powerup + # Send reset 3 times + self.hal_write_init_nibble(self.LCD_FUNCTION_RESET) + utime.sleep_ms(5) # Need to delay at least 4.1 msec + self.hal_write_init_nibble(self.LCD_FUNCTION_RESET) + utime.sleep_ms(1) + self.hal_write_init_nibble(self.LCD_FUNCTION_RESET) + utime.sleep_ms(1) + # Put LCD into 4-bit mode + self.hal_write_init_nibble(self.LCD_FUNCTION) + utime.sleep_ms(1) + LcdApi.__init__(self, num_lines, num_columns) + cmd = self.LCD_FUNCTION + if num_lines > 1: + cmd |= self.LCD_FUNCTION_2LINES + self.hal_write_command(cmd) + gc.collect() + + def hal_write_init_nibble(self, nibble): + # Writes an initialization nibble to the LCD. + # This particular function is only used during initialization. + byte = ((nibble >> 4) & 0x0f) << SHIFT_DATA + self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E])) + self.i2c.writeto(self.i2c_addr, bytes([byte])) + gc.collect() + + def hal_backlight_on(self): + # Allows the hal layer to turn the backlight on + self.i2c.writeto(self.i2c_addr, bytes([1 << SHIFT_BACKLIGHT])) + gc.collect() + + def hal_backlight_off(self): + # Allows the hal layer to turn the backlight off + self.i2c.writeto(self.i2c_addr, bytes([0])) + gc.collect() + + def hal_write_command(self, cmd): + # Write a command to the LCD. Data is latched on the falling edge of E. + byte = ((self.backlight << SHIFT_BACKLIGHT) | + (((cmd >> 4) & 0x0f) << SHIFT_DATA)) + self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E])) + self.i2c.writeto(self.i2c_addr, bytes([byte])) + byte = ((self.backlight << SHIFT_BACKLIGHT) | + ((cmd & 0x0f) << SHIFT_DATA)) + self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E])) + self.i2c.writeto(self.i2c_addr, bytes([byte])) + if cmd <= 3: + # The home and clear commands require a worst case delay of 4.1 msec + utime.sleep_ms(5) + gc.collect() + + def hal_write_data(self, data): + # Write data to the LCD. Data is latched on the falling edge of E. + byte = (MASK_RS | + (self.backlight << SHIFT_BACKLIGHT) | + (((data >> 4) & 0x0f) << SHIFT_DATA)) + self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E])) + self.i2c.writeto(self.i2c_addr, bytes([byte])) + byte = (MASK_RS | + (self.backlight << SHIFT_BACKLIGHT) | + ((data & 0x0f) << SHIFT_DATA)) + self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E])) + self.i2c.writeto(self.i2c_addr, bytes([byte])) + gc.collect() diff --git a/src/lib/lcd_api.py b/src/lib/lcd_api.py new file mode 100644 index 0000000..61945d5 --- /dev/null +++ b/src/lib/lcd_api.py @@ -0,0 +1,208 @@ +"""Provides an API for talking to HD44780 compatible character LCDs.""" + +import time + +class LcdApi: + """Implements the API for talking with HD44780 compatible character LCDs. + This class only knows what commands to send to the LCD, and not how to get + them to the LCD. + + It is expected that a derived class will implement the hal_xxx functions. + """ + + # The following constant names were lifted from the avrlib lcd.h + # header file, however, I changed the definitions from bit numbers + # to bit masks. + # + # HD44780 LCD controller command set + + LCD_CLR = 0x01 # DB0: clear display + LCD_HOME = 0x02 # DB1: return to home position + + LCD_ENTRY_MODE = 0x04 # DB2: set entry mode + LCD_ENTRY_INC = 0x02 # --DB1: increment + LCD_ENTRY_SHIFT = 0x01 # --DB0: shift + + LCD_ON_CTRL = 0x08 # DB3: turn lcd/cursor on + LCD_ON_DISPLAY = 0x04 # --DB2: turn display on + LCD_ON_CURSOR = 0x02 # --DB1: turn cursor on + LCD_ON_BLINK = 0x01 # --DB0: blinking cursor + + LCD_MOVE = 0x10 # DB4: move cursor/display + LCD_MOVE_DISP = 0x08 # --DB3: move display (0-> move cursor) + LCD_MOVE_RIGHT = 0x04 # --DB2: move right (0-> left) + + LCD_FUNCTION = 0x20 # DB5: function set + LCD_FUNCTION_8BIT = 0x10 # --DB4: set 8BIT mode (0->4BIT mode) + LCD_FUNCTION_2LINES = 0x08 # --DB3: two lines (0->one line) + LCD_FUNCTION_10DOTS = 0x04 # --DB2: 5x10 font (0->5x7 font) + LCD_FUNCTION_RESET = 0x30 # See "Initializing by Instruction" section + + LCD_CGRAM = 0x40 # DB6: set CG RAM address + LCD_DDRAM = 0x80 # DB7: set DD RAM address + + LCD_RS_CMD = 0 + LCD_RS_DATA = 1 + + LCD_RW_WRITE = 0 + LCD_RW_READ = 1 + + def __init__(self, num_lines, num_columns): + self.num_lines = num_lines + if self.num_lines > 4: + self.num_lines = 4 + self.num_columns = num_columns + if self.num_columns > 40: + self.num_columns = 40 + self.cursor_x = 0 + self.cursor_y = 0 + self.implied_newline = False + self.backlight = True + self.display_off() + self.backlight_on() + self.clear() + self.hal_write_command(self.LCD_ENTRY_MODE | self.LCD_ENTRY_INC) + self.hide_cursor() + self.display_on() + + def clear(self): + """Clears the LCD display and moves the cursor to the top left + corner. + """ + self.hal_write_command(self.LCD_CLR) + self.hal_write_command(self.LCD_HOME) + self.cursor_x = 0 + self.cursor_y = 0 + + def show_cursor(self): + """Causes the cursor to be made visible.""" + self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY | + self.LCD_ON_CURSOR) + + def hide_cursor(self): + """Causes the cursor to be hidden.""" + self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY) + + def blink_cursor_on(self): + """Turns on the cursor, and makes it blink.""" + self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY | + self.LCD_ON_CURSOR | self.LCD_ON_BLINK) + + def blink_cursor_off(self): + """Turns on the cursor, and makes it no blink (i.e. be solid).""" + self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY | + self.LCD_ON_CURSOR) + + def display_on(self): + """Turns on (i.e. unblanks) the LCD.""" + self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY) + + def display_off(self): + """Turns off (i.e. blanks) the LCD.""" + self.hal_write_command(self.LCD_ON_CTRL) + + def backlight_on(self): + """Turns the backlight on. + + This isn't really an LCD command, but some modules have backlight + controls, so this allows the hal to pass through the command. + """ + self.backlight = True + self.hal_backlight_on() + + def backlight_off(self): + """Turns the backlight off. + + This isn't really an LCD command, but some modules have backlight + controls, so this allows the hal to pass through the command. + """ + self.backlight = False + self.hal_backlight_off() + + def move_to(self, cursor_x, cursor_y): + """Moves the cursor position to the indicated position. The cursor + position is zero based (i.e. cursor_x == 0 indicates first column). + """ + self.cursor_x = cursor_x + self.cursor_y = cursor_y + addr = cursor_x & 0x3f + if cursor_y & 1: + addr += 0x40 # Lines 1 & 3 add 0x40 + if cursor_y & 2: # Lines 2 & 3 add number of columns + addr += self.num_columns + self.hal_write_command(self.LCD_DDRAM | addr) + + def putchar(self, char): + """Writes the indicated character to the LCD at the current cursor + position, and advances the cursor by one position. + """ + if char == '\n': + if self.implied_newline: + # self.implied_newline means we advanced due to a wraparound, + # so if we get a newline right after that we ignore it. + pass + else: + self.cursor_x = self.num_columns + else: + self.hal_write_data(ord(char)) + self.cursor_x += 1 + if self.cursor_x >= self.num_columns: + self.cursor_x = 0 + self.cursor_y += 1 + self.implied_newline = (char != '\n') + if self.cursor_y >= self.num_lines: + self.cursor_y = 0 + self.move_to(self.cursor_x, self.cursor_y) + + def putstr(self, string): + """Write the indicated string to the LCD at the current cursor + position and advances the cursor position appropriately. + """ + for char in string: + self.putchar(char) + + def custom_char(self, location, charmap): + """Write a character to one of the 8 CGRAM locations, available + as chr(0) through chr(7). + """ + location &= 0x7 + self.hal_write_command(self.LCD_CGRAM | (location << 3)) + self.hal_sleep_us(40) + for i in range(8): + self.hal_write_data(charmap[i]) + self.hal_sleep_us(40) + self.move_to(self.cursor_x, self.cursor_y) + + def hal_backlight_on(self): + """Allows the hal layer to turn the backlight on. + + If desired, a derived HAL class will implement this function. + """ + pass + + def hal_backlight_off(self): + """Allows the hal layer to turn the backlight off. + + If desired, a derived HAL class will implement this function. + """ + pass + + def hal_write_command(self, cmd): + """Write a command to the LCD. + + It is expected that a derived HAL class will implement this + function. + """ + raise NotImplementedError + + def hal_write_data(self, data): + """Write data to the LCD. + + It is expected that a derived HAL class will implement this + function. + """ + raise NotImplementedError + + def hal_sleep_us(self, usecs): + """Sleep for some time (given in microseconds).""" + time.sleep_us(usecs) diff --git a/src/lib/mfrc522.py b/src/lib/mfrc522.py new file mode 100644 index 0000000..cfc1c01 --- /dev/null +++ b/src/lib/mfrc522.py @@ -0,0 +1,367 @@ +from machine import Pin, SPI +from os import uname + + +class MFRC522: + DEBUG = False + OK = 0 + NOTAGERR = 1 + ERR = 2 + + REQIDL = 0x26 + REQALL = 0x52 + AUTHENT1A = 0x60 + AUTHENT1B = 0x61 + + PICC_ANTICOLL1 = 0x93 + PICC_ANTICOLL2 = 0x95 + PICC_ANTICOLL3 = 0x97 + + def __init__(self, sck, mosi, miso, rst, cs, baudrate=1000000, spi_id=0): + + self.sck = Pin(sck, Pin.OUT) + self.mosi = Pin(mosi, Pin.OUT) + self.miso = Pin(miso) + self.rst = Pin(rst, Pin.OUT) + self.cs = Pin(cs, Pin.OUT) + + self.rst.value(0) + self.cs.value(1) + + board = uname()[0] + + if board == 'WiPy' or board == 'LoPy' or board == 'FiPy': + self.spi = SPI(0) + self.spi.init(SPI.MASTER, baudrate=1000000, pins=(self.sck, self.mosi, self.miso)) + elif (board == 'esp8266') or (board == 'esp32'): + self.spi = SPI(baudrate=100000, polarity=0, phase=0, sck=self.sck, mosi=self.mosi, miso=self.miso) + self.spi.init() + elif board == 'rp2': + self.spi = SPI(spi_id, baudrate=baudrate, sck=self.sck, mosi=self.mosi, miso=self.miso) + else: + raise RuntimeError("Unsupported platform") + + 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, anticolN): + + ser_chk = 0 + ser = [anticolN, 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 PcdSelect(self, serNum, anticolN): + backData = [] + buf = [] + buf.append(anticolN) + buf.append(0x70) + # i = 0 + ###xorsum=0; + for i in serNum: + buf.append(i) + # while i<5: + # buf.append(serNum[i]) + # i = i + 1 + pOut = self._crc(buf) + buf.append(pOut[0]) + buf.append(pOut[1]) + (status, backData, backLen) = self._tocard(0x0C, buf) + if (status == self.OK) and (backLen == 0x18): + return 1 + else: + return 0 + + def SelectTag(self, uid): + byte5 = 0 + + # (status,puid)= self.anticoll(self.PICC_ANTICOLL1) + # print("uid",uid,"puid",puid) + for i in uid: + byte5 = byte5 ^ i + puid = uid + [byte5] + + if self.PcdSelect(puid, self.PICC_ANTICOLL1) == 0: + return (self.ERR, []) + return (self.OK, uid) + + def tohexstring(self, v): + s = "[" + for i in v: + if i != v[0]: + s = s + ", " + s = s + "0x{:02X}".format(i) + s = s + "]" + return s + + def SelectTagSN(self): + valid_uid = [] + (status, uid) = self.anticoll(self.PICC_ANTICOLL1) + # print("Select Tag 1:",self.tohexstring(uid)) + if status != self.OK: + return (self.ERR, []) + + if self.DEBUG: print("anticol(1) {}".format(uid)) + if self.PcdSelect(uid, self.PICC_ANTICOLL1) == 0: + return (self.ERR, []) + if self.DEBUG: print("pcdSelect(1) {}".format(uid)) + + # check if first byte is 0x88 + if uid[0] == 0x88: + # ok we have another type of card + valid_uid.extend(uid[1:4]) + (status, uid) = self.anticoll(self.PICC_ANTICOLL2) + # print("Select Tag 2:",self.tohexstring(uid)) + if status != self.OK: + return (self.ERR, []) + if self.DEBUG: print("Anticol(2) {}".format(uid)) + rtn = self.PcdSelect(uid, self.PICC_ANTICOLL2) + if self.DEBUG: print("pcdSelect(2) return={} uid={}".format(rtn, uid)) + if rtn == 0: + return (self.ERR, []) + if self.DEBUG: print("PcdSelect2() {}".format(uid)) + # now check again if uid[0] is 0x88 + if uid[0] == 0x88: + valid_uid.extend(uid[1:4]) + (status, uid) = self.anticoll(self.PICC_ANTICOLL3) + # print("Select Tag 3:",self.tohexstring(uid)) + if status != self.OK: + return (self.ERR, []) + if self.DEBUG: print("Anticol(3) {}".format(uid)) + if self.MFRC522_PcdSelect(uid, self.PICC_ANTICOLL3) == 0: + return (self.ERR, []) + if self.DEBUG: print("PcdSelect(3) {}".format(uid)) + valid_uid.extend(uid[0:5]) + # if we are here than the uid is ok + # let's remove the last BYTE whic is the XOR sum + + return (self.OK, valid_uid[:len(valid_uid) - 1]) + # return (self.OK , valid_uid) + + def auth(self, mode, addr, sect, ser): + return self._tocard(0x0E, [mode, addr] + sect + ser[:4])[0] + + def authKeys(self, uid, addr, keyA=None, keyB=None): + status = self.ERR + if keyA is not None: + status = self.auth(self.AUTHENT1A, addr, keyA, uid) + elif keyB is not None: + status = self.auth(self.AUTHENT1B, addr, keyB, uid) + return status + + 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 stat, recv + + 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 + + def writeSectorBlock(self, uid, sector, block, data, keyA=None, keyB=None): + absoluteBlock = sector * 4 + (block % 4) + if absoluteBlock > 63: + return self.ERR + if len(data) != 16: + return self.ERR + if self.authKeys(uid, absoluteBlock, keyA, keyB) != self.ERR: + return self.write(absoluteBlock, data) + return self.ERR + + def readSectorBlock(self, uid, sector, block, keyA=None, keyB=None): + absoluteBlock = sector * 4 + (block % 4) + if absoluteBlock > 63: + return self.ERR, None + if self.authKeys(uid, absoluteBlock, keyA, keyB) != self.ERR: + return self.read(absoluteBlock) + return self.ERR, None + + def MFRC522_DumpClassic1K(self, uid, Start=0, End=64, keyA=None, keyB=None): + for absoluteBlock in range(Start, End): + status = self.authKeys(uid, absoluteBlock, keyA, keyB) + # Check if authenticated + print("{:02d} S{:02d} B{:1d}: ".format(absoluteBlock, absoluteBlock // 4, absoluteBlock % 4), end="") + if status == self.OK: + status, block = self.read(absoluteBlock) + if status == self.ERR: + break + else: + for value in block: + print("{:02X} ".format(value), end="") + print(" ", end="") + for value in block: + if (value > 0x20) and (value < 0x7f): + print(chr(value), end="") + else: + print('.', end="") + print("") + else: + break + if status == self.ERR: + print("Authentication error") + return self.ERR + return self.OK + diff --git a/src/main.py b/src/main.py index b1eb888..271d3d1 100644 --- a/src/main.py +++ b/src/main.py @@ -82,8 +82,6 @@ def __change_device(self, device_data: dict) -> None: self.__display.print("No devices", line=2) return - print(device_data) - text = f"{device_data['index'] + 1}/{device_data['total']} {device_data['device']['name']}" self.__display.print(text, line=2)