1use core::fmt;
4
5use alloc::format;
6
7use crate::{
8 bindings,
9 error::{get_errno, Error},
10 rtos::DataSource,
11};
12
13pub struct InertialSensor {
15 port: u8,
16}
17
18impl InertialSensor {
19 pub unsafe fn new(port: u8) -> InertialSensor {
27 InertialSensor { port }
28 }
29
30 pub fn calibrate(&mut self) -> Result<(), InertialSensorError> {
35 match unsafe { bindings::imu_reset(self.port) } {
36 bindings::PROS_ERR_ => Err(InertialSensorError::from_errno()),
37 _ => Ok(()),
38 }
39 }
40
41 pub fn get_rotation(&self) -> Result<f64, InertialSensorError> {
48 match unsafe { bindings::imu_get_rotation(self.port) } {
49 x if x == bindings::PROS_ERR_F_ => Err(InertialSensorError::from_errno()),
50 x => Ok(x),
51 }
52 }
53
54 pub fn get_heading(&self) -> Result<f64, InertialSensorError> {
61 match unsafe { bindings::imu_get_heading(self.port) } {
62 x if x == bindings::PROS_ERR_F_ => Err(InertialSensorError::from_errno()),
63 x => Ok(x),
64 }
65 }
66
67 pub fn get_quaternion(&self) -> Result<InertialSensorQuaternion, InertialSensorError> {
69 match unsafe { bindings::imu_get_quaternion(self.port) } {
70 x if x.x == bindings::PROS_ERR_F_ => Err(InertialSensorError::from_errno()),
71 x => Ok(InertialSensorQuaternion {
72 x: x.x,
73 y: x.y,
74 z: x.z,
75 w: x.w,
76 }),
77 }
78 }
79
80 pub fn get_euler(&self) -> Result<InertialSensorEuler, InertialSensorError> {
82 match unsafe { bindings::imu_get_euler(self.port) } {
83 x if x.pitch == bindings::PROS_ERR_F_ => Err(InertialSensorError::from_errno()),
84 x => Ok(InertialSensorEuler {
85 pitch: x.pitch,
86 roll: x.roll,
87 yaw: x.yaw,
88 }),
89 }
90 }
91
92 pub fn get_pitch(&self) -> Result<f64, InertialSensorError> {
94 match unsafe { bindings::imu_get_pitch(self.port) } {
95 x if x == bindings::PROS_ERR_F_ => Err(InertialSensorError::from_errno()),
96 x => Ok(x),
97 }
98 }
99
100 pub fn get_roll(&self) -> Result<f64, InertialSensorError> {
102 match unsafe { bindings::imu_get_roll(self.port) } {
103 x if x == bindings::PROS_ERR_F_ => Err(InertialSensorError::from_errno()),
104 x => Ok(x),
105 }
106 }
107
108 pub fn get_yaw(&self) -> Result<f64, InertialSensorError> {
110 match unsafe { bindings::imu_get_yaw(self.port) } {
111 x if x == bindings::PROS_ERR_F_ => Err(InertialSensorError::from_errno()),
112 x => Ok(x),
113 }
114 }
115
116 pub fn get_gyro_rate(&self) -> Result<InertialSensorRaw, InertialSensorError> {
118 match unsafe { bindings::imu_get_gyro_rate(self.port) } {
119 x if x.x == bindings::PROS_ERR_F_ => Err(InertialSensorError::from_errno()),
120 x => Ok(InertialSensorRaw {
121 x: x.x,
122 y: x.y,
123 z: x.z,
124 }),
125 }
126 }
127
128 pub fn get_accel(&self) -> Result<InertialSensorRaw, InertialSensorError> {
130 match unsafe { bindings::imu_get_accel(self.port) } {
131 x if x.x == bindings::PROS_ERR_F_ => Err(InertialSensorError::from_errno()),
132 x => Ok(InertialSensorRaw {
133 x: x.x,
134 y: x.y,
135 z: x.z,
136 }),
137 }
138 }
139
140 pub fn get_status(&self) -> Result<InertialSensorStatus, InertialSensorError> {
142 let status = unsafe { bindings::imu_get_status(self.port) };
143
144 if status == bindings::imu_status_e_E_IMU_STATUS_ERROR {
145 Err(InertialSensorError::from_errno())
146 } else {
147 Ok(InertialSensorStatus(status))
148 }
149 }
150
151 pub fn reset_heading(&mut self) -> Result<(), InertialSensorError> {
153 match unsafe { bindings::imu_tare_heading(self.port) } {
154 bindings::PROS_ERR_ => Err(InertialSensorError::from_errno()),
155 _ => Ok(()),
156 }
157 }
158
159 pub fn reset_rotation(&mut self) -> Result<(), InertialSensorError> {
161 match unsafe { bindings::imu_tare_rotation(self.port) } {
162 bindings::PROS_ERR_ => Err(InertialSensorError::from_errno()),
163 _ => Ok(()),
164 }
165 }
166
167 pub fn reset_pitch(&mut self) -> Result<(), InertialSensorError> {
169 match unsafe { bindings::imu_tare_pitch(self.port) } {
170 bindings::PROS_ERR_ => Err(InertialSensorError::from_errno()),
171 _ => Ok(()),
172 }
173 }
174
175 pub fn reset_roll(&mut self) -> Result<(), InertialSensorError> {
177 match unsafe { bindings::imu_tare_roll(self.port) } {
178 bindings::PROS_ERR_ => Err(InertialSensorError::from_errno()),
179 _ => Ok(()),
180 }
181 }
182
183 pub fn reset_yaw(&mut self) -> Result<(), InertialSensorError> {
185 match unsafe { bindings::imu_tare_yaw(self.port) } {
186 bindings::PROS_ERR_ => Err(InertialSensorError::from_errno()),
187 _ => Ok(()),
188 }
189 }
190
191 pub fn reset_euler(&mut self) -> Result<(), InertialSensorError> {
193 match unsafe { bindings::imu_tare_euler(self.port) } {
194 bindings::PROS_ERR_ => Err(InertialSensorError::from_errno()),
195 _ => Ok(()),
196 }
197 }
198
199 pub fn reset(&mut self) -> Result<(), InertialSensorError> {
201 match unsafe { bindings::imu_tare(self.port) } {
202 bindings::PROS_ERR_ => Err(InertialSensorError::from_errno()),
203 _ => Ok(()),
204 }
205 }
206
207 pub fn set_zero_euler(
210 &mut self,
211 euler: InertialSensorEuler,
212 ) -> Result<(), InertialSensorError> {
213 match unsafe {
214 bindings::imu_set_euler(
215 self.port,
216 bindings::euler_s_t {
217 pitch: euler.pitch,
218 roll: euler.roll,
219 yaw: euler.yaw,
220 },
221 )
222 } {
223 bindings::PROS_ERR_ => Err(InertialSensorError::from_errno()),
224 _ => Ok(()),
225 }
226 }
227
228 pub fn set_rotation(&mut self, rotation: f64) -> Result<(), InertialSensorError> {
231 match unsafe { bindings::imu_set_rotation(self.port, rotation) } {
232 bindings::PROS_ERR_ => Err(InertialSensorError::from_errno()),
233 _ => Ok(()),
234 }
235 }
236
237 pub fn set_heading(&mut self, heading: f64) -> Result<(), InertialSensorError> {
241 match unsafe { bindings::imu_set_heading(self.port, heading) } {
242 bindings::PROS_ERR_ => Err(InertialSensorError::from_errno()),
243 _ => Ok(()),
244 }
245 }
246
247 pub fn set_pitch(&mut self, pitch: f64) -> Result<(), InertialSensorError> {
250 match unsafe { bindings::imu_set_pitch(self.port, pitch) } {
251 bindings::PROS_ERR_ => Err(InertialSensorError::from_errno()),
252 _ => Ok(()),
253 }
254 }
255
256 pub fn set_roll(&mut self, roll: f64) -> Result<(), InertialSensorError> {
259 match unsafe { bindings::imu_set_roll(self.port, roll) } {
260 bindings::PROS_ERR_ => Err(InertialSensorError::from_errno()),
261 _ => Ok(()),
262 }
263 }
264
265 pub fn set_yaw(&mut self, yaw: f64) -> Result<(), InertialSensorError> {
268 match unsafe { bindings::imu_set_yaw(self.port, yaw) } {
269 bindings::PROS_ERR_ => Err(InertialSensorError::from_errno()),
270 _ => Ok(()),
271 }
272 }
273}
274
275impl DataSource for InertialSensor {
276 type Data = InertialSensorData;
277
278 type Error = InertialSensorError;
279
280 fn read(&self) -> Result<Self::Data, Self::Error> {
281 Ok(InertialSensorData {
282 status: self.get_status()?,
283 quaternion: self.get_quaternion()?,
284 euler: self.get_euler()?,
285 gyro_rate: self.get_gyro_rate()?,
286 accel: self.get_accel()?,
287 })
288 }
289}
290
291#[derive(Clone, Copy, Debug, PartialEq)]
293pub struct InertialSensorData {
294 pub status: InertialSensorStatus,
296 pub quaternion: InertialSensorQuaternion,
298 pub euler: InertialSensorEuler,
300 pub gyro_rate: InertialSensorRaw,
302 pub accel: InertialSensorRaw,
304}
305
306#[derive(Debug)]
308pub enum InertialSensorError {
309 PortOutOfRange,
311 PortNotInertialSensor,
313 SensorAlreadyCalibrating,
315 UnknownStatusCode(u32),
317 Unknown(i32),
319}
320
321impl InertialSensorError {
322 fn from_errno() -> Self {
323 match get_errno() {
324 libc::ENXIO => Self::PortOutOfRange,
325 libc::ENODEV => Self::PortNotInertialSensor,
326 libc::EAGAIN => Self::SensorAlreadyCalibrating,
327 x => Self::Unknown(x),
328 }
329 }
330}
331
332impl From<InertialSensorError> for Error {
333 fn from(err: InertialSensorError) -> Self {
334 match err {
335 InertialSensorError::PortOutOfRange => Error::Custom("port out of range".into()),
336 InertialSensorError::PortNotInertialSensor => {
337 Error::Custom("port not a inertial sensor".into())
338 }
339 InertialSensorError::SensorAlreadyCalibrating => {
340 Error::Custom("sensor already calibrating".into())
341 }
342 InertialSensorError::UnknownStatusCode(n) => {
343 Error::Custom(format!("sensor returned unknown status code {}", n))
344 }
345 InertialSensorError::Unknown(n) => Error::System(n),
346 }
347 }
348}
349
350#[derive(Clone, Copy, Debug, PartialEq)]
352pub struct InertialSensorRaw {
353 pub x: f64,
355 pub y: f64,
357 pub z: f64,
359}
360
361#[derive(Clone, Copy, Debug, PartialEq)]
363pub struct InertialSensorQuaternion {
364 pub x: f64,
366 pub y: f64,
368 pub z: f64,
370 pub w: f64,
372}
373
374#[derive(Clone, Copy, Debug, PartialEq)]
376pub struct InertialSensorEuler {
377 pub pitch: f64,
379 pub roll: f64,
381 pub yaw: f64,
383}
384
385#[derive(Clone, Copy, PartialEq, Eq)]
386pub struct InertialSensorStatus(bindings::imu_status_e);
388
389impl InertialSensorStatus {
390 #[inline]
391 pub fn into_raw(self) -> bindings::imu_status_e {
393 self.0
394 }
395
396 #[inline]
397 pub fn is_calibrating(self) -> bool {
399 self.0 & bindings::imu_status_e_E_IMU_STATUS_CALIBRATING != 0
400 }
401}
402
403impl fmt::Debug for InertialSensorStatus {
404 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
405 f.debug_struct("InertialSensorStatus")
406 .field("is_calibrating", &self.is_calibrating())
407 .finish()
408 }
409}