95 lines
3.0 KiB
Python
95 lines
3.0 KiB
Python
import time
|
|
import pigpio
|
|
from typing import Optional
|
|
from sensors.lock import serial_lock
|
|
|
|
|
|
class RFIDReader:
|
|
"""
|
|
Grove 125kHz RFID Reader using bit-banged software serial on GPIO 17 (Pin 11).
|
|
Parses 14-byte frame: [0x02 STX] + [10 ASCII ID] + [2 ASCII Checksum] + [0x03 ETX]
|
|
"""
|
|
|
|
def __init__(self, rx_pin: int = 17, baudrate: int = 9600):
|
|
self.rx_pin = rx_pin
|
|
self.baudrate = baudrate
|
|
self.buffer = bytearray()
|
|
self.pi = pigpio.pi()
|
|
|
|
if not self.pi.connected:
|
|
raise RuntimeError("pigpio daemon is not running. Run 'sudo systemctl start pigpiod'.")
|
|
|
|
with serial_lock:
|
|
self.pi.set_mode(self.rx_pin, pigpio.INPUT)
|
|
|
|
# Clean up lingering serial sessions on this pin
|
|
try:
|
|
self.pi.bb_serial_read_close(self.rx_pin)
|
|
except pigpio.error:
|
|
pass
|
|
|
|
self.pi.bb_serial_read_open(self.rx_pin, self.baudrate, 8)
|
|
|
|
def read_tag(self) -> Optional[str]:
|
|
"""
|
|
Reads and accumulates bytes, returning the 10-digit Tag ID.
|
|
"""
|
|
with serial_lock:
|
|
if not self.pi or not self.pi.connected:
|
|
return None
|
|
|
|
count, data = self.pi.bb_serial_read(self.rx_pin)
|
|
if count > 0:
|
|
self.buffer.extend(data)
|
|
|
|
# Look for Start-of-Text (0x02)
|
|
stx_idx = self.buffer.find(b"\x02")
|
|
|
|
if stx_idx != -1:
|
|
# Discard noise prior to 0x02
|
|
if stx_idx > 0:
|
|
self.buffer = self.buffer[stx_idx:]
|
|
|
|
# Wait for full 14-byte payload
|
|
if len(self.buffer) >= 14:
|
|
raw_frame = self.buffer[:14]
|
|
self.buffer = self.buffer[14:] # Flush parsed frame
|
|
|
|
# Verify End-of-Text (0x03)
|
|
if raw_frame[-1] == 0x03:
|
|
try:
|
|
# Extract 10-character ID (indices 1 through 10)
|
|
return raw_frame[1:11].decode("ascii")
|
|
except UnicodeDecodeError:
|
|
return None
|
|
else:
|
|
# Flush buffer if filled with noise without STX marker
|
|
if len(self.buffer) > 64:
|
|
self.buffer.clear()
|
|
|
|
return None
|
|
|
|
def close(self):
|
|
with serial_lock:
|
|
if self.pi and self.pi.connected:
|
|
try:
|
|
self.pi.bb_serial_read_close(self.rx_pin)
|
|
except pigpio.error:
|
|
pass
|
|
self.pi.stop()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
reader = RFIDReader(rx_pin=17)
|
|
print("RFID Reader active on GPIO 17 (Pin 11). Swipe a tag...")
|
|
|
|
try:
|
|
while True:
|
|
tag = reader.read_tag()
|
|
if tag:
|
|
print(f"Scanned Tag ID: {tag}")
|
|
time.sleep(0.05)
|
|
except KeyboardInterrupt:
|
|
print("\nStopping reader.")
|
|
finally:
|
|
reader.close() |