summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDevaev Maxim <[email protected]>2018-07-07 06:04:44 +0000
committerDevaev Maxim <[email protected]>2018-07-07 06:04:44 +0000
commite71252933aa938d31b0e24cbbeca5999ad8b303d (patch)
treed5651ef9da542ee2e84d6bc6beb154d3bd0b2188
parenta33965b6a5d0d7f2ba30505e34cfa2e8ae02001d (diff)
bind for streamer device
-rw-r--r--kvmd/kvmd/__init__.py1
-rw-r--r--kvmd/kvmd/extras/explorehw/__init__.py48
-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__.py21
-rw-r--r--kvmd/kvmd/msd.py26
-rw-r--r--kvmd/kvmd/streamer.py64
-rwxr-xr-xkvmd/setup.py4
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",
],
},