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 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}