diff --git a/NfcReaderService.py b/NfcReaderService.py index 721e4fb..95740fd 100644 --- a/NfcReaderService.py +++ b/NfcReaderService.py @@ -10,69 +10,98 @@ from pynput.keyboard import Controller from card_reader import read_card +GET_UID = [0xFF, 0xCA, 0x00, 0x00, 0x00] class NfcReaderService: def __init__(self) -> None: self._is_running = True self._last_uid = None self._keyboard = Controller() - self._last_write = datetime(1900, 1, 1) + self._last_write = datetime.min def run(self) -> None: print("Reader ready.") while self._is_running: try: - time.sleep(0.1) - card_request = CardRequest(timeout=None) - print("Waiting for card...") - card_service = card_request.waitforcard() - connection = card_service.connection - print("Connected to card!") - - try: - connection.connect(CardConnection.T1_protocol) - - GET_UID = [0xFF, 0xCA, 0x00, 0x00, 0x00] - uid, sw1, sw2 = connection.transmit(GET_UID) - - if sw1 != 0x90: - raise CardConnectionException("UID read failed") - - uid_hex = toHexString(uid) - - if uid_hex == self._last_uid: - connection.disconnect() - time.sleep(0.5) - self._last_uid = None - continue - - self._last_uid = uid_hex - - user_id = read_card(connection) - if user_id is not None: - now = datetime.now() - if now - self._last_write > timedelta(seconds=2): - self._keyboard.type(str(user_id)) - self._last_write = now - - except (CardConnectionException, NoCardException): - pass - - finally: - try: - connection.disconnect() - except: - pass - - time.sleep(0.5) + self._poll_card() except (KeyboardInterrupt, SystemExit): self.stop() + except Exception as e: + print(f"[ERROR] Unexpected failure: {e}") + time.sleep(1) + + def _poll_card(self) -> None: + card_request = CardRequest(timeout=1) + + try: + card_service = card_request.waitforcard() + except NoCardException: + self._last_uid = None + return + + connection = card_service.connection + + try: + connection.connect(CardConnection.T1_protocol) + + uid_hex = self._read_uid(connection) + if uid_hex is None: + return + + # Card still present and unchanged -> ignore + if uid_hex == self._last_uid: + return + + self._last_uid = uid_hex + + self._handle_card(connection) + + except (CardConnectionException, NoCardException) as e: + print(f"[CARD ERROR] {e}") + + finally: + try: + connection.disconnect() + except Exception: + pass + + def _read_uid(self, connection) -> Optional[str]: + uid, sw1, sw2 = connection.transmit(GET_UID) + + if sw1 != 0x90: + raise CardConnectionException("UID read failed") + + return toHexString(uid) + + def _handle_card(self, connection) -> None: + user_id = read_card(connection) + + if user_id is None: + return + + now = datetime.now() + + # debounce keyboard output + if now - self._last_write < timedelta(seconds=2): + return + + self._send_to_keyboard(user_id) + self._last_write = now + + def _send_to_keyboard(self, user_id: str) -> None: + try: + self._keyboard.type(f"{user_id}\n") + except Exception as e: + print(f"[KEYBOARD ERROR] {e}") + def stop(self) -> None: + print("Stopping NFC service.") self._is_running = False + if __name__ == "__main__": service = NfcReaderService() - service.run() + service.run() \ No newline at end of file