updated client/server for video

This commit is contained in:
Brad Stein 2025-06-25 07:46:50 -05:00
parent 57b6da0895
commit a968218f60
4 changed files with 45 additions and 32 deletions

View File

@ -10,6 +10,7 @@ use tonic::Request;
use tracing::{debug, error, info, warn};
use winit::{
event_loop::EventLoopBuilder,
platform::x11::EventLoopBuilderExtX11,
platform::unix::EventLoopBuilderExtUnix,
event::Event,
};
@ -79,14 +80,14 @@ impl LesavkaClientApp {
.unwrap();
std::thread::spawn(move || {
let el = EventLoopBuilder::default()
let el = EventLoopBuilder::<()>::new()
.with_any_thread(true)
.build()
.unwrap();
let win0 = MonitorWindow::new(0, &el).expect("win0");
let win1 = MonitorWindow::new(1, &el).expect("win1");
el.run(move |_: Event<()>, _el| {
el.run(move |_: Event<'_, ()>, _| {
while let Ok(pkt) = video_rx.try_recv() {
match pkt.id {
0 => win0.push_packet(pkt),

View File

@ -29,18 +29,34 @@ echo "==> 2b. Predictable /dev names for each capture card"
# ATTRS{serial}=="1200655409098", ATTR{index}=="0", \
# SYMLINK+="lesavka_l_eye"
# RULES
sudo tee /etc/udev/rules.d/85-gc311.rules >/dev/null <<'RULES'
# LEFT eye GC311 on hubport 13
SUBSYSTEM=="video4linux", ATTRS{idVendor}=="07ca", ATTRS{idProduct}=="3311", \
ATTRS{index}=="0", ENV{ID_PATH_TAG}=="usb-platform-1a400000.xhci-usb-0_1_3_1_0", \
SYMLINK+="lesavka_l_eye"
# RIGHT eye GC311 on hubport 14
SUBSYSTEM=="video4linux", ATTRS{idVendor}=="07ca", ATTRS{idProduct}=="3311", \
ATTRS{index}=="0", ENV{ID_PATH_TAG}=="usb-platform-1a400000.xhci-usb-0_1_4_1_0", \
SYMLINK+="lesavka_r_eye"
RULES
# probe all v4l2 devices, keep only the two GC311 capture cards
mapfile -t TAGS < <(
for v in /dev/video*; do
if udevadm info -q property -n "$v" | grep -q 'ID_VENDOR_ID=07ca'; then
# extract the stable port token (ID_PATH_TAG=…)
udevadm info -q property -n "$v" |
awk -F= '/^ID_PATH_TAG=/{print $2}'
fi
done | sort
)
if [ "${#TAGS[@]}" -ne 2 ]; then
echo "❌ Exactly two GC311 devices must be attached!" >&2
exit 1
fi
LEFT_TAG=${TAGS[0]}
RIGHT_TAG=${TAGS[1]}
cat <<EOF | sudo tee /etc/udev/rules.d/85-gc311.rules
# autogenerated by installserver.sh DO NOT EDIT
SUBSYSTEM=="video4linux", ATTRS{idVendor}=="07ca", ATTRS{idProduct}=="3311", \\
ATTRS{index}=="0", ENV{ID_PATH_TAG}=="$LEFT_TAG", SYMLINK+="lesavka_l_eye"
SUBSYSTEM=="video4linux", ATTRS{idVendor}=="07ca", ATTRS{idProduct}=="3311", \\
ATTRS{index}=="0", ENV{ID_PATH_TAG}=="$RIGHT_TAG", SYMLINK+="lesavka_r_eye"
EOF
sudo udevadm control --reload
sudo udevadm trigger --subsystem-match=video4linux
udevadm settle

View File

@ -11,7 +11,7 @@ use tracing::{info, trace};
use tracing_subscriber::{fmt, EnvFilter};
use udev::{MonitorBuilder};
use usb_gadget::UsbGadgetManager;
use usb_gadget::UsbGadget;
use lesavka_server::{video, usb_reset};
use lesavka_common::lesavka::{
@ -77,11 +77,11 @@ fn list_gc311_devices() -> anyhow::Result<Vec<String>> {
struct Handler {
kb: Arc<Mutex<tokio::fs::File>>,
ms: Arc<Mutex<tokio::fs::File>>,
gadget: UsbGadgetManager,
gadget: UsbGadget,
}
impl Handler {
fn make(gadget: UsbGadget) -> anyhow::Result<Self> {
async fn make(gadget: UsbGadget) -> anyhow::Result<Self> {
let kb = OpenOptions::new().write(true).open("/dev/hidg0").await?;
let ms = OpenOptions::new().write(true)
.custom_flags(libc::O_NONBLOCK)
@ -191,10 +191,10 @@ async fn main() -> anyhow::Result<()> {
/* autocycle task */
// tokio::spawn(async { monitor_gc311_disconnect().await.ok(); });
let gadget = UsbGadgetManager::new("lesavka");
let gadget = UsbGadget::new("lesavka");
gadget.cycle().ok();
let handler = Handler::make(gadget.clone())?;
let handler = Handler::make(gadget.clone()).await?;
tokio::spawn({
let gadget = gadget.clone();

View File

@ -7,32 +7,28 @@ pub struct UsbGadget {
udc_file: &'static str,
}
impl UsbGadgetManager {
pub fn new(gadget_name: &'static str) -> Self {
impl UsbGadget {
pub fn new(name: &'static str) -> Self {
// /sys/kernel/config/usb_gadget/<name>/UDC
Self { udc_file: Box::leak(
format!("/sys/kernel/config/usb_gadget/{gadget_name}/UDC").into_boxed_str())
format!("/sys/kernel/config/usb_gadget/{name}/UDC").into_boxed_str())
}
}
/// Force the host to reenumerate our HID gadget.
pub fn cycle(&self) -> Result<()> {
// 1. detach
info!("UDCcycle: detaching gadget");
OpenOptions::new().write(true).open(self.udc_file)?
.write_all(b"")?;
OpenOptions::new().write(true).open(self.udc_file)?.write_all(b"")?;
thread::sleep(Duration::from_millis(200));
// 2. wait ≥ 100 ms so host sees a disconnect
std::thread::sleep(Duration::from_millis(200));
// 3. reattach to **first** UDC (dwc2)
let udc = std::fs::read_dir("/sys/class/udc")?
.next().context("no UDC present")?
let udc_name = std::fs::read_dir("/sys/class/udc")?
.next()
.transpose()?
.context("no UDC present")?
.file_name();
let name = udc.to_string_lossy();
info!("UDCcycle: reattaching to {name}");
OpenOptions::new().write(true).open(self.udc_file)?
.write_all(name.as_bytes())?;
.write_all(udc_name.to_str().unwrap().as_bytes())?;
info!("USBgadget cycled");
Ok(())
}
}