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