Migrates all 43 sim modules and 23 test files (~7.8k LOC, 686 tests) from .worktrees/sim-framework/ into pm3py/sim/. Import fixes: - 4 files: ..protocol/..transport → ..core.protocol/..core.transport - trace_fmt.py: pm3py.hf_15 → pm3py.trace.ndef - test_sim_pm3medium.py: flat imports → core.* - test_sim_trace_fmt.py: flat imports → core.* - Added sim Cmd entries to core/protocol.py (EML_SETMEM, SIM_TABLE_*) 751 tests passing (686 sim + 65 core). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
74 lines
2.3 KiB
Python
74 lines
2.3 KiB
Python
"""Wiegand protocol — encode/decode, software and hardware I/O."""
|
|
from __future__ import annotations
|
|
|
|
from .credential import Credential, encode_wiegand, decode_wiegand
|
|
|
|
|
|
class WiegandOutput:
|
|
"""Wiegand output — software mode or GPIO (via pigpio)."""
|
|
|
|
def __init__(self, d0_pin: int | None = None, d1_pin: int | None = None,
|
|
pulse_width_us: int = 50, interval_us: int = 2000,
|
|
pi=None):
|
|
self._d0_pin = d0_pin
|
|
self._d1_pin = d1_pin
|
|
self._pulse_width_us = pulse_width_us
|
|
self._interval_us = interval_us
|
|
self._pi = pi
|
|
self._last_bits: list[int] = []
|
|
|
|
@property
|
|
def pulse_width_us(self) -> int:
|
|
return self._pulse_width_us
|
|
|
|
@property
|
|
def interval_us(self) -> int:
|
|
return self._interval_us
|
|
|
|
@property
|
|
def last_bits(self) -> list[int]:
|
|
return self._last_bits
|
|
|
|
def send(self, cred: Credential) -> None:
|
|
"""Send credential as Wiegand bit stream."""
|
|
bits = encode_wiegand(cred)
|
|
self._last_bits = bits
|
|
|
|
if self._pi is not None and self._d0_pin is not None:
|
|
self._send_gpio(bits)
|
|
|
|
def _send_gpio(self, bits: list[int]) -> None:
|
|
"""Send Wiegand bits via GPIO (requires pigpio)."""
|
|
for bit in bits:
|
|
if bit == 0:
|
|
self._pi.gpio_trigger(self._d0_pin, self._pulse_width_us, 0)
|
|
else:
|
|
self._pi.gpio_trigger(self._d1_pin, self._pulse_width_us, 0)
|
|
# Inter-pulse interval handled by pigpio timing
|
|
|
|
|
|
class WiegandInput:
|
|
"""Wiegand input — software mode or GPIO (via pigpio)."""
|
|
|
|
def __init__(self, d0_pin: int | None = None, d1_pin: int | None = None,
|
|
pi=None):
|
|
self._d0_pin = d0_pin
|
|
self._d1_pin = d1_pin
|
|
self._pi = pi
|
|
self._bits: list[int] = []
|
|
|
|
def decode(self, bits: list[int], format: str = "H10301") -> Credential:
|
|
"""Decode Wiegand bit stream to credential."""
|
|
return decode_wiegand(bits, format)
|
|
|
|
def feed_bit(self, bit: int) -> None:
|
|
"""Feed a single bit (for GPIO callback use)."""
|
|
self._bits.append(bit)
|
|
|
|
@property
|
|
def accumulated_bits(self) -> list[int]:
|
|
return self._bits
|
|
|
|
def reset(self) -> None:
|
|
self._bits.clear()
|