Skip to content

Commit

Permalink
USB stall handling
Browse files Browse the repository at this point in the history
  • Loading branch information
windoze committed Jan 17, 2025
1 parent 646a743 commit 3196bfc
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 35 deletions.
36 changes: 17 additions & 19 deletions src/barrier_client/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ pub async fn start_barrier_client<Actor: Actuator>(
stream.write_str(device_name).await?;

actor.connected().await?;
// watchdog.feed();

#[cfg(feature = "clipboard")]
let mut clipboard_stage = ClipboardStage::None;
Expand Down Expand Up @@ -102,23 +101,16 @@ pub async fn start_barrier_client<Actor: Actuator>(
}
Packet::KeepAlive => {
match packet_stream.write(Packet::KeepAlive).await {
Ok(_) => {
debug!("Feed watchdog on KeepAlive");
// watchdog.feed();
Ok(())
}
Ok(_) => Ok(()),
Err(e) => {
actor.disconnected().await?;
Err(e)
}
}?;
}
Packet::MouseMoveAbs { x, y } => {
// There is no `ceil` function in `no_std` environment
let abs_x = (x as u32 * 0x7fff).div_ceil(screen_size.0 as u32) as u16;
let abs_y = (y as u32 * 0x7fff).div_ceil(screen_size.1 as u32) as u16;
// let abs_x = ((x as f32) * (0x7fff as f32 / (screen_size.0 as f32))).ceil() as u16;
// let abs_y = ((y as f32) * (0x7fff as f32 / (screen_size.1 as f32))).ceil() as u16;
actor.set_cursor_position(abs_x, abs_y).await?;
}
Packet::MouseMove { x, y } => {
Expand Down Expand Up @@ -147,8 +139,6 @@ pub async fn start_barrier_client<Actor: Actuator>(
Packet::MouseWheel { x_delta, y_delta } => {
actor.mouse_wheel(x_delta, y_delta).await?;
}
Packet::InfoAck => { //Ignore
}
Packet::CursorEnter {
x,
y,
Expand All @@ -173,15 +163,15 @@ pub async fn start_barrier_client<Actor: Actuator>(
actor.set_clipboard(data).await?;
}
}
Packet::DeviceInfo { .. } | Packet::ErrorUnknownDevice | Packet::ClientNoOp => {
// Server only packets
}
Packet::ServerBusy => {
warn!("Server is busy, disconnecting");
break;
}
Packet::ResetOptions => {
info!("Reset options");
Packet::DeviceInfo { .. }
| Packet::ClientNoOp
| Packet::InfoAck
| Packet::ResetOptions => {
// Do nothing
}
Packet::GoodBye => {
info!("Goodbye");
Expand All @@ -191,14 +181,22 @@ pub async fn start_barrier_client<Actor: Actuator>(
error!("Bad protocol");
break;
}
Packet::UnknownDevice => {
error!("Unknown device");
break;
}
Packet::IncompatibleVersion { major, minor } => {
error!("Incompatible version: {}:{}", major, minor);
break;
}
Packet::Unknown(cmd) => {
debug!(
"Unknown packet: {}",
core::str::from_utf8(&cmd).unwrap_or("????")
log::info!(
"Unknown packet code: '{}' ({:02X} {:02X} {:02X} {:02X})",
core::str::from_utf8(&cmd).unwrap_or("????"),
cmd[0],
cmd[1],
cmd[2],
cmd[3]
);
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/barrier_client/packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub enum Packet {
InfoAck,
KeepAlive,
ClientNoOp,
ErrorUnknownDevice,
UnknownDevice,
GrabClipboard {
id: u8,
seq_num: u32,
Expand Down Expand Up @@ -130,7 +130,7 @@ impl Packet {
out.write_str("CALV").await?;
Ok(())
}
Packet::ErrorUnknownDevice => {
Packet::UnknownDevice => {
out.write_str("EUNK").await?;
Ok(())
}
Expand Down
7 changes: 2 additions & 5 deletions src/barrier_client/packet_stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ impl<S: PacketReader + PacketWriter> PacketStream<S> {
b"QINF" => Packet::QueryInfo,
b"CIAK" => Packet::InfoAck,
b"CALV" => Packet::KeepAlive,
b"EUNK" => Packet::ErrorUnknownDevice,
b"EUNK" => Packet::UnknownDevice,
b"EBSY" => Packet::ServerBusy,
b"DMMV" => {
let x = chunk.read_u16().await?;
Expand Down Expand Up @@ -226,10 +226,7 @@ impl<S: PacketReader + PacketWriter> PacketStream<S> {
}
Packet::ClientNoOp
}
_ => {
log::info!("Unknown packet code: {:?}", code);
Packet::Unknown(code)
}
_ => Packet::Unknown(code),
};

// Discard the rest of the packet
Expand Down
4 changes: 2 additions & 2 deletions src/bin/app_main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ async fn main(spawner: Spawner) {

// Setup watchdog on TIMG1, which is by default disabled by the bootloader
let wdt1 = mk_static!(Wdt<TIMG1>, TimerGroup::new(peripherals.TIMG1).wdt);
wdt1.set_timeout(MwdtStage::Stage0, fugit::MicrosDurationU64::secs(2));
wdt1.set_timeout(MwdtStage::Stage0, fugit::MicrosDurationU64::secs(1));
wdt1.set_stage_action(MwdtStage::Stage0, MwdtStageAction::ResetSystem);
wdt1.enable();
wdt1.feed();
Expand Down Expand Up @@ -172,7 +172,7 @@ async fn watchdog_task(
) {
loop {
watchdog.feed();
Timer::after(Duration::from_secs(1)).await;
Timer::after(Duration::from_millis(500)).await;
}
}

Expand Down
26 changes: 21 additions & 5 deletions src/hid_report_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,9 @@ impl HidReportWriter for UsbHidReportWriter<'_> {
HidReport::Mouse(data) => data,
HidReport::Consumer(data) => data,
};
with_timeout(Duration::from_millis(1), async {
// As we asked the host to poll the device every 1 ms, we can safely assume
// that 5ms is already timed-out.
with_timeout(Duration::from_millis(5), async {
self.hid_report_writer
.write(data)
.await
Expand All @@ -87,10 +89,24 @@ impl HidReportWriter for UsbHidReportWriter<'_> {
.ok();
})
.await
.inspect_err(|_| {
warn!("Timeout writing HID report");
})
.unwrap();
.expect(
// This can happen if the device is writing the report while unplugged.
// Some board doesn't really support `self_powered` because the VBUS pin
// in USB-OTG port is not solely powered by the host, or, it has not
// configured a GPIO pin to monitor the VBUS voltage, which doesn't meet
// the standard of USB self-powered device.
// In this case, the board cannot detect the unplugging event even the
// function is already implemented by the underlying OTG driver. And if a
// report is being sent while the device is unplugged, the USB stack will
// be stalled.
// Above scenario may happen if the device is plugged into a USB hub which
// supplies power to the device even if the host is disconnected or powered
// off.
// There is no way we can resume the USB stack, so we just panic here, and
// the watchdog will reset the board.
// @see https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32s3/api-reference/peripherals/usb_device.html#self-powered-device
"Timeout writing HID report",
);
}
}

Expand Down
8 changes: 6 additions & 2 deletions src/synergy_hid/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ impl SynergyHid {
// debug!("Key Down {:#04x} -> Keycode: {:?}", key, hid);
match hid {
KeyCode::None => {
warn!("Keycode {} not found", key);
if key != 0 {
warn!("Keycode {} not found", key);
}
report[0] = ReportType::Keyboard as u8;
report[1..9].copy_from_slice(&self.keyboard_report.clear());
(ReportType::Keyboard, &report[0..9])
Expand Down Expand Up @@ -120,7 +122,9 @@ impl SynergyHid {
// debug!("Key Down {:#04x} -> Keycode: {:?}", key, hid);
match hid {
KeyCode::None => {
warn!("Keycode {} not found", key);
if key != 0 {
warn!("Keycode {} not found", key);
}
report[0] = ReportType::Keyboard as u8;
report[1..9].copy_from_slice(&self.keyboard_report.clear());
(ReportType::Keyboard, &report[0..9])
Expand Down

0 comments on commit 3196bfc

Please sign in to comment.