hidpp/feature/hosts_info/
mod.rs1use std::sync::Arc;
4
5use num_enum::TryFromPrimitive;
6
7use crate::{
8 channel::HidppChannel,
9 feature::{CreatableFeature, Feature, FeatureEndpoint},
10 protocol::v20::Hidpp20Error,
11};
12
13bitflags::bitflags! {
14 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
16 #[cfg_attr(feature = "serde", derive(serde::Serialize))]
17 pub struct HostsInfoCapabilities: u8 {
18 const GET_NAME = 1 << 0;
20 const SET_NAME = 1 << 1;
22 const MOVE_HOST = 1 << 2;
24 const DELETE_HOST = 1 << 3;
26 const SET_OS_VERSION = 1 << 4;
28 }
29}
30
31bitflags::bitflags! {
32 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
34 #[cfg_attr(feature = "serde", derive(serde::Serialize))]
35 pub struct HostDescriptorCapabilities: u8 {
36 const EQUAD = 1 << 0;
38 const USB = 1 << 1;
40 const BT = 1 << 2;
42 const BLE = 1 << 3;
44 }
45}
46
47#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
49#[cfg_attr(feature = "serde", derive(serde::Serialize))]
50#[non_exhaustive]
51pub enum HostIndex {
52 Current,
54 Slot(u8),
56}
57
58impl From<HostIndex> for u8 {
59 fn from(value: HostIndex) -> Self {
60 match value {
61 HostIndex::Current => 0xff,
62 HostIndex::Slot(index) => index,
63 }
64 }
65}
66
67impl From<u8> for HostIndex {
68 fn from(value: u8) -> Self {
69 if value == 0xff {
70 Self::Current
71 } else {
72 Self::Slot(value)
73 }
74 }
75}
76
77#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TryFromPrimitive)]
79#[cfg_attr(feature = "serde", derive(serde::Serialize))]
80#[non_exhaustive]
81#[repr(u8)]
82pub enum HostSlotStatus {
83 Empty = 0,
85 Paired = 1,
87}
88
89#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TryFromPrimitive)]
91#[cfg_attr(feature = "serde", derive(serde::Serialize))]
92#[non_exhaustive]
93#[repr(u8)]
94pub enum HostBusType {
95 Undefined = 0,
97 Equad = 1,
99 Usb = 2,
101 Bt = 3,
103 Ble = 4,
105 BlePro = 5,
107}
108
109#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
111#[cfg_attr(feature = "serde", derive(serde::Serialize))]
112#[non_exhaustive]
113pub struct HostsInfoFeatureInfo {
114 pub capabilities: HostsInfoCapabilities,
116 pub descriptor_capabilities: HostDescriptorCapabilities,
118 pub host_count: u8,
120 pub current_host: HostIndex,
122}
123
124#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
126#[cfg_attr(feature = "serde", derive(serde::Serialize))]
127#[non_exhaustive]
128pub struct HostInfo {
129 pub host_index: HostIndex,
131 pub status: HostSlotStatus,
133 pub bus_type: HostBusType,
135 pub page_count: u8,
137 pub name_len: u8,
139 pub name_max_len: u8,
141}
142
143#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
145#[cfg_attr(feature = "serde", derive(serde::Serialize))]
146#[non_exhaustive]
147pub struct HostDescriptorPage {
148 pub host_index: HostIndex,
150 pub bus_type: HostBusType,
152 pub page_index: u8,
154 pub body: [u8; 14],
156}
157
158#[derive(Clone)]
160pub struct HostsInfoFeature {
161 endpoint: FeatureEndpoint,
163}
164
165impl CreatableFeature for HostsInfoFeature {
166 const ID: u16 = 0x1815;
167 const STARTING_VERSION: u8 = 2;
168
169 fn new(chan: Arc<HidppChannel>, device_index: u8, feature_index: u8) -> Self {
170 Self {
171 endpoint: FeatureEndpoint::new(chan, device_index, feature_index),
172 }
173 }
174}
175
176impl Feature for HostsInfoFeature {}
177
178impl HostsInfoFeature {
179 pub async fn get_feature_info(&self) -> Result<HostsInfoFeatureInfo, Hidpp20Error> {
181 let payload = self.endpoint.call(0, [0; 3]).await?.extend_payload();
182 Ok(HostsInfoFeatureInfo {
183 capabilities: HostsInfoCapabilities::from_bits_retain(payload[0]),
184 descriptor_capabilities: HostDescriptorCapabilities::from_bits_retain(payload[1]),
185 host_count: payload[2],
186 current_host: HostIndex::from(payload[3]),
187 })
188 }
189
190 pub async fn get_host_info(&self, host: HostIndex) -> Result<HostInfo, Hidpp20Error> {
192 let payload = self
193 .endpoint
194 .call(1, [u8::from(host), 0, 0])
195 .await?
196 .extend_payload();
197 Ok(HostInfo {
198 host_index: HostIndex::from(payload[0]),
199 status: HostSlotStatus::try_from(payload[1])
200 .map_err(|_| Hidpp20Error::UnsupportedResponse)?,
201 bus_type: HostBusType::try_from(payload[2])
202 .map_err(|_| Hidpp20Error::UnsupportedResponse)?,
203 page_count: payload[3],
204 name_len: payload[4],
205 name_max_len: payload[5],
206 })
207 }
208
209 pub async fn get_host_descriptor(
211 &self,
212 host: HostIndex,
213 page: u8,
214 ) -> Result<HostDescriptorPage, Hidpp20Error> {
215 let payload = self
216 .endpoint
217 .call(2, [u8::from(host), page, 0])
218 .await?
219 .extend_payload();
220 let mut body = [0; 14];
221 body.copy_from_slice(&payload[2..16]);
222 Ok(HostDescriptorPage {
223 host_index: HostIndex::from(payload[0]),
224 bus_type: HostBusType::try_from(payload[1] >> 4)
225 .map_err(|_| Hidpp20Error::UnsupportedResponse)?,
226 page_index: payload[1] & 0x0f,
227 body,
228 })
229 }
230}