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}