Skip to main content

hidpp/feature/
wireless_device_status.rs

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