mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2025-12-13 17:50:29 +08:00
bind for streamer device
This commit is contained in:
parent
a33965b6a5
commit
e71252933a
@ -43,6 +43,7 @@ def main() -> None:
|
|||||||
streamer = Streamer(
|
streamer = Streamer(
|
||||||
cap_power=int(config["streamer"]["pinout"].get("cap", -1)),
|
cap_power=int(config["streamer"]["pinout"].get("cap", -1)),
|
||||||
conv_power=int(config["streamer"]["pinout"].get("conv", -1)),
|
conv_power=int(config["streamer"]["pinout"].get("conv", -1)),
|
||||||
|
bind=str(config["streamer"].get("bind", "")),
|
||||||
sync_delay=float(config["streamer"]["sync_delay"]),
|
sync_delay=float(config["streamer"]["sync_delay"]),
|
||||||
init_delay=float(config["streamer"]["init_delay"]),
|
init_delay=float(config["streamer"]["init_delay"]),
|
||||||
width=int(config["streamer"]["size"]["width"]),
|
width=int(config["streamer"]["size"]["width"]),
|
||||||
|
|||||||
48
kvmd/kvmd/extras/explorehw/__init__.py
Normal file
48
kvmd/kvmd/extras/explorehw/__init__.py
Normal 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")
|
||||||
@ -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)
|
|
||||||
@ -98,18 +98,23 @@ def _parse_disk_meta(data: bytes) -> Dict:
|
|||||||
return disk_meta
|
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)
|
# udevadm info -a -p $(udevadm info -q path -n /dev/sda)
|
||||||
ctx = pyudev.Context()
|
ctx = pyudev.Context()
|
||||||
|
|
||||||
block_device = pyudev.Devices.from_device_file(ctx, path)
|
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")
|
interface_device = block_device.find_parent("usb", "usb_interface")
|
||||||
assert storage_device.driver == "usb-storage", (storage_device.driver, storage_device)
|
if not interface_device:
|
||||||
|
return None
|
||||||
|
|
||||||
usb_device = block_device.find_parent("usb", "usb_device")
|
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:
|
with open(path, "rb") as device_file:
|
||||||
device_file.seek(size - _DISK_META_SIZE)
|
device_file.seek(size - _DISK_META_SIZE)
|
||||||
@ -117,7 +122,7 @@ def explore_device(path: str) -> MassStorageDeviceInfo:
|
|||||||
|
|
||||||
return MassStorageDeviceInfo(
|
return MassStorageDeviceInfo(
|
||||||
path=path,
|
path=path,
|
||||||
bind=storage_device.sys_name,
|
bind=interface_device.sys_name,
|
||||||
size=size,
|
size=size,
|
||||||
manufacturer=usb_device.attributes.asstring("manufacturer").strip(),
|
manufacturer=usb_device.attributes.asstring("manufacturer").strip(),
|
||||||
product=usb_device.attributes.asstring("product").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()
|
await self.__close_device_file()
|
||||||
|
|
||||||
async def __reread_device_info(self) -> None:
|
async def __reread_device_info(self) -> None:
|
||||||
path = await self.__loop.run_in_executor(None, locate_by_bind, self._bind)
|
device_path = await self.__loop.run_in_executor(None, locate_by_bind, self._bind)
|
||||||
if not path:
|
if not device_path:
|
||||||
raise MassStorageError("Can't locate device by bind %r" % (self._bind))
|
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:
|
async def __close_device_file(self) -> None:
|
||||||
try:
|
try:
|
||||||
|
|||||||
@ -1,9 +1,14 @@
|
|||||||
|
import os
|
||||||
import asyncio
|
import asyncio
|
||||||
import asyncio.subprocess
|
import asyncio.subprocess
|
||||||
|
|
||||||
from typing import List
|
from typing import List
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
from typing import NamedTuple
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import pyudev
|
||||||
|
|
||||||
from .logging import get_logger
|
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
|
class Streamer: # pylint: disable=too-many-instance-attributes
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
cap_power: int,
|
cap_power: int,
|
||||||
conv_power: int,
|
conv_power: int,
|
||||||
|
bind: str,
|
||||||
sync_delay: float,
|
sync_delay: float,
|
||||||
init_delay: float,
|
init_delay: float,
|
||||||
width: int,
|
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.__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.__conv_power = (gpio.set_output(conv_power) if conv_power > 0 else conv_power)
|
||||||
|
self.__bind = bind
|
||||||
self.__sync_delay = sync_delay
|
self.__sync_delay = sync_delay
|
||||||
self.__init_delay = init_delay
|
self.__init_delay = init_delay
|
||||||
self.__width = width
|
self.__width = width
|
||||||
self.__height = height
|
self.__height = height
|
||||||
self.__cmd = [part.format(width=width, height=height) for part in cmd]
|
self.__cmd = cmd
|
||||||
|
|
||||||
self.__loop = loop
|
self.__loop = loop
|
||||||
|
|
||||||
@ -79,18 +126,27 @@ class Streamer: # pylint: disable=too-many-instance-attributes
|
|||||||
if enabled:
|
if enabled:
|
||||||
await asyncio.sleep(self.__init_delay)
|
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)
|
logger = get_logger(0)
|
||||||
|
|
||||||
while True: # pylint: disable=too-many-nested-blocks
|
while True: # pylint: disable=too-many-nested-blocks
|
||||||
proc: Optional[asyncio.subprocess.Process] = None # pylint: disable=no-member
|
proc: Optional[asyncio.subprocess.Process] = None # pylint: disable=no-member
|
||||||
try:
|
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(
|
proc = await asyncio.create_subprocess_exec(
|
||||||
*self.__cmd,
|
*cmd,
|
||||||
stdout=asyncio.subprocess.PIPE,
|
stdout=asyncio.subprocess.PIPE,
|
||||||
stderr=asyncio.subprocess.STDOUT,
|
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
|
empty = 0
|
||||||
while proc.returncode is None:
|
while proc.returncode is None:
|
||||||
|
|||||||
@ -24,7 +24,7 @@ def main() -> None:
|
|||||||
"kvmd.extras",
|
"kvmd.extras",
|
||||||
"kvmd.extras.cleanup",
|
"kvmd.extras.cleanup",
|
||||||
"kvmd.extras.wscli",
|
"kvmd.extras.wscli",
|
||||||
"kvmd.extras.exploremsd",
|
"kvmd.extras.explorehw",
|
||||||
],
|
],
|
||||||
|
|
||||||
entry_points={
|
entry_points={
|
||||||
@ -32,7 +32,7 @@ def main() -> None:
|
|||||||
"kvmd = kvmd:main",
|
"kvmd = kvmd:main",
|
||||||
"kvmd-cleanup = kvmd.extras.cleanup:main",
|
"kvmd-cleanup = kvmd.extras.cleanup:main",
|
||||||
"kvmd-wscli = kvmd.extras.wscli:main",
|
"kvmd-wscli = kvmd.extras.wscli:main",
|
||||||
"kvmd-exploremsd = kvmd.extras.exploremsd:main",
|
"kvmd-explorehw = kvmd.extras.explorehw:main",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user