Source code for olaf.board.gpio

"""Quick GPIO legacy sysfs wrapper that supports mocking."""

import os

GPIO_LOW = 0
"""int: GPIO pin value is low"""
GPIO_HIGH = 1
"""int: GPIO pin value is high"""
GPIO_IN = "in"
"""str: GPIO pin is a input"""
GPIO_OUT = "out"
"""str: GPIO pin is a output"""


[docs] class GpioError(Exception): """Error with :py:class:`Gpio`"""
[docs] class Gpio: """ Quick GPIO legacy sysfs wrapper class that can handle issues with gpio pin on the OreSat cards when those pins are configured with device tree and/or device tree overlays. Also supports mocking. """ _GPIO_DIR_PATH = "/sys/class/gpio" _LABELS = {} if os.path.isdir(_GPIO_DIR_PATH): for i in os.listdir(_GPIO_DIR_PATH): if i.startswith("gpiochip") or i in ["export", "unexport"]: continue with open(f"{_GPIO_DIR_PATH}/{i}/label", "r") as f: _LABELS[f.read()[:-1]] = int(i[4:]) # remove the trailing '\n' def __init__(self, pin: str, mock: bool = False): """ Parameters ---------- pin: str or int The GPIO name/label defined by device tree or the pin number. The name from the device tree is the preferred value. mock: bool Mock the GPIO. """ self._mock = mock # defaults self._pin = 0 self._mock_value = 0 self._name = "MOCKED" self._mode = GPIO_OUT if isinstance(pin, int): self._pin = pin elif isinstance(pin, str): if mock: self._name = pin else: self._pin = self._LABELS[pin] else: raise GpioError(f"invalid pin {pin}") self._gpio_dir_path = f"{self._GPIO_DIR_PATH}/gpio{self._pin}" if not self._mock: if not os.path.isdir(self._gpio_dir_path): raise GpioError(f"gpio pin {self._name} (gpio{self._pin}) does not exist") with open(f"{self._gpio_dir_path}/direction", "r") as f: self._mode = f.read() with open(f"{self._gpio_dir_path}/label", "r") as f: self._name = f.read() @property def mode(self) -> str: """str: The GPIO pin mode. Readwrite.""" return self._mode @mode.setter def mode(self, new_mode: str): if new_mode == self._mode: return # already in the correct mode if not self._mock: with open(f"{self._gpio_dir_path}/direction", "w") as f: f.write(new_mode) self._mode = new_mode @property def value(self) -> int: """bool: The value of GPIO pin. Readwrite.""" if self._mock: return self._mock_value with open(f"{self._gpio_dir_path}/value", "r") as f: value = int(f.read()) return value @value.setter def value(self, new_value: int): if self._mode == "in": raise GpioError(f"Cannot set GPIO {self.number} value, it is in input mode") if self._mock: self._mock_value = new_value else: with open(f"{self._gpio_dir_path}/value", "w") as f: f.write(str(new_value))
[docs] def high(self): """Set the GPIO high.""" self.value = 1
[docs] def low(self): """Set the GPIO low.""" self.value = 0
@property def is_high(self) -> bool: """bool: Check if the GPIO is set high. Readonly.""" return bool(self.value) @property def number(self) -> int: """int: The GPIO number. Readonly.""" return self._pin @property def name(self) -> str: """str: The GPIO name/label. Readonly.""" return self._name