diff --git a/pm3py/transponders/hf/iso15693/base.py b/pm3py/transponders/hf/iso15693/base.py index 1efef7b..9932ac5 100644 --- a/pm3py/transponders/hf/iso15693/base.py +++ b/pm3py/transponders/hf/iso15693/base.py @@ -128,6 +128,46 @@ class Tag15693(Transponder): random_bytes = os.urandom(8 - len(prefix)) 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: return decode_15693(direction, payload)