diff --git a/src/input/ukeypad.py b/src/input/ukeypad.py index 946a93d..059dc83 100644 --- a/src/input/ukeypad.py +++ b/src/input/ukeypad.py @@ -2,7 +2,7 @@ import machine import utime -class membrane: +class Membrane: """Class for interpreting input from a membran-like keypad, the default is a 4x4 matrix array membrane keypad. The layout of key bindings and size (i.e. 4x3 alternative) @@ -244,7 +244,7 @@ class membrane: if __name__ == "__main__": - membrane_keypad = membrane() + membrane_keypad = Membrane() pin_size = 12 while len(membrane_keypad) < pin_size: diff --git a/src/radiotech/rfid/umfrc522.py b/src/radiotech/rfid/umfrc522.py index 6d2a836..2b1bfe6 100644 --- a/src/radiotech/rfid/umfrc522.py +++ b/src/radiotech/rfid/umfrc522.py @@ -636,7 +636,7 @@ if __name__ == "__main__": ) for sector_block in range(4) ) - print(f"Sector {sector: 02d}: {sector_text}") + print(f"Sector {sector:02d}: {sector_text}") except TypeError: break # When removing card, just skip else: diff --git a/src/systems/cardterm.py b/src/systems/cardterm.py new file mode 100644 index 0000000..6f97adb --- /dev/null +++ b/src/systems/cardterm.py @@ -0,0 +1,202 @@ +import utime +from machine import Pin, Timer, PWM +from input.ukeypad import Membrane as KeyPad +from radiotech.rfid.umfrc522 import UMFRC522 as MFRC522 + +class CardTermRC522: + @classmethod + def led_pulse(cls, led_pwm, led_timer, period=1000, half=False): + led_pwm.freq(period) + def inputblink(t): + maxvalue = 2**17 if not half else 2**16 + halfvalue = 2**16 if not half else 2**15 + freq = ( + (utime.ticks_ms() % period) * (maxvalue//period) + ) % maxvalue + duty = freq if freq < halfvalue else (maxvalue - freq) + led_pwm.duty_u16(duty) + led_timer.init(freq=period, callback=inputblink) + @classmethod + def callback_ok(cls, cardid, data): + print("Status: OK") + print(f"Card ID: {cardid}") + print(f"Data: {data}") + @classmethod + def callback_nok(cls, cardid): + print("Status: NOT OK") + print(f"Card ID: {cardid}") + + DEFAULT_KEY_PAD = ( + ('1', '2', '3', 'A'), + ('4', '5', '6', 'B'), + ('7', '8', '9', 'C'), + ('F', '0', 'E', 'D') + ) + + def __init__( + self, key_length=12, key_pad=DEFAULT_KEY_PAD, led_period=1000, + led_inverted=False, pin_led_status=(16,15,14), + pins_keypad_row=(2, 3, 4, 5), pins_keypad_col=(6, 7, 8, 9), + pin_rc522_sck=10, pin_rc522_miso=11, pin_rc522_mosi=12, + pin_rc522_cs=13, pin_rc522_rst=22, spi_device=1, + time_wait_success=10, time_wait_failure=3): + self._key_length = key_length + self._key_pad = key_pad + self._led_period = led_period + self._led_inverted = led_inverted + self._pin_led_status = pin_led_status[0] + self._pin_led_ok = pin_led_status[1] + self._pin_led_nok = pin_led_status[2] + self._pins_keypad_row = pins_keypad_row + self._pins_keypad_col = pins_keypad_col + self._pin_rc522_sck = pin_rc522_sck + self._pin_rc522_miso = pin_rc522_mosi + self._pin_rc522_mosi = pin_rc522_miso + self._pin_rc522_cs = pin_rc522_cs + self._pin_rc522_rst = pin_rc522_rst + self._spi_dev = spi_device + self._time_wait_success = time_wait_success + self._time_wait_failure = time_wait_failure + self._setup() + + @property + def callback_success(self): + return (self._callback_success, dict(self._callback_success_kwargs)) + @callback_success.setter + def callback_success(self, callback, kwargs): + self._callback_success = callback + self._callback_success_kwargs = dict(kwargs) + + @property + def callback_failure(self): + return (self._callback_failure, dict(self._callback_failure_kwargs)) + @callback_failure.setter + def callback_failure(self, callback, kwargs): + self._callback_failure = callback + self._callback_failure_kwargs = dict(kwargs) + + def _setup(self): + val = self._led_inverted + self._led_nok = Pin(self._pin_led_nok, Pin.OUT, value=val) + self._pwm_nok = PWM(self._led_nok) + self._timer_nok = Timer() + + self._led_ok = Pin(self._pin_led_ok, Pin.OUT, value=val) + self._pwm_ok = PWM(self._led_ok) + self._timer_ok = Timer() + + self._led_status = Pin(self._pin_led_status, Pin.OUT, value=val) + self._pwm_status = PWM(self._led_status) + self._timer_status = Timer() + + self._reader = MFRC522( + spi_dev=self._spi_dev, sck=self._pin_rc522_sck, + mosi=self._pin_rc522_mosi, miso=self._pin_rc522_miso, + cs=self._pin_rc522_cs, rst=self._pin_rc522_rst + ) + self._keypad = KeyPad(characters=self._key_pad) + + self._led_init() + self.led_pulse( + led_pwm=self._pwm_status, led_timer=self._timer_status, + period=self._led_period*2, half=True + ) + + self._callback_success = self.callback_ok + self._callback_success_kwargs = {} + self._callback_failure = self.callback_nok + self._callback_failure_kwargs = {} + + def _led_init(self): + self._timer_nok.deinit() + self._pwm_nok.freq(self._led_period) + self._pwm_nok.duty_u16(2**16 if self._led_inverted else 0) + self._timer_ok.deinit() + self._pwm_ok.freq(self._led_period) + self._pwm_ok.duty_u16(2**16 if self._led_inverted else 0) + self._timer_status.deinit() + self._pwm_status.freq(self._led_period) + self._pwm_status.duty_u16(2**16 if self._led_inverted else 0) + + def read_card(self): + self._reader.clear_state() + status, token = self._reader.request(self._reader.REQUEST_IDLE) + if status == self._reader.STATUS_OK: + status, serial_number = self._reader.select_near_token() + if status == self._reader.STATUS_OK: + card_id = MFRC522.id_to_string(serial_number) + self._led_init() + self.led_pulse( + led_pwm=self._pwm_status, led_timer=self._timer_status, + period=self._led_period + ) + self._keypad.clear() + while len(self._keypad) < self._key_length: + utime.sleep(self._keypad.DEFAULT_BUFFER_TIME) + key = self._keypad.pop_all() + key_bytes = [ + int(f'{key[i]}{key[i+1]}',16) + for i in range(0,len(key),2) + ] + + data = [] + for sector in range(16): + login_block = sector*4 + 3 + status = self._reader.authenticate( + serial_number, login_block, key_bytes, + self._reader.AUTH_MODE_A + ) + if status != self._reader.STATUS_OK: + continue + try: + sector_data = [ + [ + c + for c in self._reader.read( + sector*4 + sector_block + ) + ] + for sector_block in range(4) + ] + data.append(sector_data) + except TypeError: + data.clear() + self._led_init() + self.led_pulse( + led_pwm=self._pwm_nok, led_timer=self._timer_nok, + period=self._led_period//2 + ) + self._callback_failure_kwargs["cardid"] = card_id + self._callback_failure(**self._callback_failure_kwargs) + utime.sleep(self._time_wait_failure) + self._led_init() + self.led_pulse( + led_pwm=self._pwm_status, period=self._led_period*2, + led_timer=self._timer_status, half=True + ) + del self._callback_failure_kwargs["cardid"] + break + else: + self._led_init() + self.led_pulse( + led_pwm=self._pwm_ok, led_timer=self._timer_ok, + period=self._led_period + ) + self._callback_success_kwargs["cardid"] = card_id + self._callback_success_kwargs["data"] = data + self._callback_success(**self._callback_success_kwargs) + utime.sleep(self._time_wait_success) + self._led_init() + self.led_pulse( + led_pwm=self._pwm_status, led_timer=self._timer_status, + period=self._led_period*2, half=True + ) + del self._callback_success_kwargs["cardid"] + del self._callback_success_kwargs["data"] + def find_card_loop(self): + while True: + self.read_card() + utime.sleep(1) + +cardterm = CardTermRC522(led_inverted=True) +cardterm.find_card_loop() \ No newline at end of file