Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .clang-format
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2025 PN5180-tagomatic contributors
# SPDX-FileCopyrightText: 2026 PN5180-tagomatic contributors
# SPDX-License-Identifier: GPL-3.0-or-later

---
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/arduino-ci.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2025 PN5180-tagomatic contributors
# SPDX-FileCopyrightText: 2026 PN5180-tagomatic contributors
# SPDX-License-Identifier: GPL-3.0-or-later

name: Arduino CI
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2025 PN5180-tagomatic contributors
# SPDX-FileCopyrightText: 2026 PN5180-tagomatic contributors
# SPDX-License-Identifier: GPL-3.0-or-later

name: Publish to PyPI
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/python-ci.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2025 PN5180-tagomatic contributors
# SPDX-FileCopyrightText: 2026 PN5180-tagomatic contributors
# SPDX-License-Identifier: GPL-3.0-or-later

name: Python CI
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/reuse.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2025 PN5180-tagomatic contributors
# SPDX-FileCopyrightText: 2026 PN5180-tagomatic contributors
# SPDX-License-Identifier: GPL-3.0-or-later

name: REUSE Compliance
Expand Down
2 changes: 1 addition & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2025 PN5180-tagomatic contributors
# SPDX-FileCopyrightText: 2026 PN5180-tagomatic contributors
# SPDX-License-Identifier: GPL-3.0-or-later

include README.md
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2025 PN5180-tagomatic contributors
# SPDX-FileCopyrightText: 2026 PN5180-tagomatic contributors
# SPDX-License-Identifier: GPL-3.0-or-later

VENV := venv
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# PN5180-tagomatic

<!--
SPDX-FileCopyrightText: 2025 PN5180-tagomatic contributors
SPDX-FileCopyrightText: 2026 PN5180-tagomatic contributors
SPDX-License-Identifier: GPL-3.0-or-later
-->

Expand Down
6 changes: 3 additions & 3 deletions REUSE.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2025 PN5180-tagomatic contributors
# SPDX-FileCopyrightText: 2026 PN5180-tagomatic contributors
# SPDX-License-Identifier: CC0-1.0

version = 1
Expand All @@ -9,13 +9,13 @@ SPDX-PackageDownloadLocation = "https://github.com/bofh69/PN5180-tagomatic"
[[annotations]]
path = ["sketch/board.jpg"]
precedence = "aggregate"
SPDX-FileCopyrightText = "2025 PN5180-tagomatic contributors"
SPDX-FileCopyrightText = "2026 PN5180-tagomatic contributors"
SPDX-License-Identifier = "GPL-3.0-or-later"

[[annotations]]
path = [".gitignore", ".clang-format"]
precedence = "aggregate"
SPDX-FileCopyrightText = "2025 PN5180-tagomatic contributors"
SPDX-FileCopyrightText = "2026 PN5180-tagomatic contributors"
SPDX-License-Identifier = "CC0-1.0"

[[annotations]]
Expand Down
2 changes: 1 addition & 1 deletion examples/basic_example.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# SPDX-FileCopyrightText: 2025 PN5180-tagomatic contributors
# SPDX-FileCopyrightText: 2026 PN5180-tagomatic contributors
# SPDX-License-Identifier: GPL-3.0-or-later

"""Example program demonstrating PN5180 reader usage.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# SPDX-FileCopyrightText: 2025 PN5180-tagomatic contributors
# SPDX-FileCopyrightText: 2026 PN5180-tagomatic contributors
# SPDX-License-Identifier: GPL-3.0-or-later

"""Example program demonstrating PN5180 reader usage.
Expand Down
2 changes: 1 addition & 1 deletion examples/iso_14443-read-memory.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# SPDX-FileCopyrightText: 2025 PN5180-tagomatic contributors
# SPDX-FileCopyrightText: 2026 PN5180-tagomatic contributors
# SPDX-License-Identifier: GPL-3.0-or-later

"""Example program demonstrating PN5180 reader usage.
Expand Down
2 changes: 1 addition & 1 deletion examples/iso_14443_reqa.py → examples/iso_14443-reqa.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# SPDX-FileCopyrightText: 2025 PN5180-tagomatic contributors
# SPDX-FileCopyrightText: 2026 PN5180-tagomatic contributors
# SPDX-License-Identifier: GPL-3.0-or-later

"""Example program demonstrating PN5180 reader usage.
Expand Down
4 changes: 2 additions & 2 deletions examples/iso_14443-write-memory.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# SPDX-FileCopyrightText: 2025 PN5180-tagomatic contributors
# SPDX-FileCopyrightText: 2026 PN5180-tagomatic contributors
# SPDX-License-Identifier: GPL-3.0-or-later

