pub struct HidInterface<'a, B: UsbBus, const KBD_SIZE: usize, const KBD_LED_SIZE: usize, const MOUSE_SIZE: usize, const CTRL_SIZE: usize> { /* private fields */ }
Expand description

USB HID Combination Interface

Handles creation and management of multiple USB HID interfaces through SPSC queues. Maintains state for you so you only need to send state changes and poll events.

Typical Usage

  • Queue up changes using SPSC queues
  • Call push to send the current states of all the queues (queues are not processed until push() is called)

HID-IO

  • Queue up changes, or receive changes using hidio_rx and hidio_tx spsc queues
  • Call poll to process queues in both directions (or push, which will call poll for you) Will attempt to push and pull as many packets as possible in case the USB device supports larger buffers (e.g. double buffering)

Example Usage (atsam4s)

use heapless::spsc::Queue;
use usbd_hid::hid_class::{HidCountryCode, HidProtocolMode, ProtocolModeConfig};

// These define the maximum pending items in each queue
const KBD_QUEUE_SIZE: usize = 10; // This would limit NKRO mode to 10KRO
const KBD_LED_QUEUE_SIZE: usize = 3;
const MOUSE_QUEUE_SIZE: usize = 5;
const CTRL_QUEUE_SIZE: usize = 2;

type HidInterface =
    kiibohd_usb::HidInterface<'static, UdpBus, KBD_QUEUE_SIZE, MOUSE_QUEUE_SIZE, CTRL_QUEUE_SIZE>;

pub struct HidioInterface<const H: usize> {}

impl<const H: usize> HidioInterface<H> {
    fn new() -> Self {
        Self {}
    }
}

impl<const H: usize> KiibohdCommandInterface<H> for HidioInterface<H> {
    fn h0001_device_name(&self) -> Option<&str> {
        Some("Input Club Keystone - TKL")
    }

    fn h0001_firmware_name(&self) -> Option<&str> {
        Some("kiibohd-firmware")
    }
}

// Setup the queues used to generate the input reports (ctrl, keyboard and mouse)
let ctrl_queue: Queue<kiibohd_usb::CtrlState, CTRL_QUEUE_SIZE> = Queue::new();
let kbd_queue: Queue<kiibohd_usb::KeyState, KBD_QUEUE_SIZE> = Queue::new();
let kbd_led_queue: Queue<kiibohd_usb::LedState, KBD_LED_QUEUE_SIZE> = Queue::new();
let mouse_queue: Queue<kiibohd_usb::MouseState, MOUSE_QUEUE_SIZE> = Queue::new();
let (kbd_producer, kbd_consumer) = kbd_queue.split();
let (mouse_producer, mouse_consumer) = mouse_queue.split();
let (ctrl_producer, ctrl_consumer) = ctrl_queue.split();

// Setup the interface
// NOTE: Ignoring usb_bus setup in this example, use a compliant usb-device UsbBus interface
let usb_hid = HidInterface::new(
    usb_bus,
    HidCountryCode::NotSupported,
    kbd_consumer,
    kbd_led_producer,
    mouse_consumer,
    ctrl_consumer,
);

// Basic CommandInterface
let hidio_intf = CommandInterface::<
    HidioInterface<MESSAGE_LEN>,
    TX_BUF,
    RX_BUF,
    BUF_CHUNK,
    MESSAGE_LEN,
    SERIALIZATION_LEN,
    ID_LEN,
>::new(
    &[
        HidIoCommandId::SupportedIds,
        HidIoCommandId::GetInfo,
        HidIoCommandId::TestPacket,
    ],
    HidioInterface::<MESSAGE_LEN>::new(),
)
.unwrap();

// To push keyboard key report, first push to the queue, then process all queues
kbd_producer.enqueue(kiibohd_usb::KeyState::Press(0x04)); // Press the A key
usb_hid.push();
// To retrieve lock leds (and enqueue events)
usb_hid.pull();

// In the USB interrupt (or similar), usb_hid will also need to be handled (Ctrl EP requests)
fn usb_irq() {
    let usb_dev = some_global_mechanism.usb_dev;
    let usb_hid = some_global_mechanism.usb_hid;
    let hidio_intf = some_global_mechanism.hidio_intf;
    if usb_dev.poll(&mut usb_hid.interfaces()) {
        // poll is only available with the hidio feature
        usb_hid.poll(hidio_intf);
    }
}

Implementations§

source§

