Skip to main content

hidpp/
receiver.rs

1//! Implements the different HID++ wireless receivers.
2//!
3//! Because of the lack of public documentation about the different receivers
4//! and their capabilities, and because I currently only own a single Bolt
5//! receiver, this module is largely incomplete. I would be more than happy for
6//! anyone who owns a different receiver, with Unifying having the highest
7//! priority, and who is willing to actively support its implementation by
8//! providing information and testing.
9//!
10//! Receivers can generally only be differentiated by their USB vendor and
11//! product IDs, so [`detect`] dispatches through the shared
12//! `openlogi-device-registry`.
13
14use std::sync::Arc;
15
16use openlogi_device_registry::receiver::{ReceiverProtocol, find_receiver};
17use thiserror::Error;
18
19use crate::{channel::HidppChannel, protocol::v10::Hidpp10Error};
20
21pub mod bolt;
22pub mod unifying;
23
24/// The index to use when communicating with the receiver on any HID++ channel.
25pub const RECEIVER_DEVICE_INDEX: u8 = 0xff;
26
27/// Tries to detect the receiver present on a HID++ channel.
28pub fn detect(chan: Arc<HidppChannel>) -> Option<Receiver> {
29    match find_receiver(chan.vendor_id, chan.product_id)?.protocol {
30        ReceiverProtocol::Bolt => bolt::Receiver::new(chan).ok().map(Receiver::Bolt),
31        ReceiverProtocol::Unifying => unifying::Receiver::new(chan).ok().map(Receiver::Unifying),
32    }
33}
34
35/// Represents a HID++ wireless receiver.
36#[derive(Clone)]
37#[non_exhaustive]
38pub enum Receiver {
39    /// Logi Bolt receiver.
40    Bolt(bolt::Receiver),
41    /// Logitech Unifying receiver.
42    Unifying(unifying::Receiver),
43}
44
45impl Receiver {
46    /// Provides a human-readable name for the receiver.
47    #[must_use]
48    pub fn name(&self) -> String {
49        match self {
50            Self::Bolt(_) => "Logi Bolt Receiver",
51            Self::Unifying(_) => "Unifying Receiver",
52        }
53        .to_string()
54    }
55
56    /// Provides a string that uniquely identifies the specific receiver.
57    ///
58    /// This MAY be the serial number, but it may also be any other value that
59    /// is defined as unique.
60    pub async fn get_unique_id(&self) -> Result<String, ReceiverError> {
61        match self {
62            Self::Bolt(bolt) => bolt.get_unique_id().await,
63            Self::Unifying(unifying) => unifying.get_unique_id().await,
64        }
65    }
66}
67
68/// Represents an error returned by a receiver.
69#[derive(Debug, Error)]
70#[non_exhaustive]
71pub enum ReceiverError {
72    /// Indicates that no supported receiver could be identified on a HID++
73    /// channel.
74    #[error("no (supported) receiver could be found")]
75    UnknownReceiver,
76
77    /// Indicates that a HID++1.0 register access resulted in an error.
78    #[error("a HID++1.0 error occurred")]
79    Protocol(#[from] Hidpp10Error),
80}