Skip to main content

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 [id_hi, id_lo] = id.to_be_bytes();
44        let payload = self
45            .endpoint
46            .call(0, [id_hi, id_lo, 0x00])
47            .await?
48            .extend_payload();
49        if payload[0] == 0 {
50            return Ok(None);
51        }
52
53        Ok(Some(FeatureInformation {
54            index: payload[0],
55            typ: FeatureType::from_bits_retain(payload[1]),
56            version: payload[2],
57        }))
58    }
59
60    /// Pings the device with an arbitrary data byte. The device will respond
61    /// with the same data if communication succeeds.
62    ///
63    /// The underlying function, as described in the protocol specification,
64    /// will also look up the protocol version supported by the device.\
65    /// This is not implemented here, as the
66    /// [`crate::protocol::determine_version`] function does so in a more
67    /// general manner.
68    pub async fn ping(&self, data: u8) -> Result<u8, Hidpp20Error> {
69        let payload = self
70            .endpoint
71            .call(1, [0x00, 0x00, data])
72            .await?
73            .extend_payload();
74        Ok(payload[2])
75    }
76}
77
78/// Represents information about a specific feature as returned by the
79/// [`RootFeature::get_feature`] function.
80#[derive(Clone, Copy, Hash, Debug)]
81#[cfg_attr(feature = "serde", derive(serde::Serialize))]
82#[non_exhaustive]
83pub struct FeatureInformation {
84    /// The index of the feature in the version table.
85    /// This is used for invocations of functions of that feature.
86    pub index: u8,
87
88    /// The type of the feature.
89    pub typ: FeatureType,
90
91    /// The latest supported version of the feature.
92    ///
93    /// Multi-version features are always backwards compatible as long as the
94    /// feature ID does not change, meaning functions implemented for an older
95    /// version of the same feature will behave as expected for every later
96    /// version.
97    ///
98    /// This field was added in feature version 1 and will be `0` for all older
99    /// versions.
100    pub version: u8,
101}