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
58/// Represents an event emitted by the [`WirelessDeviceStatusFeature`]
59/// feature.
60#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
61#[cfg_attr(feature = "serde", derive(serde::Serialize))]
62#[non_exhaustive]
63pub enum WirelessDeviceStatusEvent {
64    /// Is emitted whenever a device (re)connects to the host.
65    ///
66    /// This event is always enabled.
67    StatusBroadcast(WirelessDeviceStatusBroadcast),
68}
69
70/// Represents the data of the [`WirelessDeviceStatusEvent::StatusBroadcast`]
71/// event.
72#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
73#[cfg_attr(feature = "serde", derive(serde::Serialize))]
74#[non_exhaustive]
75pub struct WirelessDeviceStatusBroadcast {
76    /// The status the device reports to be in.
77    pub status: WirelessDeviceStatus,
78
79    /// The request the devices expresses towards the host.
80    pub request: WirelessDeviceStatusRequest,
81
82    /// The reason for the status broadcast.
83    pub reason: WirelessDeviceStatusReason,
84}
85
86/// Represents a device status as reported in
87/// [`WirelessDeviceStatusBroadcast::status`].
88#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, IntoPrimitive, FromPrimitive)]
89#[cfg_attr(feature = "serde", derive(serde::Serialize))]
90#[non_exhaustive]
91#[repr(u8)]
92pub enum WirelessDeviceStatus {
93    /// Unknown wireless device status.
94    Unknown = 0x00,
95    /// Device is reconnecting.
96    Reconnection = 0x01,
97    /// A status value this crate does not model; carries the raw byte.
98    #[num_enum(catch_all)]
99    Other(u8),
100}
101
102/// Represents a request as reported in
103/// [`WirelessDeviceStatusBroadcast::request`].
104#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, IntoPrimitive, FromPrimitive)]
105#[cfg_attr(feature = "serde", derive(serde::Serialize))]
106#[non_exhaustive]
107#[repr(u8)]
108pub enum WirelessDeviceStatusRequest {
109    /// No host action requested.
110    NoRequest = 0x00,
111    /// Host software must reconfigure the device.
112    SoftwareReconfigurationNeeded = 0x01,
113    /// A request value this crate does not model; carries the raw byte.
114    #[num_enum(catch_all)]
115    Other(u8),
116}
117
118/// Represents a broadcast reason as reported in
119/// [`WirelessDeviceStatusBroadcast::reason`].
120#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, IntoPrimitive, FromPrimitive)]
121#[cfg_attr(feature = "serde", derive(serde::Serialize))]
122#[non_exhaustive]
123#[repr(u8)]
124pub enum WirelessDeviceStatusReason {
125    /// Unknown broadcast reason.
126    Unknown = 0x00,
127    /// Broadcast was caused by the device power switch.
128    PowerSwitchActivated = 0x01,
129    /// A reason value this crate does not model; carries the raw byte.
130    #[num_enum(catch_all)]
131    Other(u8),
132}