hid-service: add timeout for I2C device operations#697
hid-service: add timeout for I2C device operations#697jerrysxie merged 6 commits intoOpenDevicePartnership:mainfrom
Conversation
Wrap all I2C master bus operations with timeouts to prevent indefinite blocking when communicating with HID devices. - Add DEVICE_RESPONSE_TIMEOUT_MS (200ms) for descriptor reads and commands - Add DATA_READ_TIMEOUT_MS (50ms) for input reports and feature data - Return Error::Hid(hid::Error::Timeout) on timeout expiry
There was a problem hiding this comment.
Pull request overview
This PR adds bounded timeouts around all I2C master operations performed by the HID I2C device side, preventing indefinite blocking when devices misbehave or stop responding.
Changes:
- Introduced
DEVICE_RESPONSE_TIMEOUT_MS(200 ms) andDATA_READ_TIMEOUT_MS(50 ms) in the I2C device implementation. - Wrapped all
bus.write_read,bus.read, andbus.writecalls inhid-service/src/i2c/device.rswithembassy_time::with_timeout, mapping timeout expiries toError::Hid(hid::Error::Timeout). - Added per-call logging for timeout vs. underlying bus errors for descriptor reads, report descriptor reads, input reports, and command/host-data transfers.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Replace hardcoded timeout constants in both device.rs and host.rs with configurable structs (DeviceTimeoutConfig, HostTimeoutConfig) that are passed in at construction time. Both provide Default impls preserving the original values (200ms for device response, 50ms for data reads). Update call sites in passthrough macros and keyboard-service to pass the default configs.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- rename host/device timeout configs to Config and re-export as HostConfig/DeviceConfig - update passthrough macros and keyboard host task to use new aliases
tullom
left a comment
There was a problem hiding this comment.
Two nb comments, otherwise lgtm!
Change Config struct fields in both host and device modules from raw u64 millisecond values to embassy_time::Duration. This removes the need for Duration::from_millis() conversions at each call site and makes the timeout units explicit in the type system.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (1)
hid-service/src/i2c/host.rs:83
- Both
read_busandwrite_buslog the same "Response timeout" message on timeout, which makes it hard to tell whether the host timed out on a write vs read. Consider using distinct messages (or include operation context) so logs are actionable.
async fn read_bus(&self, timeout: Duration, buffer: &mut [u8]) -> Result<(), Error<B::Error>> {
let mut bus = self.bus.lock().await;
with_timeout(timeout, bus.respond_to_write(buffer))
.await
.map_err(|_| {
error!("Response timeout");
Error::Hid(hid::Error::Timeout)
})?
.map_err(|e| {
error!("Failed to read from bus");
Error::Bus(e)
})
}
async fn write_bus(&self, timeout: Duration, buffer: &[u8]) -> Result<(), Error<B::Error>> {
let mut bus = self.bus.lock().await;
// Send response, timeout if the host doesn't read so we don't get stuck here
trace!("Sending {} bytes", buffer.len());
with_timeout(timeout, bus.respond_to_read(buffer))
.await
.map_err(|_| {
error!("Response timeout");
Error::Hid(hid::Error::Timeout)
})?
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Announced API changes on Zulip: #embedded-controller > hid-service API breaking changes @ 💬 |
This pull request introduces configurable timeout handling for I2C HID device and host operations, replacing hardcoded timeouts with new
Configstructs. This change allows users to customize operation timeouts and improves error handling by reporting specific timeout errors. The update also modifies all usages of the device and host constructors to accept these new configuration parameters, ensuring consistent timeout management throughout the codebase.Timeout configuration and usage improvements:
Configstructs for bothDeviceandHostinhid-service/src/i2c/device.rsandhid-service/src/i2c/host.rs, allowing customization of timeouts for device response and data reads. Default values are provided. [1] [2]DeviceandHostconstructors to accept a timeout configuration parameter, and refactored all internal timeout usages to reference these configuration values instead of hardcoded constants. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15]Error handling enhancements:
Devicenow use thewith_timeoutwrapper, returning a specific timeout error if the operation exceeds the configured duration and logging the error for better traceability. [1] [2] [3] [4]API and macro updates:
hid-service/src/i2c/mod.rsto include the newConfigtypes asDeviceConfigandHostConfig.hid-service/src/i2c/passthrough/mod.rsandkeyboard-service/src/task.rsto use the new constructors and pass default timeout configurations. [1] [2] [3]