1use std::sync::Arc;
12
13use num_enum::{IntoPrimitive, TryFromPrimitive};
14
15use crate::{
16 channel::HidppChannel,
17 event::EventEmitter,
18 protocol::v10::{self, Hidpp10Error},
19 receiver::{ListenerDropGuard, RECEIVER_DEVICE_INDEX, ReceiverError},
20};
21
22pub const VPID_PAIRS: &[(u16, u16)] = &[(0x046d, 0xc52b), (0x046d, 0xc532)];
25
26#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, IntoPrimitive, TryFromPrimitive)]
28#[cfg_attr(feature = "serde", derive(serde::Serialize))]
29#[non_exhaustive]
30#[repr(u8)]
31pub enum Register {
32 Connections = 0x02,
35
36 ReceiverInfo = 0xb5,
40}
41
42#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, IntoPrimitive, TryFromPrimitive)]
45#[cfg_attr(feature = "serde", derive(serde::Serialize))]
46#[non_exhaustive]
47#[repr(u8)]
48pub enum InfoSubRegister {
49 ReceiverInfo = 0x03,
52
53 DevicePairingInformation = 0x50,
57
58 DeviceCodename = 0x60,
61}
62
63#[derive(Clone)]
65pub struct Receiver {
66 chan: Arc<HidppChannel>,
67 emitter: Arc<EventEmitter<Event>>,
68 _listener: Arc<ListenerDropGuard>,
69}
70
71impl Receiver {
72 pub fn new(chan: Arc<HidppChannel>) -> Result<Self, ReceiverError> {
77 if !VPID_PAIRS.contains(&(chan.vendor_id, chan.product_id)) {
78 return Err(ReceiverError::UnknownReceiver);
79 }
80
81 let emitter = Arc::new(EventEmitter::new());
82
83 let hdl = chan.add_msg_listener({
84 let emitter = Arc::clone(&emitter);
85 move |raw, matched| {
86 if matched {
87 return;
88 }
89
90 let parsed = v10::Message::from(raw);
91 let header = parsed.header();
92 let payload = parsed.extend_payload();
93
94 if header.sub_id != 0x41 {
97 return;
98 }
99
100 let Ok(kind) = DeviceKind::try_from(payload[1] & 0x0f) else {
101 return;
102 };
103
104 emitter.emit(Event::DeviceConnection(DeviceConnection {
105 index: header.device_index,
106 kind,
107 encrypted: payload[1] & (1 << 4) != 0,
108 online: payload[1] & (1 << 6) == 0,
109 wpid: u16::from_le_bytes(payload[2..=3].try_into().unwrap()),
110 }));
111 }
112 });
113
114 Ok(Receiver {
115 _listener: Arc::new(ListenerDropGuard {
116 chan: Arc::clone(&chan),
117 hdl,
118 }),
119 chan,
120 emitter,
121 })
122 }
123
124 pub fn listen(&self) -> async_channel::Receiver<Event> {
126 self.emitter.create_receiver()
127 }
128
129 pub async fn count_pairings(&self) -> Result<u8, ReceiverError> {
132 let response = self
133 .chan
134 .read_register(
135 RECEIVER_DEVICE_INDEX,
136 Register::Connections.into(),
137 [0u8; 3],
138 )
139 .await?;
140
141 Ok(response[1])
142 }
143
144 pub async fn trigger_device_arrival(&self) -> Result<(), ReceiverError> {
147 self.chan
148 .write_register(
149 RECEIVER_DEVICE_INDEX,
150 Register::Connections.into(),
151 [0x02, 0x00, 0x00],
152 )
153 .await?;
154
155 Ok(())
156 }
157
158 pub async fn get_receiver_info(&self) -> Result<ReceiverInfo, ReceiverError> {
161 let response = self
162 .chan
163 .read_long_register(
164 RECEIVER_DEVICE_INDEX,
165 Register::ReceiverInfo.into(),
166 [InfoSubRegister::ReceiverInfo.into(), 0, 0],
167 )
168 .await?;
169
170 Ok(ReceiverInfo {
171 serial_number: hex::encode_upper(&response[1..=4]),
172 pairing_slots: response[6],
173 })
174 }
175
176 pub async fn get_device_pairing_information(
179 &self,
180 device_index: u8,
181 ) -> Result<DevicePairingInformation, ReceiverError> {
182 let response = self
183 .chan
184 .read_long_register(
185 RECEIVER_DEVICE_INDEX,
186 Register::ReceiverInfo.into(),
187 [
188 u8::from(InfoSubRegister::DevicePairingInformation) | (device_index & 0x0f),
189 0x00,
190 0x00,
191 ],
192 )
193 .await?;
194
195 Ok(DevicePairingInformation {
196 wpid: u16::from_le_bytes(response[2..=3].try_into().unwrap()),
197 kind: DeviceKind::try_from(response[1] & 0x0f)
198 .map_err(|_| Hidpp10Error::UnsupportedResponse)?,
199 encrypted: response[1] & (1 << 4) != 0,
200 online: response[1] & (1 << 6) == 0,
201 unit_id: response[4..=7].try_into().unwrap(),
202 })
203 }
204
205 pub async fn get_unique_id(&self) -> Result<String, ReceiverError> {
207 self.get_receiver_info().await.map(|i| i.serial_number)
208 }
209}
210
211#[derive(Clone, PartialEq, Eq, Hash, Debug)]
213#[cfg_attr(feature = "serde", derive(serde::Serialize))]
214#[non_exhaustive]
215pub struct ReceiverInfo {
216 pub serial_number: String,
217 pub pairing_slots: u8,
218}
219
220#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
223#[cfg_attr(feature = "serde", derive(serde::Serialize))]
224#[non_exhaustive]
225pub struct DevicePairingInformation {
226 pub wpid: u16,
227 pub kind: DeviceKind,
228 pub encrypted: bool,
229 pub online: bool,
230 pub unit_id: [u8; 4],
231}
232
233#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, IntoPrimitive, TryFromPrimitive)]
239#[cfg_attr(feature = "serde", derive(serde::Serialize))]
240#[non_exhaustive]
241#[repr(u8)]
242pub enum DeviceKind {
243 Unknown = 0x00,
244 Keyboard = 0x01,
245 Mouse = 0x02,
246 Numpad = 0x03,
247 Presenter = 0x04,
248 Remote = 0x05,
249 Trackball = 0x06,
250 Touchpad = 0x07,
251}
252
253#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
256#[cfg_attr(feature = "serde", derive(serde::Serialize))]
257#[non_exhaustive]
258pub struct DeviceConnection {
259 pub index: u8,
261 pub kind: DeviceKind,
262 pub encrypted: bool,
263 pub online: bool,
264 pub wpid: u16,
266}
267
268#[derive(Clone, PartialEq, Eq, Hash, Debug)]
270#[cfg_attr(feature = "serde", derive(serde::Serialize))]
271#[non_exhaustive]
272pub enum Event {
273 DeviceConnection(DeviceConnection),
276}