diff options
author | Devaev Maxim <[email protected]> | 2019-03-18 02:00:58 +0300 |
---|---|---|
committer | Devaev Maxim <[email protected]> | 2019-03-18 03:32:14 +0300 |
commit | d049400a97d7c0d785298f23c34bd4e3ed612f36 (patch) | |
tree | aaaa299770c0be464bcbd9728e60903202ca1e2f /kvmd | |
parent | d1a6d79af5043ba8c0b2e085e0ca32922d8b23e1 (diff) |
optional msd and atx
Diffstat (limited to 'kvmd')
-rw-r--r-- | kvmd/apps/__init__.py | 25 | ||||
-rw-r--r-- | kvmd/apps/kvmd/atx.py | 58 | ||||
-rw-r--r-- | kvmd/apps/kvmd/msd.py | 63 | ||||
-rw-r--r-- | kvmd/apps/kvmd/server.py | 3 | ||||
-rw-r--r-- | kvmd/apps/kvmd/streamer.py | 4 | ||||
-rw-r--r-- | kvmd/gpio.py | 4 |
6 files changed, 113 insertions, 44 deletions
diff --git a/kvmd/apps/__init__.py b/kvmd/apps/__init__.py index bbe7c29a..644cc109 100644 --- a/kvmd/apps/__init__.py +++ b/kvmd/apps/__init__.py @@ -103,7 +103,7 @@ def _as_pin(pin: int) -> int: def _as_optional_pin(pin: int) -> int: - if not isinstance(pin, int) or pin == 0: + if not isinstance(pin, int) or pin < -1: raise ValueError("Invalid optional pin number") return pin @@ -168,11 +168,13 @@ def _get_config_scheme() -> Dict: }, "atx": { - "power_led_pin": Option(0, type=_as_pin), - "hdd_led_pin": Option(0, type=_as_pin), + "enabled": Option(True), + + "power_led_pin": Option(-1, type=_as_optional_pin), + "hdd_led_pin": Option(-1, type=_as_optional_pin), + "power_switch_pin": Option(-1, type=_as_optional_pin), + "reset_switch_pin": Option(-1, type=_as_optional_pin), - "power_switch_pin": Option(0, type=_as_pin), - "reset_switch_pin": Option(0, type=_as_pin), "click_delay": Option(0.1), "long_click_delay": Option(5.5), @@ -180,9 +182,12 @@ def _get_config_scheme() -> Dict: }, "msd": { - "target_pin": Option(0, type=_as_pin), - "reset_pin": Option(0, type=_as_pin), - "device": Option("", type=_as_path, rename="device_path"), + "enabled": Option(True), + + "target_pin": Option(-1, type=_as_optional_pin), + "reset_pin": Option(-1, type=_as_optional_pin), + + "device": Option("", type=_as_optional_path, rename="device_path"), "init_delay": Option(2.0), "reset_delay": Option(1.0), "write_meta": Option(True), @@ -190,8 +195,8 @@ def _get_config_scheme() -> Dict: }, "streamer": { - "cap_pin": Option(-1, type=_as_optional_pin), - "conv_pin": Option(-1, type=_as_optional_pin), + "cap_pin": Option(0, type=_as_optional_pin), + "conv_pin": Option(0, type=_as_optional_pin), "sync_delay": Option(1.0), "init_delay": Option(1.0), diff --git a/kvmd/apps/kvmd/atx.py b/kvmd/apps/kvmd/atx.py index 4d42c6cc..9cff48af 100644 --- a/kvmd/apps/kvmd/atx.py +++ b/kvmd/apps/kvmd/atx.py @@ -23,7 +23,9 @@ import asyncio from typing import Dict +from typing import Callable from typing import AsyncGenerator +from typing import Any from ...logging import get_logger @@ -32,13 +34,36 @@ from ... import gpio # ===== -class AtxIsBusy(aioregion.RegionIsBusyError): +class AtxError(Exception): pass +class AtxOperationError(AtxError): + pass + + +class AtxDisabledError(AtxOperationError): + def __init__(self) -> None: + super().__init__("ATX is disabled") + + +class AtxIsBusyError(AtxOperationError, aioregion.RegionIsBusyError): + pass + + +def _atx_working(method: Callable) -> Callable: + async def wrap(self: "Atx", *args: Any, **kwargs: Any) -> Any: + if not self._enabled: # pylint: disable=protected-access + raise AtxDisabledError() + return (await method(self, *args, **kwargs)) + return wrap + + class Atx: # pylint: disable=too-many-instance-attributes def __init__( self, + enabled: bool, + power_led_pin: int, hdd_led_pin: int, @@ -50,31 +75,43 @@ class Atx: # pylint: disable=too-many-instance-attributes state_poll: float, ) -> None: - self.__power_led_pin = gpio.set_input(power_led_pin) - self.__hdd_led_pin = gpio.set_input(hdd_led_pin) + self._enabled = enabled + + if self._enabled: + self.__power_led_pin = gpio.set_input(power_led_pin) + self.__hdd_led_pin = gpio.set_input(hdd_led_pin) + self.__power_switch_pin = gpio.set_output(power_switch_pin) + self.__reset_switch_pin = gpio.set_output(reset_switch_pin) + else: + self.__power_led_pin = -1 + self.__hdd_led_pin = -1 + self.__power_switch_pin = -1 + self.__reset_switch_pin = -1 - self.__power_switch_pin = gpio.set_output(power_switch_pin) - self.__reset_switch_pin = gpio.set_output(reset_switch_pin) self.__click_delay = click_delay self.__long_click_delay = long_click_delay self.__state_poll = state_poll - self.__region = aioregion.AioExclusiveRegion(AtxIsBusy) + self.__region = aioregion.AioExclusiveRegion(AtxIsBusyError) def get_state(self) -> Dict: return { + "enabled": self._enabled, "busy": self.__region.is_busy(), "leds": { - "power": (not gpio.read(self.__power_led_pin)), - "hdd": (not gpio.read(self.__hdd_led_pin)), + "power": ((not gpio.read(self.__power_led_pin)) if self._enabled else False), + "hdd": ((not gpio.read(self.__hdd_led_pin)) if self._enabled else False), }, } async def poll_state(self) -> AsyncGenerator[Dict, None]: while True: - yield self.get_state() - await asyncio.sleep(self.__state_poll) + if self._enabled: + yield self.get_state() + await asyncio.sleep(self.__state_poll) + else: + await asyncio.sleep(60) async def click_power(self) -> None: get_logger().info("Clicking power ...") @@ -88,6 +125,7 @@ class Atx: # pylint: disable=too-many-instance-attributes get_logger().info("Clicking reset") await self.__click(self.__reset_switch_pin, self.__click_delay) + @_atx_working async def __click(self, pin: int, delay: float) -> None: self.__region.enter() asyncio.ensure_future(self.__inner_click(pin, delay)) diff --git a/kvmd/apps/kvmd/msd.py b/kvmd/apps/kvmd/msd.py index 8ec7c3b8..44f836a3 100644 --- a/kvmd/apps/kvmd/msd.py +++ b/kvmd/apps/kvmd/msd.py @@ -54,9 +54,14 @@ class MsdOperationError(MsdError): pass -class MsdIsNotOperationalError(MsdOperationError): +class MsdDisabledError(MsdOperationError): def __init__(self) -> None: - super().__init__("Missing path for mass-storage device") + super().__init__("Mass-storage device is disabled") + + +class MsdOfflineError(MsdOperationError): + def __init__(self) -> None: + super().__init__("Mass-storage device is not found") class MsdAlreadyConnectedToPcError(MsdOperationError): @@ -69,7 +74,7 @@ class MsdAlreadyConnectedToKvmError(MsdOperationError): super().__init__("Mass-storage is already connected to KVM") -class MsdIsNotConnectedToKvmError(MsdOperationError): +class MsdNotConnectedToKvmError(MsdOperationError): def __init__(self) -> None: super().__init__("Mass-storage is not connected to KVM") @@ -177,10 +182,12 @@ def _explore_device(device_path: str) -> Optional[_MassStorageDeviceInfo]: ) -def _msd_operated(method: Callable) -> Callable: +def _msd_working(method: Callable) -> Callable: async def wrap(self: "MassStorageDevice", *args: Any, **kwargs: Any) -> Any: + if not self._enabled: # pylint: disable=protected-access + raise MsdDisabledError() if not self._device_path: # pylint: disable=protected-access - MsdIsNotOperationalError() + raise MsdOfflineError() return (await method(self, *args, **kwargs)) return wrap @@ -189,6 +196,8 @@ def _msd_operated(method: Callable) -> Callable: class MassStorageDevice: # pylint: disable=too-many-instance-attributes def __init__( self, + enabled: bool, + target_pin: int, reset_pin: int, @@ -201,8 +210,15 @@ class MassStorageDevice: # pylint: disable=too-many-instance-attributes loop: asyncio.AbstractEventLoop, ) -> None: - self.__target_pin = gpio.set_output(target_pin) - self.__reset_pin = gpio.set_output(reset_pin) + self._enabled = enabled + + if self._enabled: + self.__target_pin = gpio.set_output(target_pin) + self.__reset_pin = gpio.set_output(reset_pin) + assert bool(device_path) + else: + self.__target_pin = -1 + self.__reset_pin = -1 self._device_path = device_path self.__init_delay = init_delay @@ -221,7 +237,7 @@ class MassStorageDevice: # pylint: disable=too-many-instance-attributes self.__state_queue: asyncio.queues.Queue = asyncio.Queue() logger = get_logger(0) - if self._device_path: + if self._enabled: logger.info("Using %r as mass-storage device", self._device_path) try: logger.info("Enabled image metadata writing") @@ -231,10 +247,10 @@ class MassStorageDevice: # pylint: disable=too-many-instance-attributes log = logger.error else: log = logger.exception - log("Mass-storage device is not operational: %s", err) + log("Mass-storage device is offline: %s", err) self._device_path = "" else: - logger.warning("Mass-storage device is not operational") + logger.info("Mass-storage device is disabled") def get_state(self) -> Dict: info = (self.__saved_device_info._asdict() if self.__saved_device_info else None) @@ -243,11 +259,12 @@ class MassStorageDevice: # pylint: disable=too-many-instance-attributes info["image"] = (info["image"]._asdict() if info["image"] else None) connected_to: Optional[str] = None - if self._device_path: + if self._enabled and self._device_path: connected_to = ("kvm" if self.__device_info else "server") return { - "in_operate": bool(self._device_path), + "enabled": self._enabled, + "online": (self._enabled and bool(self._device_path)), "connected_to": connected_to, "busy": bool(self.__device_file), "written": self.__written, @@ -256,14 +273,18 @@ class MassStorageDevice: # pylint: disable=too-many-instance-attributes async def poll_state(self) -> AsyncGenerator[Dict, None]: while True: - yield (await self.__state_queue.get()) + if self._enabled: + yield (await self.__state_queue.get()) + else: + await asyncio.sleep(60) async def cleanup(self) -> None: - await self.__close_device_file() - gpio.write(self.__target_pin, False) - gpio.write(self.__reset_pin, False) + if self._enabled: + await self.__close_device_file() + gpio.write(self.__target_pin, False) + gpio.write(self.__reset_pin, False) - @_msd_operated + @_msd_working async def connect_to_kvm(self, no_delay: bool=False) -> Dict: with self.__region: if self.__device_info: @@ -277,7 +298,7 @@ class MassStorageDevice: # pylint: disable=too-many-instance-attributes get_logger().info("Mass-storage device switched to KVM: %s", self.__device_info) return state - @_msd_operated + @_msd_working async def connect_to_pc(self) -> Dict: with self.__region: if not self.__device_info: @@ -289,7 +310,7 @@ class MassStorageDevice: # pylint: disable=too-many-instance-attributes get_logger().info("Mass-storage device switched to Server") return state - @_msd_operated + @_msd_working async def reset(self) -> None: with self.__region: get_logger().info("Mass-storage device reset") @@ -298,12 +319,12 @@ class MassStorageDevice: # pylint: disable=too-many-instance-attributes gpio.write(self.__reset_pin, False) await self.__state_queue.put(self.get_state()) - @_msd_operated + @_msd_working async def __aenter__(self) -> "MassStorageDevice": self.__region.enter() try: if not self.__device_info: - raise MsdIsNotConnectedToKvmError() + raise MsdNotConnectedToKvmError() self.__device_file = await aiofiles.open(self.__device_info.path, mode="w+b", buffering=0) self.__written = 0 return self diff --git a/kvmd/apps/kvmd/server.py b/kvmd/apps/kvmd/server.py index ed25f82a..864e0b64 100644 --- a/kvmd/apps/kvmd/server.py +++ b/kvmd/apps/kvmd/server.py @@ -51,6 +51,7 @@ from .auth import AuthManager from .info import InfoManager from .logreader import LogReader from .hid import Hid +from .atx import AtxOperationError from .atx import Atx from .msd import MsdOperationError from .msd import MassStorageDevice @@ -148,7 +149,7 @@ def _exposed(http_method: str, path: str, auth_required: bool=True) -> Callable: except RegionIsBusyError as err: return _json_exception(err, 409) - except (BadRequestError, MsdOperationError) as err: + except (BadRequestError, AtxOperationError, MsdOperationError) as err: return _json_exception(err, 400) except UnauthorizedError as err: return _json_exception(err, 401) diff --git a/kvmd/apps/kvmd/streamer.py b/kvmd/apps/kvmd/streamer.py index ab5e8d59..8b939929 100644 --- a/kvmd/apps/kvmd/streamer.py +++ b/kvmd/apps/kvmd/streamer.py @@ -63,8 +63,8 @@ class Streamer: # pylint: disable=too-many-instance-attributes loop: asyncio.AbstractEventLoop, ) -> None: - self.__cap_pin = (gpio.set_output(cap_pin) if cap_pin > 0 else cap_pin) - self.__conv_pin = (gpio.set_output(conv_pin) if conv_pin > 0 else conv_pin) + self.__cap_pin = (gpio.set_output(cap_pin) if cap_pin > 0 else 0) + self.__conv_pin = (gpio.set_output(conv_pin) if conv_pin > 0 else 0) self.__sync_delay = sync_delay self.__init_delay = init_delay diff --git a/kvmd/gpio.py b/kvmd/gpio.py index fccdf936..fbcdba99 100644 --- a/kvmd/gpio.py +++ b/kvmd/gpio.py @@ -43,18 +43,22 @@ def bcm() -> Generator[None, None, None]: def set_output(pin: int, initial: bool=False) -> int: + assert pin > 0, pin GPIO.setup(pin, GPIO.OUT, initial=initial) return pin def set_input(pin: int) -> int: + assert pin > 0, pin GPIO.setup(pin, GPIO.IN) return pin def read(pin: int) -> bool: + assert pin > 0, pin return bool(GPIO.input(pin)) def write(pin: int, flag: bool) -> None: + assert pin > 0, pin GPIO.output(pin, flag) |