#[cfg_attr(feature = "defmt_print", derive(defmt::Format))]
#[derive(Debug, Default)]
pub struct ClassicReading {
pub joystick_left_x: u8,
pub joystick_left_y: u8,
pub joystick_right_x: u8,
pub joystick_right_y: u8,
pub trigger_left: u8,
pub trigger_right: u8,
pub dpad_up: bool,
pub dpad_down: bool,
pub dpad_left: bool,
pub dpad_right: bool,
pub button_b: bool,
pub button_a: bool,
pub button_x: bool,
pub button_y: bool,
pub button_trigger_l: bool,
pub button_trigger_r: bool,
pub button_zl: bool,
pub button_zr: bool,
pub button_minus: bool,
pub button_plus: bool,
pub button_home: bool,
}
#[cfg_attr(feature = "defmt_print", derive(defmt::Format))]
#[derive(Debug, Default)]
pub struct ClassicReadingCalibrated {
pub joystick_left_x: i8,
pub joystick_left_y: i8,
pub joystick_right_x: i8,
pub joystick_right_y: i8,
pub trigger_left: i8,
pub trigger_right: i8,
pub dpad_up: bool,
pub dpad_down: bool,
pub dpad_left: bool,
pub dpad_right: bool,
pub button_b: bool,
pub button_a: bool,
pub button_x: bool,
pub button_y: bool,
pub button_trigger_l: bool,
pub button_trigger_r: bool,
pub button_zl: bool,
pub button_zr: bool,
pub button_minus: bool,
pub button_plus: bool,
pub button_home: bool,
}
impl ClassicReadingCalibrated {
pub fn new(r: ClassicReading, c: &CalibrationData) -> ClassicReadingCalibrated {
fn ext_u8_sub(a: u8, b: u8) -> i8 {
let res = (a as i16) - (b as i16);
res.clamp(i8::MIN as i16, i8::MAX as i16) as i8
}
ClassicReadingCalibrated {
joystick_left_x: ext_u8_sub(r.joystick_left_x, c.joystick_left_x),
joystick_left_y: ext_u8_sub(r.joystick_left_y, c.joystick_left_y),
joystick_right_x: ext_u8_sub(r.joystick_right_x, c.joystick_right_x),
joystick_right_y: ext_u8_sub(r.joystick_right_y, c.joystick_right_y),
trigger_left: ext_u8_sub(r.trigger_left, c.trigger_left),
trigger_right: ext_u8_sub(r.trigger_right, c.trigger_right),
dpad_up: r.dpad_up,
dpad_down: r.dpad_down,
dpad_left: r.dpad_left,
dpad_right: r.dpad_right,
button_b: r.button_b,
button_a: r.button_a,
button_x: r.button_x,
button_y: r.button_y,
button_trigger_l: r.button_trigger_l,
button_trigger_r: r.button_trigger_r,
button_zl: r.button_zl,
button_zr: r.button_zr,
button_minus: r.button_minus,
button_plus: r.button_plus,
button_home: r.button_home,
}
}
}
#[rustfmt::skip]
pub(crate) fn decode_classic_report(data: &[u8]) -> ClassicReading {
ClassicReading {
joystick_left_x: ClassicReading::scale_6bit_8bit(data[0] & 0b0011_1111),
joystick_left_y: ClassicReading::scale_6bit_8bit(data[1] & 0b0011_1111),
joystick_right_x: ClassicReading::scale_5bit_8bit(
((data[2] & 0b1000_0000) >> 7) |
((data[1] & 0b1100_0000) >> 5) |
((data[0] & 0b1100_0000) >> 3)
),
joystick_right_y: ClassicReading::scale_5bit_8bit(data[2] & 0b0001_1111),
trigger_left: ClassicReading::scale_5bit_8bit(
((data[2] & 0b0110_0000) >> 2) |
((data[3] & 0b1110_0000) >> 5)
),
trigger_right: ClassicReading::scale_5bit_8bit(data[3] & 0b0001_1111),
dpad_right: data[4] & 0b1000_0000 == 0,
dpad_down: data[4] & 0b0100_0000 == 0,
button_trigger_l: data[4] & 0b0010_0000 == 0,
button_minus: data[4] & 0b0001_0000 == 0,
button_home: data[4] & 0b0000_1000 == 0,
button_plus: data[4] & 0b0000_0100 == 0,
button_trigger_r: data[4] & 0b0000_0010 == 0,
button_zl: data[5] & 0b1000_0000 == 0,
button_b: data[5] & 0b0100_0000 == 0,
button_y: data[5] & 0b0010_0000 == 0,
button_a: data[5] & 0b0001_0000 == 0,
button_x: data[5] & 0b0000_1000 == 0,
button_zr: data[5] & 0b0000_0100 == 0,
dpad_left: data[5] & 0b0000_0010 == 0,
dpad_up: data[5] & 0b0000_0001 == 0,
}
}
#[rustfmt::skip]
pub(crate) fn decode_classic_hd_report(data: &[u8]) -> ClassicReading {
ClassicReading {
joystick_left_x: data[0],
joystick_right_x: data[1],
joystick_left_y: data[2],
joystick_right_y: data[3],
trigger_left: data[4],
trigger_right: data[5],
dpad_right: data[6] & 0b1000_0000 == 0,
dpad_down: data[6] & 0b0100_0000 == 0,
button_trigger_l: data[6] & 0b0010_0000 == 0,
button_minus: data[6] & 0b0001_0000 == 0,
button_home: data[6] & 0b0000_1000 == 0,
button_plus: data[6] & 0b0000_0100 == 0,
button_trigger_r: data[6] & 0b0000_0010 == 0,
button_zl: data[7] & 0b1000_0000 == 0,
button_b: data[7] & 0b0100_0000 == 0,
button_y: data[7] & 0b0010_0000 == 0,
button_a: data[7] & 0b0001_0000 == 0,
button_x: data[7] & 0b0000_1000 == 0,
button_zr: data[7] & 0b0000_0100 == 0,
dpad_left: data[7] & 0b0000_0010 == 0,
dpad_up: data[7] & 0b0000_0001 == 0,
}
}
#[cfg_attr(feature = "defmt_print", derive(defmt::Format))]
#[derive(Debug, Default)]
pub struct CalibrationData {
pub joystick_left_x: u8,
pub joystick_left_y: u8,
pub joystick_right_x: u8,
pub joystick_right_y: u8,
pub trigger_left: u8,
pub trigger_right: u8,
}
impl ClassicReading {
#[cfg(test)]
pub fn assert_digital_eq(&self, other: ClassicReading) {
assert_eq!(self.button_a, other.button_a);
assert_eq!(self.button_b, other.button_b);
assert_eq!(self.button_x, other.button_x);
assert_eq!(self.button_y, other.button_y);
assert_eq!(self.button_trigger_l, other.button_trigger_l);
assert_eq!(self.button_trigger_r, other.button_trigger_r);
assert_eq!(self.button_zl, other.button_zl);
assert_eq!(self.button_zr, other.button_zr);
assert_eq!(self.button_home, other.button_home);
assert_eq!(self.button_plus, other.button_plus);
assert_eq!(self.button_minus, other.button_minus);
}
pub(crate) fn scale_5bit_8bit(reading: u8) -> u8 {
((reading as u32 * u8::MAX as u32) / 31) as u8
}
pub(crate) fn scale_6bit_8bit(reading: u8) -> u8 {
((reading as u32 * u8::MAX as u32) / 63) as u8
}
pub fn from_data(data: &[u8]) -> Option<ClassicReading> {
if data.len() == 6 {
Some(decode_classic_report(data))
} else if data.len() == 8 {
Some(decode_classic_hd_report(data))
} else {
None
}
}
}