1use crate::frame::CanFdFrame;
27use crate::mode::Mode;
28use crate::multiplex::{self, WriteCanData, WriteCombiner};
29use crate::register::Register;
30use crate::resolution::Resolution;
31use moteus_derive::Setters;
32
33#[non_exhaustive]
35#[derive(Debug, Clone)]
36pub struct PositionFormat {
37 pub position: Resolution,
38 pub velocity: Resolution,
39 pub feedforward_torque: Resolution,
40 pub kp_scale: Resolution,
41 pub kd_scale: Resolution,
42 pub maximum_torque: Resolution,
43 pub stop_position: Resolution,
44 pub watchdog_timeout: Resolution,
45 pub velocity_limit: Resolution,
46 pub accel_limit: Resolution,
47 pub fixed_voltage_override: Resolution,
48 pub ilimit_scale: Resolution,
49 pub fixed_current_override: Resolution,
50 pub ignore_position_bounds: Resolution,
51}
52
53impl Default for PositionFormat {
54 fn default() -> Self {
55 PositionFormat {
56 position: Resolution::Float,
57 velocity: Resolution::Float,
58 feedforward_torque: Resolution::Float,
59 kp_scale: Resolution::Float,
60 kd_scale: Resolution::Float,
61 maximum_torque: Resolution::Float,
62 stop_position: Resolution::Float,
63 watchdog_timeout: Resolution::Float,
64 velocity_limit: Resolution::Float,
65 accel_limit: Resolution::Float,
66 fixed_voltage_override: Resolution::Float,
67 ilimit_scale: Resolution::Float,
68 fixed_current_override: Resolution::Float,
69 ignore_position_bounds: Resolution::Float,
70 }
71 }
72}
73
74#[non_exhaustive]
98#[derive(Debug, Clone, Default, Setters)]
99pub struct PositionCommand {
100 pub position: Option<f32>,
102 pub velocity: Option<f32>,
104 pub feedforward_torque: Option<f32>,
106 pub kp_scale: Option<f32>,
108 pub kd_scale: Option<f32>,
110 pub maximum_torque: Option<f32>,
112 pub stop_position: Option<f32>,
114 pub watchdog_timeout: Option<f32>,
116 pub velocity_limit: Option<f32>,
118 pub accel_limit: Option<f32>,
120 pub fixed_voltage_override: Option<f32>,
122 pub ilimit_scale: Option<f32>,
124 pub fixed_current_override: Option<f32>,
126 pub ignore_position_bounds: Option<f32>,
128}
129
130impl PositionCommand {
131 pub fn new() -> Self {
133 Self::default()
134 }
135
136 pub fn serialize(&self, frame: &mut CanFdFrame, format: &PositionFormat) {
138 let mut writer = WriteCanData::new(frame);
139
140 writer.write_u8(multiplex::WRITE_INT8 | 0x01);
142 writer.write_u8(Register::Mode.address() as u8);
143 writer.write_i8(Mode::Position as i8);
144
145 let resolutions = [
147 if self.position.is_some() {
148 format.position
149 } else {
150 Resolution::Ignore
151 },
152 if self.velocity.is_some() {
153 format.velocity
154 } else {
155 Resolution::Ignore
156 },
157 if self.feedforward_torque.is_some() {
158 format.feedforward_torque
159 } else {
160 Resolution::Ignore
161 },
162 if self.kp_scale.is_some() {
163 format.kp_scale
164 } else {
165 Resolution::Ignore
166 },
167 if self.kd_scale.is_some() {
168 format.kd_scale
169 } else {
170 Resolution::Ignore
171 },
172 if self.maximum_torque.is_some() {
173 format.maximum_torque
174 } else {
175 Resolution::Ignore
176 },
177 if self.stop_position.is_some() {
178 format.stop_position
179 } else {
180 Resolution::Ignore
181 },
182 if self.watchdog_timeout.is_some() {
183 format.watchdog_timeout
184 } else {
185 Resolution::Ignore
186 },
187 if self.velocity_limit.is_some() {
188 format.velocity_limit
189 } else {
190 Resolution::Ignore
191 },
192 if self.accel_limit.is_some() {
193 format.accel_limit
194 } else {
195 Resolution::Ignore
196 },
197 if self.fixed_voltage_override.is_some() {
198 format.fixed_voltage_override
199 } else {
200 Resolution::Ignore
201 },
202 if self.ilimit_scale.is_some() {
203 format.ilimit_scale
204 } else {
205 Resolution::Ignore
206 },
207 if self.fixed_current_override.is_some() {
208 format.fixed_current_override
209 } else {
210 Resolution::Ignore
211 },
212 if self.ignore_position_bounds.is_some() {
213 format.ignore_position_bounds
214 } else {
215 Resolution::Ignore
216 },
217 ];
218
219 let mut combiner =
220 WriteCombiner::new(0x00, Register::CommandPosition.address(), &resolutions);
221
222 if combiner.maybe_write(&mut writer) {
223 writer.write_position(self.position.unwrap_or(0.0), format.position);
224 }
225 if combiner.maybe_write(&mut writer) {
226 writer.write_velocity(self.velocity.unwrap_or(0.0), format.velocity);
227 }
228 if combiner.maybe_write(&mut writer) {
229 writer.write_torque(
230 self.feedforward_torque.unwrap_or(0.0),
231 format.feedforward_torque,
232 );
233 }
234 if combiner.maybe_write(&mut writer) {
235 writer.write_pwm(self.kp_scale.unwrap_or(1.0), format.kp_scale);
236 }
237 if combiner.maybe_write(&mut writer) {
238 writer.write_pwm(self.kd_scale.unwrap_or(1.0), format.kd_scale);
239 }
240 if combiner.maybe_write(&mut writer) {
241 writer.write_torque(
242 self.maximum_torque.unwrap_or(f32::NAN),
243 format.maximum_torque,
244 );
245 }
246 if combiner.maybe_write(&mut writer) {
247 writer.write_position(self.stop_position.unwrap_or(f32::NAN), format.stop_position);
248 }
249 if combiner.maybe_write(&mut writer) {
250 writer.write_time(
251 self.watchdog_timeout.unwrap_or(f32::NAN),
252 format.watchdog_timeout,
253 );
254 }
255 if combiner.maybe_write(&mut writer) {
256 writer.write_velocity(
257 self.velocity_limit.unwrap_or(f32::NAN),
258 format.velocity_limit,
259 );
260 }
261 if combiner.maybe_write(&mut writer) {
262 writer.write_accel(self.accel_limit.unwrap_or(f32::NAN), format.accel_limit);
263 }
264 if combiner.maybe_write(&mut writer) {
265 writer.write_voltage(
266 self.fixed_voltage_override.unwrap_or(f32::NAN),
267 format.fixed_voltage_override,
268 );
269 }
270 if combiner.maybe_write(&mut writer) {
271 writer.write_pwm(self.ilimit_scale.unwrap_or(1.0), format.ilimit_scale);
272 }
273 if combiner.maybe_write(&mut writer) {
274 writer.write_current(
275 self.fixed_current_override.unwrap_or(f32::NAN),
276 format.fixed_current_override,
277 );
278 }
279 if combiner.maybe_write(&mut writer) {
280 writer.write_int(
281 self.ignore_position_bounds.unwrap_or(0.0) as i32,
282 format.ignore_position_bounds,
283 );
284 }
285 }
286}
287
288#[non_exhaustive]
290#[derive(Debug, Clone)]
291pub struct VFOCFormat {
292 pub theta: Resolution,
293 pub voltage: Resolution,
294 pub theta_rate: Resolution,
295}
296
297impl Default for VFOCFormat {
298 fn default() -> Self {
299 VFOCFormat {
300 theta: Resolution::Float,
301 voltage: Resolution::Float,
302 theta_rate: Resolution::Float,
303 }
304 }
305}
306
307#[non_exhaustive]
311#[derive(Debug, Clone, Setters)]
312pub struct VFOCCommand {
313 pub theta: f32,
315 pub voltage: f32,
317 pub theta_rate: Option<f32>,
319}
320
321impl Default for VFOCCommand {
322 fn default() -> Self {
323 VFOCCommand {
324 theta: 0.0,
325 voltage: 0.0,
326 theta_rate: None,
327 }
328 }
329}
330
331impl VFOCCommand {
332 pub fn new() -> Self {
334 Self::default()
335 }
336
337 pub fn serialize(&self, frame: &mut CanFdFrame, format: &VFOCFormat) {
339 let mut writer = WriteCanData::new(frame);
340
341 writer.write_u8(multiplex::WRITE_INT8 | 0x01);
343 writer.write_u8(Register::Mode.address() as u8);
344 writer.write_i8(Mode::VoltageFoc as i8);
345
346 let resolutions = [
348 format.theta,
349 format.voltage,
350 Resolution::Ignore, Resolution::Ignore, Resolution::Ignore, Resolution::Ignore, if self.theta_rate.is_some() && self.theta_rate != Some(0.0) {
355 format.theta_rate
356 } else {
357 Resolution::Ignore
358 },
359 ];
360
361 let mut combiner = WriteCombiner::new(0x00, Register::VFocTheta.address(), &resolutions);
362
363 if combiner.maybe_write(&mut writer) {
364 writer.write_pwm(self.theta / core::f32::consts::PI, format.theta);
366 }
367 if combiner.maybe_write(&mut writer) {
368 writer.write_voltage(self.voltage, format.voltage);
369 }
370 combiner.maybe_write(&mut writer);
372 combiner.maybe_write(&mut writer);
373 combiner.maybe_write(&mut writer);
374 combiner.maybe_write(&mut writer);
375 if combiner.maybe_write(&mut writer) {
376 writer.write_velocity(
377 self.theta_rate.unwrap_or(0.0) / core::f32::consts::PI,
378 format.theta_rate,
379 );
380 }
381 }
382}
383
384#[non_exhaustive]
386#[derive(Debug, Clone)]
387pub struct CurrentFormat {
388 pub d_a: Resolution,
389 pub q_a: Resolution,
390}
391
392impl Default for CurrentFormat {
393 fn default() -> Self {
394 CurrentFormat {
395 d_a: Resolution::Float,
396 q_a: Resolution::Float,
397 }
398 }
399}
400
401#[non_exhaustive]
416#[derive(Debug, Clone)]
417pub struct CurrentCommand {
418 pub d_a: f32,
420 pub q_a: f32,
422}
423
424impl Default for CurrentCommand {
425 fn default() -> Self {
426 CurrentCommand { d_a: 0.0, q_a: 0.0 }
427 }
428}
429
430impl CurrentCommand {
431 pub fn new() -> Self {
433 Self::default()
434 }
435
436 #[must_use]
438 pub fn d_current(mut self, v: f32) -> Self {
439 self.d_a = v;
440 self
441 }
442
443 #[must_use]
445 pub fn q_current(mut self, v: f32) -> Self {
446 self.q_a = v;
447 self
448 }
449
450 pub fn serialize(&self, frame: &mut CanFdFrame, format: &CurrentFormat) {
452 let mut writer = WriteCanData::new(frame);
453
454 writer.write_u8(multiplex::WRITE_INT8 | 0x01);
456 writer.write_u8(Register::Mode.address() as u8);
457 writer.write_i8(Mode::Current as i8);
458
459 let resolutions = [format.q_a, format.d_a];
461
462 let mut combiner =
463 WriteCombiner::new(0x00, Register::CommandQCurrent.address(), &resolutions);
464
465 if combiner.maybe_write(&mut writer) {
466 writer.write_current(self.q_a, format.q_a);
467 }
468 if combiner.maybe_write(&mut writer) {
469 writer.write_current(self.d_a, format.d_a);
470 }
471 }
472}
473
474#[non_exhaustive]
476#[derive(Debug, Clone)]
477pub struct StayWithinFormat {
478 pub lower_bound: Resolution,
479 pub upper_bound: Resolution,
480 pub feedforward_torque: Resolution,
481 pub kp_scale: Resolution,
482 pub kd_scale: Resolution,
483 pub maximum_torque: Resolution,
484 pub watchdog_timeout: Resolution,
485 pub ilimit_scale: Resolution,
486 pub ignore_position_bounds: Resolution,
487}
488
489impl Default for StayWithinFormat {
490 fn default() -> Self {
491 StayWithinFormat {
492 lower_bound: Resolution::Float,
493 upper_bound: Resolution::Float,
494 feedforward_torque: Resolution::Float,
495 kp_scale: Resolution::Float,
496 kd_scale: Resolution::Float,
497 maximum_torque: Resolution::Float,
498 watchdog_timeout: Resolution::Float,
499 ilimit_scale: Resolution::Float,
500 ignore_position_bounds: Resolution::Float,
501 }
502 }
503}
504
505#[non_exhaustive]
523#[derive(Debug, Clone, Default, Setters)]
524pub struct StayWithinCommand {
525 pub lower_bound: Option<f32>,
527 pub upper_bound: Option<f32>,
529 pub feedforward_torque: Option<f32>,
531 pub kp_scale: Option<f32>,
533 pub kd_scale: Option<f32>,
535 pub maximum_torque: Option<f32>,
537 pub watchdog_timeout: Option<f32>,
539 pub ilimit_scale: Option<f32>,
541 pub ignore_position_bounds: Option<f32>,
543}
544
545impl StayWithinCommand {
546 pub fn new() -> Self {
548 Self::default()
549 }
550
551 pub fn serialize(&self, frame: &mut CanFdFrame, format: &StayWithinFormat) {
553 let mut writer = WriteCanData::new(frame);
554
555 writer.write_u8(multiplex::WRITE_INT8 | 0x01);
557 writer.write_u8(Register::Mode.address() as u8);
558 writer.write_i8(Mode::StayWithin as i8);
559
560 let resolutions = [
561 if self.lower_bound.is_some() {
562 format.lower_bound
563 } else {
564 Resolution::Ignore
565 },
566 if self.upper_bound.is_some() {
567 format.upper_bound
568 } else {
569 Resolution::Ignore
570 },
571 if self.feedforward_torque.is_some() {
572 format.feedforward_torque
573 } else {
574 Resolution::Ignore
575 },
576 if self.kp_scale.is_some() {
577 format.kp_scale
578 } else {
579 Resolution::Ignore
580 },
581 if self.kd_scale.is_some() {
582 format.kd_scale
583 } else {
584 Resolution::Ignore
585 },
586 if self.maximum_torque.is_some() {
587 format.maximum_torque
588 } else {
589 Resolution::Ignore
590 },
591 if self.watchdog_timeout.is_some() {
592 format.watchdog_timeout
593 } else {
594 Resolution::Ignore
595 },
596 if self.ilimit_scale.is_some() {
597 format.ilimit_scale
598 } else {
599 Resolution::Ignore
600 },
601 if self.ignore_position_bounds.is_some() {
602 format.ignore_position_bounds
603 } else {
604 Resolution::Ignore
605 },
606 ];
607
608 let mut combiner = WriteCombiner::new(
609 0x00,
610 Register::CommandStayWithinLowerBound.address(),
611 &resolutions,
612 );
613
614 if combiner.maybe_write(&mut writer) {
615 writer.write_position(self.lower_bound.unwrap_or(f32::NAN), format.lower_bound);
616 }
617 if combiner.maybe_write(&mut writer) {
618 writer.write_position(self.upper_bound.unwrap_or(f32::NAN), format.upper_bound);
619 }
620 if combiner.maybe_write(&mut writer) {
621 writer.write_torque(
622 self.feedforward_torque.unwrap_or(0.0),
623 format.feedforward_torque,
624 );
625 }
626 if combiner.maybe_write(&mut writer) {
627 writer.write_pwm(self.kp_scale.unwrap_or(1.0), format.kp_scale);
628 }
629 if combiner.maybe_write(&mut writer) {
630 writer.write_pwm(self.kd_scale.unwrap_or(1.0), format.kd_scale);
631 }
632 if combiner.maybe_write(&mut writer) {
633 writer.write_torque(self.maximum_torque.unwrap_or(0.0), format.maximum_torque);
634 }
635 if combiner.maybe_write(&mut writer) {
636 writer.write_time(
637 self.watchdog_timeout.unwrap_or(f32::NAN),
638 format.watchdog_timeout,
639 );
640 }
641 if combiner.maybe_write(&mut writer) {
642 writer.write_pwm(self.ilimit_scale.unwrap_or(1.0), format.ilimit_scale);
643 }
644 if combiner.maybe_write(&mut writer) {
645 writer.write_int(
646 self.ignore_position_bounds.unwrap_or(0.0) as i32,
647 format.ignore_position_bounds,
648 );
649 }
650 }
651}
652
653#[non_exhaustive]
655#[derive(Debug, Clone)]
656pub struct ZeroVelocityFormat {
657 pub kd_scale: Resolution,
658}
659
660impl Default for ZeroVelocityFormat {
661 fn default() -> Self {
662 ZeroVelocityFormat {
663 kd_scale: Resolution::Float,
664 }
665 }
666}
667
668#[non_exhaustive]
672#[derive(Debug, Clone, Default, Setters)]
673pub struct ZeroVelocityCommand {
674 pub kd_scale: Option<f32>,
676}
677
678impl ZeroVelocityCommand {
679 pub fn new() -> Self {
681 Self::default()
682 }
683
684 pub fn serialize(&self, frame: &mut CanFdFrame, format: &ZeroVelocityFormat) {
686 let mut writer = WriteCanData::new(frame);
687
688 writer.write_u8(multiplex::WRITE_INT8 | 0x01);
690 writer.write_u8(Register::Mode.address() as u8);
691 writer.write_i8(Mode::ZeroVelocity as i8);
692
693 if let Some(kd) = self.kd_scale {
695 let resolutions = [format.kd_scale];
696 let mut combiner =
697 WriteCombiner::new(0x00, Register::CommandKdScale.address(), &resolutions);
698
699 if combiner.maybe_write(&mut writer) {
700 writer.write_pwm(kd, format.kd_scale);
701 }
702 }
703 }
704}
705
706pub struct StopCommand;
708
709impl StopCommand {
710 pub fn serialize(frame: &mut CanFdFrame) {
712 let mut writer = WriteCanData::new(frame);
713
714 writer.write_u8(multiplex::WRITE_INT8 | 0x01);
715 writer.write_u8(Register::Mode.address() as u8);
716 writer.write_i8(Mode::Stopped as i8);
717 }
718}
719
720pub struct BrakeCommand;
722
723impl BrakeCommand {
724 pub fn serialize(frame: &mut CanFdFrame) {
726 let mut writer = WriteCanData::new(frame);
727
728 writer.write_u8(multiplex::WRITE_INT8 | 0x01);
729 writer.write_u8(Register::Mode.address() as u8);
730 writer.write_i8(Mode::Brake as i8);
731 }
732}
733
734pub struct OutputNearestCommand {
736 pub position: f32,
738}
739
740impl OutputNearestCommand {
741 pub fn new(position: f32) -> Self {
743 OutputNearestCommand { position }
744 }
745
746 pub fn serialize(&self, frame: &mut CanFdFrame) {
748 let mut writer = WriteCanData::new(frame);
749
750 writer.write_u8(multiplex::WRITE_FLOAT | 0x01);
751 writer.write_varuint(Register::SetOutputNearest.address() as u32);
752 writer.write_f32(self.position);
753 }
754}
755
756pub struct OutputExactCommand {
758 pub position: f32,
760}
761
762impl OutputExactCommand {
763 pub fn new(position: f32) -> Self {
765 OutputExactCommand { position }
766 }
767
768 pub fn serialize(&self, frame: &mut CanFdFrame) {
770 let mut writer = WriteCanData::new(frame);
771
772 writer.write_u8(multiplex::WRITE_FLOAT | 0x01);
773 writer.write_varuint(Register::SetOutputExact.address() as u32);
774 writer.write_f32(self.position);
775 }
776}
777
778pub struct RequireReindexCommand;
780
781impl RequireReindexCommand {
782 pub fn serialize(frame: &mut CanFdFrame) {
784 let mut writer = WriteCanData::new(frame);
785
786 writer.write_u8(multiplex::WRITE_INT8 | 0x01);
787 writer.write_varuint(Register::RequireReindex.address() as u32);
788 writer.write_i8(1);
789 }
790}
791
792pub struct RecapturePositionVelocityCommand;
794
795impl RecapturePositionVelocityCommand {
796 pub fn serialize(frame: &mut CanFdFrame) {
798 let mut writer = WriteCanData::new(frame);
799
800 writer.write_u8(multiplex::WRITE_INT8 | 0x01);
801 writer.write_varuint(Register::RecapturePositionVelocity.address() as u32);
802 writer.write_i8(1);
803 }
804}
805
806#[non_exhaustive]
808#[derive(Debug, Clone)]
809pub struct AuxPwmFormat {
810 pub aux1_pwm1: Resolution,
811 pub aux1_pwm2: Resolution,
812 pub aux1_pwm3: Resolution,
813 pub aux1_pwm4: Resolution,
814 pub aux1_pwm5: Resolution,
815 pub aux2_pwm1: Resolution,
816 pub aux2_pwm2: Resolution,
817 pub aux2_pwm3: Resolution,
818 pub aux2_pwm4: Resolution,
819 pub aux2_pwm5: Resolution,
820}
821
822impl Default for AuxPwmFormat {
823 fn default() -> Self {
824 AuxPwmFormat {
825 aux1_pwm1: Resolution::Float,
826 aux1_pwm2: Resolution::Float,
827 aux1_pwm3: Resolution::Float,
828 aux1_pwm4: Resolution::Float,
829 aux1_pwm5: Resolution::Float,
830 aux2_pwm1: Resolution::Float,
831 aux2_pwm2: Resolution::Float,
832 aux2_pwm3: Resolution::Float,
833 aux2_pwm4: Resolution::Float,
834 aux2_pwm5: Resolution::Float,
835 }
836 }
837}
838
839#[non_exhaustive]
845#[derive(Debug, Clone, Default, Setters)]
846pub struct AuxPwmCommand {
847 pub aux1_pwm1: Option<f32>,
849 pub aux1_pwm2: Option<f32>,
851 pub aux1_pwm3: Option<f32>,
853 pub aux1_pwm4: Option<f32>,
855 pub aux1_pwm5: Option<f32>,
857 pub aux2_pwm1: Option<f32>,
859 pub aux2_pwm2: Option<f32>,
861 pub aux2_pwm3: Option<f32>,
863 pub aux2_pwm4: Option<f32>,
865 pub aux2_pwm5: Option<f32>,
867}
868
869impl AuxPwmCommand {
870 pub fn new() -> Self {
872 Self::default()
873 }
874
875 pub fn serialize(&self, frame: &mut CanFdFrame, format: &AuxPwmFormat) {
877 let mut writer = WriteCanData::new(frame);
878
879 let resolutions = [
880 if self.aux1_pwm1.is_some() {
881 format.aux1_pwm1
882 } else {
883 Resolution::Ignore
884 },
885 if self.aux1_pwm2.is_some() {
886 format.aux1_pwm2
887 } else {
888 Resolution::Ignore
889 },
890 if self.aux1_pwm3.is_some() {
891 format.aux1_pwm3
892 } else {
893 Resolution::Ignore
894 },
895 if self.aux1_pwm4.is_some() {
896 format.aux1_pwm4
897 } else {
898 Resolution::Ignore
899 },
900 if self.aux1_pwm5.is_some() {
901 format.aux1_pwm5
902 } else {
903 Resolution::Ignore
904 },
905 if self.aux2_pwm1.is_some() {
906 format.aux2_pwm1
907 } else {
908 Resolution::Ignore
909 },
910 if self.aux2_pwm2.is_some() {
911 format.aux2_pwm2
912 } else {
913 Resolution::Ignore
914 },
915 if self.aux2_pwm3.is_some() {
916 format.aux2_pwm3
917 } else {
918 Resolution::Ignore
919 },
920 if self.aux2_pwm4.is_some() {
921 format.aux2_pwm4
922 } else {
923 Resolution::Ignore
924 },
925 if self.aux2_pwm5.is_some() {
926 format.aux2_pwm5
927 } else {
928 Resolution::Ignore
929 },
930 ];
931
932 let mut combiner = WriteCombiner::new(0x00, Register::Aux1Pwm1.address(), &resolutions);
933
934 if combiner.maybe_write(&mut writer) {
935 writer.write_pwm(self.aux1_pwm1.unwrap_or(0.0), format.aux1_pwm1);
936 }
937 if combiner.maybe_write(&mut writer) {
938 writer.write_pwm(self.aux1_pwm2.unwrap_or(0.0), format.aux1_pwm2);
939 }
940 if combiner.maybe_write(&mut writer) {
941 writer.write_pwm(self.aux1_pwm3.unwrap_or(0.0), format.aux1_pwm3);
942 }
943 if combiner.maybe_write(&mut writer) {
944 writer.write_pwm(self.aux1_pwm4.unwrap_or(0.0), format.aux1_pwm4);
945 }
946 if combiner.maybe_write(&mut writer) {
947 writer.write_pwm(self.aux1_pwm5.unwrap_or(0.0), format.aux1_pwm5);
948 }
949 if combiner.maybe_write(&mut writer) {
950 writer.write_pwm(self.aux2_pwm1.unwrap_or(0.0), format.aux2_pwm1);
951 }
952 if combiner.maybe_write(&mut writer) {
953 writer.write_pwm(self.aux2_pwm2.unwrap_or(0.0), format.aux2_pwm2);
954 }
955 if combiner.maybe_write(&mut writer) {
956 writer.write_pwm(self.aux2_pwm3.unwrap_or(0.0), format.aux2_pwm3);
957 }
958 if combiner.maybe_write(&mut writer) {
959 writer.write_pwm(self.aux2_pwm4.unwrap_or(0.0), format.aux2_pwm4);
960 }
961 if combiner.maybe_write(&mut writer) {
962 writer.write_pwm(self.aux2_pwm5.unwrap_or(0.0), format.aux2_pwm5);
963 }
964 }
965}
966
967pub struct SetTrimCommand {
969 pub trim: i32,
971}
972
973impl SetTrimCommand {
974 pub fn new(trim: i32) -> Self {
976 SetTrimCommand { trim }
977 }
978
979 pub fn serialize(&self, frame: &mut CanFdFrame) {
981 let mut writer = WriteCanData::new(frame);
982
983 writer.write_u8(multiplex::WRITE_INT32 | 0x01);
984 writer.write_varuint(Register::ClockTrim.address() as u32);
985 writer.write_i32(self.trim);
986 }
987}
988
989#[cfg(test)]
990mod tests {
991 use super::*;
992
993 fn bytes(frame: &CanFdFrame) -> &[u8] {
994 &frame.data[..frame.size as usize]
995 }
996
997 #[test]
998 fn test_stop_command() {
999 let mut f = CanFdFrame::new();
1000 StopCommand::serialize(&mut f);
1001 assert_eq!(bytes(&f), [1, 0, 0]);
1002 }
1003
1004 #[test]
1005 fn test_brake_command() {
1006 let mut f = CanFdFrame::new();
1007 BrakeCommand::serialize(&mut f);
1008 assert_eq!(bytes(&f), [1, 0, 15]);
1009 }
1010
1011 #[test]
1012 fn test_position_command() {
1013 let mut f = CanFdFrame::new();
1014 PositionCommand::new()
1015 .position(0.5)
1016 .velocity(1.0)
1017 .serialize(&mut f, &PositionFormat::default());
1018 assert_eq!(bytes(&f), [1, 0, 10, 14, 32, 0, 0, 0, 63, 0, 0, 128, 63]);
1019 }
1020
1021 #[test]
1022 fn test_vfoc_command() {
1023 let mut f = CanFdFrame::new();
1024 VFOCCommand::new()
1025 .theta(1.0)
1026 .voltage(2.0)
1027 .serialize(&mut f, &VFOCFormat::default());
1028 assert_eq!(bytes(&f), [1, 0, 7, 14, 24, 131, 249, 162, 62, 0, 0, 0, 64]);
1029 }
1030
1031 #[test]
1032 fn test_current_command() {
1033 let mut f = CanFdFrame::new();
1034 CurrentCommand::new()
1035 .q_current(1.5)
1036 .d_current(0.5)
1037 .serialize(&mut f, &CurrentFormat::default());
1038 assert_eq!(bytes(&f), [1, 0, 9, 14, 28, 0, 0, 192, 63, 0, 0, 0, 63]);
1039 }
1040
1041 #[test]
1042 fn test_stay_within_command() {
1043 let mut f = CanFdFrame::new();
1044 StayWithinCommand::new()
1045 .lower_bound(-1.0)
1046 .upper_bound(1.0)
1047 .maximum_torque(0.3)
1048 .serialize(&mut f, &StayWithinFormat::default());
1049 assert_eq!(
1050 bytes(&f),
1051 [1, 0, 13, 14, 64, 0, 0, 128, 191, 0, 0, 128, 63, 13, 69, 154, 153, 153, 62]
1052 );
1053 }
1054
1055 #[test]
1056 fn test_zero_velocity_command() {
1057 let mut f = CanFdFrame::new();
1058 ZeroVelocityCommand::new()
1059 .kd_scale(0.5)
1060 .serialize(&mut f, &ZeroVelocityFormat::default());
1061 assert_eq!(bytes(&f), [1, 0, 12, 13, 36, 0, 0, 0, 63]);
1062 }
1063
1064 #[test]
1065 fn test_output_nearest_command() {
1066 let mut f = CanFdFrame::new();
1067 OutputNearestCommand::new(2.5).serialize(&mut f);
1068 assert_eq!(bytes(&f), [13, 176, 2, 0, 0, 32, 64]);
1069 }
1070
1071 #[test]
1072 fn test_output_exact_command() {
1073 let mut f = CanFdFrame::new();
1074 OutputExactCommand::new(3.0).serialize(&mut f);
1075 assert_eq!(bytes(&f), [13, 177, 2, 0, 0, 64, 64]);
1076 }
1077
1078 #[test]
1079 fn test_require_reindex_command() {
1080 let mut f = CanFdFrame::new();
1081 RequireReindexCommand::serialize(&mut f);
1082 assert_eq!(bytes(&f), [1, 178, 2, 1]);
1083 }
1084
1085 #[test]
1086 fn test_recapture_position_velocity_command() {
1087 let mut f = CanFdFrame::new();
1088 RecapturePositionVelocityCommand::serialize(&mut f);
1089 assert_eq!(bytes(&f), [1, 179, 2, 1]);
1090 }
1091
1092 #[test]
1093 fn test_aux_pwm_command() {
1094 let mut f = CanFdFrame::new();
1095 AuxPwmCommand::new()
1096 .aux1_pwm1(0.75)
1097 .aux2_pwm3(0.25)
1098 .serialize(&mut f, &AuxPwmFormat::default());
1099 assert_eq!(bytes(&f), [13, 118, 0, 0, 64, 63, 13, 125, 0, 0, 128, 62]);
1100 }
1101
1102 #[test]
1103 fn test_set_trim_command() {
1104 let mut f = CanFdFrame::new();
1105 SetTrimCommand::new(42).serialize(&mut f);
1106 assert_eq!(bytes(&f), [9, 113, 42, 0, 0, 0]);
1107 }
1108}