简体   繁体   中英

Python daemon to monitor GPIO pins using pyxs Xenstore client

I'm using the pyxs Python Xenstore client module to write an Upstart daemon that monitors a bunch of output pins on a GPIO controller on a box. The basic structure of the daemon, after startup, is to export the relevant pins, add the corresponding Xenstore paths for the pins, and add and monitor watches for each of the Xenstore paths. The watches part is threaded - for each watch a thread is created with a target worker method that monitors the watch for changes. According to the PyXS docs you basically have to do something like:

# monitor is a pyxs.client.Client.Monitor object, and watch adds a
# watch to the given path
monitor.watch(path, path_token)
# wait for events on the watched path - returns a pair if there is an
# event, the first is the event path and the second is the path token
monitor.wait(sleep=...)

My question is whether the call to wait blocks if no sleep=<time> argument is specified - it is not clear from the PyXS docs whether this is the case or not.

The code is roughly something like this:

from pyxs.client import Client
from pyxs.exceptions import PyXSError
from threading import Thread

...
class gpiod(object):

    def __init__(self,...):
        ...
        # stores pin numbers using descriptive labels as keys
        self._gpio_pins = {}
        # stores Xenstore paths for the pins, using the pin labels as keys
        self._xenstore_paths = {}
        self._xenstore_client = Client()
        self._xenstore_monitor = self._xenstore_client.monitor()
        # stores threads that monitor the watches added for the paths
        self._xenstore_watchers = {}

        self.start()
        self.run()

    def _watch_xenstore_path(self, watch_path):
    """
    A worker method that is a target for a watch thread.
    """
        while True:
            try:
                path_change = self._xenstore_monitor.wait(sleep=1)
                while not path_change:
                    path_change = self._xenstore_monitor.wait(sleep=1)
                if path_change[0] == watch_path:
                # write changed value to the pin
           except PyXSError as e:
                # log the error

    def start(self):
        # load config
        ...
        # export relevant GPIO output pins (using system calls to sysfs)
        ...
        # create Xenstore paths using _xenstore_client
        ...
        # set watches on the paths
        for path in self._xenstore_paths:
            self._xenstore_monitor.watch(wpath=path, token=path)
            self._xenstore_watchers.update(
                {pin_label: Thread(target=self._watch_xenstore_path, args=(path,))}
            )

    def run(self):
        for watcher in self._xenstore_watchers:
            watcher.start()

From the pyxs documentation:

wait(sleep=None)

Waits for any of the watched paths to generate an event, which is a (path, token) pair, where the first element is event path, ie the actual path that was modified and second element is a token, passed to the watch(). Parameters: sleep (float) – number of seconds to sleep between event checks.

That means, the sleep parameters is actually to separate even checks on the wait method and if you look at the code from github:

def wait(self, sleep=None):
    """Waits for any of the watched paths to generate an event,
    which is a ``(path, token)`` pair, where the first element
    is event path, i.e. the actual path that was modified and
    second element is a token, passed to the :meth:`watch`.
    :param float sleep: number of seconds to sleep between event
                        checks.
    """
    while True:
        if self.client.events:
            packet = self.client.events.popleft()
            return Event(*packet.payload.split("\x00")[:-1])

        # Executing a noop, hopefuly we'll get some events queued
        # in the meantime. Note: I know it sucks, but it seems like
        # there's no other way ...
        self.client.execute_command(Op.DEBUG, "")

        if sleep is not None: #sleep here is to provide tap gap between event check
            time.sleep(sleep)

You'll see that sleep parameters is only to provide tap gap between event check where as the while True loop keeps going until you get un event or if you want: How fast to check for event , the smaller sleep the faster the regular check.

So, in conclusion:

The call to wait method already blocks, sleep is only to give time separation between event checks.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM