summaryrefslogtreecommitdiff
path: root/kvmd
diff options
context:
space:
mode:
authorDevaev Maxim <[email protected]>2020-09-10 07:09:03 +0300
committerDevaev Maxim <[email protected]>2020-09-10 07:09:03 +0300
commita6385cd20e4c4119d9679ed6a58fd9e302d10efe (patch)
tree74a4d71ae0240bb62927b65901e4513763a56072 /kvmd
parent31fdcd2f3c9284cf72d6b92d51b88273d50e8dc1 (diff)
fixes
Diffstat (limited to 'kvmd')
-rw-r--r--kvmd/apps/kvmd/api/ugpio.py5
-rw-r--r--kvmd/apps/kvmd/ugpio.py64
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)