hardwareusb

Communicating with a USB HID (Human Interface Device) involves understanding the specific protocols and structures used by these devices. Here’s a detailed breakdown of how to communicate with a USB HID device, including the concept of a “report” and the communication flow:

Overview

USB HID devices, such as keyboards, mice, and game controllers, follow a standardized communication protocol defined by the USB Implementers Forum (USB-IF). This protocol is designed to allow easy interaction between the device and the host (e.g., a computer). Here’s how communication generally works:

  1. Enumeration and Initialization:

    • When a USB HID device is connected to the host, the host performs a process called enumeration.
    • During enumeration, the host retrieves the device descriptor, configuration descriptor, and HID descriptor. These descriptors contain information about the device’s capabilities and requirements.
  2. Descriptors:

    • Device Descriptor: Basic information about the device (e.g., vendor ID, product ID).
    • Configuration Descriptor: Information about the device’s power requirements and interfaces.
    • HID Descriptor: Contains details specific to the HID class, including the size and format of reports.
  3. Reports:

    • Reports are the primary data structures used in USB HID communication. Reports are used to transmit data between the device and the host.
    • There are three main types of reports: Input Reports, Output Reports, and Feature Reports.
      • Input Reports: Sent from the device to the host to convey information such as keystrokes or mouse movements.
      • Output Reports: Sent from the host to the device to control its behavior, such as turning on an LED.
      • Feature Reports: Can be sent in both directions to retrieve or set the state of the device.

Request and Response Flow

The communication flow for USB HID devices does have similarities to TCP or HTTP in terms of request and response, but it is simpler and more hardware-focused. Here’s a high-level overview of the flow:

  1. Control Transfers:

    • Used for configuration and setup, typically during enumeration.
    • The host sends standard or class-specific control requests to get descriptors or set configuration.
  2. Interrupt Transfers:

    • Used for regular, low-latency data exchange (e.g., key presses from a keyboard).
    • The device periodically sends input reports to the host.
    • The host can send output reports to the device as needed.
  3. Data Flow:

    • The host initiates communication by sending requests (control or interrupt transfers).
    • The device responds with data or acknowledges the receipt of data.
    • Input reports are typically sent from the device to the host without explicit requests (polling mechanism).
    • Output and feature reports are sent by the host to control or query the device.

Example of Report Structure

A report is a structured packet of data defined by the HID Report Descriptor, which outlines the format and meaning of the data within the report. Here’s an example structure for a simple HID report:

  • Report ID (1 byte): Identifier for the report (if multiple reports are used).
  • Data Bytes: The actual data being transmitted, which can vary in length.

For instance, a mouse might have a report structure like:

  • Report ID: 1
  • Buttons: 1 byte (bitmask for button states)
  • X Movement: 1 byte (signed integer for X-axis movement)
  • Y Movement: 1 byte (signed integer for Y-axis movement)

Practical Communication Example

To communicate with a USB HID device programmatically, you can use libraries available in various programming languages. For example, in Python, you can use the hid library:

import hid
 
# Open the device
device = hid.device()
device.open(vendor_id, product_id)
 
# Set non-blocking mode
device.set_nonblocking(1)
 
# Read input report (example with a report of 64 bytes)
report = device.read(64)
print(report)
 
# Write output report (example with a report of 64 bytes)
report_id = 0x01
data = [report_id] + [0x00] * 63
device.write(data)
 
# Close the device
device.close()

Summary

  • Reports are the primary data structures used in USB HID communication, which include input, output, and feature reports.
  • The communication flow involves control transfers for setup and interrupt transfers for regular data exchange.
  • Reports are structured packets of data defined by the HID Report Descriptor.
  • Libraries such as hid in Python can be used to interact programmatically with USB HID devices.

Transfers

In USB HID communication, reports are primarily used in interrupt transfers. Control transfers are used for specific setup and configuration tasks rather than regular data communication. Here’s a breakdown of how reports and transfers are used in the context of USB HID devices:

Interrupt Transfers

Interrupt transfers are the main method for regular data exchange between the host and the HID device. This is where reports come into play.

  • Input Reports: Sent by the device to the host. For example, a keyboard sends keystroke data, or a mouse sends movement and button state data.
  • Output Reports: Sent by the host to the device. For instance, the host can send a command to change the state of an LED on a keyboard.
  • Feature Reports: Can be sent in either direction to retrieve or set specific device state information. They are less common than input and output reports but still use interrupt transfers when applicable.

Control Transfers

Control transfers are used for initial configuration and occasional specific commands. These are essential during the enumeration process when the host queries the device for its descriptors and sets it up for operation. Control transfers can also be used to send and receive feature reports.

  • Get_Report Request: The host can request an input, output, or feature report from the device. This is done using a control transfer.
  • Set_Report Request: The host can send an output or feature report to the device using a control transfer.

