hidpp/feature/extended_report_rate/
mod.rs1use std::sync::Arc;
4
5use num_enum::{IntoPrimitive, TryFromPrimitive};
6
7use crate::{
8 channel::HidppChannel,
9 feature::{CreatableFeature, Feature, FeatureEndpoint},
10 protocol::v20::Hidpp20Error,
11};
12
13bitflags::bitflags! {
14 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
16 #[cfg_attr(feature = "serde", derive(serde::Serialize))]
17 pub struct ExtendedReportRateList: u16 {
18 const HZ_125 = 1 << 0;
20 const HZ_250 = 1 << 1;
22 const HZ_500 = 1 << 2;
24 const HZ_1000 = 1 << 3;
26 const HZ_2000 = 1 << 4;
28 const HZ_4000 = 1 << 5;
30 const HZ_8000 = 1 << 6;
32 }
33}
34
35#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, IntoPrimitive, TryFromPrimitive)]
37#[cfg_attr(feature = "serde", derive(serde::Serialize))]
38#[non_exhaustive]
39#[repr(u8)]
40pub enum ConnectionType {
41 Wired = 0,
43 GamingWireless = 1,
45}
46
47#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, IntoPrimitive, TryFromPrimitive)]
49#[cfg_attr(feature = "serde", derive(serde::Serialize))]
50#[non_exhaustive]
51#[repr(u8)]
52pub enum ExtendedReportRate {
53 Hz125 = 0,
55 Hz250 = 1,
57 Hz500 = 2,
59 Hz1000 = 3,
61 Hz2000 = 4,
63 Hz4000 = 5,
65 Hz8000 = 6,
67}
68
69#[derive(Clone)]
71pub struct ExtendedReportRateFeature {
72 endpoint: FeatureEndpoint,
74}
75
76impl CreatableFeature for ExtendedReportRateFeature {
77 const ID: u16 = 0x8061;
78 const STARTING_VERSION: u8 = 0;
79
80 fn new(chan: Arc<HidppChannel>, device_index: u8, feature_index: u8) -> Self {
81 Self {
82 endpoint: FeatureEndpoint::new(chan, device_index, feature_index),
83 }
84 }
85}
86
87impl Feature for ExtendedReportRateFeature {}
88
89impl ExtendedReportRateFeature {
90 pub async fn get_device_capabilities(
92 &self,
93 connection_type: ConnectionType,
94 ) -> Result<ExtendedReportRateList, Hidpp20Error> {
95 let payload = self
96 .endpoint
97 .call(0, [u8::from(connection_type), 0, 0])
98 .await?
99 .extend_payload();
100 Ok(report_rate_list_from_payload(payload))
101 }
102
103 pub async fn get_actual_report_rate_list(
105 &self,
106 ) -> Result<ExtendedReportRateList, Hidpp20Error> {
107 let payload = self.endpoint.call(1, [0; 3]).await?.extend_payload();
108 Ok(report_rate_list_from_payload(payload))
109 }
110
111 pub async fn get_report_rate(
113 &self,
114 connection_type: ConnectionType,
115 ) -> Result<ExtendedReportRate, Hidpp20Error> {
116 let payload = self
117 .endpoint
118 .call(2, [u8::from(connection_type), 0, 0])
119 .await?
120 .extend_payload();
121 ExtendedReportRate::try_from(payload[0]).map_err(|_| Hidpp20Error::UnsupportedResponse)
122 }
123
124 pub async fn set_report_rate(
126 &self,
127 report_rate: ExtendedReportRate,
128 ) -> Result<(), Hidpp20Error> {
129 self.endpoint.call(3, [u8::from(report_rate), 0, 0]).await?;
130 Ok(())
131 }
132}
133
134fn report_rate_list_from_payload(payload: [u8; 16]) -> ExtendedReportRateList {
135 ExtendedReportRateList::from_bits_retain(u16::from_be_bytes([payload[0], payload[1]]))
136}
137
138#[cfg(test)]
139mod tests {
140 use super::{ExtendedReportRateList, report_rate_list_from_payload};
141
142 #[test]
143 fn parses_report_rate_mask() {
144 let mut payload = [0; 16];
145 payload[1] = 0b0100_1001;
146
147 let rates = report_rate_list_from_payload(payload);
148
149 assert!(rates.contains(ExtendedReportRateList::HZ_125));
150 assert!(rates.contains(ExtendedReportRateList::HZ_1000));
151 assert!(rates.contains(ExtendedReportRateList::HZ_8000));
152 }
153}