1use crate::state::{self, ReadComm};
2use crate::state::ODriveCommand;
3use socketcan::CANFrame;
4
5pub type CANRequest = ODriveCANFrame;
6pub type CANResponse = ODriveCANFrame;
7
8pub fn ticket(id: usize, command: ODriveCommand, data: [u8; 8]) -> CANRequest {
10 CANRequest { axis: id as u32, cmd: command, data: data }
11}
12
13pub fn read_can(id: usize, command: ReadComm) -> CANRequest {
14 ticket(id, ODriveCommand::Read(command), [0; 8])
15}
16
17#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
18pub struct ODriveCANFrame {
19 pub axis: u32,
20 pub cmd: ODriveCommand,
21 pub data: [u8; 8],
22}
23
24impl ODriveCANFrame {
25 const AXIS_BITS: u32 = 5;
26
27 pub fn to_can(&self, rtr: bool) -> socketcan::CANFrame {
28 let id = self.axis << Self::AXIS_BITS | self.get_cmd_id();
29 return socketcan::CANFrame::new(id, &self.data, rtr, false).unwrap(); }
31
32 fn get_cmd_id(&self) -> u32 {
33 match self.cmd {
34 ODriveCommand::Read(cmd) => cmd as u32,
35 ODriveCommand::Write(cmd) => cmd as u32,
36 }
37 }
38
39 fn to_cmd(can_id: u32) -> ODriveCommand {
40 let cmd_id = can_id & 0x1F;
42
43 match TryInto::<state::WriteComm>::try_into(cmd_id) {
45 Ok(cmd) => return ODriveCommand::Write(cmd),
46 Err(_) => {}
47 }
48
49 match TryInto::<state::ReadComm>::try_into(cmd_id) {
51 Ok(cmd) => return ODriveCommand::Read(cmd),
52 Err(_) => panic!("CAN ID {} not able to be converted to a command", can_id),
53 }
54 }
55
56 pub fn from_can(frame: &CANFrame) -> Self {
57 let axis = frame.id() >> Self::AXIS_BITS;
59 let cmd = Self::to_cmd(frame.id());
60
61 ODriveCANFrame {
62 axis,
63 cmd,
64 data: frame.data().try_into().expect(
65 "Error with CANFrame. data() returned slice that could not be coerced into [u8; 8]",
66 ),
67 }
68 }
69
70 pub fn is_response(&self, other: &ODriveCANFrame) -> bool {
72 self.axis == other.axis && self.cmd == other.cmd
73 }
74}
75
76#[derive(Clone, PartialEq, Debug)]
78pub struct ThreadCANFrame {
79 pub thread_name: &'static str,
80 pub body: ODriveCANFrame,
81}
82
83
84#[cfg(test)]
85mod tests {
86 use crate::{
87 state::{ODriveCommand, ReadComm, WriteComm},
88 canframe::{CANRequest, CANResponse},
89 };
90
91 use super::ODriveCANFrame;
92
93 #[test]
94 fn test_conversion_to_frame() {
95 let msg1 = CANRequest {
97 axis: 0x1,
98 cmd: ODriveCommand::Write(WriteComm::SetInputPosition), data: [0; 8],
100 };
101
102 let msg2 = CANRequest {
103 axis: 0x293874,
104 cmd: ODriveCommand::Read(ReadComm::GetEncoderCount), data: [0; 8],
106 };
107
108 let rtr_enabled = true;
110 let can_frame = msg1.to_can(rtr_enabled);
111 assert_eq!(can_frame.id(), 0x2C);
112 assert_eq!(can_frame.data(), [0, 0, 0, 0, 0, 0, 0, 0]);
113 assert_eq!(can_frame.is_rtr(), rtr_enabled);
114
115 assert_eq!(msg1, msg1.clone()); assert_eq!(msg1, ODriveCANFrame::from_can(&can_frame));
118
119 assert_eq!(msg2, ODriveCANFrame::from_can(&msg2.to_can(true)));
123 }
124
125 #[test]
126 #[should_panic]
127 fn test_command_not_found() {
128 ODriveCANFrame::to_cmd(0xFFFF);
129 }
130
131 #[test]
132 fn test_is_response() {
133 let msg1 = CANRequest {
134 axis: 0x1,
135 cmd: ODriveCommand::Write(WriteComm::SetInputPosition), data: [0; 8],
137 };
138 let fake_response = CANResponse {
139 axis: 0x1,
140 cmd: ODriveCommand::Write(WriteComm::SetInputPosition), data: [1; 8], };
143 assert_eq!(msg1.is_response(&fake_response), true);
144 }
145}