autd3_driver/firmware/operation/
segment.rs1use std::mem::size_of;
2
3use crate::{
4 error::AUTDDriverError,
5 firmware::{
6 fpga::{Segment, TransitionMode},
7 operation::TypeTag,
8 },
9 geometry::Device,
10};
11
12use super::Operation;
13
14use zerocopy::{Immutable, IntoBytes};
15
16#[derive(Debug, Clone, Copy)]
20pub enum SwapSegment {
21 Gain(Segment, TransitionMode),
25 Modulation(Segment, TransitionMode),
29 FociSTM(Segment, TransitionMode),
33 GainSTM(Segment, TransitionMode),
37}
38
39#[repr(C, align(2))]
40#[derive(IntoBytes, Immutable)]
41struct SwapSegmentT {
42 tag: TypeTag,
43 segment: u8,
44}
45
46#[repr(C, align(2))]
47#[derive(IntoBytes, Immutable)]
48struct SwapSegmentTWithTransition {
49 tag: TypeTag,
50 segment: u8,
51 transition_mode: u8,
52 __: [u8; 5],
53 transition_value: u64,
54}
55
56pub struct SwapSegmentOp {
57 is_done: bool,
58 segment: SwapSegment,
59}
60
61impl SwapSegmentOp {
62 pub(crate) fn new(segment: SwapSegment) -> Self {
63 Self {
64 is_done: false,
65 segment,
66 }
67 }
68}
69
70impl Operation for SwapSegmentOp {
71 type Error = AUTDDriverError;
72
73 fn pack(&mut self, _: &Device, tx: &mut [u8]) -> Result<usize, Self::Error> {
74 self.is_done = true;
75
76 let tag = match self.segment {
77 SwapSegment::Gain(_, _) => TypeTag::GainSwapSegment,
78 SwapSegment::Modulation(_, _) => TypeTag::ModulationSwapSegment,
79 SwapSegment::FociSTM(_, _) => TypeTag::FociSTMSwapSegment,
80 SwapSegment::GainSTM(_, _) => TypeTag::GainSTMSwapSegment,
81 };
82
83 match self.segment {
84 SwapSegment::Gain(segment, transition) => {
85 if transition != TransitionMode::Immediate {
86 return Err(AUTDDriverError::InvalidTransitionMode);
87 }
88 super::write_to_tx(
89 tx,
90 SwapSegmentT {
91 tag,
92 segment: segment as u8,
93 },
94 );
95
96 Ok(size_of::<SwapSegmentT>())
97 }
98 SwapSegment::Modulation(segment, transition)
99 | SwapSegment::FociSTM(segment, transition)
100 | SwapSegment::GainSTM(segment, transition) => {
101 super::write_to_tx(
102 tx,
103 SwapSegmentTWithTransition {
104 tag,
105 segment: segment as u8,
106 transition_mode: transition.mode(),
107 __: [0; 5],
108 transition_value: transition.value(),
109 },
110 );
111 Ok(size_of::<SwapSegmentTWithTransition>())
112 }
113 }
114 }
115
116 fn required_size(&self, _: &Device) -> usize {
117 match self.segment {
118 SwapSegment::Gain(_, _) => size_of::<SwapSegmentT>(),
119 SwapSegment::Modulation(_, _)
120 | SwapSegment::FociSTM(_, _)
121 | SwapSegment::GainSTM(_, _) => size_of::<SwapSegmentTWithTransition>(),
122 }
123 }
124
125 fn is_done(&self) -> bool {
126 self.is_done
127 }
128}
129
130#[cfg(test)]
131mod tests {
132 use crate::{ethercat::DcSysTime, firmware::operation::tests::create_device};
133
134 use super::*;
135
136 const NUM_TRANS_IN_UNIT: u8 = 249;
137
138 #[test]
139 fn gain() {
140 const FRAME_SIZE: usize = size_of::<SwapSegmentT>();
141
142 let device = create_device(NUM_TRANS_IN_UNIT);
143 let mut tx = vec![0x00u8; FRAME_SIZE];
144
145 let mut op = SwapSegmentOp::new(SwapSegment::Gain(Segment::S0, TransitionMode::Immediate));
146
147 assert_eq!(size_of::<SwapSegmentT>(), op.required_size(&device));
148 assert_eq!(Ok(size_of::<SwapSegmentT>()), op.pack(&device, &mut tx));
149 assert!(op.is_done());
150 assert_eq!(TypeTag::GainSwapSegment as u8, tx[0]);
151 assert_eq!(Segment::S0 as u8, tx[1]);
152 }
153
154 #[test]
155 fn gain_invalid_transition_mode() {
156 const FRAME_SIZE: usize = size_of::<SwapSegmentT>();
157
158 let device = create_device(NUM_TRANS_IN_UNIT);
159 let mut tx = vec![0x00u8; FRAME_SIZE];
160
161 let mut op = SwapSegmentOp::new(SwapSegment::Gain(Segment::S0, TransitionMode::Ext));
162
163 assert_eq!(
164 Some(AUTDDriverError::InvalidTransitionMode),
165 op.pack(&device, &mut tx).err()
166 );
167 }
168
169 #[test]
170 fn modulation() {
171 const FRAME_SIZE: usize = size_of::<SwapSegmentTWithTransition>();
172
173 let device = create_device(NUM_TRANS_IN_UNIT);
174 let mut tx = vec![0x00u8; FRAME_SIZE];
175
176 let sys_time = DcSysTime::ZERO + std::time::Duration::from_nanos(0x0123456789ABCDEF);
177 let transition_mode = TransitionMode::SysTime(sys_time);
178 let mut op = SwapSegmentOp::new(SwapSegment::Modulation(Segment::S0, transition_mode));
179
180 assert_eq!(
181 size_of::<SwapSegmentTWithTransition>(),
182 op.required_size(&device)
183 );
184 assert_eq!(
185 Ok(size_of::<SwapSegmentTWithTransition>()),
186 op.pack(&device, &mut tx)
187 );
188 assert!(op.is_done());
189 assert_eq!(TypeTag::ModulationSwapSegment as u8, tx[0]);
190 assert_eq!(Segment::S0 as u8, tx[1]);
191 let mode = transition_mode.mode();
192 let value = transition_mode.value();
193 assert_eq!(mode, tx[2]);
194 assert_eq!(value, u64::from_le_bytes(tx[8..].try_into().unwrap()));
195 }
196
197 #[test]
198 fn foci_stm() {
199 const FRAME_SIZE: usize = size_of::<SwapSegmentTWithTransition>();
200
201 let device = create_device(NUM_TRANS_IN_UNIT);
202 let mut tx = vec![0x00u8; FRAME_SIZE];
203
204 let sys_time = DcSysTime::ZERO + std::time::Duration::from_nanos(0x0123456789ABCDEF);
205 let transition_mode = TransitionMode::SysTime(sys_time);
206 let mut op = SwapSegmentOp::new(SwapSegment::FociSTM(Segment::S0, transition_mode));
207
208 assert_eq!(
209 size_of::<SwapSegmentTWithTransition>(),
210 op.required_size(&device)
211 );
212 assert_eq!(
213 Ok(size_of::<SwapSegmentTWithTransition>()),
214 op.pack(&device, &mut tx)
215 );
216 assert!(op.is_done());
217 assert_eq!(TypeTag::FociSTMSwapSegment as u8, tx[0]);
218 assert_eq!(Segment::S0 as u8, tx[1]);
219 let mode = transition_mode.mode();
220 let value = transition_mode.value();
221 assert_eq!(mode, tx[2]);
222 assert_eq!(value, u64::from_le_bytes(tx[8..].try_into().unwrap()));
223 }
224
225 #[test]
226 fn gain_stm() {
227 const FRAME_SIZE: usize = size_of::<SwapSegmentTWithTransition>();
228
229 let device = create_device(NUM_TRANS_IN_UNIT);
230 let mut tx = vec![0x00u8; FRAME_SIZE];
231
232 let sys_time = DcSysTime::ZERO + std::time::Duration::from_nanos(0x0123456789ABCDEF);
233 let transition_mode = TransitionMode::SysTime(sys_time);
234 let mut op = SwapSegmentOp::new(SwapSegment::GainSTM(Segment::S0, transition_mode));
235
236 assert_eq!(
237 size_of::<SwapSegmentTWithTransition>(),
238 op.required_size(&device)
239 );
240 assert_eq!(
241 Ok(size_of::<SwapSegmentTWithTransition>()),
242 op.pack(&device, &mut tx)
243 );
244 assert!(op.is_done());
245 assert_eq!(TypeTag::GainSTMSwapSegment as u8, tx[0]);
246 assert_eq!(Segment::S0 as u8, tx[1]);
247 let mode = transition_mode.mode();
248 let value = transition_mode.value();
249 assert_eq!(mode, tx[2]);
250 assert_eq!(value, u64::from_le_bytes(tx[8..].try_into().unwrap()));
251 }
252}