Skip to main content

hidpp/feature/
mode_status.rs

1//! Implements `ModeStatus` (feature `0x8090`).
2
3use openlogi_hidpp_derive::Feature;
4
5use crate::{feature::FeatureEndpoint, protocol::v20::Hidpp20Error};
6
7bitflags::bitflags! {
8    /// The first mode-status byte.
9    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
10    #[cfg_attr(feature = "serde", derive(serde::Serialize))]
11    pub struct ModeStatus0: u8 {
12        /// Performance mode. When unset, the device is in endurance mode.
13        const PERFORMANCE = 1 << 0;
14    }
15}
16
17bitflags::bitflags! {
18    /// Capabilities reported by `ModeStatus`.
19    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
20    #[cfg_attr(feature = "serde", derive(serde::Serialize))]
21    pub struct ModeStatusCapabilities: u16 {
22        /// A hardware switch can change the mode bit.
23        const HARDWARE_SWITCH = 1 << 0;
24        /// Software can change the mode bit.
25        const SOFTWARE_SWITCH = 1 << 1;
26    }
27}
28
29/// Current mode-status bytes.
30#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
31#[cfg_attr(feature = "serde", derive(serde::Serialize))]
32#[non_exhaustive]
33pub struct ModeStatus {
34    /// Primary status bits.
35    pub status0: ModeStatus0,
36    /// Secondary status byte, reserved by v1 but preserved for callers.
37    pub status1: u8,
38}
39
40/// A mode-status update request.
41#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
42#[cfg_attr(feature = "serde", derive(serde::Serialize))]
43pub struct ModeStatusChange {
44    /// Desired primary status bits.
45    pub status0: ModeStatus0,
46    /// Desired secondary status byte.
47    pub status1: u8,
48    /// Primary changed-bit mask.
49    pub changed_mask0: ModeStatus0,
50    /// Secondary changed-bit mask.
51    pub changed_mask1: u8,
52}
53
54/// Implements the `ModeStatus` / `0x8090` feature.
55#[derive(Clone, Feature)]
56#[creatable(id = 0x8090, version = 1)]
57pub struct ModeStatusFeature {
58    /// The endpoint this feature talks to.
59    endpoint: FeatureEndpoint,
60}
61
62impl ModeStatusFeature {
63    /// Retrieves the current mode status.
64    pub async fn get_mode_status(&self) -> Result<ModeStatus, Hidpp20Error> {
65        let payload = self.endpoint.call(0, [0; 3]).await?.extend_payload();
66        Ok(ModeStatus {
67            status0: ModeStatus0::from_bits_retain(payload[0]),
68            status1: payload[1],
69        })
70    }
71
72    /// Sets selected mode-status bits.
73    pub async fn set_mode_status(&self, change: ModeStatusChange) -> Result<(), Hidpp20Error> {
74        let mut args = [0; 16];
75        args[0] = change.status0.bits();
76        args[1] = change.status1;
77        args[2] = change.changed_mask0.bits();
78        args[3] = change.changed_mask1;
79
80        self.endpoint.call_long(1, args).await?;
81        Ok(())
82    }
83
84    /// Enables or disables performance mode.
85    pub async fn set_performance_mode(&self, enabled: bool) -> Result<(), Hidpp20Error> {
86        let status0 = if enabled {
87            ModeStatus0::PERFORMANCE
88        } else {
89            ModeStatus0::empty()
90        };
91        self.set_mode_status(ModeStatusChange {
92            status0,
93            status1: 0,
94            changed_mask0: ModeStatus0::PERFORMANCE,
95            changed_mask1: 0,
96        })
97        .await
98    }
99
100    /// Retrieves device capabilities for mode switching.
101    pub async fn get_device_config(&self) -> Result<ModeStatusCapabilities, Hidpp20Error> {
102        let payload = self.endpoint.call(2, [0; 3]).await?.extend_payload();
103        Ok(ModeStatusCapabilities::from_bits_retain(
104            u16::from_be_bytes([payload[0], payload[1]]),
105        ))
106    }
107}