diff options
author | Devaev Maxim <[email protected]> | 2020-09-10 07:09:03 +0300 |
---|---|---|
committer | Devaev Maxim <[email protected]> | 2020-09-10 07:09:03 +0300 |
commit | a6385cd20e4c4119d9679ed6a58fd9e302d10efe (patch) | |
tree | 74a4d71ae0240bb62927b65901e4513763a56072 | |
parent | 31fdcd2f3c9284cf72d6b92d51b88273d50e8dc1 (diff) |
fixes
-rw-r--r-- | kvmd/apps/kvmd/api/ugpio.py | 5 | ||||
-rw-r--r-- | kvmd/apps/kvmd/ugpio.py | 64 |
2 files changed, 42 insertions, 27 deletions
diff --git a/kvmd/apps/kvmd/api/ugpio.py b/kvmd/apps/kvmd/api/ugpio.py index ddd28477..48b60ab1 100644 --- a/kvmd/apps/kvmd/api/ugpio.py +++ b/kvmd/apps/kvmd/api/ugpio.py @@ -52,8 +52,9 @@ class UserGpioApi: async def __switch_handler(self, request: Request) -> Response: channel = valid_ugpio_channel(request.query.get("channel")) state = valid_bool(request.query.get("state")) - done = await self.__user_gpio.switch(channel, state) - return make_json_response({"done": done}) + wait = valid_bool(request.query.get("wait", "0")) + await self.__user_gpio.switch(channel, state, wait) + return make_json_response() @exposed_http("POST", "/gpio/pulse") async def __pulse_handler(self, request: Request) -> Response: diff --git a/kvmd/apps/kvmd/ugpio.py b/kvmd/apps/kvmd/ugpio.py index e2cd2116..3f455833 100644 --- a/kvmd/apps/kvmd/ugpio.py +++ b/kvmd/apps/kvmd/ugpio.py @@ -26,7 +26,9 @@ import operator from typing import List from typing import Dict from typing import AsyncGenerator +from typing import Callable from typing import Optional +from typing import Any from ...logging import get_logger @@ -120,9 +122,14 @@ class _GpioOutput: # pylint: disable=too-many-instance-attributes self.__switch: bool = config.switch - self.__pulse_delay: float = config.pulse.delay - self.__min_pulse_delay: float = config.pulse.min_delay - self.__max_pulse_delay: float = config.pulse.max_delay + self.__pulse_delay = 0.0 + self.__min_pulse_delay = 0.0 + self.__max_pulse_delay = 0.0 + if config.pulse.delay: + assert config.pulse.max_delay > 0 + self.__pulse_delay = min(max(config.pulse.delay, config.pulse.min_delay), config.pulse.max_delay) + self.__min_pulse_delay = config.pulse.min_delay + self.__max_pulse_delay = config.pulse.max_delay self.__busy_delay: float = config.busy_delay @@ -135,9 +142,9 @@ class _GpioOutput: # pylint: disable=too-many-instance-attributes return { "switch": self.__switch, "pulse": { - "delay": min(max(self.__pulse_delay, self.__min_pulse_delay), self.__max_pulse_delay), - "min_delay": (self.__min_pulse_delay if self.__pulse_delay else 0), - "max_delay": (self.__max_pulse_delay if self.__pulse_delay else 0), + "delay": self.__pulse_delay, + "min_delay": self.__min_pulse_delay, + "max_delay": self.__max_pulse_delay, }, "hw": { "driver": self.__driver.get_instance_id(), @@ -159,39 +166,44 @@ class _GpioOutput: # pylint: disable=too-many-instance-attributes "busy": busy, } - async def switch(self, state: bool) -> bool: + async def switch(self, state: bool, wait: bool) -> None: if not self.__switch: raise GpioSwitchNotSupported() - async with self.__region: - if state != self.__read(): - self.__write(state) - get_logger(0).info("Switched %s to state=%d", self, state) - await asyncio.sleep(self.__busy_delay) - return True - await asyncio.sleep(self.__busy_delay) - return False + await self.__run_action(wait, "switch", self.__inner_switch, state) @aiotools.atomic async def pulse(self, delay: float, wait: bool) -> None: if not self.__pulse_delay: raise GpioPulseNotSupported() delay = min(max((delay or self.__pulse_delay), self.__min_pulse_delay), self.__max_pulse_delay) + await self.__run_action(wait, "pulse", self.__inner_pulse, delay) + + # ===== + + @aiotools.atomic + async def __run_action(self, wait: bool, name: str, method: Callable, *args: Any) -> None: if wait: async with self.__region: - await self.__inner_pulse(delay) + await method(*args) else: await aiotools.run_region_task( - f"Can't perform pulse of {self} or operation was not completed", - self.__region, self.__inner_pulse_tasked, delay, + f"Can't perform {name} of {self} or operation was not completed", + self.__region, self.__action_task_wrapper, name, method, *args, ) @aiotools.atomic - async def __inner_pulse_tasked(self, delay: float) -> None: + async def __action_task_wrapper(self, name: str, method: Callable, *args: Any) -> None: try: - await self.__inner_pulse(delay) + return (await method(*args)) except GpioDriverOfflineError: - get_logger(0).error("Can't perform pulse of %s or operation was not completed" - " because the driver is offline", self) + get_logger(0).error("Can't perform %s of %s or operation was not completed: driver offline", name, self) + + @aiotools.atomic + async def __inner_switch(self, state: bool) -> None: + if state != self.__read(): + self.__write(state) + get_logger(0).info("Switched %s to state=%d", self, state) + await asyncio.sleep(self.__busy_delay) @aiotools.atomic async def __inner_pulse(self, delay: float) -> None: @@ -203,6 +215,8 @@ class _GpioOutput: # pylint: disable=too-many-instance-attributes await asyncio.sleep(self.__busy_delay) get_logger(0).info("Pulsed %s with delay=%.2f", self, delay) + # ===== + def __read(self) -> bool: return (self.__driver.read(self.__pin) ^ self.__inverted) @@ -228,7 +242,7 @@ class UserGpio: notifier=self.__notifier, **drv_config._unpack(ignore=["instance_name", "notifier", "type"]), ) - for (driver, drv_config) in config.drivers.items() + for (driver, drv_config) in sorted(config.drivers.items(), key=operator.itemgetter(0)) } self.__inputs: Dict[str, _GpioInput] = {} @@ -284,11 +298,11 @@ class UserGpio: except Exception: get_logger().exception("Can't cleanup driver %s", driver) - async def switch(self, channel: str, state: bool) -> bool: + async def switch(self, channel: str, state: bool, wait: bool) -> None: gout = self.__outputs.get(channel) if gout is None: raise GpioChannelNotFoundError() - return (await gout.switch(state)) + await gout.switch(state, wait) async def pulse(self, channel: str, delay: float, wait: bool) -> None: gout = self.__outputs.get(channel) |