1use nom::{combinator::eof, sequence::tuple};
2
3use crate::{
4 error::{JoyConDriverError, JoyConDriverResult},
5 joycon::{JoyConDevice, SUB_COMMAND_READ_HEADER_BYTES, USER_CALIBRATION_DATA_MAGIC},
6 parser::{parse_stick_data, parse_stick_data_var},
7};
8
9#[derive(Debug, Clone)]
10pub struct StickData {
11 pub horizontal: u16,
12 pub vertical: u16,
13}
14
15impl TryFrom<&[u8]> for StickData {
16 type Error = JoyConDriverError;
17
18 fn try_from(buf: &[u8]) -> JoyConDriverResult<Self> {
19 let (_, ((horizontal, vertical), _)) = tuple((parse_stick_data_var, eof))(buf)
20 .map_err(|_| JoyConDriverError::InvalidResultBuffer)?;
21
22 Ok(Self {
23 horizontal,
24 vertical,
25 })
26 }
27}
28
29#[derive(Debug, Clone, Copy)]
30pub enum StickDirection {
31 Top,
32 TopRight,
33 Right,
34 BottomRight,
35 Bottom,
36 BottomLeft,
37 Left,
38 TopLeft,
39 Neutral,
40}
41
42impl TryFrom<u8> for StickDirection {
43 type Error = JoyConDriverError;
44
45 fn try_from(data: u8) -> JoyConDriverResult<Self> {
46 Ok(match data {
47 0 => StickDirection::Top,
48 1 => StickDirection::TopRight,
49 2 => StickDirection::Right,
50 3 => StickDirection::BottomRight,
51 4 => StickDirection::Bottom,
52 5 => StickDirection::BottomLeft,
53 6 => StickDirection::Left,
54 7 => StickDirection::TopLeft,
55 8 => StickDirection::Neutral,
56 _ => return Err(JoyConDriverError::InvalidResultBuffer),
57 })
58 }
59}
60
61#[derive(Debug, Clone, Copy)]
62pub struct StickAxisCalibration {
63 pub max: u16,
64 pub center: u16,
65 pub min: u16,
66}
67
68impl StickAxisCalibration {
69 fn from_data(center: u16, max_above_center: u16, min_below_center: u16) -> Self {
70 Self {
71 max: center.saturating_add(max_above_center),
72 center,
73 min: center.saturating_sub(min_below_center),
74 }
75 }
76}
77
78#[derive(Debug, Clone)]
79pub struct StickCalibration {
80 pub x: StickAxisCalibration,
81 pub y: StickAxisCalibration,
82}
83
84impl StickCalibration {
85 const DATA_BYTES: usize = 9;
86
87 pub fn read_left_factory_data(device: &JoyConDevice) -> JoyConDriverResult<Option<Self>> {
88 let mut buf = [0u8; SUB_COMMAND_READ_HEADER_BYTES + Self::DATA_BYTES];
89 device.read(&mut buf, 0x603D)?;
90 Self::try_from_left(&buf[SUB_COMMAND_READ_HEADER_BYTES..])
91 }
92
93 pub fn read_left_user_data(device: &JoyConDevice) -> JoyConDriverResult<Option<Self>> {
94 let mut buf = [0u8; SUB_COMMAND_READ_HEADER_BYTES
95 + USER_CALIBRATION_DATA_MAGIC.len()
96 + Self::DATA_BYTES];
97 device.read(&mut buf, 0x8010)?;
98 const DATA_START: usize = SUB_COMMAND_READ_HEADER_BYTES + USER_CALIBRATION_DATA_MAGIC.len();
99 if buf[SUB_COMMAND_READ_HEADER_BYTES..DATA_START] == USER_CALIBRATION_DATA_MAGIC {
100 Self::try_from_left(&buf[DATA_START..])
101 } else {
102 Ok(None)
103 }
104 }
105
106 fn try_from_left(buf: &[u8]) -> JoyConDriverResult<Option<Self>> {
107 if buf.iter().all(|b| *b == 0xFF) {
108 return Ok(None);
109 }
110
111 let (_, (max_above_center, center, min_below_center, _)) =
112 tuple((parse_stick_data, parse_stick_data, parse_stick_data, eof))(buf)
113 .map_err(|_| JoyConDriverError::InvalidResultBuffer)?;
114
115 Ok(Some(Self {
116 x: StickAxisCalibration::from_data(center.0, max_above_center.0, min_below_center.0),
117 y: StickAxisCalibration::from_data(center.1, max_above_center.1, min_below_center.1),
118 }))
119 }
120
121 pub fn read_right_factory_data(device: &JoyConDevice) -> JoyConDriverResult<Option<Self>> {
122 let mut buf = [0u8; SUB_COMMAND_READ_HEADER_BYTES + Self::DATA_BYTES];
123 device.read(&mut buf, 0x6046)?;
124 Self::try_from_right(&buf[SUB_COMMAND_READ_HEADER_BYTES..])
125 }
126
127 pub fn read_right_user_data(device: &JoyConDevice) -> JoyConDriverResult<Option<Self>> {
128 let mut buf = [0u8; SUB_COMMAND_READ_HEADER_BYTES
129 + USER_CALIBRATION_DATA_MAGIC.len()
130 + Self::DATA_BYTES];
131 device.read(&mut buf, 0x801B)?;
132 const DATA_START: usize = SUB_COMMAND_READ_HEADER_BYTES + USER_CALIBRATION_DATA_MAGIC.len();
133 if buf[SUB_COMMAND_READ_HEADER_BYTES..DATA_START] == USER_CALIBRATION_DATA_MAGIC {
134 Self::try_from_left(&buf[DATA_START..])
135 } else {
136 Ok(None)
137 }
138 }
139
140 fn try_from_right(buf: &[u8]) -> JoyConDriverResult<Option<Self>> {
141 if buf.iter().all(|b| *b == 0xFF) {
142 return Ok(None);
143 }
144
145 let (_, (center, min_below_center, max_above_center, _)) =
146 tuple((parse_stick_data, parse_stick_data, parse_stick_data, eof))(buf)
147 .map_err(|_| JoyConDriverError::InvalidResultBuffer)?;
148
149 Ok(Some(Self {
150 x: StickAxisCalibration::from_data(center.0, max_above_center.0, min_below_center.0),
151 y: StickAxisCalibration::from_data(center.1, max_above_center.1, min_below_center.1),
152 }))
153 }
154}