1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//! Implements the `WirelessDeviceStatus` feature (ID `0x1d4b`) that notifies
//! the host about device reconnections.
use std::sync::Arc;
use num_enum::{FromPrimitive, IntoPrimitive};
use crate::{
channel::HidppChannel,
feature::{CreatableFeature, DecodeEvent, EmittingFeature, EventSource, Feature},
};
/// Implements the `WirelessDeviceStatus` / `0x1d4b` feature.
pub struct WirelessDeviceStatusFeature {
/// Publishes decoded events to listeners.
events: EventSource<WirelessDeviceStatusEvent>,
}
impl CreatableFeature for WirelessDeviceStatusFeature {
const ID: u16 = 0x1d4b;
const STARTING_VERSION: u8 = 0;
fn new(chan: Arc<HidppChannel>, device_index: u8, feature_index: u8) -> Self {
Self {
events: EventSource::attach(&chan, device_index, feature_index),
}
}
}
impl Feature for WirelessDeviceStatusFeature {}
impl EmittingFeature<WirelessDeviceStatusEvent> for WirelessDeviceStatusFeature {
fn listen(&self) -> async_channel::Receiver<WirelessDeviceStatusEvent> {
self.events.listen()
}
}
impl DecodeEvent for WirelessDeviceStatusEvent {
fn decode(sub_id: u8, payload: &[u8; 16]) -> Option<Self> {
// The reconnection broadcast is the only event and carries sub-id 0.
if sub_id != 0 {
return None;
}
// This broadcast is the device's (re)connection signal; an
// unrecognised field value must not swallow it, so every field
// decodes infallibly and carries unknown raw bytes.
Some(WirelessDeviceStatusEvent::StatusBroadcast(
WirelessDeviceStatusBroadcast {
status: WirelessDeviceStatus::from(payload[0]),
request: WirelessDeviceStatusRequest::from(payload[1]),
reason: WirelessDeviceStatusReason::from(payload[2]),
},
))
}
}
impl WirelessDeviceStatusEvent {
/// Decodes one event payload for this feature, or returns `None` for an
/// unsupported event function.
///
/// Consumers that already own a channel-level listener can use this
/// without constructing a second [`WirelessDeviceStatusFeature`].
#[must_use]
pub fn decode(function_id: u8, payload: &[u8; 16]) -> Option<Self> {
<Self as DecodeEvent>::decode(function_id, payload)
}
}
/// Represents an event emitted by the [`WirelessDeviceStatusFeature`]
/// feature.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
pub enum WirelessDeviceStatusEvent {
/// Is emitted whenever a device (re)connects to the host.
///
/// This event is always enabled.
StatusBroadcast(WirelessDeviceStatusBroadcast),
}
/// Represents the data of the [`WirelessDeviceStatusEvent::StatusBroadcast`]
/// event.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
pub struct WirelessDeviceStatusBroadcast {
/// The status the device reports to be in.
pub status: WirelessDeviceStatus,
/// The request the devices expresses towards the host.
pub request: WirelessDeviceStatusRequest,
/// The reason for the status broadcast.
pub reason: WirelessDeviceStatusReason,
}
/// Represents a device status as reported in
/// [`WirelessDeviceStatusBroadcast::status`].
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, IntoPrimitive, FromPrimitive)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
#[repr(u8)]
pub enum WirelessDeviceStatus {
/// Unknown wireless device status.
Unknown = 0x00,
/// Device is reconnecting.
Reconnection = 0x01,
/// A status value this crate does not model; carries the raw byte.
#[num_enum(catch_all)]
Other(u8),
}
/// Represents a request as reported in
/// [`WirelessDeviceStatusBroadcast::request`].
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, IntoPrimitive, FromPrimitive)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
#[repr(u8)]
pub enum WirelessDeviceStatusRequest {
/// No host action requested.
NoRequest = 0x00,
/// Host software must reconfigure the device.
SoftwareReconfigurationNeeded = 0x01,
/// A request value this crate does not model; carries the raw byte.
#[num_enum(catch_all)]
Other(u8),
}
/// Represents a broadcast reason as reported in
/// [`WirelessDeviceStatusBroadcast::reason`].
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, IntoPrimitive, FromPrimitive)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
#[repr(u8)]
pub enum WirelessDeviceStatusReason {
/// Unknown broadcast reason.
Unknown = 0x00,
/// Broadcast was caused by the device power switch.
PowerSwitchActivated = 0x01,
/// A reason value this crate does not model; carries the raw byte.
#[num_enum(catch_all)]
Other(u8),
}