Practical Examples

Input Reports (Interrupt Transfers)

A keyboard sending keystroke data to the host is a typical example of an input report using an interrupt transfer. The device sends this data at regular intervals or when there’s new data to report.

Output Reports (Interrupt Transfers)

An example of an output report using an interrupt transfer is when the host sends a command to turn on an LED on the keyboard.

Feature Reports (Interrupt and Control Transfers)

Feature reports are often used to set or query the state of the device. For example, configuring the sensitivity of a gaming mouse might involve feature reports. These can be transmitted using control transfers if needed.

Summary

  • Interrupt Transfers: Primarily used for regular data exchange using input, output, and feature reports.
  • Control Transfers: Used for setup, configuration, and less frequent commands, including sending and receiving feature reports.

To programmatically interact with these transfers, libraries like hidapi in Python can be used. Here’s an example to illustrate:

import hid
 
# Open the device
device = hid.device()
device.open(vendor_id, product_id)
 
# Set non-blocking mode
device.set_nonblocking(1)
 
# Read an input report (example with a report of 64 bytes)
input_report = device.read(64)
print("Input Report:", input_report)
 
# Write an output report (example with a report of 64 bytes)
output_report_id = 0x01
output_data = [output_report_id] + [0x00] * 63
device.write(output_data)
 
# Send a feature report using control transfer
feature_report_id = 0x02
feature_data = [feature_report_id] + [0x00] * 63
device.send_feature_report(feature_data)
 
# Retrieve a feature report using control transfer
feature_report = device.get_feature_report(feature_report_id, 64)
print("Feature Report:", feature_report)
 
# Close the device
device.close()

This code demonstrates how to read and write different types of reports using both interrupt and control transfers, providing a practical approach to USB HID communication.

The Web HID API allows web applications to interact with Human Interface Devices (HIDs) directly from the browser. This API provides a way to send and receive HID reports, enabling control and data exchange with devices like keyboards, mice, game controllers, and custom HID devices. Below is a guide on how to send input and output reports using the Web HID API.

Web HID API

Using the API

  1. Request Access to HID Device:

    • First, you need to request access to the HID device from the user.
  2. Open the Device:

    • Once access is granted, you need to open the device for communication.
  3. Send Output Reports:

    • Use the sendReport() method to send output reports to the device.
  4. Receive Input Reports:

    • Set up an event listener for input reports using the oninputreport event.

Example Code

Here is an example demonstrating how to send and receive reports using the Web HID API:

// Request access to HID devices
async function requestDevice() {
  const devices = await navigator.hid.requestDevice({
    filters: [{ vendorId: 0x1234 }] // Replace with your device's vendor ID
  });
 
  if (devices.length > 0) {
    return devices[0];
  } else {
    throw new Error("No HID devices selected.");
  }
}
 
// Open the device and start communication
async function openDevice(device) {
  await device.open();
 
  // Listen for input reports
  device.oninputreport = event => {
    const { data, device, reportId } = event;
    console.log(`Received input report ${reportId}: ${data}`);
  };
}
 
// Send an output report to the device
async function sendOutputReport(device, reportId, data) {
  await device.sendReport(reportId, data);
}
 
// Main function to handle the device communication
async function main() {
  try {
    const device = await requestDevice();
    await openDevice(device);
 
    // Example data to send as output report
    const reportId = 0x01;
    const data = new Uint8Array([0x01, 0x00, 0x00, 0x00]); // Example data
 
    // Send output report
    await sendOutputReport(device, reportId, data);
    console.log(`Sent output report ${reportId}: ${data}`);
  } catch (error) {
    console.error('Error:', error);
  }
}
 
// Run the main function
main();

Explanation

  1. Request Device:

    • The navigator.hid.requestDevice() function prompts the user to select a HID device. The filters parameter allows you to specify criteria for the devices you want to access, such as vendorId.
  2. Open Device:

    • Once a device is selected, the open() method is called to open the device for communication.
    • An event listener is set up for oninputreport to handle incoming input reports from the device. When an input report is received, the event handler logs the report data.
  3. Send Output Report:

    • The sendReport() method sends an output report to the device. It takes the reportId and the data to send (as a Uint8Array).
  4. Main Function:

    • This function orchestrates the process by requesting the device, opening it, and sending an output report with example data.

Notes

  • The navigator.hid API requires a secure context (HTTPS).
  • The vendorId and reportId should be replaced with those specific to your HID device.
  • The data format in the Uint8Array should match the expected report format of your HID device.
  • Make sure the browser supports the Web HID API. As of my knowledge cutoff in June 2023, Chrome and Edge have support for the Web HID API.

Using this example, you can modify the code to fit your specific HID device and the reports you need to send or receive.