Esempio n. 1
0
    def interrupt(self, callback, pin, interrupt_trigger=None, timeout=0):
        """Init interrupt callback function for pin.

        Args:
            callback (function): function to call on interrupt
            pin (int): the pin to monitor for interrupts

        """
        with self._gpio_lock:
            gpio_pin = GPIO(pin, "preserve")
            if gpio_pin.supports_interrupts:
                gpio_pin.direction = "in"
                gpio_pin.edge = interrupt_trigger
                if gpio_pin.poll(timeout):
                    # Enter callback function
                    pass
                gpio_pin.edge = "none"  #need to set to none inorder to reuse pin for anything else
            else:
                self.logger.error(
                    "GPIO pin {} does not support interrupts".format(pin))

            self.logger.debug(
                "Set interrupt callback of GPIO pin {}".format(pin))
Esempio n. 2
0
class Launcher(object):
    """Stores data coming from PRU's in HDF5 format

    Args:
        pin_button (int): Pin number where button is connected. Must be
            configured as input with pull up and connected against ground
        pin_led (int): Pin number of LED for displaying launcher status
        service_name (str): Name of shepherd systemd service

    """
    def __init__(
        self,
        pin_button: int = 81,
        pin_led: int = 9,
        service_name: str = "shepherd",
    ):
        self.pin_button = pin_button
        self.pin_led = pin_led
        self.service_name = service_name

    def __enter__(self):
        self.gpio_led = GPIO(self.pin_led, "out")
        self.gpio_button = GPIO(self.pin_button, "in")
        self.gpio_button.edge = "falling"
        logger.debug("configured gpio")

        sysbus = dbus.SystemBus()
        systemd1 = sysbus.get_object("org.freedesktop.systemd1",
                                     "/org/freedesktop/systemd1")
        self.manager = dbus.Interface(systemd1,
                                      "org.freedesktop.systemd1.Manager")

        shepherd_object = self.manager.LoadUnit(
            f"{ self.service_name }.service")
        self.shepherd_proxy = sysbus.get_object("org.freedesktop.systemd1",
                                                str(shepherd_object))
        logger.debug("configured dbus for systemd")

        return self

    def __exit__(self, *exc):
        self.gpio_led.close()
        self.gpio_button.close()

    def run(self) -> NoReturn:
        """Infinite loop waiting for button presses.

        Waits for falling edge on configured button pin. On detection of the
        edge, shepherd service is either started or stopped. Double button
        press while idle causes system shutdown.
        """
        while True:
            logger.info("waiting for falling edge..")
            self.gpio_led.write(True)
            if not self.gpio_button.poll():
                # note: poll is suspected to exit after ~ 1-2 weeks running -> fills mmc with random measurement
                # TODO: observe behavior, hopefully this change fixes the bug
                continue
            self.gpio_led.write(False)
            logger.debug("edge detected")
            if not self.get_state():
                time.sleep(0.25)
                if self.gpio_button.poll(timeout=5):
                    logging.debug("falling edge detected")
                    logging.info("shutdown requested")
                    self.initiate_shutdown()
                    self.gpio_led.write(False)
                    time.sleep(3)
                    continue
            self.set_service(not self.get_state())
            time.sleep(10)

    def get_state(self, timeout: float = 10) -> bool:
        """Queries systemd for state of shepherd service.

        Args:
            timeout (float): Time to wait for service state to settle

        Raises:
            TimeoutError: If state remains changing for longer than timeout
        """
        ts_end = time.time() + timeout

        while True:
            systemd_state = self.shepherd_proxy.Get(
                "org.freedesktop.systemd1.Unit",
                "ActiveState",
                dbus_interface="org.freedesktop.DBus.Properties",
            )
            if systemd_state in ["deactivating", "activating"]:
                time.sleep(0.1)
                continue
            else:
                break
            if time.time() > ts_end:
                raise TimeoutError("Timed out waiting for service state")

        logger.debug(f"service ActiveState: { systemd_state }")

        if systemd_state == "active":
            return True
        elif systemd_state == "inactive":
            return False
        raise Exception(f"Unknown state { systemd_state }")

    def set_service(self, requested_state: bool):
        """Changes state of shepherd service.

        Args:
            requested_state (bool): Target state of service
        """
        active_state = self.get_state()

        if requested_state == active_state:
            logger.debug("service already in requested state")
            self.gpio_led.write(active_state)
            return

        if active_state:
            logger.info("stopping service")
            self.manager.StopUnit("shepherd.service", "fail")
        else:
            logger.info("starting service")
            self.manager.StartUnit("shepherd.service", "fail")

        time.sleep(1)

        new_state = self.get_state()
        if new_state != requested_state:
            raise Exception(f"state didn't change")

        return new_state

    def initiate_shutdown(self, timeout: int = 5) -> NoReturn:
        """ Initiates system shutdown.

        Args:
            timeout (int): Number of seconds to wait before powering off
                system
        """
        logger.debug("initiating shutdown routine..")
        time.sleep(0.25)
        for _ in range(timeout):
            if self.gpio_button.poll(timeout=0.5):
                logger.debug("edge detected")
                logger.info("shutdown cancelled")
                return
            self.gpio_led.write(True)
            if self.gpio_button.poll(timeout=0.5):
                logger.debug("edge detected")
                logger.info("shutdown cancelled")
                return
            self.gpio_led.write(False)
        os.sync()
        logger.info("shutting down now")
        self.manager.PowerOff()