hidpp/feature/device_friendly_name/
mod.rs1use std::sync::Arc;
5
6use crate::{
7 channel::HidppChannel,
8 feature::{CreatableFeature, Feature},
9 nibble::U4,
10 protocol::v20::{self, Hidpp20Error},
11};
12
13#[derive(Clone)]
15pub struct DeviceFriendlyNameFeature {
16 chan: Arc<HidppChannel>,
18
19 device_index: u8,
21
22 feature_index: u8,
24}
25
26impl CreatableFeature for DeviceFriendlyNameFeature {
27 const ID: u16 = 0x0007;
28 const STARTING_VERSION: u8 = 0;
29
30 fn new(chan: Arc<HidppChannel>, device_index: u8, feature_index: u8) -> Self {
31 Self {
32 chan,
33 device_index,
34 feature_index,
35 }
36 }
37}
38
39impl Feature for DeviceFriendlyNameFeature {}
40
41impl DeviceFriendlyNameFeature {
42 pub async fn get_friendly_name_length(&self) -> Result<DeviceFriendlyNameLength, Hidpp20Error> {
44 let response = self
45 .chan
46 .send_v20(v20::Message::Short(
47 v20::MessageHeader {
48 device_index: self.device_index,
49 feature_index: self.feature_index,
50 function_id: U4::from_lo(0),
51 software_id: self.chan.get_sw_id(),
52 },
53 [0x00, 0x00, 0x00],
54 ))
55 .await?;
56
57 let payload = response.extend_payload();
58
59 Ok(DeviceFriendlyNameLength {
60 name_length: payload[0],
61 name_max_length: payload[1],
62 default_name_length: payload[2],
63 })
64 }
65
66 pub async fn get_friendly_name(&self, index: u8) -> Result<[u8; 15], Hidpp20Error> {
77 let response = self
78 .chan
79 .send_v20(v20::Message::Short(
80 v20::MessageHeader {
81 device_index: self.device_index,
82 feature_index: self.feature_index,
83 function_id: U4::from_lo(1),
84 software_id: self.chan.get_sw_id(),
85 },
86 [index, 0x00, 0x00],
87 ))
88 .await?;
89
90 Ok(response.extend_payload()[1..].try_into().unwrap())
91 }
92
93 pub async fn get_whole_friendly_name(&self) -> Result<String, Hidpp20Error> {
97 let count = self.get_friendly_name_length().await?.name_length;
98 let mut string = String::with_capacity(count as usize);
99
100 let mut len = 0;
101 while len < count as usize {
102 let part = self.get_friendly_name(len as u8).await?;
103 string.push_str(str::from_utf8(&part).map_err(|_| Hidpp20Error::UnsupportedResponse)?);
104 len = string.len();
105 }
106
107 Ok(string.trim_end_matches(char::from(0)).to_string())
108 }
109
110 pub async fn get_default_friendly_name(&self, index: u8) -> Result<[u8; 15], Hidpp20Error> {
121 let response = self
122 .chan
123 .send_v20(v20::Message::Short(
124 v20::MessageHeader {
125 device_index: self.device_index,
126 feature_index: self.feature_index,
127 function_id: U4::from_lo(2),
128 software_id: self.chan.get_sw_id(),
129 },
130 [index, 0x00, 0x00],
131 ))
132 .await?;
133
134 Ok(response.extend_payload()[1..].try_into().unwrap())
135 }
136
137 pub async fn get_whole_default_friendly_name(&self) -> Result<String, Hidpp20Error> {
141 let count = self.get_friendly_name_length().await?.default_name_length;
142 let mut string = String::with_capacity(count as usize);
143
144 let mut len = 0;
145 while len < count as usize {
146 let part = self.get_default_friendly_name(len as u8).await?;
147 string.push_str(str::from_utf8(&part).map_err(|_| Hidpp20Error::UnsupportedResponse)?);
148 len = string.len();
149 }
150
151 Ok(string.trim_end_matches(char::from(0)).to_string())
152 }
153
154 pub async fn set_friendly_name(&self, index: u8, chunk: [u8; 15]) -> Result<u8, Hidpp20Error> {
166 let mut data = [0u8; 16];
167 data[0] = index;
168 data[1..].copy_from_slice(&chunk);
169
170 let response = self
171 .chan
172 .send_v20(v20::Message::Long(
173 v20::MessageHeader {
174 device_index: self.device_index,
175 feature_index: self.feature_index,
176 function_id: U4::from_lo(3),
177 software_id: self.chan.get_sw_id(),
178 },
179 data,
180 ))
181 .await?;
182
183 Ok(response.extend_payload()[0])
184 }
185
186 pub async fn set_whole_device_name(&self, name: String) -> Result<u8, Hidpp20Error> {
195 let max_len = self.get_friendly_name_length().await?.name_max_length;
196 let mut bytes = name.into_bytes();
197 bytes.truncate(max_len as usize);
198 let chunks = bytes.chunks_exact(15);
199 let remainder = chunks.remainder();
200
201 let mut index = 0;
202 for chunk in chunks {
203 index += self
204 .set_friendly_name(index, chunk.try_into().unwrap())
205 .await?;
206 }
207
208 if !remainder.is_empty() {
209 let mut chunk = [0u8; 15];
210 chunk[..remainder.len()].copy_from_slice(remainder);
211 index += self.set_friendly_name(index, chunk).await?;
212 }
213
214 Ok(index)
215 }
216
217 pub async fn reset_friendly_name(&self) -> Result<u8, Hidpp20Error> {
221 let response = self
222 .chan
223 .send_v20(v20::Message::Short(
224 v20::MessageHeader {
225 device_index: self.device_index,
226 feature_index: self.feature_index,
227 function_id: U4::from_lo(4),
228 software_id: self.chan.get_sw_id(),
229 },
230 [0x00, 0x00, 0x00],
231 ))
232 .await?;
233
234 Ok(response.extend_payload()[0])
235 }
236}
237
238#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
241#[cfg_attr(feature = "serde", derive(serde::Serialize))]
242#[non_exhaustive]
243pub struct DeviceFriendlyNameLength {
244 pub name_length: u8,
246
247 pub name_max_length: u8,
249
250 pub default_name_length: u8,
252}