impl<B: UsbBus, const KBD_SIZE: usize, const KBD_LED_SIZE: usize, const MOUSE_SIZE: usize, const CTRL_SIZE: usize> HidInterface<'_, B, KBD_SIZE, KBD_LED_SIZE, MOUSE_SIZE, CTRL_SIZE>

source

pub fn new<'a>( alloc: &'a UsbBusAllocator<B>, locale: HidCountryCode, kbd_consumer: Consumer<'a, KeyState, KBD_SIZE>, kbd_led_producer: Producer<'a, LedState, KBD_LED_SIZE>, mouse_consumer: Consumer<'a, MouseState, MOUSE_SIZE>, ctrl_consumer: Consumer<'a, CtrlState, CTRL_SIZE> ) -> HidInterface<'a, B, KBD_SIZE, KBD_LED_SIZE, MOUSE_SIZE, CTRL_SIZE>

source

pub fn set_kbd_protocol_mode( &mut self, mode: HidProtocolMode, config: ProtocolModeConfig )

Dynamically update the keyboard protocol mode (and behavior) Used to force NKRO or 6KRO regardless of what the host configures

source

pub fn get_kbd_protocol_mode(&self) -> HidProtocolMode

Retrieves the current protocol mode Uses the 6kro keyboard (both HID Classes should return the same value)

source

pub fn interfaces(&mut self) -> [&mut dyn UsbClass<B>; 5]

Used to pass all of the interfaces to usb_dev.poll()

source

pub fn update(&mut self) -> bool

Update buffers to be ready to push over USB This is useful for remote wakeup where we only want to send a remote wakeup if an event has occurred. But before sending the data to the USB buffer registers.

Returns true if any descriptor was updated

source

pub fn push(&mut self) -> Result<(), UsbError>

Processes each of the spsc queues and pushes data over USB This is primarily for keyboard, mouse and ctrl interfaces. HID-IO is handled with poll()

This function automatically handles USB Resume if required.

NOTE: You must call update() first before calling push().

Returns possibly returns UsbError::WouldBlock in which case the USB buffer is full and you should call push before queuing up more keypresses. Normally it’s safe to add more events; however, it’s possible you may lose an event (very slim chance).

source

pub fn pull(&mut self)

Query HID lock LED state The state used depends on which protocol mode is selected (there are different lock LEDs for the 6KRO/Boot and NKRO keyboard descriptors.

source

pub fn pull_hidio<KINTF: KiibohdCommandInterface<H>, const TX: usize, const RX: usize, const N: usize, const H: usize, const S: usize, const ID: usize>( &mut self, interface: &mut CommandInterface<KINTF, TX, RX, N, H, S, ID> )

Pull the HID-IO interface (RX)

source

pub fn push_hidio<KINTF: KiibohdCommandInterface<H>, const TX: usize, const RX: usize, const N: usize, const H: usize, const S: usize, const ID: usize>( &mut self, interface: &mut CommandInterface<KINTF, TX, RX, N, H, S, ID> )

Push the HID-IO interface (TX)

Auto Trait Implementations§

§

impl<'a, B, const KBD_SIZE: usize, const KBD_LED_SIZE: usize, const MOUSE_SIZE: usize, const CTRL_SIZE: usize> !RefUnwindSafe for HidInterface<'a, B, KBD_SIZE, KBD_LED_SIZE, MOUSE_SIZE, CTRL_SIZE>

§

impl<'a, B, const KBD_SIZE: usize, const KBD_LED_SIZE: usize, const MOUSE_SIZE: usize, const CTRL_SIZE: usize> Send for HidInterface<'a, B, KBD_SIZE, KBD_LED_SIZE, MOUSE_SIZE, CTRL_SIZE>

§

impl<'a, B, const KBD_SIZE: usize, const KBD_LED_SIZE: usize, const MOUSE_SIZE: usize, const CTRL_SIZE: usize> !Sync for HidInterface<'a, B, KBD_SIZE, KBD_LED_SIZE, MOUSE_SIZE, CTRL_SIZE>

§

impl<'a, B, const KBD_SIZE: usize, const KBD_LED_SIZE: usize, const MOUSE_SIZE: usize, const CTRL_SIZE: usize> Unpin for HidInterface<'a, B, KBD_SIZE, KBD_LED_SIZE, MOUSE_SIZE, CTRL_SIZE>

§

impl<'a, B, const KBD_SIZE: usize, const KBD_LED_SIZE: usize, const MOUSE_SIZE: usize, const CTRL_SIZE: usize> !UnwindSafe for HidInterface<'a, B, KBD_SIZE, KBD_LED_SIZE, MOUSE_SIZE, CTRL_SIZE>

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for Twhere U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.