"""Native GPIO driver for HMC349A switch.""" from __future__ import annotations from dataclasses import dataclass, field from python_app.hardware_full.switch_drivers.gpio_uapi import GpioOutputLines @dataclass(slots=True) class HMC349ADriver: """Drive HMC349A using one control GPIO line.""" name: str positions: int = 2 default_position: int = 0 gpio_chip: str = "/dev/gpiochip0" pin_a: int = 17 invert_logic: bool = False _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() offsets = [self.pin_a] self._lines = GpioOutputLines( chip=self.gpio_chip, offsets=offsets, 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}") control = int(position & 0x01) if self.invert_logic: control ^= 0x01 self._lines.set_values([control]) self._current_position = int(position) @property def current_position(self) -> int: """Return current position.""" return self._current_position def _validate(self) -> None: """Validate HMC349A driver parameters.""" if self.positions <= 0 or self.positions > 2: raise ValueError(f"HMC349A positions must be in range [1,2] 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: raise ValueError(f"pin_a is invalid for {self.name}")