Skip to main content

hidpp/receiver/
mod.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 the [`detect`] function does nothing more than matching
12//! those values to the sets of known vendor and product ID pairs of the
13//! different receivers.
14
15use std::sync::Arc;
16
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    let vpid_pair = &(chan.vendor_id, chan.product_id);
30
31    if bolt::VPID_PAIRS.contains(vpid_pair) {
32        return bolt::Receiver::new(chan).ok().map(Receiver::Bolt);
33    }
34
35    if unifying::VPID_PAIRS.contains(vpid_pair) {
36        return unifying::Receiver::new(chan).ok().map(Receiver::Unifying);
37    }
38    None
39}
40
41/// Represents a HID++ wireless receiver.
42#[derive(Clone)]
43#[non_exhaustive]
44pub enum Receiver {
45    /// Logi Bolt receiver.
46    Bolt(bolt::Receiver),
47    /// Logitech Unifying receiver.
48    Unifying(unifying::Receiver),
49}
50
51impl Receiver {
52    /// Provides a human-readable name for the receiver.
53    pub fn name(&self) -> String {
54        match self {
55            Self::Bolt(_) => "Logi Bolt Receiver",
56            Self::Unifying(_) => "Unifying Receiver",
57        }
58        .to_string()
59    }
60
61    /// Provides a string that uniquely identifies the specific receiver.
62    ///
63    /// This MAY be the serial number, but it may also be any other value that
64    /// is defined as unique.
65    pub async fn get_unique_id(&self) -> Result<String, ReceiverError> {
66        match self {
67            Self::Bolt(bolt) => bolt.get_unique_id().await,
68            Self::Unifying(unifying) => unifying.get_unique_id().await,
69        }
70    }
71}
72
73/// Represents an error returned by a receiver.
74#[derive(Debug, Error)]
75#[non_exhaustive]
76pub enum ReceiverError {
77    /// Indicates that no supported receiver could be identified on a HID++
78    /// channel.
79    #[error("no (supported) receiver could be found")]
80    UnknownReceiver,
81
82    /// Indicates that a HID++1.0 register access resulted in an error.
83    #[error("a HID++1.0 error occurred")]
84    Protocol(#[from] Hidpp10Error),
85}