diff options
author | Devaev Maxim <[email protected]> | 2018-07-07 06:04:44 +0000 |
---|---|---|
committer | Devaev Maxim <[email protected]> | 2018-07-07 06:04:44 +0000 |
commit | e71252933aa938d31b0e24cbbeca5999ad8b303d (patch) | |
tree | d5651ef9da542ee2e84d6bc6beb154d3bd0b2188 | |
parent | a33965b6a5d0d7f2ba30505e34cfa2e8ae02001d (diff) |
bind for streamer device
-rw-r--r-- | kvmd/kvmd/__init__.py | 1 | ||||
-rw-r--r-- | kvmd/kvmd/extras/explorehw/__init__.py | 48 | ||||
-rw-r--r-- | kvmd/kvmd/extras/explorehw/__main__.py (renamed from kvmd/kvmd/extras/exploremsd/__main__.py) | 0 | ||||
-rw-r--r-- | kvmd/kvmd/extras/exploremsd/__init__.py | 21 | ||||
-rw-r--r-- | kvmd/kvmd/msd.py | 26 | ||||
-rw-r--r-- | kvmd/kvmd/streamer.py | 64 | ||||
-rwxr-xr-x | kvmd/setup.py | 4 |
7 files changed, 128 insertions, 36 deletions
diff --git a/kvmd/kvmd/__init__.py b/kvmd/kvmd/__init__.py index 7dfa1349..c4b8dc9a 100644 --- a/kvmd/kvmd/__init__.py +++ b/kvmd/kvmd/__init__.py @@ -43,6 +43,7 @@ def main() -> None: streamer = Streamer( cap_power=int(config["streamer"]["pinout"].get("cap", -1)), conv_power=int(config["streamer"]["pinout"].get("conv", -1)), + bind=str(config["streamer"].get("bind", "")), sync_delay=float(config["streamer"]["sync_delay"]), init_delay=float(config["streamer"]["init_delay"]), width=int(config["streamer"]["size"]["width"]), diff --git a/kvmd/kvmd/extras/explorehw/__init__.py b/kvmd/kvmd/extras/explorehw/__init__.py new file mode 100644 index 00000000..42ade82f --- /dev/null +++ b/kvmd/kvmd/extras/explorehw/__init__.py @@ -0,0 +1,48 @@ +import argparse + +from ... import msd +from ... import streamer + + +# ===== +def _probe_msd(path: str) -> bool: + info = msd.explore_device(path) + if info: + print("It's a mass-storage device") + print("--------------------------") + print("Path: ", info.path) + print("Bind: ", info.bind) + print("Size: ", info.size) + print("Manufacturer:", info.manufacturer) + print("Product: ", info.product) + print("Serial: ", info.serial) + print("Image name: ", info.image_name) + assert msd.locate_by_bind(info.bind), info.bind + return bool(info) + + +def _probe_streamer(path: str) -> bool: + info = streamer.explore_device(path) + if info: + print("It's a streamer device") + print("----------------------") + print("Path: ", info.path) + print("Bind: ", info.bind) + print("Driver:", info.driver) + assert streamer.locate_by_bind(info.bind), info.bind + return bool(info) + + +def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument("device") + options = parser.parse_args() + + for probe in [ + _probe_msd, + _probe_streamer, + ]: + if probe(options.device): + break + else: + raise RuntimeError("Can't recognize device") diff --git a/kvmd/kvmd/extras/exploremsd/__main__.py b/kvmd/kvmd/extras/explorehw/__main__.py index 031df43e..031df43e 100644 --- a/kvmd/kvmd/extras/exploremsd/__main__.py +++ b/kvmd/kvmd/extras/explorehw/__main__.py diff --git a/kvmd/kvmd/extras/exploremsd/__init__.py b/kvmd/kvmd/extras/exploremsd/__init__.py deleted file mode 100644 index d9406f6b..00000000 --- a/kvmd/kvmd/extras/exploremsd/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -import argparse - -from ...msd import explore_device -from ...msd import locate_by_bind - - -# ===== -def main() -> None: - parser = argparse.ArgumentParser() - parser.add_argument("-d", "--device", default="/dev/sda") - options = parser.parse_args() - - info = explore_device(options.device) - print("Path: ", info.path) - print("Bind: ", info.bind) - print("Size: ", info.size) - print("Manufacturer:", info.manufacturer) - print("Product: ", info.product) - print("Serial: ", info.serial) - print("Image name: ", info.image_name) - assert locate_by_bind(info.bind), "WTF?! Can't locate device file using bind %r" % (info.bind) diff --git a/kvmd/kvmd/msd.py b/kvmd/kvmd/msd.py index f4358006..c6694cb4 100644 --- a/kvmd/kvmd/msd.py +++ b/kvmd/kvmd/msd.py @@ -98,18 +98,23 @@ def _parse_disk_meta(data: bytes) -> Dict: return disk_meta -def explore_device(path: str) -> MassStorageDeviceInfo: +def explore_device(path: str) -> Optional[MassStorageDeviceInfo]: # udevadm info -a -p $(udevadm info -q path -n /dev/sda) ctx = pyudev.Context() block_device = pyudev.Devices.from_device_file(ctx, path) - size = block_device.attributes.asint("size") * 512 + try: + size = block_device.attributes.asint("size") * 512 + except KeyError: + return None - storage_device = block_device.find_parent("usb", "usb_interface") - assert storage_device.driver == "usb-storage", (storage_device.driver, storage_device) + interface_device = block_device.find_parent("usb", "usb_interface") + if not interface_device: + return None usb_device = block_device.find_parent("usb", "usb_device") - assert usb_device.driver == "usb", (usb_device.driver, usb_device) + if not usb_device: + return None with open(path, "rb") as device_file: device_file.seek(size - _DISK_META_SIZE) @@ -117,7 +122,7 @@ def explore_device(path: str) -> MassStorageDeviceInfo: return MassStorageDeviceInfo( path=path, - bind=storage_device.sys_name, + bind=interface_device.sys_name, size=size, manufacturer=usb_device.attributes.asstring("manufacturer").strip(), product=usb_device.attributes.asstring("product").strip(), @@ -250,10 +255,13 @@ class MassStorageDevice: # pylint: disable=too-many-instance-attributes await self.__close_device_file() async def __reread_device_info(self) -> None: - path = await self.__loop.run_in_executor(None, locate_by_bind, self._bind) - if not path: + device_path = await self.__loop.run_in_executor(None, locate_by_bind, self._bind) + if not device_path: raise MassStorageError("Can't locate device by bind %r" % (self._bind)) - self.__device_info = await self.__loop.run_in_executor(None, explore_device, path) + device_info = await self.__loop.run_in_executor(None, explore_device, device_path) + if not device_info: + raise MassStorageError("Can't explore device %r" % (device_path)) + self.__device_info = device_info async def __close_device_file(self) -> None: try: diff --git a/kvmd/kvmd/streamer.py b/kvmd/kvmd/streamer.py index f77b5f9d..c5e9fd41 100644 --- a/kvmd/kvmd/streamer.py +++ b/kvmd/kvmd/streamer.py @@ -1,9 +1,14 @@ +import os import asyncio import asyncio.subprocess from typing import List from typing import Dict +from typing import NamedTuple from typing import Optional +from typing import Any + +import pyudev from .logging import get_logger @@ -11,11 +16,52 @@ from . import gpio # ===== +class StreamerDeviceInfo(NamedTuple): + path: str + bind: str + driver: str + + +def explore_device(path: str) -> Optional[StreamerDeviceInfo]: + # udevadm info -a -p $(udevadm info -q path -n /dev/sda) + ctx = pyudev.Context() + + video_device = pyudev.Devices.from_device_file(ctx, path) + if video_device.subsystem != "video4linux": + return None + try: + if int(video_device.attributes.get("index")) != 0: + # My strange laptop configuration + return None + except ValueError: + return None + + interface_device = video_device.find_parent("usb", "usb_interface") + if not interface_device: + return None + + return StreamerDeviceInfo( + path=path, + bind=interface_device.sys_name, + driver=interface_device.driver, + ) + + +def locate_by_bind(bind: str) -> str: + ctx = pyudev.Context() + for device in ctx.list_devices(subsystem="video4linux"): + interface_device = device.find_parent("usb", "usb_interface") + if interface_device and interface_device.sys_name == bind: + return os.path.join("/dev", device.sys_name) + return "" + + class Streamer: # pylint: disable=too-many-instance-attributes def __init__( self, cap_power: int, conv_power: int, + bind: str, sync_delay: float, init_delay: float, width: int, @@ -28,11 +74,12 @@ class Streamer: # pylint: disable=too-many-instance-attributes self.__cap_power = (gpio.set_output(cap_power) if cap_power > 0 else cap_power) self.__conv_power = (gpio.set_output(conv_power) if conv_power > 0 else conv_power) + self.__bind = bind self.__sync_delay = sync_delay self.__init_delay = init_delay self.__width = width self.__height = height - self.__cmd = [part.format(width=width, height=height) for part in cmd] + self.__cmd = cmd self.__loop = loop @@ -79,18 +126,27 @@ class Streamer: # pylint: disable=too-many-instance-attributes if enabled: await asyncio.sleep(self.__init_delay) - async def __process(self) -> None: + async def __process(self) -> None: # pylint: disable=too-many-branches logger = get_logger(0) while True: # pylint: disable=too-many-nested-blocks proc: Optional[asyncio.subprocess.Process] = None # pylint: disable=no-member try: + cmd_placeholders: Dict[str, Any] = {"width": self.__width, "height": self.__height} + if self.__bind: + logger.info("Using bind %r as streamer device", self.__bind) + device_path = await self.__loop.run_in_executor(None, locate_by_bind, self.__bind) + if not device_path: + raise RuntimeError("Can't locate device by bind %r" % (self.__bind)) + cmd_placeholders["device"] = device_path + cmd = [part.format(**cmd_placeholders) for part in self.__cmd] + proc = await asyncio.create_subprocess_exec( - *self.__cmd, + *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.STDOUT, ) - logger.info("Started streamer pid=%d: %s", proc.pid, self.__cmd) + logger.info("Started streamer pid=%d: %s", proc.pid, cmd) empty = 0 while proc.returncode is None: diff --git a/kvmd/setup.py b/kvmd/setup.py index fe70a089..3f599aca 100755 --- a/kvmd/setup.py +++ b/kvmd/setup.py @@ -24,7 +24,7 @@ def main() -> None: "kvmd.extras", "kvmd.extras.cleanup", "kvmd.extras.wscli", - "kvmd.extras.exploremsd", + "kvmd.extras.explorehw", ], entry_points={ @@ -32,7 +32,7 @@ def main() -> None: "kvmd = kvmd:main", "kvmd-cleanup = kvmd.extras.cleanup:main", "kvmd-wscli = kvmd.extras.wscli:main", - "kvmd-exploremsd = kvmd.extras.exploremsd:main", + "kvmd-explorehw = kvmd.extras.explorehw:main", ], }, |