1use super::DshotError;
2
3#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
4pub enum DshotCommand {
5 #[default]
6 MotorStop = 0,
7 Beep1,
9 Beep2,
11 Beep3,
13 Beep4,
15 Beep5,
17 EscInfo,
19 SpinDirection1,
21 SpinDirection2,
23 ThreeDModeOn,
25 ThreeDModeOff,
27 SettingsRequest,
28 SettingsSave,
30 ExtendedTelemetryEnable,
32 ExtendedTelemetryDisable,
34
35 SpinDirectionNormal = 20,
38 SpinDirectionReversed,
40 Led0On,
41 Led1On,
42 Led2On,
43 Led3On,
44 Led0Off,
45 Led1Off,
46 Led2Off,
47 Led3Off,
48 AudioStreamModeToggle,
49 SilentModeToggle,
50 SignalLineTelemetryEnable,
52 SignalLineTelemetryDisable,
54 SignalLineContinuousErpmTelemetry,
56 SignalLineContinuousErpmPeriodTelemetry,
58
59 SignalLineTemperatureTelemetry = 42,
62 SignalLineVoltageTelemetry,
64 SignalLineCurrentTelemetry,
66 SignalLineConsumptionTelemetry,
68 SignalLineErpmTelemetry,
70 SignalLineErpmPeriodTelemetry,
72}
73
74impl TryFrom<u8> for DshotCommand {
75 type Error = DshotError;
76
77 fn try_from(value: u8) -> Result<Self, DshotError> {
79 let default = Self::default();
80 if value == default as u8 {
81 Ok(default)
82 } else {
83 let ret = Self::from_u8(value);
84 if ret == default {
85 Err(DshotError::InvalidDshotCommand)
86 } else {
87 Ok(ret)
88 }
89 }
90 }
91}
92
93impl DshotCommand {
94 #[must_use]
96 pub fn from_u8(value: u8) -> Self {
97 match value {
98 0 => Self::MotorStop,
99 1 => Self::Beep1,
100 2 => Self::Beep2,
101 3 => Self::Beep3,
102 4 => Self::Beep4,
103 5 => Self::Beep5,
104 6 => Self::EscInfo,
105 7 => Self::SpinDirection1,
106 8 => Self::SpinDirection2,
107 9 => Self::ThreeDModeOn,
108 10 => Self::ThreeDModeOff,
109 11 => Self::SettingsRequest,
110 12 => Self::SettingsSave,
111 13 => Self::ExtendedTelemetryEnable,
112 14 => Self::ExtendedTelemetryDisable,
113 20 => Self::SpinDirectionNormal,
114 21 => Self::SpinDirectionReversed,
115 22 => Self::Led0On,
116 23 => Self::Led1On,
117 24 => Self::Led2On,
118 25 => Self::Led3On,
119 26 => Self::Led0Off,
120 27 => Self::Led1Off,
121 28 => Self::Led2Off,
122 29 => Self::Led3Off,
123 30 => Self::AudioStreamModeToggle,
124 31 => Self::SilentModeToggle,
125 32 => Self::SignalLineTelemetryEnable,
126 33 => Self::SignalLineTelemetryDisable,
127 34 => Self::SignalLineContinuousErpmTelemetry,
128 35 => Self::SignalLineContinuousErpmPeriodTelemetry,
129 42 => Self::SignalLineTemperatureTelemetry,
131 43 => Self::SignalLineVoltageTelemetry,
132 44 => Self::SignalLineCurrentTelemetry,
133 45 => Self::SignalLineConsumptionTelemetry,
134 46 => Self::SignalLineErpmTelemetry,
135 47 => Self::SignalLineErpmPeriodTelemetry,
136 _ => Self::default(),
137 }
138 }
139}
140
141impl DshotCommand {
142 #[must_use]
143 pub const fn repetitions_required(self) -> u8 {
144 match self {
145 Self::SpinDirection1
148 | Self::SpinDirection2
149 | Self::ThreeDModeOn
150 | Self::ThreeDModeOff
151 | Self::SettingsSave
152 | Self::ExtendedTelemetryEnable
153 | Self::ExtendedTelemetryDisable
154 | Self::SpinDirectionNormal
155 | Self::SpinDirectionReversed
156 | Self::SignalLineTelemetryEnable
157 | Self::SignalLineTelemetryDisable
158 | Self::SignalLineContinuousErpmTelemetry
159 | Self::SignalLineContinuousErpmPeriodTelemetry => 10,
160 _ => 1,
161 }
162 }
163
164 #[allow(unused)]
165 #[must_use]
166 pub const fn delay_required_us(self) -> u32 {
167 match self {
168 Self::Beep1 | Self::Beep2 | Self::Beep3 | Self::Beep4 | Self::Beep5 => 260_000,
169 Self::EscInfo => 12_000,
170 Self::SettingsSave => 35_000,
171 _ => 0,
172 }
173 }
174}
175
176#[cfg(test)]
177mod test_traits {
178 use super::*;
179
180 fn is_full_eq<T: Sized + Send + Sync + Unpin + Copy + Clone + Default + Eq + PartialEq>() {}
181
182 #[test]
183 fn normal_types() {
184 is_full_eq::<DshotCommand>();
185 }
186}
187
188#[cfg(test)]
189mod tests {
190 use super::*;
191
192 #[test]
193 fn u8_to_command() {
194 assert_eq!(DshotCommand::from_u8(0), DshotCommand::MotorStop);
196 assert_eq!(DshotCommand::from_u8(1), DshotCommand::Beep1);
197 assert_eq!(DshotCommand::from_u8(35), DshotCommand::SignalLineContinuousErpmPeriodTelemetry);
198 assert_eq!(DshotCommand::from_u8(36), DshotCommand::MotorStop);
199 assert_eq!(DshotCommand::from_u8(37), DshotCommand::MotorStop);
200 assert_eq!(DshotCommand::from_u8(38), DshotCommand::MotorStop);
201 assert_eq!(DshotCommand::from_u8(39), DshotCommand::MotorStop);
202 assert_eq!(DshotCommand::from_u8(40), DshotCommand::MotorStop);
203 assert_eq!(DshotCommand::from_u8(41), DshotCommand::MotorStop);
204 assert_eq!(DshotCommand::from_u8(42), DshotCommand::SignalLineTemperatureTelemetry);
205 assert_eq!(DshotCommand::from_u8(47), DshotCommand::SignalLineErpmPeriodTelemetry);
206 assert_eq!(DshotCommand::from_u8(48), DshotCommand::MotorStop);
207 assert_eq!(DshotCommand::from_u8(49), DshotCommand::MotorStop);
208 assert_eq!(DshotCommand::from_u8(50), DshotCommand::MotorStop);
209 assert_eq!(DshotCommand::from_u8(255), DshotCommand::MotorStop);
210
211 assert_eq!(DshotCommand::try_from(0), Ok(DshotCommand::MotorStop));
213 assert_eq!(DshotCommand::try_from(1), Ok(DshotCommand::Beep1));
214 assert_eq!(DshotCommand::try_from(35), Ok(DshotCommand::SignalLineContinuousErpmPeriodTelemetry));
215 assert_eq!(DshotCommand::try_from(36), Err(DshotError::InvalidDshotCommand));
216 assert_eq!(DshotCommand::try_from(37), Err(DshotError::InvalidDshotCommand));
217 assert_eq!(DshotCommand::try_from(38), Err(DshotError::InvalidDshotCommand));
218 assert_eq!(DshotCommand::try_from(39), Err(DshotError::InvalidDshotCommand));
219 assert_eq!(DshotCommand::try_from(40), Err(DshotError::InvalidDshotCommand));
220 assert_eq!(DshotCommand::try_from(41), Err(DshotError::InvalidDshotCommand));
221 assert_eq!(DshotCommand::try_from(42), Ok(DshotCommand::SignalLineTemperatureTelemetry));
222 assert_eq!(DshotCommand::try_from(47), Ok(DshotCommand::SignalLineErpmPeriodTelemetry));
223 assert_eq!(DshotCommand::try_from(48), Err(DshotError::InvalidDshotCommand));
224 assert_eq!(DshotCommand::try_from(49), Err(DshotError::InvalidDshotCommand));
225 assert_eq!(DshotCommand::try_from(50), Err(DshotError::InvalidDshotCommand));
226 assert_eq!(DshotCommand::try_from(255), Err(DshotError::InvalidDshotCommand));
227 }
228}