"""Example program demonstrating PN5180 reader usage.
Expand Down Expand Up @@ -48,7 +48,7 @@ def main() -> int:
# Write memory based on card type
if len(card.uid) == 4:
# MIFARE Classic card
raise NotImplemented("Not yet implemented")
raise NotImplementedError("Not yet implemented")
else:
# Other ISO 14443-A card (e.g., NTAG)
card.write_memory(16//4, 0xEFBEADDE)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#!/usr/bin/env python3
# SPDX-FileCopyrightText: 2025 PN5180-tagomatic contributors
# SPDX-FileCopyrightText: 2026 PN5180-tagomatic contributors
# SPDX-License-Identifier: GPL-3.0-or-later

"""Example program demonstrating PN5180 ISO 15693 inventory.

This example program finds the UID of ISO-15963 cards
This example program finds the UID of ISO-15693 cards

Usage:
examples/iso_15693_inventory.py /dev/ttyACM0
Expand Down
75 changes: 75 additions & 0 deletions examples/iso_15693-update-memory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/usr/bin/env python3

# SPDX-FileCopyrightText: 2026 PN5180-tagomatic contributors
# SPDX-License-Identifier: GPL-3.0-or-later

"""Example program demonstrating PN5180 ISO 15693 operations.

This example program finds the UID of ISO-15693 cards

Usage:
examples/iso_15693-update-memory.py /dev/ttyACM0
examples/iso_15693-update-memory.py COM3
"""

import argparse
import sys

from pn5180_tagomatic import PN5180


def main() -> int:
"""Main entry point for the example program."""
parser = argparse.ArgumentParser(
description="PN5180 ISO 15693 Inventory Example",
formatter_class=argparse.RawDescriptionHelpFormatter,
)
parser.add_argument(
"tty",
help="Serial port device (e.g., /dev/ttyACM0 or COM3)",
)
args = parser.parse_args()

try:
# Create PN5180 reader instance
with PN5180(args.tty) as reader:
print("PN5180 reader initialized")

# Start ISO 15693 communication session
# 0x0D = TX config for ISO 15693
# 0x8D = RX config for ISO 15693
with reader.start_session(0x0D, 0x8D) as session:
print("Performing ISO 15693 inventory...")

# Perform inventory
uids = session.iso15693_inventory()

# Display results
if uids:
print(f"\nFound {len(uids)} tag(s):")
for i, uid in enumerate(uids, 1):
print(f" {i}. UID: {uid.hex(':')}")

card = session.connect_iso15693(uids[0])
card.write_memory(4, b' Hello! ')

memory = card.read_memory()
for offset in range(0, len(memory), 16):
chunk = memory[offset : offset + 16]
ascii_values = "".join(
chr(byte) if 32 <= byte <= 126 else "."
for byte in chunk
)
print(f"({offset:03x}): {chunk.hex(' ')} {ascii_values}")
else:
print("\nNo tags found")

return 0

except Exception as e:
print(f"Error: {e}", file=sys.stderr)
return 1


if __name__ == "__main__":
sys.exit(main())
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2025 PN5180-tagomatic contributors
# SPDX-FileCopyrightText: 2026 PN5180-tagomatic contributors
# SPDX-License-Identifier: GPL-3.0-or-later

[build-system]
Expand Down
2 changes: 1 addition & 1 deletion sketch/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!--
SPDX-FileCopyrightText: 2025 PN5180-tagomatic contributors
SPDX-FileCopyrightText: 2026 PN5180-tagomatic contributors
SPDX-License-Identifier: GPL-3.0-or-later
-->

Expand Down
Binary file modified sketch/board.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion sketch/pn5180_reader/pn5180_reader.ino
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2025 PN5180-tagomatic contributors
// SPDX-FileCopyrightText: 2026 PN5180-tagomatic contributors
// SPDX-License-Identifier: GPL-3.0-or-later

