read_tag.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. #!/usr/bin/env python3
  2. """PN5180 NFC Tag Reader diagnostic script.
  3. Standalone diagnostic — the PN5180 driver lives in
  4. spoolbuddy/daemon/pn5180.py and is imported from there.
  5. Supports: Bambu (MIFARE Classic) + NTAG (SpoolEase/OpenPrintTag)
  6. """
  7. import logging
  8. import sys
  9. import time
  10. from pathlib import Path
  11. # Add daemon package to sys.path so we can import the driver
  12. sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
  13. from daemon.pn5180 import BAMBU_BLOCKS, PN5180
  14. # Show driver debug output during diagnostics
  15. logging.basicConfig(level=logging.DEBUG, format=" %(message)s")
  16. def _print_hex_dump(data: bytes, label: str, bytes_per_line: int = 16):
  17. """Print a hex dump with ASCII sidebar."""
  18. for i in range(0, len(data), bytes_per_line):
  19. chunk = data[i : i + bytes_per_line]
  20. hex_str = " ".join(f"{b:02X}" for b in chunk)
  21. ascii_str = "".join(chr(b) if 32 <= b < 127 else "." for b in chunk)
  22. print(f" {label}{i:3d}: {hex_str:<{bytes_per_line * 3}}|{ascii_str}|")
  23. def main():
  24. print("=" * 60)
  25. print("PN5180 NFC Tag Reader")
  26. print(" Supports: Bambu (MIFARE Classic) + NTAG (SpoolEase/OpenPrintTag)")
  27. print("=" * 60)
  28. try:
  29. nfc = PN5180()
  30. except (OSError, RuntimeError, PermissionError) as e:
  31. print(f"\nERROR: Failed to initialize NFC reader: {e}")
  32. # Check if it's a resource conflict
  33. error_str = str(e).lower()
  34. is_resource_conflict = any(x in error_str for x in ["busy", "resource", "already in use", "permission denied"])
  35. if is_resource_conflict:
  36. print("\nGPIO/SPI RESOURCE IN USE: Another process is using the NFC reader.")
  37. print("This typically means the SpoolBuddy daemon is already reading tags.")
  38. print("\nTo run this diagnostic, stop the daemon first:")
  39. print(" sudo systemctl stop bambuddy")
  40. print(" # Run diagnostic")
  41. print(" .../read_tag.py")
  42. print(" # Restart daemon when done:")
  43. print(" sudo systemctl start bambuddy")
  44. else:
  45. print("\nCheck:")
  46. print(" - Correct GPIO chip is available (/dev/gpiochip0 or /dev/gpiochip4)")
  47. print(" - SPI device is available")
  48. print(" - GPIO and SPI permissions are correct")
  49. # Only print full traceback for unexpected errors
  50. import traceback
  51. traceback.print_exc()
  52. sys.exit(1)
  53. try:
  54. nfc.reset()
  55. ver = nfc.read_eeprom(0x10, 2)
  56. print(f"[1] Reset OK — product v{ver[1]}.{ver[0]}")
  57. nfc.load_rf_config(0x00, 0x80) # ISO 14443A
  58. time.sleep(0.010)
  59. nfc.rf_on()
  60. time.sleep(0.030)
  61. nfc.set_transceive_mode()
  62. rf = nfc.read_reg(0x1D)
  63. print(f"[2] RF ON (RF_STATUS=0x{rf:08X}, TX_RF={'ON' if rf & 1 else 'OFF'})")
  64. print("[3] Scanning for tag...")
  65. result = nfc.activate_type_a()
  66. if result is None:
  67. print(" No tag found.")
  68. sys.exit(1)
  69. uid, sak = result
  70. tag_types = {0x00: "NTAG", 0x08: "MIFARE Classic 1K", 0x18: "MIFARE Classic 4K"}
  71. print(f" UID : {uid.hex().upper()}")
  72. print(f" SAK : 0x{sak:02X} ({tag_types.get(sak, 'Unknown')})")
  73. if sak in (0x08, 0x18):
  74. # MIFARE Classic 1K or 4K — Bambu Lab tag
  75. print("[4] Reading Bambu tag data (MIFARE Classic)...")
  76. blocks = nfc.read_bambu_tag(uid)
  77. if blocks is None:
  78. print(" Failed to read tag data.")
  79. nfc.rf_off()
  80. sys.exit(1)
  81. print("[5] Tag data:")
  82. for block_num in BAMBU_BLOCKS:
  83. data = blocks[block_num]
  84. hex_str = " ".join(f"{b:02X}" for b in data)
  85. ascii_str = "".join(chr(b) if 32 <= b < 127 else "." for b in data)
  86. print(f" Block {block_num:2d}: {hex_str} |{ascii_str}|")
  87. raw = b""
  88. for block_num in BAMBU_BLOCKS:
  89. raw += blocks[block_num]
  90. print(f"\n Raw payload ({len(raw)} bytes): {raw.hex().upper()}")
  91. elif sak == 0x00:
  92. # NTAG — SpoolEase / OpenPrintTag
  93. print("[4] Reading NTAG data (pages 4-20)...")
  94. ntag_data = nfc.read_ntag(uid)
  95. if ntag_data is None:
  96. print(" Failed to read NTAG data.")
  97. nfc.rf_off()
  98. sys.exit(1)
  99. print(f"[5] NTAG data ({len(ntag_data)} bytes):")
  100. _print_hex_dump(ntag_data, "page ")
  101. else:
  102. print(f" Unsupported tag type (SAK=0x{sak:02X})")
  103. nfc.rf_off()
  104. sys.exit(1)
  105. nfc.rf_off()
  106. print("\n" + "=" * 60)
  107. print("Tag read complete!")
  108. print("=" * 60)
  109. except Exception as e:
  110. print(f"\nERROR: {e}")
  111. import traceback
  112. traceback.print_exc()
  113. sys.exit(1)
  114. finally:
  115. nfc.close()
  116. if __name__ == "__main__":
  117. main()