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}