use std::fmt;
use crate::{RawId, U16LE};
#[repr(u8)]
#[derive(Copy, Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, Eq)]
pub enum AccessoryCommandId {
Get = 4,
Reset = 8,
Write = 20,
}
#[repr(u8)]
#[derive(Copy, Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, Eq)]
pub enum AccessoryType {
Ringcon = 4,
}
#[repr(u8)]
#[derive(Copy, Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, Eq)]
pub enum RingconItemId {
Calibration = 26,
OfflineSteps = 49,
}
#[repr(packed)]
#[derive(Copy, Clone, Debug)]
#[allow(dead_code)]
pub struct AccessoryCommand {
id: RawId<AccessoryCommandId>,
ty: RawId<AccessoryType>,
item: RawId<RingconItemId>,
maybe_includes_arg: u8,
maybe_arg_size: u8,
raw: [u8; 18],
}
impl AccessoryCommand {
pub fn get_offline_steps() -> Self {
AccessoryCommand {
id: AccessoryCommandId::Get.into(),
ty: AccessoryType::Ringcon.into(),
item: RingconItemId::OfflineSteps.into(),
maybe_includes_arg: 2,
maybe_arg_size: 0,
raw: [0; 18],
}
}
pub fn write_offline_steps(steps: u16, sum: u8) -> Self {
let steps = steps.to_le_bytes();
AccessoryCommand {
id: AccessoryCommandId::Reset.into(),
ty: AccessoryType::Ringcon.into(),
item: RingconItemId::OfflineSteps.into(),
maybe_includes_arg: 1,
maybe_arg_size: 4,
raw: [
steps[0], steps[1], 0, sum, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
],
}
}
}
#[repr(packed)]
#[derive(Copy, Clone)]
pub struct AccessoryResponse {
error: u8,
len: u8,
unknown_0x00: [u8; 4],
u: AccessoryResponseUnion,
}
impl AccessoryResponse {
fn check_error(&self) -> Result<(), Error> {
match self.error {
0 => Ok(()),
254 => Err(Error::NoAccessoryConnected),
e => Err(Error::Other(e)),
}
}
pub fn offline_steps(&self) -> Result<OfflineSteps, Error> {
self.check_error()?;
Ok(unsafe { self.u.offline_steps })
}
}
impl fmt::Debug for AccessoryResponse {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AccessoryResponse")
.field("maybe_error", &self.error)
.field("always_0x00", &self.unknown_0x00)
.field("data", unsafe { &&self.u.raw[..self.len as usize] })
.finish()
}
}
#[derive(Copy, Clone)]
union AccessoryResponseUnion {
offline_steps: OfflineSteps,
raw: [u8; 20],
}
#[repr(packed)]
#[derive(Copy, Clone, Debug)]
#[allow(dead_code)]
pub struct OfflineSteps {
pub steps: U16LE,
unknown0x00: u8,
maybe_crc: u8,
}
#[derive(Debug, Clone, Copy)]
pub enum Error {
NoAccessoryConnected,
Other(u8),
}
impl std::error::Error for Error {}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::NoAccessoryConnected => f.write_str("no accessory connected"),
Error::Other(e) => f.write_fmt(format_args!("unknown accessory error: {}", e)),
}
}
}