Skip to main content

hidpp/receiver/
unifying.rs

1//! Implements the Unifying Receiver.
2//!
3//! Unifying is a very versatile receiver that can pair up to 6 supported
4//! devices.
5
6use std::sync::Arc;
7
8use num_enum::{IntoPrimitive, TryFromPrimitive};
9
10use crate::{
11    channel::HidppChannel,
12    receiver::{RECEIVER_DEVICE_INDEX, ReceiverError},
13};
14
15/// All USB vendor & product ID pairs that are known to identify Unifying
16/// receivers.
17pub const VPID_PAIRS: &[(u16, u16)] = &[(0x046d, 0xc52b), (0x046d, 0xc532)];
18
19/// All known registers of the Unifying receiver.
20///
21/// In most cases you should not need to access these manually, as [`Receiver`]
22/// implements many features.
23#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, IntoPrimitive, TryFromPrimitive)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize))]
25#[non_exhaustive]
26#[repr(u8)]
27pub enum Register {
28    /// Provides information about the receiver and paired devices. It uses
29    /// sub-registers, as defined in [`UnifyingInfoSubRegister`], to
30    /// differentiate between different kinds of information.
31    ReceiverInfo = 0xb5,
32}
33
34/// Represents the known sub-registers of the [`UnifyingRegister::ReceiverInfo`]
35/// register.
36#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, IntoPrimitive, TryFromPrimitive)]
37#[cfg_attr(feature = "serde", derive(serde::Serialize))]
38#[non_exhaustive]
39#[repr(u8)]
40pub enum InfoSubRegister {
41    /// Provides general information about the receiver.
42    ReceiverInfo = 0x03,
43}
44
45/// Implements the Unifying wireless receiver.
46#[derive(Clone)]
47pub struct Receiver {
48    /// The underlying HID++ channel.
49    chan: Arc<HidppChannel>,
50}
51
52impl Receiver {
53    /// Tries to initialize a new [`UnifyingReceiver`] from a raw HID++ channel.
54    ///
55    /// If no receiver could be found, or if the vendor and product IDs don't
56    /// match the ones of any known Unifying receiver, this function will return
57    /// [`ReceiverError::UnknownReceiver`].
58    pub fn new(chan: Arc<HidppChannel>) -> Result<Self, ReceiverError> {
59        if !VPID_PAIRS.contains(&(chan.vendor_id, chan.product_id)) {
60            return Err(ReceiverError::UnknownReceiver);
61        }
62
63        Ok(Receiver { chan })
64    }
65
66    /// Provides general information about the receiver.
67    pub async fn get_receiver_info(&self) -> Result<ReceiverInfo, ReceiverError> {
68        let response = self
69            .chan
70            .read_long_register(
71                RECEIVER_DEVICE_INDEX,
72                Register::ReceiverInfo.into(),
73                [InfoSubRegister::ReceiverInfo.into(), 0, 0],
74            )
75            .await?;
76
77        Ok(ReceiverInfo {
78            serial_number: hex::encode_upper(&response[1..=4]),
79            pairing_slots: response[6],
80        })
81    }
82}
83
84/// Represents some general information about a Unifying receiver.
85#[derive(Clone, PartialEq, Eq, Hash, Debug)]
86#[cfg_attr(feature = "serde", derive(serde::Serialize))]
87#[non_exhaustive]
88pub struct ReceiverInfo {
89    pub serial_number: String,
90    pub pairing_slots: u8,
91}