use std::sync::Arc;
use crate::{
channel::HidppChannel,
feature::{CreatableFeature, Feature},
nibble::U4,
protocol::v20::{self, Hidpp20Error},
};
#[derive(Clone)]
pub struct DeviceFriendlyNameFeatureV0 {
chan: Arc<HidppChannel>,
device_index: u8,
feature_index: u8,
}
impl CreatableFeature for DeviceFriendlyNameFeatureV0 {
const ID: u16 = 0x0007;
const STARTING_VERSION: u8 = 0;
fn new(chan: Arc<HidppChannel>, device_index: u8, feature_index: u8) -> Self {
Self {
chan,
device_index,
feature_index,
}
}
}
impl Feature for DeviceFriendlyNameFeatureV0 {
}
impl DeviceFriendlyNameFeatureV0 {
pub async fn get_friendly_name_length(&self) -> Result<DeviceFriendlyNameLength, Hidpp20Error> {
let response = self
.chan
.send_v20(v20::Message::Short(
v20::MessageHeader {
device_index: self.device_index,
feature_index: self.feature_index,
function_id: U4::from_lo(0),
software_id: self.chan.get_sw_id(),
},
[0x00, 0x00, 0x00],
))
.await?;
let payload = response.extend_payload();
Ok(DeviceFriendlyNameLength {
name_length: payload[0],
name_max_length: payload[1],
default_name_length: payload[2],
})
}
pub async fn get_friendly_name(&self, index: u8) -> Result<[u8; 15], Hidpp20Error> {
let response = self
.chan
.send_v20(v20::Message::Short(
v20::MessageHeader {
device_index: self.device_index,
feature_index: self.feature_index,
function_id: U4::from_lo(1),
software_id: self.chan.get_sw_id(),
},
[index, 0x00, 0x00],
))
.await?;
Ok(response.extend_payload()[1..].try_into().unwrap())
}
pub async fn get_whole_friendly_name(&self) -> Result<String, Hidpp20Error> {
let count = self.get_friendly_name_length().await?.name_length;
let mut string = String::with_capacity(count as usize);
let mut len = 0;
while len < count as usize {
let part = self.get_friendly_name(len as u8).await?;
string.push_str(
core::str::from_utf8(&part).map_err(|_| Hidpp20Error::UnsupportedResponse)?,
);
len = string.len();
}
Ok(string)
}
pub async fn get_default_friendly_name(&self, index: u8) -> Result<[u8; 15], Hidpp20Error> {
let response = self
.chan
.send_v20(v20::Message::Short(
v20::MessageHeader {
device_index: self.device_index,
feature_index: self.feature_index,
function_id: U4::from_lo(2),
software_id: self.chan.get_sw_id(),
},
[index, 0x00, 0x00],
))
.await?;
Ok(response.extend_payload()[1..].try_into().unwrap())
}
pub async fn get_whole_default_friendly_name(&self) -> Result<String, Hidpp20Error> {
let count = self.get_friendly_name_length().await?.default_name_length;
let mut string = String::with_capacity(count as usize);
let mut len = 0;
while len < count as usize {
let part = self.get_default_friendly_name(len as u8).await?;
string.push_str(
core::str::from_utf8(&part).map_err(|_| Hidpp20Error::UnsupportedResponse)?,
);
len = string.len();
}
Ok(string)
}
pub async fn set_friendly_name(&self, index: u8, chunk: [u8; 15]) -> Result<u8, Hidpp20Error> {
let mut data = [0u8; 16];
data[0] = index;
data[1..].copy_from_slice(&chunk);
let response = self
.chan
.send_v20(v20::Message::Long(
v20::MessageHeader {
device_index: self.device_index,
feature_index: self.feature_index,
function_id: U4::from_lo(3),
software_id: self.chan.get_sw_id(),
},
data,
))
.await?;
Ok(response.extend_payload()[0])
}
pub async fn set_whole_device_name(&self, name: String) -> Result<u8, Hidpp20Error> {
let max_len = self.get_friendly_name_length().await?.name_max_length;
let mut bytes = name.into_bytes();
bytes.truncate(max_len as usize);
let chunks = bytes.chunks_exact(15);
let remainder = chunks.remainder();
let mut index = 0;
for chunk in chunks {
index += self
.set_friendly_name(index, chunk.try_into().unwrap())
.await?;
}
if !remainder.is_empty() {
let mut chunk = [0u8; 15];
chunk[..remainder.len()].copy_from_slice(remainder);
index += self.set_friendly_name(index, chunk).await?;
}
Ok(index)
}
pub async fn reset_friendly_name(&self) -> Result<u8, Hidpp20Error> {
let response = self
.chan
.send_v20(v20::Message::Short(
v20::MessageHeader {
device_index: self.device_index,
feature_index: self.feature_index,
function_id: U4::from_lo(4),
software_id: self.chan.get_sw_id(),
},
[0x00, 0x00, 0x00],
))
.await?;
Ok(response.extend_payload()[0])
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
#[non_exhaustive]
pub struct DeviceFriendlyNameLength {
pub name_length: u8,
pub name_max_length: u8,
pub default_name_length: u8,
}