feat: set_uid() with validation and random generation for 15693 tags

Tag15693.set_uid() now:
- Accepts None (or no args) to generate a random valid UID with the
  correct IC-specific prefix (E0 + mfg + IC type)
- Validates length (must be 8 bytes)
- Warns on prefix mismatch (wrong IC type for product-specific tags)
- Warns on non-NXP manufacturer code
- Warns on missing E0 prefix
This commit is contained in:
michael
2026-03-19 12:56:57 -07:00
parent 06de521d02
commit cb5d06da14

View File

@@ -128,6 +128,46 @@ class Tag15693(Transponder):
random_bytes = os.urandom(8 - len(prefix)) random_bytes = os.urandom(8 - len(prefix))
return prefix + random_bytes return prefix + random_bytes
def set_uid(self, uid: bytes | str | None = None) -> None:
"""Change the tag UID. Call sync() to push to firmware.
uid=None generates a random valid UID with the correct IC prefix.
Warns if the UID prefix doesn't match the expected IC type.
"""
import warnings
if uid is None:
self._uid = self._generate_uid()
self._uid_dirty = True
return
uid = self._parse_uid(uid)
if len(uid) != 8:
raise ValueError(f"UID must be 8 bytes, got {len(uid)}")
prefix = self._uid_prefix
if len(prefix) > 2 and uid[:len(prefix)] != prefix:
expected = prefix.hex().upper()
actual = uid[:len(prefix)].hex().upper()
cls_name = type(self).__name__
warnings.warn(
f"{cls_name}: UID prefix {actual} doesn't match expected {expected}. "
f"Phones/readers may not identify the IC type correctly. "
f"Use set_uid() with no args for a valid random UID.",
stacklevel=2,
)
elif uid[:2] != b"\xE0\x04" and uid[:1] == b"\xE0":
warnings.warn(
f"UID manufacturer code {uid[1]:02X} is not NXP (04). "
f"Phones may not recognize this as an NXP tag.",
stacklevel=2,
)
elif uid[:1] != b"\xE0":
warnings.warn(
f"UID must start with E0 (ISO 15693 IC manufacturer prefix). "
f"Got {uid[0]:02X}. This UID will not be recognized by readers.",
stacklevel=2,
)
self._uid = uid
self._uid_dirty = True
def decode_trace(self, direction: int, payload: bytes) -> str | None: def decode_trace(self, direction: int, payload: bytes) -> str | None:
return decode_15693(direction, payload) return decode_15693(direction, payload)