1use crate::fps_stats::FpsStatistics;
4use arc_swap::ArcSwap;
5use std::sync::{Arc, RwLock};
6
7#[derive(Debug, Clone, Default)]
12pub struct JointPositionState {
13 pub hardware_timestamp_us: u64,
17
18 pub system_timestamp_us: u64,
22
23 pub joint_pos: [f64; 6],
25
26 pub frame_valid_mask: u8,
30}
31
32impl JointPositionState {
33 pub fn is_fully_valid(&self) -> bool {
39 self.frame_valid_mask == 0b0000_0111 }
41
42 pub fn missing_frames(&self) -> Vec<usize> {
46 (0..3).filter(|&i| (self.frame_valid_mask & (1 << i)) == 0).collect()
47 }
48}
49
50#[derive(Debug, Clone, Default)]
55pub struct EndPoseState {
56 pub hardware_timestamp_us: u64,
58
59 pub system_timestamp_us: u64,
61
62 pub end_pose: [f64; 6],
67
68 pub frame_valid_mask: u8,
70}
71
72impl EndPoseState {
73 pub fn is_fully_valid(&self) -> bool {
79 self.frame_valid_mask == 0b0000_0111 }
81
82 pub fn missing_frames(&self) -> Vec<usize> {
86 (0..3).filter(|&i| (self.frame_valid_mask & (1 << i)) == 0).collect()
87 }
88}
89
90#[derive(Debug, Clone)]
95pub struct MotionSnapshot {
96 pub joint_position: JointPositionState,
98
99 pub end_pose: EndPoseState,
101 }
104
105#[derive(Debug, Clone, Default)]
112pub struct JointDynamicState {
113 pub group_timestamp_us: u64,
118
119 pub joint_vel: [f64; 6],
122 pub joint_current: [f64; 6],
128
129 pub timestamps: [u64; 6],
131
132 pub valid_mask: u8,
136}
137
138impl JointDynamicState {
139 pub const COEFFICIENT_1_3: f64 = 1.18125;
144
145 pub const COEFFICIENT_4_6: f64 = 0.95844;
150
151 pub fn calculate_torque(joint_index: usize, current: f64) -> f64 {
168 let coefficient = if joint_index < 3 {
169 Self::COEFFICIENT_1_3
170 } else {
171 Self::COEFFICIENT_4_6
172 };
173 current * coefficient
174 }
175
176 pub fn get_torque(&self, joint_index: usize) -> f64 {
194 if joint_index < 6 {
195 Self::calculate_torque(joint_index, self.joint_current[joint_index])
196 } else {
197 0.0
198 }
199 }
200
201 pub fn get_all_torques(&self) -> [f64; 6] {
218 [
219 Self::calculate_torque(0, self.joint_current[0]),
220 Self::calculate_torque(1, self.joint_current[1]),
221 Self::calculate_torque(2, self.joint_current[2]),
222 Self::calculate_torque(3, self.joint_current[3]),
223 Self::calculate_torque(4, self.joint_current[4]),
224 Self::calculate_torque(5, self.joint_current[5]),
225 ]
226 }
227
228 pub fn is_complete(&self) -> bool {
230 self.valid_mask == 0b111111
231 }
232
233 pub fn missing_joints(&self) -> Vec<usize> {
235 (0..6).filter(|&i| (self.valid_mask & (1 << i)) == 0).collect()
236 }
237}
238
239#[derive(Debug, Clone, Default)]
244pub struct RobotControlState {
245 pub hardware_timestamp_us: u64,
247
248 pub system_timestamp_us: u64,
250
251 pub control_mode: u8,
253
254 pub robot_status: u8,
256
257 pub move_mode: u8,
259
260 pub teach_status: u8,
262
263 pub motion_status: u8,
265
266 pub trajectory_point_index: u8,
268
269 pub fault_angle_limit_mask: u8,
273
274 pub fault_comm_error_mask: u8,
276
277 pub is_enabled: bool,
279
280 pub feedback_counter: u8,
284}
285
286impl RobotControlState {
287 pub fn is_angle_limit(&self, joint_index: usize) -> bool {
289 if joint_index >= 6 {
290 return false;
291 }
292 (self.fault_angle_limit_mask >> joint_index) & 1 == 1
293 }
294
295 pub fn is_comm_error(&self, joint_index: usize) -> bool {
297 if joint_index >= 6 {
298 return false;
299 }
300 (self.fault_comm_error_mask >> joint_index) & 1 == 1
301 }
302}
303
304#[derive(Debug, Clone, Default)]
309pub struct GripperState {
310 pub hardware_timestamp_us: u64,
312
313 pub system_timestamp_us: u64,
315
316 pub travel: f64,
318
319 pub torque: f64,
321
322 pub status_code: u8,
326
327 pub last_travel: f64,
331}
332
333impl GripperState {
334 pub fn is_voltage_low(&self) -> bool {
336 self.status_code & 1 == 1
337 }
338
339 pub fn is_motor_over_temp(&self) -> bool {
341 (self.status_code >> 1) & 1 == 1
342 }
343
344 pub fn is_over_current(&self) -> bool {
346 (self.status_code >> 2) & 1 == 1
347 }
348
349 pub fn is_driver_over_temp(&self) -> bool {
351 (self.status_code >> 3) & 1 == 1
352 }
353
354 pub fn is_sensor_error(&self) -> bool {
356 (self.status_code >> 4) & 1 == 1
357 }
358
359 pub fn is_driver_error(&self) -> bool {
361 (self.status_code >> 5) & 1 == 1
362 }
363
364 pub fn is_enabled(&self) -> bool {
366 (self.status_code >> 6) & 1 == 1
367 }
368
369 pub fn is_homed(&self) -> bool {
371 (self.status_code >> 7) & 1 == 1
372 }
373
374 pub fn is_moving(&self) -> bool {
378 (self.travel - self.last_travel).abs() > 0.1
379 }
380}
381
382#[derive(Debug, Clone, Default)]
390pub struct JointDriverLowSpeedState {
391 pub hardware_timestamp_us: u64,
393
394 pub system_timestamp_us: u64,
396
397 pub motor_temps: [f32; 6],
400 pub driver_temps: [f32; 6],
402
403 pub joint_voltage: [f32; 6],
406 pub joint_bus_current: [f32; 6],
408
409 pub driver_voltage_low_mask: u8,
412 pub driver_motor_over_temp_mask: u8,
414 pub driver_over_current_mask: u8,
416 pub driver_over_temp_mask: u8,
418 pub driver_collision_protection_mask: u8,
420 pub driver_error_mask: u8,
422 pub driver_enabled_mask: u8,
424 pub driver_stall_protection_mask: u8,
426
427 pub hardware_timestamps: [u64; 6],
430 pub system_timestamps: [u64; 6],
432
433 pub valid_mask: u8,
438}
439
440impl JointDriverLowSpeedState {
441 pub fn is_fully_valid(&self) -> bool {
443 self.valid_mask == 0b111111
444 }
445
446 pub fn missing_joints(&self) -> Vec<usize> {
448 (0..6).filter(|&i| (self.valid_mask & (1 << i)) == 0).collect()
449 }
450
451 pub fn is_voltage_low(&self, joint_index: usize) -> bool {
453 if joint_index >= 6 {
454 return false;
455 }
456 (self.driver_voltage_low_mask >> joint_index) & 1 == 1
457 }
458
459 pub fn is_motor_over_temp(&self, joint_index: usize) -> bool {
461 if joint_index >= 6 {
462 return false;
463 }
464 (self.driver_motor_over_temp_mask >> joint_index) & 1 == 1
465 }
466
467 pub fn is_over_current(&self, joint_index: usize) -> bool {
469 if joint_index >= 6 {
470 return false;
471 }
472 (self.driver_over_current_mask >> joint_index) & 1 == 1
473 }
474
475 pub fn is_driver_over_temp(&self, joint_index: usize) -> bool {
477 if joint_index >= 6 {
478 return false;
479 }
480 (self.driver_over_temp_mask >> joint_index) & 1 == 1
481 }
482
483 pub fn is_collision_protection(&self, joint_index: usize) -> bool {
485 if joint_index >= 6 {
486 return false;
487 }
488 (self.driver_collision_protection_mask >> joint_index) & 1 == 1
489 }
490
491 pub fn is_driver_error(&self, joint_index: usize) -> bool {
493 if joint_index >= 6 {
494 return false;
495 }
496 (self.driver_error_mask >> joint_index) & 1 == 1
497 }
498
499 pub fn is_enabled(&self, joint_index: usize) -> bool {
501 if joint_index >= 6 {
502 return false;
503 }
504 (self.driver_enabled_mask >> joint_index) & 1 == 1
505 }
506
507 pub fn is_stall_protection(&self, joint_index: usize) -> bool {
509 if joint_index >= 6 {
510 return false;
511 }
512 (self.driver_stall_protection_mask >> joint_index) & 1 == 1
513 }
514}
515
516#[derive(Debug, Clone, Default)]
524pub struct CollisionProtectionState {
525 pub hardware_timestamp_us: u64,
527
528 pub system_timestamp_us: u64,
530
531 pub protection_levels: [u8; 6],
537}
538
539#[derive(Debug, Clone, Default)]
549pub struct JointLimitConfigState {
550 pub last_update_hardware_timestamp_us: u64,
552
553 pub last_update_system_timestamp_us: u64,
555
556 pub joint_limits_max: [f64; 6],
559 pub joint_limits_min: [f64; 6],
561 pub joint_max_velocity: [f64; 6],
563
564 pub joint_update_hardware_timestamps: [u64; 6],
567 pub joint_update_system_timestamps: [u64; 6],
569
570 pub valid_mask: u8,
575}
576
577impl JointLimitConfigState {
578 pub fn is_fully_valid(&self) -> bool {
580 self.valid_mask == 0b111111
581 }
582
583 pub fn missing_joints(&self) -> Vec<usize> {
585 (0..6).filter(|&i| (self.valid_mask & (1 << i)) == 0).collect()
586 }
587}
588
589#[derive(Debug, Clone, Default)]
597pub struct JointAccelConfigState {
598 pub last_update_hardware_timestamp_us: u64,
600
601 pub last_update_system_timestamp_us: u64,
603
604 pub max_acc_limits: [f64; 6],
607
608 pub joint_update_hardware_timestamps: [u64; 6],
611 pub joint_update_system_timestamps: [u64; 6],
613
614 pub valid_mask: u8,
619}
620
621impl JointAccelConfigState {
622 pub fn is_fully_valid(&self) -> bool {
624 self.valid_mask == 0b111111
625 }
626
627 pub fn missing_joints(&self) -> Vec<usize> {
629 (0..6).filter(|&i| (self.valid_mask & (1 << i)) == 0).collect()
630 }
631}
632
633#[derive(Debug, Clone, Default)]
641pub struct EndLimitConfigState {
642 pub last_update_hardware_timestamp_us: u64,
644
645 pub last_update_system_timestamp_us: u64,
647
648 pub max_end_linear_velocity: f64,
651 pub max_end_angular_velocity: f64,
653 pub max_end_linear_accel: f64,
655 pub max_end_angular_accel: f64,
657
658 pub is_valid: bool,
661}
662
663#[derive(Debug, Clone, Default)]
673pub struct FirmwareVersionState {
674 pub hardware_timestamp_us: u64,
676
677 pub system_timestamp_us: u64,
679
680 pub firmware_data: Vec<u8>,
683
684 pub is_complete: bool,
687
688 pub version_string: Option<String>,
691}
692
693impl FirmwareVersionState {
694 pub fn clear(&mut self) {
698 self.firmware_data.clear();
699 self.version_string = None;
700 self.is_complete = false;
701 self.hardware_timestamp_us = 0;
702 self.system_timestamp_us = 0;
703 }
704
705 pub fn check_completeness(&mut self) -> bool {
714 if let Some(version_start) = self.firmware_data.windows(3).position(|w| w == b"S-V") {
715 let required_length = version_start + 8;
717 self.is_complete = self.firmware_data.len() >= required_length;
718 } else {
719 self.is_complete = false;
720 }
721 self.is_complete
722 }
723
724 pub fn parse_version(&mut self) -> Option<String> {
728 use piper_protocol::feedback::FirmwareReadFeedback;
730 if let Some(version) = FirmwareReadFeedback::parse_version_string(&self.firmware_data) {
731 self.version_string = Some(version.clone());
732 self.check_completeness();
734 Some(version)
735 } else {
736 self.version_string = None;
737 self.is_complete = false;
738 None
739 }
740 }
741
742 pub fn version_string(&self) -> Option<&String> {
744 self.version_string.as_ref()
745 }
746}
747
748#[derive(Debug, Clone, Default)]
758pub struct MasterSlaveControlModeState {
759 pub hardware_timestamp_us: u64,
761
762 pub system_timestamp_us: u64,
764
765 pub control_mode: u8, pub move_mode: u8, pub speed_percent: u8,
769 pub mit_mode: u8, pub trajectory_stay_time: u8,
771 pub install_position: u8, pub is_valid: bool,
775}
776
777#[derive(Debug, Clone, Default)]
785pub struct MasterSlaveJointControlState {
786 pub hardware_timestamp_us: u64,
788
789 pub system_timestamp_us: u64,
791
792 pub joint_target_deg: [i32; 6],
794
795 pub frame_valid_mask: u8,
799}
800
801impl MasterSlaveJointControlState {
802 pub fn is_fully_valid(&self) -> bool {
808 self.frame_valid_mask == 0b0000_0111 }
810
811 pub fn missing_frames(&self) -> Vec<usize> {
815 (0..3).filter(|&i| (self.frame_valid_mask & (1 << i)) == 0).collect()
816 }
817
818 pub fn joint_target_deg(&self, joint_index: usize) -> Option<f64> {
820 if joint_index < 6 {
821 Some(self.joint_target_deg[joint_index] as f64 / 1000.0)
822 } else {
823 None
824 }
825 }
826
827 pub fn joint_target_rad(&self, joint_index: usize) -> Option<f64> {
829 self.joint_target_deg(joint_index).map(|deg| deg * std::f64::consts::PI / 180.0)
830 }
831}
832
833#[derive(Debug, Clone, Default)]
839pub struct MasterSlaveGripperControlState {
840 pub hardware_timestamp_us: u64,
842
843 pub system_timestamp_us: u64,
845
846 pub gripper_target_travel_mm: i32,
848
849 pub gripper_target_torque_nm: i16,
851
852 pub gripper_status_code: u8,
854
855 pub gripper_set_zero: u8,
857
858 pub is_valid: bool,
860}
861
862impl MasterSlaveGripperControlState {
863 pub fn gripper_target_travel(&self) -> f64 {
865 self.gripper_target_travel_mm as f64 / 1000.0
866 }
867
868 pub fn gripper_target_torque(&self) -> f64 {
870 self.gripper_target_torque_nm as f64 / 1000.0
871 }
872}
873
874use crate::hooks::HookManager;
907
908pub struct PiperContext {
910 pub joint_position: Arc<ArcSwap<JointPositionState>>,
914 pub end_pose: Arc<ArcSwap<EndPoseState>>,
916 pub joint_dynamic: Arc<ArcSwap<JointDynamicState>>,
918
919 pub robot_control: Arc<ArcSwap<RobotControlState>>,
923
924 pub gripper: Arc<ArcSwap<GripperState>>,
926
927 pub joint_driver_low_speed: Arc<ArcSwap<JointDriverLowSpeedState>>,
931
932 pub collision_protection: Arc<RwLock<CollisionProtectionState>>,
936
937 pub joint_limit_config: Arc<RwLock<JointLimitConfigState>>,
939
940 pub joint_accel_config: Arc<RwLock<JointAccelConfigState>>,
942
943 pub end_limit_config: Arc<RwLock<EndLimitConfigState>>,
945
946 pub firmware_version: Arc<RwLock<FirmwareVersionState>>,
949
950 pub master_slave_control_mode: Arc<ArcSwap<MasterSlaveControlModeState>>,
953
954 pub master_slave_joint_control: Arc<ArcSwap<MasterSlaveJointControlState>>,
956
957 pub master_slave_gripper_control: Arc<ArcSwap<MasterSlaveGripperControlState>>,
959
960 pub fps_stats: Arc<ArcSwap<FpsStatistics>>,
967
968 pub connection_monitor: crate::heartbeat::ConnectionMonitor,
973
974 pub hooks: Arc<RwLock<HookManager>>,
1004}
1005
1006impl PiperContext {
1007 pub fn new() -> Self {
1025 Self {
1026 joint_position: Arc::new(ArcSwap::from_pointee(JointPositionState::default())),
1028 end_pose: Arc::new(ArcSwap::from_pointee(EndPoseState::default())),
1029 joint_dynamic: Arc::new(ArcSwap::from_pointee(JointDynamicState::default())),
1030
1031 robot_control: Arc::new(ArcSwap::from_pointee(RobotControlState::default())),
1033 gripper: Arc::new(ArcSwap::from_pointee(GripperState::default())),
1034 joint_driver_low_speed: Arc::new(ArcSwap::from_pointee(
1035 JointDriverLowSpeedState::default(),
1036 )),
1037
1038 collision_protection: Arc::new(RwLock::new(CollisionProtectionState::default())),
1040 joint_limit_config: Arc::new(RwLock::new(JointLimitConfigState::default())),
1041 joint_accel_config: Arc::new(RwLock::new(JointAccelConfigState::default())),
1042 end_limit_config: Arc::new(RwLock::new(EndLimitConfigState::default())),
1043
1044 firmware_version: Arc::new(RwLock::new(FirmwareVersionState::default())),
1046
1047 master_slave_control_mode: Arc::new(ArcSwap::from_pointee(
1049 MasterSlaveControlModeState::default(),
1050 )),
1051 master_slave_joint_control: Arc::new(ArcSwap::from_pointee(
1052 MasterSlaveJointControlState::default(),
1053 )),
1054 master_slave_gripper_control: Arc::new(ArcSwap::from_pointee(
1055 MasterSlaveGripperControlState::default(),
1056 )),
1057
1058 fps_stats: Arc::new(ArcSwap::from_pointee(FpsStatistics::new())),
1060
1061 connection_monitor: crate::heartbeat::ConnectionMonitor::new(
1063 std::time::Duration::from_secs(1),
1064 ),
1065
1066 hooks: Arc::new(RwLock::new(HookManager::new())),
1068 }
1069 }
1070
1071 pub fn capture_motion_snapshot(&self) -> MotionSnapshot {
1091 MotionSnapshot {
1092 joint_position: self.joint_position.load().as_ref().clone(),
1093 end_pose: self.end_pose.load().as_ref().clone(),
1094 }
1095 }
1096}
1097
1098impl Default for PiperContext {
1099 fn default() -> Self {
1100 Self::new()
1101 }
1102}
1103
1104pub struct CombinedMotionState {
1106 pub joint_position: JointPositionState,
1107 pub end_pose: EndPoseState,
1108 pub joint_dynamic: JointDynamicState,
1109}
1110
1111#[derive(Debug)]
1115pub struct AlignedMotionState {
1116 pub joint_pos: [f64; 6],
1117 pub joint_vel: [f64; 6],
1118 pub joint_current: [f64; 6],
1119 pub end_pose: [f64; 6],
1120 pub timestamp: u64, pub time_diff_us: i64, }
1123
1124#[derive(Debug)]
1128pub enum AlignmentResult {
1129 Ok(AlignedMotionState),
1131 Misaligned {
1133 state: AlignedMotionState,
1134 diff_us: u64,
1135 },
1136}
1137
1138#[cfg(test)]
1139mod tests {
1140 use super::{EndPoseState, JointPositionState, MotionSnapshot, PiperContext};
1141 use std::f64::consts::PI;
1142
1143 use super::JointDynamicState;
1144
1145 #[test]
1146 fn test_joint_dynamic_state_is_complete() {
1147 let state = JointDynamicState {
1148 valid_mask: 0b111111, ..Default::default()
1150 };
1151 assert!(state.is_complete());
1152
1153 let state2 = JointDynamicState {
1154 valid_mask: 0b111110, ..Default::default()
1156 };
1157 assert!(!state2.is_complete());
1158 }
1159
1160 #[test]
1161 fn test_joint_dynamic_state_missing_joints() {
1162 let state = JointDynamicState {
1165 valid_mask: 0b001111, ..Default::default()
1167 };
1168 let missing = state.missing_joints();
1169 assert_eq!(missing, vec![4, 5]); let state2 = JointDynamicState {
1173 valid_mask: 0b000101, ..Default::default()
1175 };
1176 let missing = state2.missing_joints();
1177 assert_eq!(missing, vec![1, 3, 4, 5]); }
1179
1180 #[test]
1181 fn test_joint_dynamic_state_calculate_torque() {
1182 let torque_j1 = JointDynamicState::calculate_torque(0, 1.0);
1184 assert!((torque_j1 - 1.18125).abs() < 0.0001);
1185
1186 let torque_j2 = JointDynamicState::calculate_torque(1, 2.0);
1187 assert!((torque_j2 - 2.3625).abs() < 0.0001);
1188
1189 let torque_j3 = JointDynamicState::calculate_torque(2, 0.5);
1190 assert!((torque_j3 - 0.590625).abs() < 0.0001);
1191
1192 let torque_j4 = JointDynamicState::calculate_torque(3, 1.0);
1194 assert!((torque_j4 - 0.95844).abs() < 0.0001);
1195
1196 let torque_j5 = JointDynamicState::calculate_torque(4, 2.0);
1197 assert!((torque_j5 - 1.91688).abs() < 0.0001);
1198
1199 let torque_j6 = JointDynamicState::calculate_torque(5, 0.5);
1200 assert!((torque_j6 - 0.47922).abs() < 0.0001);
1201 }
1202
1203 #[test]
1204 fn test_joint_dynamic_state_get_torque() {
1205 let state = JointDynamicState {
1206 joint_current: [1.0, 2.0, 0.5, 1.0, 2.0, 0.5],
1207 ..Default::default()
1208 };
1209
1210 assert!((state.get_torque(0) - 1.18125).abs() < 0.0001); assert!((state.get_torque(1) - 2.3625).abs() < 0.0001); assert!((state.get_torque(2) - 0.590625).abs() < 0.0001); assert!((state.get_torque(3) - 0.95844).abs() < 0.0001); assert!((state.get_torque(4) - 1.91688).abs() < 0.0001); assert!((state.get_torque(5) - 0.47922).abs() < 0.0001); assert_eq!(state.get_torque(6), 0.0);
1222 assert_eq!(state.get_torque(100), 0.0);
1223 }
1224
1225 #[test]
1226 fn test_joint_dynamic_state_get_all_torques() {
1227 let state = JointDynamicState {
1228 joint_current: [1.0, 2.0, 0.5, 1.0, 2.0, 0.5],
1229 ..Default::default()
1230 };
1231
1232 let all_torques = state.get_all_torques();
1233
1234 assert!((all_torques[0] - 1.18125).abs() < 0.0001); assert!((all_torques[1] - 2.3625).abs() < 0.0001); assert!((all_torques[2] - 0.590625).abs() < 0.0001); assert!((all_torques[3] - 0.95844).abs() < 0.0001); assert!((all_torques[4] - 1.91688).abs() < 0.0001); assert!((all_torques[5] - 0.47922).abs() < 0.0001); for (i, &torque) in all_torques.iter().enumerate() {
1246 assert!((torque - state.get_torque(i)).abs() < 0.0001);
1247 }
1248 }
1249
1250 #[test]
1251 fn test_joint_dynamic_state_default() {
1252 let state = JointDynamicState::default();
1253 assert_eq!(state.group_timestamp_us, 0);
1254 assert_eq!(state.joint_vel, [0.0; 6]);
1255 assert_eq!(state.joint_current, [0.0; 6]);
1256 assert_eq!(state.timestamps, [0; 6]);
1257 assert_eq!(state.valid_mask, 0);
1258 assert!(!state.is_complete());
1259 assert_eq!(state.missing_joints(), vec![0, 1, 2, 3, 4, 5]);
1260 assert_eq!(state.get_torque(0), 0.0);
1262 assert_eq!(state.get_torque(5), 0.0);
1263 }
1264
1265 use super::*;
1266
1267 #[test]
1268 fn test_piper_context_new() {
1269 let ctx = PiperContext::new();
1270 let joint_pos = ctx.joint_position.load();
1272 assert_eq!(joint_pos.hardware_timestamp_us, 0);
1273 assert_eq!(joint_pos.joint_pos, [0.0; 6]);
1274
1275 let end_pose = ctx.end_pose.load();
1276 assert_eq!(end_pose.hardware_timestamp_us, 0);
1277 assert_eq!(end_pose.end_pose, [0.0; 6]);
1278
1279 let joint_dynamic = ctx.joint_dynamic.load();
1280 assert_eq!(joint_dynamic.group_timestamp_us, 0);
1281
1282 let robot_control = ctx.robot_control.load();
1283 assert_eq!(robot_control.hardware_timestamp_us, 0);
1284
1285 let driver_state = ctx.joint_driver_low_speed.load();
1286 assert_eq!(driver_state.hardware_timestamp_us, 0);
1287
1288 let limits = ctx.joint_limit_config.read().unwrap();
1289 assert_eq!(limits.joint_limits_max, [0.0; 6]);
1290 }
1291
1292 #[test]
1293 fn test_joint_dynamic_state_clone() {
1294 let state = JointDynamicState {
1295 group_timestamp_us: 1000,
1296 joint_vel: [1.0, 2.0, 3.0, 4.0, 5.0, 6.0],
1297 joint_current: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6],
1298 timestamps: [100, 200, 300, 400, 500, 600],
1299 valid_mask: 0b111111,
1300 };
1301 let cloned = state.clone();
1302 assert_eq!(state.group_timestamp_us, cloned.group_timestamp_us);
1303 assert_eq!(state.joint_vel, cloned.joint_vel);
1304 assert_eq!(state.joint_current, cloned.joint_current);
1305 assert_eq!(state.timestamps, cloned.timestamps);
1306 assert_eq!(state.valid_mask, cloned.valid_mask);
1307 assert_eq!(state.is_complete(), cloned.is_complete());
1308 for i in 0..6 {
1310 assert!((state.get_torque(i) - cloned.get_torque(i)).abs() < 0.0001);
1311 }
1312 }
1313
1314 #[test]
1315 fn test_aligned_motion_state_debug() {
1316 let state = AlignedMotionState {
1317 joint_pos: [1.0; 6],
1318 joint_vel: [2.0; 6],
1319 joint_current: [3.0; 6],
1320 end_pose: [4.0; 6],
1321 timestamp: 1000,
1322 time_diff_us: 500,
1323 };
1324 let debug_str = format!("{:?}", state);
1325 assert!(debug_str.contains("AlignedMotionState"));
1326 }
1327
1328 #[test]
1329 fn test_alignment_result_debug() {
1330 let state = AlignedMotionState {
1331 joint_pos: [1.0; 6],
1332 joint_vel: [2.0; 6],
1333 joint_current: [3.0; 6],
1334 end_pose: [4.0; 6],
1335 timestamp: 1000,
1336 time_diff_us: 500,
1337 };
1338 let result_ok = AlignmentResult::Ok(state);
1339 let debug_str = format!("{:?}", result_ok);
1340 assert!(debug_str.contains("Ok") || debug_str.contains("AlignmentResult"));
1341
1342 let state2 = AlignedMotionState {
1343 joint_pos: [1.0; 6],
1344 joint_vel: [2.0; 6],
1345 joint_current: [3.0; 6],
1346 end_pose: [4.0; 6],
1347 timestamp: 1000,
1348 time_diff_us: 500,
1349 };
1350 let result_mis = AlignmentResult::Misaligned {
1351 state: state2,
1352 diff_us: 10000,
1353 };
1354 let debug_str2 = format!("{:?}", result_mis);
1355 assert!(debug_str2.contains("Misaligned") || debug_str2.contains("AlignmentResult"));
1356 }
1357
1358 #[test]
1363 fn test_joint_position_state_default() {
1364 let state = JointPositionState::default();
1365 assert_eq!(state.hardware_timestamp_us, 0);
1366 assert_eq!(state.system_timestamp_us, 0);
1367 assert_eq!(state.joint_pos, [0.0; 6]);
1368 assert_eq!(state.frame_valid_mask, 0);
1369 }
1370
1371 #[test]
1372 fn test_joint_position_state_is_fully_valid() {
1373 let state = JointPositionState {
1375 hardware_timestamp_us: 1000,
1376 system_timestamp_us: 2000,
1377 joint_pos: [1.0, 2.0, 3.0, 4.0, 5.0, 6.0],
1378 frame_valid_mask: 0b0000_0111, };
1380 assert!(state.is_fully_valid());
1381
1382 let state_incomplete = JointPositionState {
1384 frame_valid_mask: 0b0000_0011, ..state
1386 };
1387 assert!(!state_incomplete.is_fully_valid());
1388
1389 let state_empty = JointPositionState {
1391 frame_valid_mask: 0b0000_0000,
1392 ..state
1393 };
1394 assert!(!state_empty.is_fully_valid());
1395 }
1396
1397 #[test]
1398 fn test_joint_position_state_missing_frames() {
1399 let state_complete = JointPositionState {
1401 frame_valid_mask: 0b0000_0111,
1402 ..Default::default()
1403 };
1404 assert_eq!(state_complete.missing_frames(), Vec::<usize>::new());
1405
1406 let state_missing_first = JointPositionState {
1408 frame_valid_mask: 0b0000_0110, ..Default::default()
1410 };
1411 assert_eq!(state_missing_first.missing_frames(), vec![0]);
1412
1413 let state_missing_middle = JointPositionState {
1415 frame_valid_mask: 0b0000_0101, ..Default::default()
1417 };
1418 assert_eq!(state_missing_middle.missing_frames(), vec![1]);
1419
1420 let state_missing_last = JointPositionState {
1422 frame_valid_mask: 0b0000_0011, ..Default::default()
1424 };
1425 assert_eq!(state_missing_last.missing_frames(), vec![2]);
1426
1427 let state_missing_multiple = JointPositionState {
1429 frame_valid_mask: 0b0000_0001, ..Default::default()
1431 };
1432 let missing = state_missing_multiple.missing_frames();
1433 assert_eq!(missing.len(), 2);
1434 assert!(missing.contains(&1));
1435 assert!(missing.contains(&2));
1436 }
1437
1438 #[test]
1439 fn test_joint_position_state_clone() {
1440 let state = JointPositionState {
1441 hardware_timestamp_us: 1000,
1442 system_timestamp_us: 2000,
1443 joint_pos: [1.0, 2.0, 3.0, 4.0, 5.0, 6.0],
1444 frame_valid_mask: 0b0000_0111,
1445 };
1446 let cloned = state.clone();
1447 assert_eq!(state.hardware_timestamp_us, cloned.hardware_timestamp_us);
1448 assert_eq!(state.system_timestamp_us, cloned.system_timestamp_us);
1449 assert_eq!(state.joint_pos, cloned.joint_pos);
1450 assert_eq!(state.frame_valid_mask, cloned.frame_valid_mask);
1451 assert_eq!(state.is_fully_valid(), cloned.is_fully_valid());
1452 }
1453
1454 #[test]
1455 fn test_end_pose_state_default() {
1456 let state = EndPoseState::default();
1457 assert_eq!(state.hardware_timestamp_us, 0);
1458 assert_eq!(state.system_timestamp_us, 0);
1459 assert_eq!(state.end_pose, [0.0; 6]);
1460 assert_eq!(state.frame_valid_mask, 0);
1461 }
1462
1463 #[test]
1464 fn test_end_pose_state_is_fully_valid() {
1465 let state = EndPoseState {
1467 hardware_timestamp_us: 1000,
1468 system_timestamp_us: 2000,
1469 end_pose: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6],
1470 frame_valid_mask: 0b0000_0111, };
1472 assert!(state.is_fully_valid());
1473
1474 let state_incomplete = EndPoseState {
1476 frame_valid_mask: 0b0000_0011, ..state
1478 };
1479 assert!(!state_incomplete.is_fully_valid());
1480 }
1481
1482 #[test]
1483 fn test_end_pose_state_missing_frames() {
1484 let state_complete = EndPoseState {
1486 frame_valid_mask: 0b0000_0111,
1487 ..Default::default()
1488 };
1489 assert_eq!(state_complete.missing_frames(), Vec::<usize>::new());
1490
1491 let state_missing_first = EndPoseState {
1493 frame_valid_mask: 0b0000_0110, ..Default::default()
1495 };
1496 assert_eq!(state_missing_first.missing_frames(), vec![0]);
1497
1498 let state_missing_middle = EndPoseState {
1500 frame_valid_mask: 0b0000_0101, ..Default::default()
1502 };
1503 assert_eq!(state_missing_middle.missing_frames(), vec![1]);
1504
1505 let state_missing_last = EndPoseState {
1507 frame_valid_mask: 0b0000_0011, ..Default::default()
1509 };
1510 assert_eq!(state_missing_last.missing_frames(), vec![2]);
1511 }
1512
1513 #[test]
1514 fn test_end_pose_state_clone() {
1515 let state = EndPoseState {
1516 hardware_timestamp_us: 1000,
1517 system_timestamp_us: 2000,
1518 end_pose: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6],
1519 frame_valid_mask: 0b0000_0111,
1520 };
1521 let cloned = state.clone();
1522 assert_eq!(state.hardware_timestamp_us, cloned.hardware_timestamp_us);
1523 assert_eq!(state.system_timestamp_us, cloned.system_timestamp_us);
1524 assert_eq!(state.end_pose, cloned.end_pose);
1525 assert_eq!(state.frame_valid_mask, cloned.frame_valid_mask);
1526 assert_eq!(state.is_fully_valid(), cloned.is_fully_valid());
1527 }
1528
1529 #[test]
1530 fn test_motion_snapshot_default() {
1531 let snapshot = MotionSnapshot {
1532 joint_position: JointPositionState::default(),
1533 end_pose: EndPoseState::default(),
1534 };
1535 assert_eq!(snapshot.joint_position.hardware_timestamp_us, 0);
1536 assert_eq!(snapshot.end_pose.hardware_timestamp_us, 0);
1537 }
1538
1539 #[test]
1540 fn test_motion_snapshot_clone() {
1541 let snapshot = MotionSnapshot {
1542 joint_position: JointPositionState {
1543 hardware_timestamp_us: 1000,
1544 system_timestamp_us: 2000,
1545 joint_pos: [1.0, 2.0, 3.0, 4.0, 5.0, 6.0],
1546 frame_valid_mask: 0b0000_0111,
1547 },
1548 end_pose: EndPoseState {
1549 hardware_timestamp_us: 1500,
1550 system_timestamp_us: 2500,
1551 end_pose: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6],
1552 frame_valid_mask: 0b0000_0111,
1553 },
1554 };
1555 let cloned = snapshot.clone();
1556 assert_eq!(
1557 snapshot.joint_position.joint_pos,
1558 cloned.joint_position.joint_pos
1559 );
1560 assert_eq!(snapshot.end_pose.end_pose, cloned.end_pose.end_pose);
1561 }
1562
1563 #[test]
1564 fn test_piper_context_capture_motion_snapshot() {
1565 let ctx = PiperContext::new();
1566
1567 let snapshot = ctx.capture_motion_snapshot();
1569 assert_eq!(snapshot.joint_position.hardware_timestamp_us, 0);
1570 assert_eq!(snapshot.end_pose.hardware_timestamp_us, 0);
1571 assert_eq!(snapshot.joint_position.joint_pos, [0.0; 6]);
1572 assert_eq!(snapshot.end_pose.end_pose, [0.0; 6]);
1573 }
1574
1575 #[test]
1576 fn test_piper_context_new_states() {
1577 let ctx = PiperContext::new();
1578
1579 let joint_pos = ctx.joint_position.load();
1581 assert_eq!(joint_pos.hardware_timestamp_us, 0);
1582 assert_eq!(joint_pos.joint_pos, [0.0; 6]);
1583
1584 let end_pose = ctx.end_pose.load();
1585 assert_eq!(end_pose.hardware_timestamp_us, 0);
1586 assert_eq!(end_pose.end_pose, [0.0; 6]);
1587 }
1588
1589 #[test]
1594 fn test_gripper_state_default() {
1595 let state = GripperState::default();
1596 assert_eq!(state.hardware_timestamp_us, 0);
1597 assert_eq!(state.system_timestamp_us, 0);
1598 assert_eq!(state.travel, 0.0);
1599 assert_eq!(state.torque, 0.0);
1600 assert_eq!(state.status_code, 0);
1601 assert_eq!(state.last_travel, 0.0);
1602 }
1603
1604 #[test]
1605 fn test_gripper_state_status_flags() {
1606 let state_voltage_low = GripperState {
1608 status_code: 0b0000_0001, ..Default::default()
1610 };
1611 assert!(state_voltage_low.is_voltage_low());
1612 assert!(!state_voltage_low.is_motor_over_temp());
1613
1614 let state_motor_over_temp = GripperState {
1615 status_code: 0b0000_0010, ..Default::default()
1617 };
1618 assert!(state_motor_over_temp.is_motor_over_temp());
1619 assert!(!state_motor_over_temp.is_voltage_low());
1620
1621 let state_over_current = GripperState {
1622 status_code: 0b0000_0100, ..Default::default()
1624 };
1625 assert!(state_over_current.is_over_current());
1626
1627 let state_driver_over_temp = GripperState {
1628 status_code: 0b0000_1000, ..Default::default()
1630 };
1631 assert!(state_driver_over_temp.is_driver_over_temp());
1632
1633 let state_sensor_error = GripperState {
1634 status_code: 0b0001_0000, ..Default::default()
1636 };
1637 assert!(state_sensor_error.is_sensor_error());
1638
1639 let state_driver_error = GripperState {
1640 status_code: 0b0010_0000, ..Default::default()
1642 };
1643 assert!(state_driver_error.is_driver_error());
1644
1645 let state_enabled = GripperState {
1646 status_code: 0b0100_0000, ..Default::default()
1648 };
1649 assert!(state_enabled.is_enabled());
1650
1651 let state_homed = GripperState {
1652 status_code: 0b1000_0000, ..Default::default()
1654 };
1655 assert!(state_homed.is_homed());
1656
1657 let state_multiple = GripperState {
1659 status_code: 0b1100_0011, ..Default::default()
1661 };
1662 assert!(state_multiple.is_voltage_low());
1663 assert!(state_multiple.is_motor_over_temp());
1664 assert!(state_multiple.is_enabled());
1665 assert!(state_multiple.is_homed());
1666 assert!(!state_multiple.is_over_current());
1667 }
1668
1669 #[test]
1670 fn test_gripper_state_is_moving() {
1671 let state_stationary = GripperState {
1673 travel: 50.0,
1674 last_travel: 50.05, ..Default::default()
1676 };
1677 assert!(!state_stationary.is_moving());
1678
1679 let state_moving = GripperState {
1681 travel: 50.0,
1682 last_travel: 50.2, ..Default::default()
1684 };
1685 assert!(state_moving.is_moving());
1686
1687 let state_moving_backward = GripperState {
1689 travel: 50.0,
1690 last_travel: 49.8, ..Default::default()
1692 };
1693 assert!(state_moving_backward.is_moving());
1694 }
1695
1696 #[test]
1697 fn test_gripper_state_clone() {
1698 let state = GripperState {
1699 hardware_timestamp_us: 1000,
1700 system_timestamp_us: 2000,
1701 travel: 50.5,
1702 torque: 2.5,
1703 status_code: 0b1100_0011,
1704 last_travel: 50.0,
1705 };
1706 let cloned = state.clone();
1707 assert_eq!(state.hardware_timestamp_us, cloned.hardware_timestamp_us);
1708 assert_eq!(state.system_timestamp_us, cloned.system_timestamp_us);
1709 assert_eq!(state.travel, cloned.travel);
1710 assert_eq!(state.torque, cloned.torque);
1711 assert_eq!(state.status_code, cloned.status_code);
1712 assert_eq!(state.last_travel, cloned.last_travel);
1713 assert_eq!(state.is_voltage_low(), cloned.is_voltage_low());
1714 assert_eq!(state.is_moving(), cloned.is_moving());
1715 }
1716
1717 #[test]
1718 fn test_robot_control_state_default() {
1719 let state = RobotControlState::default();
1720 assert_eq!(state.hardware_timestamp_us, 0);
1721 assert_eq!(state.system_timestamp_us, 0);
1722 assert_eq!(state.control_mode, 0);
1723 assert_eq!(state.robot_status, 0);
1724 assert_eq!(state.fault_angle_limit_mask, 0);
1725 assert_eq!(state.fault_comm_error_mask, 0);
1726 assert_eq!(state.feedback_counter, 0);
1727 assert!(!state.is_enabled);
1728 }
1729
1730 #[test]
1731 fn test_robot_control_state_is_angle_limit() {
1732 let state_j1 = RobotControlState {
1734 fault_angle_limit_mask: 0b0000_0001, ..Default::default()
1736 };
1737 assert!(state_j1.is_angle_limit(0));
1738 assert!(!state_j1.is_angle_limit(1));
1739 assert!(!state_j1.is_angle_limit(5));
1740
1741 let state_multiple = RobotControlState {
1745 fault_angle_limit_mask: 0b0010_0001, ..Default::default()
1747 };
1748 assert!(state_multiple.is_angle_limit(0)); assert!(!state_multiple.is_angle_limit(1)); assert!(!state_multiple.is_angle_limit(2)); assert!(!state_multiple.is_angle_limit(3)); assert!(!state_multiple.is_angle_limit(4)); assert!(state_multiple.is_angle_limit(5)); assert!(!state_j1.is_angle_limit(6)); assert!(!state_j1.is_angle_limit(100)); }
1759
1760 #[test]
1761 fn test_robot_control_state_is_comm_error() {
1762 let state_j3 = RobotControlState {
1764 fault_comm_error_mask: 0b0000_0100, ..Default::default()
1766 };
1767 assert!(!state_j3.is_comm_error(0));
1768 assert!(!state_j3.is_comm_error(1));
1769 assert!(state_j3.is_comm_error(2));
1770 assert!(!state_j3.is_comm_error(3));
1771
1772 let state_all = RobotControlState {
1774 fault_comm_error_mask: 0b0011_1111, ..Default::default()
1776 };
1777 for i in 0..6 {
1778 assert!(state_all.is_comm_error(i));
1779 }
1780
1781 assert!(!state_j3.is_comm_error(6)); }
1784
1785 #[test]
1786 fn test_robot_control_state_clone() {
1787 let state = RobotControlState {
1788 hardware_timestamp_us: 1000,
1789 system_timestamp_us: 2000,
1790 control_mode: 1,
1791 robot_status: 2,
1792 move_mode: 3,
1793 teach_status: 4,
1794 motion_status: 5,
1795 trajectory_point_index: 10,
1796 fault_angle_limit_mask: 0b0011_0001,
1797 fault_comm_error_mask: 0b0000_0100,
1798 is_enabled: true,
1799 feedback_counter: 5,
1800 };
1801 let cloned = state.clone();
1802 assert_eq!(state.hardware_timestamp_us, cloned.hardware_timestamp_us);
1803 assert_eq!(state.control_mode, cloned.control_mode);
1804 assert_eq!(state.fault_angle_limit_mask, cloned.fault_angle_limit_mask);
1805 assert_eq!(state.fault_comm_error_mask, cloned.fault_comm_error_mask);
1806 assert_eq!(state.is_enabled, cloned.is_enabled);
1807 assert_eq!(state.is_angle_limit(0), cloned.is_angle_limit(0));
1808 assert_eq!(state.is_comm_error(2), cloned.is_comm_error(2));
1809 }
1810
1811 #[test]
1812 fn test_piper_context_gripper_and_robot_control() {
1813 let ctx = PiperContext::new();
1814
1815 let gripper = ctx.gripper.load();
1817 assert_eq!(gripper.hardware_timestamp_us, 0);
1818 assert_eq!(gripper.travel, 0.0);
1819 assert_eq!(gripper.status_code, 0);
1820
1821 let robot_control = ctx.robot_control.load();
1823 assert_eq!(robot_control.hardware_timestamp_us, 0);
1824 assert_eq!(robot_control.control_mode, 0);
1825 assert_eq!(robot_control.fault_angle_limit_mask, 0);
1826 assert!(!robot_control.is_enabled);
1827 }
1828
1829 #[test]
1834 fn test_joint_driver_low_speed_state_default() {
1835 let state = JointDriverLowSpeedState::default();
1836 assert_eq!(state.hardware_timestamp_us, 0);
1837 assert_eq!(state.system_timestamp_us, 0);
1838 assert_eq!(state.motor_temps, [0.0; 6]);
1839 assert_eq!(state.driver_temps, [0.0; 6]);
1840 assert_eq!(state.joint_voltage, [0.0; 6]);
1841 assert_eq!(state.joint_bus_current, [0.0; 6]);
1842 assert_eq!(state.driver_voltage_low_mask, 0);
1843 assert_eq!(state.valid_mask, 0);
1844 }
1845
1846 #[test]
1847 fn test_joint_driver_low_speed_state_is_fully_valid() {
1848 let state_complete = JointDriverLowSpeedState {
1850 valid_mask: 0b111111, ..Default::default()
1852 };
1853 assert!(state_complete.is_fully_valid());
1854
1855 let state_incomplete = JointDriverLowSpeedState {
1857 valid_mask: 0b001111, ..Default::default()
1859 };
1860 assert!(!state_incomplete.is_fully_valid());
1861 }
1862
1863 #[test]
1864 fn test_joint_driver_low_speed_state_missing_joints() {
1865 let state_complete = JointDriverLowSpeedState {
1867 valid_mask: 0b111111,
1868 ..Default::default()
1869 };
1870 assert_eq!(state_complete.missing_joints(), Vec::<usize>::new());
1871
1872 let state_missing = JointDriverLowSpeedState {
1874 valid_mask: 0b0011110, ..Default::default()
1876 };
1877 let missing = state_missing.missing_joints();
1878 assert_eq!(missing.len(), 2);
1879 assert!(missing.contains(&0));
1880 assert!(missing.contains(&5));
1881 }
1882
1883 #[test]
1884 fn test_joint_driver_low_speed_state_status_flags() {
1885 let state_j1_voltage_low = JointDriverLowSpeedState {
1887 driver_voltage_low_mask: 0b0000_0001, ..Default::default()
1889 };
1890 assert!(state_j1_voltage_low.is_voltage_low(0));
1891 assert!(!state_j1_voltage_low.is_voltage_low(1));
1892
1893 let state_j3_motor_over_temp = JointDriverLowSpeedState {
1894 driver_motor_over_temp_mask: 0b0000_0100, ..Default::default()
1896 };
1897 assert!(state_j3_motor_over_temp.is_motor_over_temp(2));
1898 assert!(!state_j3_motor_over_temp.is_motor_over_temp(0));
1899
1900 let state_j6_over_current = JointDriverLowSpeedState {
1901 driver_over_current_mask: 0b0010_0000, ..Default::default()
1903 };
1904 assert!(state_j6_over_current.is_over_current(5));
1905 assert!(!state_j6_over_current.is_over_current(0));
1906
1907 let state_multiple = JointDriverLowSpeedState {
1909 driver_voltage_low_mask: 0b0010_0001, driver_enabled_mask: 0b111111, ..Default::default()
1912 };
1913 assert!(state_multiple.is_voltage_low(0));
1914 assert!(!state_multiple.is_voltage_low(1));
1915 assert!(state_multiple.is_voltage_low(5));
1916 assert!(state_multiple.is_enabled(0));
1917 assert!(state_multiple.is_enabled(5));
1918 }
1919
1920 #[test]
1921 fn test_joint_driver_low_speed_state_all_status_methods() {
1922 let state = JointDriverLowSpeedState {
1923 driver_voltage_low_mask: 0b0000_0001, driver_motor_over_temp_mask: 0b0000_0010, driver_over_current_mask: 0b0000_0100, driver_over_temp_mask: 0b0000_1000, driver_collision_protection_mask: 0b0001_0000, driver_error_mask: 0b0010_0000, driver_enabled_mask: 0b111111, driver_stall_protection_mask: 0b0000_0001, ..Default::default()
1932 };
1933
1934 assert!(state.is_voltage_low(0));
1935 assert!(state.is_motor_over_temp(1));
1936 assert!(state.is_over_current(2));
1937 assert!(state.is_driver_over_temp(3));
1938 assert!(state.is_collision_protection(4));
1939 assert!(state.is_driver_error(5));
1940 assert!(state.is_enabled(0));
1941 assert!(state.is_enabled(5));
1942 assert!(state.is_stall_protection(0));
1943 }
1944
1945 #[test]
1946 fn test_joint_driver_low_speed_state_clone() {
1947 let state = JointDriverLowSpeedState {
1948 hardware_timestamp_us: 1000,
1949 system_timestamp_us: 2000,
1950 motor_temps: [25.0, 26.0, 27.0, 28.0, 29.0, 30.0],
1951 driver_temps: [35.0, 36.0, 37.0, 38.0, 39.0, 40.0],
1952 joint_voltage: [24.0, 24.1, 24.2, 24.3, 24.4, 24.5],
1953 joint_bus_current: [1.0, 1.1, 1.2, 1.3, 1.4, 1.5],
1954 driver_voltage_low_mask: 0b0000_0001,
1955 driver_motor_over_temp_mask: 0b0000_0010,
1956 driver_over_current_mask: 0b0000_0100,
1957 driver_over_temp_mask: 0b0000_1000,
1958 driver_collision_protection_mask: 0b0001_0000,
1959 driver_error_mask: 0b0010_0000,
1960 driver_enabled_mask: 0b111111,
1961 driver_stall_protection_mask: 0b0000_0001,
1962 hardware_timestamps: [100, 200, 300, 400, 500, 600],
1963 system_timestamps: [1100, 1200, 1300, 1400, 1500, 1600],
1964 valid_mask: 0b111111,
1965 };
1966 let cloned = state.clone();
1967 assert_eq!(state.hardware_timestamp_us, cloned.hardware_timestamp_us);
1968 assert_eq!(state.motor_temps, cloned.motor_temps);
1969 assert_eq!(
1970 state.driver_voltage_low_mask,
1971 cloned.driver_voltage_low_mask
1972 );
1973 assert_eq!(state.valid_mask, cloned.valid_mask);
1974 assert_eq!(state.is_fully_valid(), cloned.is_fully_valid());
1975 assert_eq!(state.is_voltage_low(0), cloned.is_voltage_low(0));
1976 }
1977
1978 #[test]
1979 fn test_piper_context_joint_driver_low_speed() {
1980 let ctx = PiperContext::new();
1981
1982 let state = ctx.joint_driver_low_speed.load();
1984 assert_eq!(state.hardware_timestamp_us, 0);
1985 assert_eq!(state.motor_temps, [0.0; 6]);
1986 assert_eq!(state.driver_voltage_low_mask, 0);
1987 assert_eq!(state.valid_mask, 0);
1988 }
1989
1990 #[test]
1995 fn test_collision_protection_state_default() {
1996 let state = CollisionProtectionState::default();
1997 assert_eq!(state.hardware_timestamp_us, 0);
1998 assert_eq!(state.system_timestamp_us, 0);
1999 assert_eq!(state.protection_levels, [0; 6]);
2000 }
2001
2002 #[test]
2003 fn test_collision_protection_state_clone() {
2004 let state = CollisionProtectionState {
2005 hardware_timestamp_us: 1000,
2006 system_timestamp_us: 2000,
2007 protection_levels: [5, 5, 5, 4, 4, 4],
2008 };
2009 let cloned = state.clone();
2010 assert_eq!(state.hardware_timestamp_us, cloned.hardware_timestamp_us);
2011 assert_eq!(state.system_timestamp_us, cloned.system_timestamp_us);
2012 assert_eq!(state.protection_levels, cloned.protection_levels);
2013 }
2014
2015 #[test]
2016 fn test_collision_protection_state_protection_levels() {
2017 let state_all_zero = CollisionProtectionState {
2019 protection_levels: [0; 6], ..Default::default()
2021 };
2022 assert_eq!(state_all_zero.protection_levels, [0; 6]);
2023
2024 let state_mixed = CollisionProtectionState {
2025 protection_levels: [8, 7, 6, 5, 4, 3], ..Default::default()
2027 };
2028 assert_eq!(state_mixed.protection_levels[0], 8);
2029 assert_eq!(state_mixed.protection_levels[5], 3);
2030 }
2031
2032 #[test]
2033 fn test_piper_context_collision_protection() {
2034 let ctx = PiperContext::new();
2035
2036 let state = ctx.collision_protection.read().unwrap();
2038 assert_eq!(state.hardware_timestamp_us, 0);
2039 assert_eq!(state.system_timestamp_us, 0);
2040 assert_eq!(state.protection_levels, [0; 6]);
2041 }
2042
2043 #[test]
2048 fn test_joint_limit_config_state_default() {
2049 let state = JointLimitConfigState::default();
2050 assert_eq!(state.last_update_hardware_timestamp_us, 0);
2051 assert_eq!(state.last_update_system_timestamp_us, 0);
2052 assert_eq!(state.joint_limits_max, [0.0; 6]);
2053 assert_eq!(state.joint_limits_min, [0.0; 6]);
2054 assert_eq!(state.joint_max_velocity, [0.0; 6]);
2055 assert_eq!(state.joint_update_hardware_timestamps, [0; 6]);
2056 assert_eq!(state.joint_update_system_timestamps, [0; 6]);
2057 assert_eq!(state.valid_mask, 0);
2058 }
2059
2060 #[test]
2061 fn test_joint_limit_config_state_is_fully_valid() {
2062 let state_complete = JointLimitConfigState {
2064 valid_mask: 0b111111, ..Default::default()
2066 };
2067 assert!(state_complete.is_fully_valid());
2068
2069 let state_incomplete = JointLimitConfigState {
2071 valid_mask: 0b001111, ..Default::default()
2073 };
2074 assert!(!state_incomplete.is_fully_valid());
2075 }
2076
2077 #[test]
2078 fn test_joint_limit_config_state_missing_joints() {
2079 let state_complete = JointLimitConfigState {
2081 valid_mask: 0b111111,
2082 ..Default::default()
2083 };
2084 assert_eq!(state_complete.missing_joints(), Vec::<usize>::new());
2085
2086 let state_missing = JointLimitConfigState {
2088 valid_mask: 0b0011110, ..Default::default()
2090 };
2091 let missing = state_missing.missing_joints();
2092 assert_eq!(missing.len(), 2);
2093 assert!(missing.contains(&0));
2094 assert!(missing.contains(&5));
2095 }
2096
2097 #[test]
2098 fn test_joint_limit_config_state_clone() {
2099 let state = JointLimitConfigState {
2100 last_update_hardware_timestamp_us: 1000,
2101 last_update_system_timestamp_us: 2000,
2102 joint_limits_max: [1.57, 1.57, 1.57, 1.57, 1.57, 1.57], joint_limits_min: [-1.57, -1.57, -1.57, -1.57, -1.57, -1.57], joint_max_velocity: [PI, PI, PI, PI, PI, PI], joint_update_hardware_timestamps: [100, 200, 300, 400, 500, 600],
2106 joint_update_system_timestamps: [1100, 1200, 1300, 1400, 1500, 1600],
2107 valid_mask: 0b111111,
2108 };
2109 let cloned = state.clone();
2110 assert_eq!(
2111 state.last_update_hardware_timestamp_us,
2112 cloned.last_update_hardware_timestamp_us
2113 );
2114 assert_eq!(state.joint_limits_max, cloned.joint_limits_max);
2115 assert_eq!(state.joint_limits_min, cloned.joint_limits_min);
2116 assert_eq!(state.joint_max_velocity, cloned.joint_max_velocity);
2117 assert_eq!(state.valid_mask, cloned.valid_mask);
2118 assert_eq!(state.is_fully_valid(), cloned.is_fully_valid());
2119 }
2120
2121 #[test]
2122 fn test_piper_context_joint_limit_config() {
2123 let ctx = PiperContext::new();
2124
2125 let state = ctx.joint_limit_config.read().unwrap();
2127 assert_eq!(state.last_update_hardware_timestamp_us, 0);
2128 assert_eq!(state.joint_limits_max, [0.0; 6]);
2129 assert_eq!(state.joint_limits_min, [0.0; 6]);
2130 assert_eq!(state.joint_max_velocity, [0.0; 6]);
2131 assert_eq!(state.valid_mask, 0);
2132 }
2133
2134 #[test]
2139 fn test_joint_accel_config_state_default() {
2140 let state = JointAccelConfigState::default();
2141 assert_eq!(state.last_update_hardware_timestamp_us, 0);
2142 assert_eq!(state.last_update_system_timestamp_us, 0);
2143 assert_eq!(state.max_acc_limits, [0.0; 6]);
2144 assert_eq!(state.joint_update_hardware_timestamps, [0; 6]);
2145 assert_eq!(state.joint_update_system_timestamps, [0; 6]);
2146 assert_eq!(state.valid_mask, 0);
2147 }
2148
2149 #[test]
2150 fn test_joint_accel_config_state_is_fully_valid() {
2151 let state_complete = JointAccelConfigState {
2153 valid_mask: 0b111111, ..Default::default()
2155 };
2156 assert!(state_complete.is_fully_valid());
2157
2158 let state_incomplete = JointAccelConfigState {
2160 valid_mask: 0b001111, ..Default::default()
2162 };
2163 assert!(!state_incomplete.is_fully_valid());
2164 }
2165
2166 #[test]
2167 fn test_joint_accel_config_state_missing_joints() {
2168 let state_complete = JointAccelConfigState {
2170 valid_mask: 0b111111,
2171 ..Default::default()
2172 };
2173 assert_eq!(state_complete.missing_joints(), Vec::<usize>::new());
2174
2175 let state_missing = JointAccelConfigState {
2177 valid_mask: 0b0011110, ..Default::default()
2179 };
2180 let missing = state_missing.missing_joints();
2181 assert_eq!(missing.len(), 2);
2182 assert!(missing.contains(&0));
2183 assert!(missing.contains(&5));
2184 }
2185
2186 #[test]
2187 fn test_joint_accel_config_state_clone() {
2188 let state = JointAccelConfigState {
2189 last_update_hardware_timestamp_us: 1000,
2190 last_update_system_timestamp_us: 2000,
2191 max_acc_limits: [10.0, 10.0, 10.0, 10.0, 10.0, 10.0], joint_update_hardware_timestamps: [100, 200, 300, 400, 500, 600],
2193 joint_update_system_timestamps: [1100, 1200, 1300, 1400, 1500, 1600],
2194 valid_mask: 0b111111,
2195 };
2196 let cloned = state.clone();
2197 assert_eq!(
2198 state.last_update_hardware_timestamp_us,
2199 cloned.last_update_hardware_timestamp_us
2200 );
2201 assert_eq!(state.max_acc_limits, cloned.max_acc_limits);
2202 assert_eq!(state.valid_mask, cloned.valid_mask);
2203 assert_eq!(state.is_fully_valid(), cloned.is_fully_valid());
2204 }
2205
2206 #[test]
2207 fn test_piper_context_joint_accel_config() {
2208 let ctx = PiperContext::new();
2209
2210 let state = ctx.joint_accel_config.read().unwrap();
2212 assert_eq!(state.last_update_hardware_timestamp_us, 0);
2213 assert_eq!(state.max_acc_limits, [0.0; 6]);
2214 assert_eq!(state.valid_mask, 0);
2215 }
2216
2217 #[test]
2222 fn test_end_limit_config_state_default() {
2223 let state = EndLimitConfigState::default();
2224 assert_eq!(state.last_update_hardware_timestamp_us, 0);
2225 assert_eq!(state.last_update_system_timestamp_us, 0);
2226 assert_eq!(state.max_end_linear_velocity, 0.0);
2227 assert_eq!(state.max_end_angular_velocity, 0.0);
2228 assert_eq!(state.max_end_linear_accel, 0.0);
2229 assert_eq!(state.max_end_angular_accel, 0.0);
2230 assert!(!state.is_valid);
2231 }
2232
2233 #[test]
2234 fn test_end_limit_config_state_clone() {
2235 let state = EndLimitConfigState {
2236 last_update_hardware_timestamp_us: 1000,
2237 last_update_system_timestamp_us: 2000,
2238 max_end_linear_velocity: 1.0, max_end_angular_velocity: 2.0, max_end_linear_accel: 0.5, max_end_angular_accel: 1.5, is_valid: true,
2243 };
2244 let cloned = state.clone();
2245 assert_eq!(
2246 state.last_update_hardware_timestamp_us,
2247 cloned.last_update_hardware_timestamp_us
2248 );
2249 assert_eq!(
2250 state.max_end_linear_velocity,
2251 cloned.max_end_linear_velocity
2252 );
2253 assert_eq!(
2254 state.max_end_angular_velocity,
2255 cloned.max_end_angular_velocity
2256 );
2257 assert_eq!(state.max_end_linear_accel, cloned.max_end_linear_accel);
2258 assert_eq!(state.max_end_angular_accel, cloned.max_end_angular_accel);
2259 assert_eq!(state.is_valid, cloned.is_valid);
2260 }
2261
2262 #[test]
2263 fn test_piper_context_end_limit_config() {
2264 let ctx = PiperContext::new();
2265
2266 let state = ctx.end_limit_config.read().unwrap();
2268 assert_eq!(state.last_update_hardware_timestamp_us, 0);
2269 assert_eq!(state.max_end_linear_velocity, 0.0);
2270 assert_eq!(state.max_end_angular_velocity, 0.0);
2271 assert_eq!(state.max_end_linear_accel, 0.0);
2272 assert_eq!(state.max_end_angular_accel, 0.0);
2273 assert!(!state.is_valid);
2274 }
2275
2276 #[test]
2281 fn test_firmware_version_state_default() {
2282 let state = FirmwareVersionState::default();
2283 assert_eq!(state.hardware_timestamp_us, 0);
2284 assert_eq!(state.system_timestamp_us, 0);
2285 assert!(state.firmware_data.is_empty());
2286 assert!(!state.is_complete);
2287 assert!(state.version_string.is_none());
2288 }
2289
2290 #[test]
2291 fn test_firmware_version_state_clear() {
2292 let mut state = FirmwareVersionState {
2293 hardware_timestamp_us: 1000,
2294 system_timestamp_us: 2000,
2295 firmware_data: vec![b'S', b'-', b'V', b'1', b'.', b'6', b'-', b'3'],
2296 is_complete: true,
2297 version_string: Some("S-V1.6-3".to_string()),
2298 };
2299
2300 state.clear();
2301
2302 assert_eq!(state.hardware_timestamp_us, 0);
2303 assert_eq!(state.system_timestamp_us, 0);
2304 assert!(state.firmware_data.is_empty());
2305 assert!(!state.is_complete);
2306 assert!(state.version_string.is_none());
2307 }
2308
2309 #[test]
2310 fn test_firmware_version_state_check_completeness() {
2311 let mut state = FirmwareVersionState {
2313 firmware_data: b"Some data".to_vec(),
2314 ..Default::default()
2315 };
2316 assert!(!state.check_completeness());
2317 assert!(!state.is_complete);
2318
2319 state.firmware_data = b"S-V1.6".to_vec();
2321 assert!(!state.check_completeness());
2322 assert!(!state.is_complete);
2323
2324 state.firmware_data = b"S-V1.6-3".to_vec();
2326 assert!(state.check_completeness());
2327 assert!(state.is_complete);
2328
2329 state.firmware_data = b"Prefix S-V1.6-3\nSuffix".to_vec();
2331 assert!(state.check_completeness());
2332 assert!(state.is_complete);
2333 }
2334
2335 #[test]
2336 fn test_firmware_version_state_parse_version() {
2337 let mut state = FirmwareVersionState {
2339 firmware_data: b"Some prefix S-V1.6-3\nOther data".to_vec(),
2340 ..Default::default()
2341 };
2342 let version = state.parse_version();
2343 assert_eq!(version, Some("S-V1.6-3".to_string()));
2344 assert_eq!(state.version_string, Some("S-V1.6-3".to_string()));
2345 assert!(state.is_complete);
2346
2347 state.firmware_data = b"Some data without version".to_vec();
2349 let version = state.parse_version();
2350 assert_eq!(version, None);
2351 assert!(state.version_string.is_none());
2352 assert!(!state.is_complete);
2353 }
2354
2355 #[test]
2356 fn test_firmware_version_state_version_string() {
2357 let mut state = FirmwareVersionState::default();
2358
2359 assert!(state.version_string().is_none());
2361
2362 state.firmware_data = b"S-V1.6-3".to_vec();
2364 state.parse_version();
2365 assert_eq!(state.version_string(), Some(&"S-V1.6-3".to_string()));
2366 }
2367
2368 #[test]
2369 fn test_piper_context_firmware_version() {
2370 let ctx = PiperContext::new();
2371
2372 let state = ctx.firmware_version.read().unwrap();
2374 assert_eq!(state.hardware_timestamp_us, 0);
2375 assert_eq!(state.system_timestamp_us, 0);
2376 assert!(state.firmware_data.is_empty());
2377 assert!(!state.is_complete);
2378 assert!(state.version_string.is_none());
2379 }
2380}