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 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 #[must_use]
54 pub fn name(&self) -> String {
55 match self {
56 Self::Bolt(_) => "Logi Bolt Receiver",
57 Self::Unifying(_) => "Unifying Receiver",
58 }
59 .to_string()
60 }
61
62 /// Provides a string that uniquely identifies the specific receiver.
63 ///
64 /// This MAY be the serial number, but it may also be any other value that
65 /// is defined as unique.
66 pub async fn get_unique_id(&self) -> Result<String, ReceiverError> {
67 match self {
68 Self::Bolt(bolt) => bolt.get_unique_id().await,
69 Self::Unifying(unifying) => unifying.get_unique_id().await,
70 }
71 }
72}
73
74/// Represents an error returned by a receiver.
75#[derive(Debug, Error)]
76#[non_exhaustive]
77pub enum ReceiverError {
78 /// Indicates that no supported receiver could be identified on a HID++
79 /// channel.
80 #[error("no (supported) receiver could be found")]
81 UnknownReceiver,
82
83 /// Indicates that a HID++1.0 register access resulted in an error.
84 #[error("a HID++1.0 error occurred")]
85 Protocol(#[from] Hidpp10Error),
86}