"""Native GPIO driver for H7992 switch.""" from __future__ import annotations from dataclasses import dataclass, field from python_app.hardware_full.switch_drivers.gpio_uapi import GpioOutputLines _POSITION_TO_AB = ( (0, 0), (0, 1), (1, 0), (1, 1), ) @dataclass(slots=True) class H7992Driver: """Drive H7992 using two GPIO lines (A/B).""" name: str positions: int = 4 default_position: int = 0 gpio_chip: str = "/dev/gpiochip0" pin_a: int = 17 pin_b: int = 27 _lines: GpioOutputLines | None = field(init=False, default=None, repr=False) _is_open: bool = field(init=False, default=False, repr=False) _current_position: int = field(init=False, default=0, repr=False) def __post_init__(self) -> None: """Initialize runtime state.""" self._lines: GpioOutputLines | None = None self._is_open = False self._current_position = 0 def open(self) -> None: """Open GPIO lines and switch to default position.""" if self._is_open: return self._validate() self._lines = GpioOutputLines( chip=self.gpio_chip, offsets=(self.pin_a, self.pin_b), consumer=f"radar_{self.name}", ) self._lines.open() self._is_open = True self.switch_to(self.default_position) def close(self) -> None: """Close GPIO lines.""" if self._lines is not None: self._lines.close() self._lines = None self._is_open = False def position_count(self) -> int: """Return number of supported positions.""" return self.positions def switch_to(self, position: int) -> None: """Switch hardware to selected position.""" if not self._is_open or self._lines is None: raise RuntimeError(f"Switch driver is not open for {self.name}") if position < 0 or position >= self.positions: raise ValueError(f"Position out of range for {self.name}: {position}") self._lines.set_values(_POSITION_TO_AB[position]) self._current_position = int(position) @property def current_position(self) -> int: """Return current position.""" return self._current_position def _validate(self) -> None: """Validate H7992 driver parameters.""" if self.positions <= 0 or self.positions > 4: raise ValueError(f"H7992 positions must be in range [1,4] for {self.name}") if self.default_position < 0 or self.default_position >= self.positions: raise ValueError(f"default_position out of range for {self.name}") if self.pin_a < 0 or self.pin_b < 0 or self.pin_a == self.pin_b: raise ValueError(f"pin_a/pin_b are invalid for {self.name}")