omnitiles/drivers/
gim6010.rs1use crate::hw::CanBus;
9
10use bxcan::{Frame, Id, OverrunError, StandardId};
11use core::convert::TryInto;
12use core::f32::consts::PI;
13use micromath::F32Ext;
14
15#[derive(Debug)]
17pub enum Error {
18 PayloadTooLong,
20 TxMailbox,
22 Rx(OverrunError),
24 NoData,
26 UnexpectedCommand(u8),
28}
29
30impl From<OverrunError> for Error {
31 fn from(e: OverrunError) -> Self {
32 Error::Rx(e)
33 }
34}
35
36pub struct Gim6010<const DEV_ADDR: u16>;
45
46impl<const DEV_ADDR: u16> Gim6010<DEV_ADDR> {
47 #[inline]
51 pub fn new() -> Self {
52 Self
53 }
54
55 #[inline]
57 fn host_id() -> StandardId {
58 StandardId::new((0x100 | (DEV_ADDR & 0x7FF)) as u16).unwrap()
59 }
60
61 #[inline]
63 fn dev_id() -> StandardId {
64 StandardId::new(DEV_ADDR & 0x7FF).unwrap()
65 }
66
67 fn request_response<I>(
78 &mut self,
79 bus: &mut CanBus<I>,
80 cmd: u8,
81 payload: &[u8],
82 wait_reply: bool,
83 ) -> Result<Option<[u8; 8]>, Error>
84 where
85 stm32f7xx_hal::can::Can<I>: bxcan::Instance,
86 {
87 if payload.len() > 7 {
89 return Err(Error::PayloadTooLong);
90 }
91
92 let mut buf = [0u8; 8];
94 buf[0] = cmd;
95 let dlc = 1 + payload.len();
96 buf[1..dlc].copy_from_slice(payload);
97
98 let tx_id = Self::host_id();
100 let tx_result = bus
101 .transmit_data(tx_id, &buf[..dlc])
102 .ok_or(Error::PayloadTooLong)?;
103
104 match tx_result {
105 Ok(_status) => {}
106 Err(_) => return Err(Error::TxMailbox),
107 }
108
109 if !wait_reply {
110 return Ok(None);
111 }
112
113 loop {
115 let frame: Frame = bus.receive()?;
116
117 let id = match frame.id() {
119 Id::Standard(id) => id,
120 Id::Extended(_) => continue,
121 };
122
123 if id != Self::dev_id() {
125 continue;
126 }
127
128 let data = match frame.data() {
129 Some(d) if d.len() > 0 => d,
130 _ => return Err(Error::NoData),
131 };
132
133 let resp_cmd = data[0];
134 if resp_cmd != cmd {
135 continue; }
137
138 let mut out = [0u8; 8];
139 let len = data.len().min(8);
140 out[..len].copy_from_slice(&data[..len]);
141 return Ok(Some(out));
142 }
143 }
144
145 pub fn clear_faults<I>(&mut self, bus: &mut CanBus<I>) -> Result<(), Error>
147 where
148 stm32f7xx_hal::can::Can<I>: bxcan::Instance,
149 {
150 let _ = self.request_response(bus, 0xAF, &[], true)?;
151 Ok(())
152 }
153
154 pub fn disable_output<I>(&mut self, bus: &mut CanBus<I>) -> Result<(), Error>
157 where
158 stm32f7xx_hal::can::Can<I>: bxcan::Instance,
159 {
160 let _ = self.request_response(bus, 0xCF, &[], false)?;
161 Ok(())
162 }
163
164 pub fn set_speed_rpm<I>(&mut self, bus: &mut CanBus<I>, rpm: f32) -> Result<(), Error>
169 where
170 stm32f7xx_hal::can::Can<I>: bxcan::Instance,
171 {
172 let scaled: i32 = (rpm * 100.0).round() as i32;
174 let bytes = scaled.to_le_bytes();
175
176 let _ = self.request_response(bus, 0xC1, &bytes, false)?;
177 Ok(())
178 }
179
180 pub fn read_speed_rpm<I>(&mut self, bus: &mut CanBus<I>) -> Result<f32, Error>
182 where
183 stm32f7xx_hal::can::Can<I>: bxcan::Instance,
184 {
185 let resp = self
186 .request_response(bus, 0xA2, &[], true)?
187 .ok_or(Error::NoData)?;
188
189 if resp[0] != 0xA2 {
190 return Err(Error::UnexpectedCommand(resp[0]));
191 }
192
193 let speed_bytes: [u8; 4] = resp[1..5].try_into().expect("slice with exact length");
194 let raw = i32::from_le_bytes(speed_bytes);
195 let rpm = raw as f32 / 100.0;
196 Ok(rpm)
197 }
198
199 pub fn read_status_frame<I>(&mut self, bus: &mut CanBus<I>) -> Result<[u8; 8], Error>
201 where
202 stm32f7xx_hal::can::Can<I>: bxcan::Instance,
203 {
204 let resp = self
205 .request_response(bus, 0xAE, &[], true)?
206 .ok_or(Error::NoData)?;
207
208 if resp[0] != 0xAE {
209 return Err(Error::UnexpectedCommand(resp[0]));
210 }
211
212 Ok(resp)
213 }
214}
215
216impl<const DEV_ADDR: u16> Gim6010<DEV_ADDR> {
217 pub const POS_MAX_0P1_RAD: i16 = 955;
222
223 #[inline]
225 pub fn shaft_pos_max_rad() -> f32 {
226 (Self::POS_MAX_0P1_RAD as f32) * 0.1
227 }
228
229 #[inline]
236 pub fn raw_angle_to_rad(raw: u16) -> f32 {
237 let max = Self::shaft_pos_max_rad(); let norm = (raw as f32) / 65535.0 * 2.0 - 1.0; norm * max
240 }
241
242 #[inline]
244 pub fn raw_angle_to_deg(raw: u16) -> f32 {
245 let rad = Self::raw_angle_to_rad(raw);
246 rad * 180.0 / PI
247 }
248
249 #[inline]
253 pub fn angle_rad_to_raw(angle_rad: f32) -> u16 {
254 let max = Self::shaft_pos_max_rad();
255 let a = if angle_rad > max {
256 max
257 } else if angle_rad < -max {
258 -max
259 } else {
260 angle_rad
261 };
262
263 let norm = a / max; let raw_f = (norm + 1.0) * 0.5 * 65535.0;
265 let raw_f = if raw_f < 0.0 {
266 0.0
267 } else if raw_f > 65535.0 {
268 65535.0
269 } else {
270 raw_f
271 };
272 raw_f.round() as u16
273 }
274
275 #[inline]
277 pub fn angle_deg_to_raw(angle_deg: f32) -> u16 {
278 let rad = angle_deg * PI / 180.0;
279 Self::angle_rad_to_raw(rad)
280 }
281}