Files
pm3py/pm3py/sim/access_control/wiegand.py
michael 668170457e feat: migrate sim framework from worktree to master
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>
2026-03-18 20:04:55 -07:00

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()