use std::sync::Arc;
use hidpp::{
channel::HidppChannel,
feature::{CreatableFeature, Feature},
nibble::U4,
protocol::v20::{self, Hidpp20Error},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SmartShiftMode {
Free,
Ratchet,
}
impl SmartShiftMode {
#[must_use]
pub fn as_byte(self) -> u8 {
match self {
SmartShiftMode::Free => 1,
SmartShiftMode::Ratchet => 2,
}
}
#[must_use]
pub fn from_byte(b: u8) -> Option<Self> {
match b {
1 => Some(Self::Free),
2 => Some(Self::Ratchet),
_ => None,
}
}
#[must_use]
pub fn flipped(self) -> Self {
match self {
Self::Free => Self::Ratchet,
Self::Ratchet => Self::Free,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct SmartShiftStatus {
pub mode: SmartShiftMode,
pub sensitivity: u8,
}
#[derive(Clone)]
pub struct SmartShiftFeatureV0 {
chan: Arc<HidppChannel>,
device_index: u8,
feature_index: u8,
}
impl CreatableFeature for SmartShiftFeatureV0 {
const ID: u16 = 0x2111;
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 SmartShiftFeatureV0 {}
const FUNCTION_GET_STATUS: u8 = 1;
const FUNCTION_SET_STATUS: u8 = 2;
impl SmartShiftFeatureV0 {
pub async fn get_status(&self) -> Result<SmartShiftStatus, 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(FUNCTION_GET_STATUS),
software_id: self.chan.get_sw_id(),
},
[0x00, 0x00, 0x00],
))
.await?;
let payload = response.extend_payload();
let mode = SmartShiftMode::from_byte(payload[0]).unwrap_or(SmartShiftMode::Ratchet);
Ok(SmartShiftStatus {
mode,
sensitivity: payload[1],
})
}
pub async fn set_status(
&self,
mode: SmartShiftMode,
sensitivity: u8,
) -> Result<(), Hidpp20Error> {
let _ = self
.chan
.send_v20(v20::Message::Short(
v20::MessageHeader {
device_index: self.device_index,
feature_index: self.feature_index,
function_id: U4::from_lo(FUNCTION_SET_STATUS),
software_id: self.chan.get_sw_id(),
},
[mode.as_byte(), sensitivity, 0],
))
.await?;
Ok(())
}
}