hidpp/feature/feature_set/mod.rs
1//! Implements the `FeatureSet` feature (ID `0x0001`) that allows enumerating
2//! all the features supported by a device.
3
4use std::sync::Arc;
5
6use crate::{
7 channel::HidppChannel,
8 feature::{CreatableFeature, Feature, FeatureType},
9 nibble::U4,
10 protocol::v20::{self, Hidpp20Error},
11};
12
13/// Implements the `FeatureSet` / `0x0001` feature.
14///
15/// This feature is primarily used to collect all features supported by the
16/// device. To achieve this, call [`Self::count`] to retrieve the amount of
17/// supported features (excluding the root feature). Then call
18/// [`Self::get_feature`] for every `i in 1..=count` (1-based, as accessing the
19/// root feature is not allowed).
20#[derive(Clone)]
21pub struct FeatureSetFeature {
22 /// The underlying HID++ channel.
23 chan: Arc<HidppChannel>,
24
25 /// The index of the device to implement the feature for.
26 device_index: u8,
27
28 /// The index of the feature in the feature table.
29 feature_index: u8,
30}
31
32impl CreatableFeature for FeatureSetFeature {
33 const ID: u16 = 0x0001;
34 const STARTING_VERSION: u8 = 0;
35
36 fn new(chan: Arc<HidppChannel>, device_index: u8, feature_index: u8) -> Self {
37 Self {
38 chan,
39 device_index,
40 feature_index,
41 }
42 }
43}
44
45impl Feature for FeatureSetFeature {}
46
47impl FeatureSetFeature {
48 /// Retrieves the amount of features supported by the device, not including
49 /// the root feature.
50 pub async fn count(&self) -> Result<u8, Hidpp20Error> {
51 let response = self
52 .chan
53 .send_v20(v20::Message::Short(
54 v20::MessageHeader {
55 device_index: self.device_index,
56 feature_index: self.feature_index,
57 function_id: U4::from_lo(0),
58 software_id: self.chan.get_sw_id(),
59 },
60 [0x00, 0x00, 0x00],
61 ))
62 .await?;
63
64 Ok(response.extend_payload()[0])
65 }
66
67 /// Retrieves the information about a specific feature based on its index in
68 /// the feature table.
69 ///
70 /// Feature index `0` for the root feature is not allowed.
71 pub async fn get_feature(&self, index: u8) -> Result<FeatureInformation, Hidpp20Error> {
72 let response = self
73 .chan
74 .send_v20(v20::Message::Short(
75 v20::MessageHeader {
76 device_index: self.device_index,
77 feature_index: self.feature_index,
78 function_id: U4::from_lo(1),
79 software_id: self.chan.get_sw_id(),
80 },
81 [index, 0x00, 0x00],
82 ))
83 .await?;
84
85 let payload = response.extend_payload();
86
87 Ok(FeatureInformation {
88 id: (payload[0] as u16) << 8 | payload[1] as u16,
89 typ: FeatureType::from(payload[2]),
90 version: payload[3],
91 })
92 }
93}
94
95/// Represents information about a specific feature as returned by the
96/// [`FeatureSetFeature::get_feature`] function.
97#[derive(Clone, Copy, Hash, Debug)]
98#[cfg_attr(feature = "serde", derive(serde::Serialize))]
99#[non_exhaustive]
100pub struct FeatureInformation {
101 /// The protocol ID of the feature.
102 pub id: u16,
103
104 /// The type of the feature.
105 pub typ: FeatureType,
106
107 /// The latest supported version of the feature.
108 ///
109 /// Multi-version features are always backwards compatible as long as the
110 /// feature ID does not change, meaning functions implemented for an older
111 /// version of the same feature will behave as expected for every later
112 /// version.
113 ///
114 /// This field was added in feature version 1 and will be `0` for all older
115 /// versions.
116 pub version: u8,
117}