/*
Expand Down
2 changes: 1 addition & 1 deletion src/pn5180_tagomatic/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!--
SPDX-FileCopyrightText: 2025 PN5180-tagomatic contributors
SPDX-FileCopyrightText: 2026 PN5180-tagomatic contributors
SPDX-License-Identifier: GPL-3.0-or-later
-->

Expand Down
6 changes: 5 additions & 1 deletion src/pn5180_tagomatic/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# SPDX-FileCopyrightText: 2025 PN5180-tagomatic contributors
# SPDX-FileCopyrightText: 2026 PN5180-tagomatic contributors
# SPDX-License-Identifier: GPL-3.0-or-later

"""PN5180-tagomatic: USB based RFID reader with Python interface."""

from .constants import (
ISO14443ACommand,
ISO15693Command,
ISO15693Error,
MifareKeyType,
PN5180Error,
RegisterOperation,
Expand All @@ -14,6 +15,7 @@
TimeslotBehavior,
)
from .iso14443a import ISO14443ACard
from .iso15693 import ISO15693Card
from .pn5180 import PN5180
from .proxy import PN5180Helper, PN5180Proxy
from .session import PN5180RFSession
Expand All @@ -22,7 +24,9 @@
__all__ = [
"ISO14443ACard",
"ISO14443ACommand",
"ISO15693Card",
"ISO15693Command",
"ISO15693Error",
"MifareKeyType",
"PN5180",
"PN5180Error",
Expand Down
36 changes: 34 additions & 2 deletions src/pn5180_tagomatic/constants.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2025 PN5180-tagomatic contributors
# SPDX-FileCopyrightText: 2026 PN5180-tagomatic contributors
# SPDX-License-Identifier: GPL-3.0-or-later

"""Constants and enumerations for PN5180 RFID reader."""
Expand All @@ -21,6 +21,28 @@ def __init__(self, operation: str, error_code: int) -> None:
super().__init__(f"{operation} failed with error code {error_code}")


class ISO15693Error(Exception):
"""Exception raised when an ISO 15693 command returns an error response."""

def __init__(
self, command: int, error_code: int, response_data: bytes
) -> None:
"""Initialize ISO15693Error.

Args:
command: The ISO 15693 command that triggered the error (8-bit value).
error_code: The error code from the tag's error response.
response_data: The full error response data from the tag.
"""
self.command = command
self.error_code = error_code
self.response_data = response_data
super().__init__(
f"ISO 15693 command 0x{command:02X} failed "
f"with error code 0x{error_code:02X}"
)


class MifareKeyType(IntEnum):
"""Mifare authentication key types."""

Expand Down Expand Up @@ -115,4 +137,14 @@ class ISO14443ACommand(IntEnum):
class ISO15693Command(IntEnum):
"""ISO 15693 protocol command bytes."""

INVENTORY = 0x01 # Inventory command
GET_SYSTEM_INFORMATION = 0x2B
GET_MULTIPLE_BLOCK_SECURITY_STATUS = 0x2C
INVENTORY = 0x01
LOCK_BLOCK = 0x22
READ_SINGLE_BLOCK = 0x20
READ_MULTIPLE_BLOCKS = 0x23
RESET_TO_READY = 0x26
SELECT = 0x25
STAY_QUIET = 0x02
WRITE_SINGLE_BLOCK = 0x21
WRITE_MULTIPLE_BLOCKS = 0x24
Comment on lines +140 to +150
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enum members should be sorted consistently. Consider sorting alphabetically or by command value for better maintainability and readability.

Suggested change
GET_SYSTEM_INFORMATION = 0x2B
GET_MULTIPLE_BLOCK_SECURITY_STATUS = 0x2C
INVENTORY = 0x01
LOCK_BLOCK = 0x22
READ_SINGLE_BLOCK = 0x20
READ_MULTIPLE_BLOCKS = 0x23
RESET_TO_READY = 0x26
SELECT = 0x25
STAY_QUIET = 0x02
WRITE_SINGLE_BLOCK = 0x21
WRITE_MULTIPLE_BLOCKS = 0x24
INVENTORY = 0x01
STAY_QUIET = 0x02
READ_SINGLE_BLOCK = 0x20
WRITE_SINGLE_BLOCK = 0x21
LOCK_BLOCK = 0x22
READ_MULTIPLE_BLOCKS = 0x23
WRITE_MULTIPLE_BLOCKS = 0x24
SELECT = 0x25
RESET_TO_READY = 0x26
GET_SYSTEM_INFORMATION = 0x2B
GET_MULTIPLE_BLOCK_SECURITY_STATUS = 0x2C

Copilot uses AI. Check for mistakes.
2 changes: 1 addition & 1 deletion src/pn5180_tagomatic/iso14443a.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2025 PN5180-tagomatic contributors
# SPDX-FileCopyrightText: 2026 PN5180-tagomatic contributors
# SPDX-License-Identifier: GPL-3.0-or-later

"""ISO 14443-A card implementation."""
Expand Down
Loading
Loading