1use crate::drivers::drv8873::{Drv8873, Fault};
16use crate::hw::SpiBus;
17
18use stm32f7xx_hal::{
19 gpio::{self, Output, PushPull},
20 prelude::*,
21 spi,
22};
23
24#[derive(Copy, Clone, Debug, PartialEq)]
26pub enum Direction {
27 Extend,
28 Retract,
29 Brake,
30}
31
32pub struct ActuonixLinear<
36 const CS_P: char,
37 const CS_N: u8,
38 const SLP_P: char,
39 const SLP_N: u8,
40 const DIS_P: char,
41 const DIS_N: u8,
42 Pwm1,
43 Pwm2,
44 ReadPos,
45> {
46 drv: Drv8873<CS_P, CS_N>,
47 pwm1: Pwm1,
48 pwm2: Pwm2,
49 nsleep: gpio::Pin<SLP_P, SLP_N, Output<PushPull>>,
50 disable: gpio::Pin<DIS_P, DIS_N, Output<PushPull>>,
51 read_position: ReadPos,
52 adc_history: [u16; 5],
53 adc_idx: usize,
54 stroke_len_mm: f32,
55 buffer_bottom_mm: f32,
56 buffer_top_mm: f32,
57 current_speed: f32,
58 limit_brake_active: bool,
59}
60
61impl<
62 const CS_P: char,
63 const CS_N: u8,
64 const SLP_P: char,
65 const SLP_N: u8,
66 const DIS_P: char,
67 const DIS_N: u8,
68 Pwm1,
69 Pwm2,
70 ReadPos,
71 > ActuonixLinear<CS_P, CS_N, SLP_P, SLP_N, DIS_P, DIS_N, Pwm1, Pwm2, ReadPos>
72where
73 Pwm1: _embedded_hal_PwmPin<Duty = u16>,
74 Pwm2: _embedded_hal_PwmPin<Duty = u16>,
75 ReadPos: FnMut() -> u16,
76{
77 pub fn new<SlpMode, DisMode>(
79 drv: Drv8873<CS_P, CS_N>,
80 pwm1: Pwm1,
81 pwm2: Pwm2,
82 nsleep: gpio::Pin<SLP_P, SLP_N, SlpMode>,
83 disable: gpio::Pin<DIS_P, DIS_N, DisMode>,
84 mut read_position: ReadPos,
85 stroke_len_mm: f32,
86 buffer_bottom_mm: f32,
87 buffer_top_mm: f32,
88 ) -> Self {
89 let mut nsleep = nsleep.into_push_pull_output();
90 let mut disable = disable.into_push_pull_output();
91
92 nsleep.set_high();
94 disable.set_low();
95
96 let initial_pos = (read_position)();
97
98 Self {
99 drv,
100 pwm1,
101 pwm2,
102 nsleep,
103 disable,
104 read_position,
105 adc_history: [initial_pos; 5],
106 adc_idx: 0,
107 stroke_len_mm,
108 buffer_bottom_mm,
109 buffer_top_mm,
110 current_speed: 0.0,
111 limit_brake_active: false,
112 }
113 }
114
115 pub fn set_speed(&mut self, speed: f32) {
119 self.limit_brake_active = false;
121
122 let mut speed = speed.clamp(-1.0, 1.0);
124
125 let pos = self.position_mm();
126 let max_pos = self.stroke_len_mm - self.buffer_top_mm;
127 let min_pos = self.buffer_bottom_mm;
128
129 if speed > 0.0 && pos >= max_pos {
131 speed = 0.0;
132 } else if speed < 0.0 && pos <= min_pos {
133 speed = 0.0;
134 }
135
136 self.current_speed = speed;
137
138 let max_duty = self.pwm1.get_max_duty(); let duty = (speed.abs() * max_duty as f32) as u16;
142
143 if speed > 0.001 {
144 self.pwm1.set_duty(duty);
146 self.pwm2.set_duty(0);
147 self.pwm1.enable();
148 self.pwm2.enable();
149 } else if speed < -0.001 {
150 self.pwm1.set_duty(0);
152 self.pwm2.set_duty(duty);
153 self.pwm1.enable();
154 self.pwm2.enable();
155 } else {
156 self.brake();
157 }
158 }
159
160 pub fn enforce_limits(&mut self) {
163 if self.current_speed.abs() < 0.001 {
165 return;
166 }
167
168 let pos = self.position_mm();
169 let max_pos = self.stroke_len_mm - self.buffer_top_mm;
170 let min_pos = self.buffer_bottom_mm;
171
172 if self.current_speed > 0.0 && pos >= max_pos {
173 self.brake_due_to_limit();
174 self.current_speed = 0.0; } else if self.current_speed < 0.0 && pos <= min_pos {
176 self.brake_due_to_limit();
177 self.current_speed = 0.0; }
179 }
180
181 #[inline]
183 pub fn extend(&mut self) {
184 self.set_speed(1.0);
185 }
186
187 #[inline]
189 pub fn retract(&mut self) {
190 self.set_speed(-1.0);
191 }
192
193 #[inline]
195 pub fn brake(&mut self) {
196 self.limit_brake_active = false;
197 self.brake_raw();
198 }
199
200 #[inline]
201 fn brake_due_to_limit(&mut self) {
202 self.limit_brake_active = true;
203 self.brake_raw();
204 }
205
206 #[inline]
207 fn brake_raw(&mut self) {
208 let max = self.pwm1.get_max_duty();
209 self.pwm1.set_duty(max);
210 self.pwm2.set_duty(max);
211 self.pwm1.enable();
212 self.pwm2.enable();
213 }
214
215 #[inline]
217 pub fn is_limit_braking(&self) -> bool {
218 self.limit_brake_active
219 }
220
221 #[inline]
223 pub fn position_raw(&mut self) -> u16 {
224 let raw = (self.read_position)();
226
227 self.adc_history[self.adc_idx] = raw;
229 self.adc_idx = (self.adc_idx + 1) % 5;
230
231 let mut sorted = self.adc_history;
233 sorted.sort_unstable();
234
235 sorted[2]
236 }
237
238 pub fn position_percent(&mut self) -> f32 {
240 let raw = self.position_raw();
241 (raw as f32) / 4095.0
243 }
244
245 pub fn position_mm(&mut self) -> f32 {
247 self.position_percent() * self.stroke_len_mm
248 }
249
250 pub fn stroke_len_mm(&self) -> f32 {
252 self.stroke_len_mm
253 }
254
255 pub fn drv(&mut self) -> &mut Drv8873<CS_P, CS_N> {
257 &mut self.drv
258 }
259
260 #[inline]
264 pub fn sleep(&mut self) {
265 self.nsleep.set_low();
266 }
267
268 #[inline]
270 pub fn wake(&mut self) {
271 self.nsleep.set_high();
272 }
273
274 #[inline]
276 pub fn enable_outputs(&mut self) {
277 self.wake();
278 self.disable.set_low();
279 }
280
281 #[inline]
283 pub fn disable_outputs(&mut self) {
284 self.brake();
285 self.disable.set_high();
286 }
287
288 pub fn read_fault<I, PINS>(
290 &mut self,
291 spi_bus: &mut SpiBus<I, PINS>,
292 ) -> Result<Fault, spi::Error>
293 where
294 I: spi::Instance,
295 PINS: spi::Pins<I>,
296 {
297 self.drv.read_fault(spi_bus)
298 }
299}