hidpp/feature/root.rs
1//! Implements the `Root` feature (ID `0x0000`) that every device supports by
2//! default.
3
4use std::sync::Arc;
5
6use super::{CreatableFeature, Feature, FeatureType};
7use crate::{
8 channel::HidppChannel,
9 nibble::U4,
10 protocol::v20::{self, Hidpp20Error},
11};
12
13/// Implements the `Root` / `0x0000` feature that every HID++2.0 device
14/// supports by default.
15///
16/// This implementation is added automatically to any [`crate::device::Device`]
17/// created using [`crate::device::Device::new`].
18#[derive(Clone)]
19pub struct RootFeature {
20 /// The underlying HID++ channel.
21 chan: Arc<HidppChannel>,
22
23 /// The index of the device to implement the feature for.
24 device_index: u8,
25}
26
27impl CreatableFeature for RootFeature {
28 const ID: u16 = 0x0000;
29 const STARTING_VERSION: u8 = 0;
30
31 fn new(chan: Arc<HidppChannel>, device_index: u8, _: u8) -> Self {
32 Self { chan, device_index }
33 }
34}
35
36impl Feature for RootFeature {}
37
38impl RootFeature {
39 /// Retrieves information about a specific feature ID, including its index
40 /// in the feature table, its type and its version.
41 ///
42 /// If the feature is not supported by the device, [`None`] is returned.
43 ///
44 /// If the device only supports the root feature version 1, the
45 /// [`FeatureInformation::version`] field will be `0` for all features.
46 pub async fn get_feature(&self, id: u16) -> Result<Option<FeatureInformation>, Hidpp20Error> {
47 let response = self
48 .chan
49 .send_v20(v20::Message::Short(
50 v20::MessageHeader {
51 device_index: self.device_index,
52 feature_index: 0,
53 function_id: U4::from_lo(0),
54 software_id: self.chan.get_sw_id(),
55 },
56 [(id >> 8) as u8, id as u8, 0x00],
57 ))
58 .await?;
59
60 let payload = response.extend_payload();
61 if payload[0] == 0 {
62 return Ok(None);
63 }
64
65 Ok(Some(FeatureInformation {
66 index: payload[0],
67 typ: FeatureType::from(payload[1]),
68 version: payload[2],
69 }))
70 }
71
72 /// Pings the device with an arbitrary data byte. The device will respond
73 /// with the same data if communication succeeds.
74 ///
75 /// The underlying function, as described in the protocol specification,
76 /// will also look up the protocol version supported by the device.\
77 /// This is not implemented here, as the
78 /// [`crate::protocol::determine_version`] function does so in a more
79 /// general manner.
80 pub async fn ping(&self, data: u8) -> Result<u8, Hidpp20Error> {
81 let response = self
82 .chan
83 .send_v20(v20::Message::Short(
84 v20::MessageHeader {
85 device_index: self.device_index,
86 feature_index: 0,
87 function_id: U4::from_lo(1),
88 software_id: self.chan.get_sw_id(),
89 },
90 [0x00, 0x00, data],
91 ))
92 .await?;
93
94 let payload = response.extend_payload();
95 Ok(payload[2])
96 }
97}
98
99/// Represents information about a specific feature as returned by the
100/// [`RootFeature::get_feature`] function.
101#[derive(Clone, Copy, Hash, Debug)]
102#[cfg_attr(feature = "serde", derive(serde::Serialize))]
103#[non_exhaustive]
104pub struct FeatureInformation {
105 /// The index of the feature in the version table.
106 /// This is used for invocations of functions of that feature.
107 pub index: u8,
108
109 /// The type of the feature.
110 pub typ: FeatureType,
111
112 /// The latest supported version of the feature.
113 ///
114 /// Multi-version features are always backwards compatible as long as the
115 /// feature ID does not change, meaning functions implemented for an older
116 /// version of the same feature will behave as expected for every later
117 /// version.
118 ///
119 /// This field was added in feature version 1 and will be `0` for all older
120 /// versions.
121 pub version: u8,
122}