1use crate::log_info;
2use crate::packets::RcPacket;
3use crate::params::{ParamId, ParamValue, Params};
4use crate::state_machine::{ErrorFlag, Event, StateManager};
5
6pub mod command_state;
7
8pub const STICKS_COUNT: usize = 4;
10pub const SWITCHES_COUNT: usize = 5;
11pub const RC_STRUCT_CHANNELS: usize = 16; const RC_TIMEOUT_US: u64 = 500_000;
14
15#[repr(usize)]
18#[derive(Debug, Copy, Clone, Eq, PartialEq)]
19pub enum Stick {
20 X = 0,
21 Y = 1,
22 Z = 2,
23 F = 3,
24}
25
26#[repr(usize)]
27#[derive(Debug, Copy, Clone, Eq, PartialEq)]
28pub enum Switch {
29 Arm = 0,
30 AttOverride = 1,
31 ThrottleOverride = 2,
32 AttType = 3,
33 OutputKill = 4,
34}
35
36#[derive(Default, Debug, Copy, Clone)]
40pub struct RcHeader {
41 pub timestamp: u64, pub status: u16, }
44
45#[derive(Default, Copy, Clone)]
46struct StickConfig {
47 channel: i32,
48 one_sided: bool,
49}
50
51#[derive(Default, Copy, Clone)]
52struct SwitchConfig {
53 channel: i32,
54 mapped: bool,
55 direction: i32,
56}
57
58pub struct RcStruct {
59 pub header: RcHeader,
60 pub chan: [f32; RC_STRUCT_CHANNELS],
61 pub num_channels: usize,
62 pub frame_lost: bool,
63 pub failsafe_activated: bool,
64}
65
66impl Default for RcStruct {
67 fn default() -> Self {
68 Self {
69 header: RcHeader::default(),
70 chan: [0.0; RC_STRUCT_CHANNELS],
71 num_channels: 0,
72 frame_lost: false,
73 failsafe_activated: false,
74 }
75 }
76}
77
78pub struct Rc {
80 rc: RcStruct, new_command: bool,
82
83 sticks: [StickConfig; STICKS_COUNT],
84 switches: [SwitchConfig; SWITCHES_COUNT],
85
86 stick_values: [f32; STICKS_COUNT],
87 switch_values: [bool; SWITCHES_COUNT],
88
89 prev_time_ms: u32,
90 time_sticks_have_been_in_arming_position_ms: u32,
91}
92
93impl Rc {
94 pub fn new() -> Self {
96 Self {
97 rc: RcStruct::default(),
98 new_command: false,
99 sticks: [StickConfig::default(); STICKS_COUNT],
100 switches: [SwitchConfig::default(); SWITCHES_COUNT],
101 stick_values: [0.0; STICKS_COUNT],
102 switch_values: [false; SWITCHES_COUNT],
103 prev_time_ms: 0,
104 time_sticks_have_been_in_arming_position_ms: 0,
105 }
106 }
107
108 pub fn init(&mut self, params: &Params) {
110 self.init_rc(params);
111 self.new_command = false;
112 }
113
114 fn init_rc(&mut self, params: &Params) {
115 self.init_sticks(params);
116 self.update_switch_mappings(params);
117 }
118
119 fn init_sticks(&mut self, params: &Params) {
121 self.sticks[Stick::X as usize] = StickConfig {
123 channel: match params.get_by_id(ParamId::PARAM_RC_X_CHANNEL) {
124 ParamValue::Int(val) => val,
125 _ => {
126 0 }
128 },
129 one_sided: false,
130 };
131
132 self.sticks[Stick::Y as usize] = StickConfig {
134 channel: match params.get_by_id(ParamId::PARAM_RC_Y_CHANNEL) {
135 ParamValue::Int(val) => val,
136 _ => {
137 1 }
139 },
140 one_sided: false,
141 };
142
143 self.sticks[Stick::Z as usize] = StickConfig {
145 channel: match params.get_by_id(ParamId::PARAM_RC_Z_CHANNEL) {
146 ParamValue::Int(val) => val,
147 _ => {
148 3 }
150 },
151 one_sided: false,
152 };
153
154 self.sticks[Stick::F as usize] = StickConfig {
156 channel: match params.get_by_id(ParamId::PARAM_RC_F_CHANNEL) {
157 ParamValue::Int(val) => val,
158 _ => {
159 2 }
161 },
162 one_sided: true,
163 };
164 }
165
166 fn update_switch_mappings(&mut self, params: &Params) {
167 let rc_num_channels = match params.get_by_id(ParamId::PARAM_RC_NUM_CHANNELS) {
169 ParamValue::Int(val) => val,
170 _ => {
171 6 }
173 };
174
175 for i in 0..SWITCHES_COUNT {
177 let channel_param_id = match i {
179 i if i == Switch::Arm as usize => Some(ParamId::PARAM_RC_ARM_CHANNEL),
180 i if i == Switch::AttOverride as usize => {
181 Some(ParamId::PARAM_RC_ATTITUDE_OVERRIDE_CHANNEL)
182 }
183 i if i == Switch::ThrottleOverride as usize => {
184 Some(ParamId::PARAM_RC_THROTTLE_OVERRIDE_CHANNEL)
185 }
186 i if i == Switch::AttType as usize => {
187 Some(ParamId::PARAM_RC_ATT_CONTROL_TYPE_CHANNEL)
188 }
189 i if i == Switch::OutputKill as usize => {
190 Some(ParamId::PARAM_RC_OUTPUT_KILL_CHANNEL)
191 }
192 _ => None,
193 };
194
195 let channel_num = if let Some(id) = channel_param_id {
197 match params.get_by_id(id) {
198 ParamValue::Int(val) => val,
199 _ => {
200 255 }
202 }
203 } else {
204 255 };
206
207 self.switches[i].channel = channel_num;
208 self.switches[i].mapped = channel_num > 3 && channel_num < rc_num_channels;
209
210 let direction_param_id = match channel_num {
211 4 => Some(ParamId::PARAM_RC_SWITCH_5_DIRECTION),
212 5 => Some(ParamId::PARAM_RC_SWITCH_6_DIRECTION),
213 6 => Some(ParamId::PARAM_RC_SWITCH_7_DIRECTION),
214 7 => Some(ParamId::PARAM_RC_SWITCH_8_DIRECTION),
215 _ => None, };
217
218 self.switches[i].direction = if let Some(id) = direction_param_id {
220 match params.get_by_id(id) {
221 ParamValue::Int(val) => val,
222 _ => {
223 1 }
225 }
226 } else {
227 1 };
229 }
230 }
231
232 fn log_switch_mappings(&self) {
233 for i in 0..SWITCHES_COUNT {
234 let (channel_name, _) = match i {
235 i if i == Switch::Arm as usize => ("ARM", Some(ParamId::PARAM_RC_ARM_CHANNEL)),
236 i if i == Switch::AttOverride as usize => (
237 "ATTITUDE OVERRIDE",
238 Some(ParamId::PARAM_RC_ATTITUDE_OVERRIDE_CHANNEL),
239 ),
240 i if i == Switch::ThrottleOverride as usize => (
241 "THROTTLE OVERRIDE",
242 Some(ParamId::PARAM_RC_THROTTLE_OVERRIDE_CHANNEL),
243 ),
244 i if i == Switch::AttType as usize => (
245 "ATTITUDE TYPE",
246 Some(ParamId::PARAM_RC_ATT_CONTROL_TYPE_CHANNEL),
247 ),
248 i if i == Switch::OutputKill as usize => {
249 ("OUTPUT KILL", Some(ParamId::PARAM_RC_OUTPUT_KILL_CHANNEL))
250 }
251 _ => ("INVALID", None),
252 };
253
254 if channel_name == "INVALID" {
255 continue;
256 }
257
258 if self.switches[i].mapped {
259 log_info!(
260 "{} switch mapped to RC Channel {}",
261 channel_name,
262 self.switches[i].channel
263 );
264 } else {
265 log_info!("{} switch not mapped", channel_name);
270 }
271 }
272 }
273
274 pub fn param_change_callback(&mut self, param_id: ParamId, params: &Params) {
275 match param_id {
276 ParamId::PARAM_RC_X_CHANNEL
278 | ParamId::PARAM_RC_Y_CHANNEL
279 | ParamId::PARAM_RC_Z_CHANNEL
280 | ParamId::PARAM_RC_F_CHANNEL => {
281 self.init_sticks(params);
282 }
283 ParamId::PARAM_RC_ATTITUDE_OVERRIDE_CHANNEL
284 | ParamId::PARAM_RC_THROTTLE_OVERRIDE_CHANNEL
285 | ParamId::PARAM_RC_ATT_CONTROL_TYPE_CHANNEL
286 | ParamId::PARAM_RC_ARM_CHANNEL
287 | ParamId::PARAM_RC_OUTPUT_KILL_CHANNEL
288 | ParamId::PARAM_RC_SWITCH_5_DIRECTION
289 | ParamId::PARAM_RC_SWITCH_6_DIRECTION
290 | ParamId::PARAM_RC_SWITCH_7_DIRECTION
291 | ParamId::PARAM_RC_SWITCH_8_DIRECTION => {
292 self.update_switch_mappings(params); self.log_switch_mappings(); }
295 _ => {
296 }
298 }
299 }
300
301 pub fn receive(&mut self, packet: &RcPacket) {
302 let len = (packet.n_chan as usize).min(self.rc.chan.len());
305 self.rc.chan[..len].copy_from_slice(&packet.chan[..len]);
306
307 self.rc.header.timestamp = packet.header.timestamp;
308 self.rc.header.status = packet.header.status;
309 self.rc.num_channels = len;
310
311 self.rc.frame_lost = packet.lol;
318 self.rc.failsafe_activated = packet.lol;
319 }
320
321 fn process_sticks_and_switches(&mut self) {
322 for channel in 0..STICKS_COUNT {
324 let config = &self.sticks[channel];
325 if config.channel < 0 || (config.channel as usize) >= self.rc.num_channels {
326 continue;
327 }
328 let pwm = self.rc.chan[config.channel as usize]; if config.one_sided {
331 self.stick_values[channel] = pwm;
333 } else {
334 self.stick_values[channel] = 2.0 * (pwm - 0.5);
336 }
337 }
338
339 for channel in 0..SWITCHES_COUNT {
342 let config = &self.switches[channel];
343 if config.mapped {
344 if config.channel < 0 || (config.channel as usize) >= self.rc.num_channels {
345 self.switch_values[channel] = false;
346 continue;
347 }
348
349 let pwm = self.rc.chan[config.channel as usize]; if config.direction < 0 {
352 self.switch_values[channel] = pwm < 0.2; } else {
354 self.switch_values[channel] = pwm >= 0.8; }
356 } else {
357 self.switch_values[channel] = false;
358 }
359 }
360 }
361
362 pub fn check_rc_health(&self, now_us: u64, params: &Params) -> bool {
363 if now_us > self.rc.header.timestamp + RC_TIMEOUT_US {
364 return false;
365 }
366
367 if self.rc.frame_lost || self.rc.failsafe_activated {
368 return false;
369 }
370
371 let num_channels = match params.get_by_id(ParamId::PARAM_RC_NUM_CHANNELS) {
372 ParamValue::Int(val) => val as usize,
373 _ => 6,
374 };
375 if self.rc.num_channels < num_channels {
376 return false;
377 }
378
379 for i in 0..num_channels {
380 let val = self.rc.chan[i];
381 if val < -0.25 || val > 1.25 {
382 return false;
383 }
384 }
385 return true;
386 }
387
388 pub fn run(
389 &mut self,
390 now_ms: u32,
391 params: &Params,
392 state_manager: &mut StateManager, ) {
394 let now_us = (now_ms as u64) * 1000;
395
396 if self.check_rc_health(now_us, params) {
397 state_manager.update(Event::ERROR_CLEARED(ErrorFlag::RC_LOST), params);
398
399 self.process_sticks_and_switches();
400 self.new_command = true;
401
402 self.look_for_arm_disarm_signal(now_ms, params, state_manager);
404 } else {
405 self.new_command = false;
406 state_manager.update(Event::ERROR_OCCURRED(ErrorFlag::RC_LOST), params);
407 }
408 }
409
410 fn look_for_arm_disarm_signal(
412 &mut self,
413 now_ms: u32,
414 params: &Params,
415 state_manager: &mut StateManager, ) {
417 let dt = now_ms.saturating_sub(self.prev_time_ms);
418 self.prev_time_ms = now_ms;
419
420 let arm_threshold = match params.get_by_id(ParamId::PARAM_ARM_THRESHOLD) {
421 ParamValue::Float(val) => val,
422 _ => {
423 0.15 }
425 };
426
427 let is_armed = state_manager.is_armed();
429
430 if !self.switch_mapped(Switch::Arm) {
431 let f_stick = self.stick(Stick::F);
433 let z_stick = self.stick(Stick::Z);
434
435 if !is_armed {
436 if f_stick < arm_threshold && z_stick > (1.0 - arm_threshold) {
439 self.time_sticks_have_been_in_arming_position_ms = self
440 .time_sticks_have_been_in_arming_position_ms
441 .saturating_add(dt);
442 } else {
443 self.time_sticks_have_been_in_arming_position_ms = 0;
444 }
445
446 if self.time_sticks_have_been_in_arming_position_ms > 1000 {
447 state_manager.update_arming_safety(
448 f_stick < arm_threshold,
449 self.switch_mapped(Switch::ThrottleOverride)
450 && self.switch_on(Switch::ThrottleOverride),
451 );
452 state_manager.update(Event::REQUEST_ARM, params);
454 }
455 } else {
456 if f_stick < arm_threshold && z_stick < -(1.0 - arm_threshold) {
459 self.time_sticks_have_been_in_arming_position_ms = self
460 .time_sticks_have_been_in_arming_position_ms
461 .saturating_add(dt);
462 } else {
463 self.time_sticks_have_been_in_arming_position_ms = 0;
464 }
465
466 if self.time_sticks_have_been_in_arming_position_ms > 1000 {
467 state_manager.update(Event::REQUEST_DISARM, params);
469 self.time_sticks_have_been_in_arming_position_ms = 0;
470 }
471 }
472 } else {
473 let f_stick = self.stick(Stick::F);
475 if self.switch_on(Switch::Arm) {
476 state_manager.update_arming_safety(
477 f_stick < arm_threshold,
478 self.switch_mapped(Switch::ThrottleOverride)
479 && self.switch_on(Switch::ThrottleOverride),
480 );
481 if !is_armed {
482 state_manager.update(Event::REQUEST_ARM, params);
484 }
485 } else {
486 if is_armed {
487 state_manager.update(Event::REQUEST_DISARM, params);
489 }
490 }
491 }
492 }
493
494 pub fn new_command(&mut self) -> bool {
500 if self.new_command {
501 self.new_command = false;
502 true
503 } else {
504 false
505 }
506 }
507
508 pub fn stick(&self, channel: Stick) -> f32 {
510 self.stick_values[channel as usize]
511 }
512
513 pub fn switch_on(&self, channel: Switch) -> bool {
515 self.switch_values[channel as usize]
516 }
517
518 pub fn switch_mapped(&self, channel: Switch) -> bool {
520 self.switches[channel as usize].mapped
521 }
522
523 pub fn get_rc_struct(&self) -> &RcStruct {
525 &self.rc
526 }
527
528 pub fn read_raw_chan(&self, chan_idx: usize) -> f32 {
530 if chan_idx < self.rc.num_channels {
531 self.rc.chan[chan_idx]
532 } else {
533 0.0 }
535 }
536}