bind for streamer device

This commit is contained in:
Devaev Maxim 2018-07-07 06:04:44 +00:00
parent a33965b6a5
commit e71252933a
7 changed files with 128 additions and 36 deletions

View File

@ -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"]),

View File

@ -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")

View File

@ -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)

View File

@ -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:

View File

@ -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:

View File

@ -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",
],
},