capsules_extra/
lsm6dsoxtr.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! LSM6DSOXTR Sensor
6//!
7//! Driver for the LSM6DSOXTR 3D accelerometer and 3D gyroscope sensor.
8//!
9//! May be used with NineDof and Temperature
10//!
11//! I2C Interface
12//!
13//! Datasheet: <https://www.digikey.sg/product-detail/en/stmicroelectronics/LSM6DSOXTR/497-18367-1-ND/9841887>
14//!
15//! Author: Cristiana Andrei <cristiana.andrei05@gmail.com>
16
17#![allow(non_camel_case_types)]
18use capsules_core::driver;
19
20use core::cell::Cell;
21use enum_primitive::cast::FromPrimitive;
22use enum_primitive::enum_from_primitive;
23use kernel::errorcode::into_statuscode;
24use kernel::grant::{AllowRoCount, AllowRwCount, Grant, UpcallCount};
25use kernel::hil::i2c;
26use kernel::hil::sensors;
27use kernel::hil::sensors::{NineDof, NineDofClient};
28use kernel::syscall::{CommandReturn, SyscallDriver};
29use kernel::utilities::cells::{OptionalCell, TakeCell};
30use kernel::utilities::registers::LocalRegisterCopy;
31use kernel::{ErrorCode, ProcessId};
32
33pub const DRIVER_NUM: usize = driver::NUM::Lsm6dsoxtr as usize;
34
35use kernel::utilities::registers::register_bitfields;
36
37pub const CHIP_ID: u8 = 0x6C;
38pub const ACCELEROMETER_BASE_ADDRESS: u8 = 0x6A;
39
40enum_from_primitive! {
41    #[derive(Clone, Copy, PartialEq)]
42    pub enum LSM6DSOXGyroDataRate {
43        LSMDSOX_GYRO_RATE_SHUTDOWN = 0,
44        LSM6DSOX_GYRO_RATE_12_5_HZ = 1,
45        LSM6DSOX_GYRO_RATE_26_HZ = 2,
46        LSM6DSOX_GYRO_RATE_52_HZ = 3,
47        LSM6DSOX_GYRO_RATE_104_HZ = 4,
48        LSM6DSOX_GYRO_RATE_208_HZ = 5,
49        LSM6DSOX_GYRO_RATE_416_HZ = 6,
50        LSM6DSOX_GYRO_RATE_833_HZ = 7,
51        LSM6DSOX_GYRO_RATE_1_66k_HZ = 8,
52        LSM6DSOX_GYRO_RATE_3_33K_HZ = 9,
53        LSM6DSOX_GYRO_RATE_6_66K_HZ = 10
54    }
55}
56
57enum_from_primitive! {
58    #[derive(Clone, Copy, PartialEq)]
59    pub enum LSM6DSOXAccelDataRate {
60        LSMDSOX_ACCEL_RATE_SHUTDOWN = 0,
61        LSM6DSOX_ACCEL_RATE_12_5_HZ = 1,
62        LSM6DSOX_ACCEL_RATE_26_HZ = 2,
63        LSM6DSOX_ACCEL_RATE_52_HZ = 3,
64        LSM6DSOX_ACCEL_RATE_104_HZ = 4,
65        LSM6DSOX_ACCEL_RATE_208_HZ = 5,
66        LSM6DSOX_ACCEL_RATE_416_HZ = 6,
67        LSM6DSOX_ACCEL_RATE_833_HZ = 7,
68        LSM6DSOX_ACCEL_RATE_1_66k_HZ = 8,
69        LSM6DSOX_ACCEL_RATE_3_33K_HZ = 9,
70        LSM6DSOX_ACCEL_RATE_6_66K_HZ = 10
71    }
72}
73
74enum_from_primitive! {
75    #[derive(Clone, Copy, PartialEq)]
76    pub enum LSM6DSOXAccelRange {
77        LSM6DSOX_ACCEL_RANGE_2_G = 0,
78        LSM6DSOX_ACCEL_RANGE_16_G = 1,
79        LSM6DSOX_ACCEL_RANGE_4_G = 2,
80        LSM6DSOX_ACCEL_RANGE_8_G = 3
81    }
82}
83
84enum_from_primitive! {
85    #[derive(Clone, Copy, PartialEq)]
86    pub enum LSM6DSOXTRGyroRange {
87        LSM6DSOX_GYRO_RANGE_250_DPS = 0,
88        LSM6DSOX_GYRO_RANGE_500_DPS = 1,
89        LSM6DSOX_GYRO_RANGE_1000_DPS = 2,
90        LSM6DSOX_GYRO_RANGE_2000_DPS = 3
91    }
92}
93
94enum_from_primitive! {
95    #[derive(Clone, Copy, PartialEq)]
96    pub enum LSM6DSOXTRGyroRegisters {
97        CTRL2_G = 0x11,
98        CTRL7_G = 0x16,
99        OUT_X_L_G = 0x22,
100        OUT_X_H_G = 0x23,
101        OUT_Y_L_G = 0x24,
102        OUT_Y_H_G = 0x25,
103        OUT_Z_L_G = 0x26,
104        OUT_Z_H_G = 0x27
105    }
106}
107
108enum_from_primitive! {
109    #[derive(Clone, Copy, PartialEq)]
110    pub enum LSM6DSOXTRTempRegisters {
111        OUT_TEMP_L = 0x20,
112        OUT_TEMP_H = 0x21
113    }
114}
115
116pub const SCALE_FACTOR_ACCEL: [u16; 4] = [61, 488, 122, 244];
117pub const SCALE_FACTOR_GYRO: [u16; 4] = [875, 1750, 3500, 7000];
118pub const TEMP_SENSITIVITY_FACTOR: u16 = 256;
119
120enum_from_primitive! {
121    #[derive(Clone, Copy, PartialEq)]
122    pub enum LSM6DSOXTRAccelRegisters {
123        CTRL1_XL = 0x10,
124        CTRL8_XL = 0x17,
125        CTRL9_XL = 0x18,
126        OUT_X_L_A = 0x28,
127        OUT_X_H_A = 0x29,
128        OUT_Y_L_A = 0x2A,
129        OUT_Y_H_A = 0x2B,
130        OUT_Z_L_A = 0x2C,
131        OUT_Z_H_A = 0x2D
132    }
133}
134
135register_bitfields![u8,
136    pub (crate) CTRL1_XL [
137        /// Output data rate
138        ODR OFFSET(4) NUMBITS(4) [],
139
140        FS OFFSET(2) NUMBITS(2) [],
141
142        LPF OFFSET(1) NUMBITS(1) [],
143
144    ],
145];
146
147register_bitfields![u8,
148    pub (crate) CTRL2_G [
149        /// Output data rate
150        ODR OFFSET(4) NUMBITS(4) [],
151
152        FS OFFSET(2) NUMBITS(2) [],
153
154        LPF OFFSET(1) NUMBITS(1) [],
155
156    ],
157];
158
159#[derive(Clone, Copy, PartialEq, Debug)]
160enum State {
161    Idle,
162    IsPresent,
163    ReadAccelerationXYZ,
164    ReadGyroscopeXYZ,
165    ReadTemperature,
166    SetPowerModeAccel,
167    SetPowerModeGyro,
168}
169#[derive(Default)]
170pub struct App {}
171
172pub struct Lsm6dsoxtrI2C<'a, I: i2c::I2CDevice> {
173    i2c: &'a I,
174    state: Cell<State>,
175    config_in_progress: Cell<bool>,
176    gyro_data_rate: Cell<LSM6DSOXGyroDataRate>,
177    accel_data_rate: Cell<LSM6DSOXAccelDataRate>,
178    accel_scale: Cell<LSM6DSOXAccelRange>,
179    gyro_range: Cell<LSM6DSOXTRGyroRange>,
180    low_power: Cell<bool>,
181    temperature: Cell<bool>,
182    nine_dof_client: OptionalCell<&'a dyn sensors::NineDofClient>,
183    temperature_client: OptionalCell<&'a dyn sensors::TemperatureClient>,
184    is_present: Cell<bool>,
185    buffer: TakeCell<'static, [u8]>,
186    apps: Grant<App, UpcallCount<1>, AllowRoCount<0>, AllowRwCount<0>>,
187    syscall_process: OptionalCell<ProcessId>,
188}
189
190impl<'a, I: i2c::I2CDevice> Lsm6dsoxtrI2C<'a, I> {
191    pub fn new(
192        i2c: &'a I,
193        buffer: &'static mut [u8],
194        grant: Grant<App, UpcallCount<1>, AllowRoCount<0>, AllowRwCount<0>>,
195    ) -> Lsm6dsoxtrI2C<'a, I> {
196        Lsm6dsoxtrI2C {
197            i2c,
198            state: Cell::new(State::Idle),
199            config_in_progress: Cell::new(false),
200            gyro_data_rate: Cell::new(LSM6DSOXGyroDataRate::LSM6DSOX_GYRO_RATE_12_5_HZ),
201            accel_data_rate: Cell::new(LSM6DSOXAccelDataRate::LSM6DSOX_ACCEL_RATE_12_5_HZ),
202            accel_scale: Cell::new(LSM6DSOXAccelRange::LSM6DSOX_ACCEL_RANGE_2_G),
203            gyro_range: Cell::new(LSM6DSOXTRGyroRange::LSM6DSOX_GYRO_RANGE_250_DPS),
204            low_power: Cell::new(false),
205            temperature: Cell::new(false),
206            nine_dof_client: OptionalCell::empty(),
207            temperature_client: OptionalCell::empty(),
208            is_present: Cell::new(false),
209            buffer: TakeCell::new(buffer),
210            apps: grant,
211            syscall_process: OptionalCell::empty(),
212        }
213    }
214
215    pub fn configure(
216        &self,
217        gyro_data_rate: LSM6DSOXGyroDataRate,
218        accel_data_rate: LSM6DSOXAccelDataRate,
219        accel_scale: LSM6DSOXAccelRange,
220        gyro_range: LSM6DSOXTRGyroRange,
221        low_power: bool,
222    ) -> Result<(), ErrorCode> {
223        if self.state.get() == State::Idle {
224            self.gyro_data_rate.set(gyro_data_rate);
225            self.accel_data_rate.set(accel_data_rate);
226            self.accel_scale.set(accel_scale);
227            self.gyro_range.set(gyro_range);
228            self.low_power.set(low_power);
229            self.temperature.set(true);
230            if self.send_is_present() == Ok(()) {
231                self.config_in_progress.set(true);
232                Ok(())
233            } else {
234                Err(ErrorCode::NODEVICE)
235            }
236        } else {
237            Err(ErrorCode::BUSY)
238        }
239    }
240
241    pub fn send_is_present(&self) -> Result<(), ErrorCode> {
242        if self.state.get() == State::Idle {
243            self.state.set(State::IsPresent);
244            self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buf| {
245                // turn on i2c to send commands
246                buf[0] = 0x0F;
247                self.i2c.enable();
248                if let Err((error, buf)) = self.i2c.write_read(buf, 1, 1) {
249                    self.state.set(State::Idle);
250                    self.buffer.replace(buf);
251                    self.i2c.disable();
252                    Err(error.into())
253                } else {
254                    Ok(())
255                }
256            })
257        } else {
258            Err(ErrorCode::BUSY)
259        }
260    }
261
262    pub fn set_accelerometer_power_mode(
263        &self,
264        data_rate: LSM6DSOXAccelDataRate,
265        low_power: bool,
266    ) -> Result<(), ErrorCode> {
267        if self.state.get() == State::Idle {
268            self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buf| {
269                self.state.set(State::SetPowerModeAccel);
270                buf[0] = LSM6DSOXTRAccelRegisters::CTRL1_XL as u8;
271                let mut reg: LocalRegisterCopy<u8, CTRL1_XL::Register> = LocalRegisterCopy::new(0);
272                reg.modify(CTRL1_XL::ODR.val(data_rate as u8));
273                reg.modify(CTRL1_XL::LPF.val(low_power as u8));
274                reg.modify(CTRL1_XL::FS.val(0));
275
276                buf[1] = reg.get();
277                self.i2c.enable();
278                if let Err((error, buf)) = self.i2c.write(buf, 2) {
279                    self.state.set(State::Idle);
280                    self.i2c.disable();
281                    self.buffer.replace(buf);
282                    Err(error.into())
283                } else {
284                    Ok(())
285                }
286            })
287        } else {
288            Err(ErrorCode::BUSY)
289        }
290    }
291
292    pub fn set_gyroscope_power_mode(
293        &self,
294        data_rate: LSM6DSOXGyroDataRate,
295        low_power: bool,
296    ) -> Result<(), ErrorCode> {
297        if self.state.get() == State::Idle {
298            self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buf| {
299                self.state.set(State::SetPowerModeGyro);
300                buf[0] = LSM6DSOXTRGyroRegisters::CTRL2_G as u8;
301                let mut reg: LocalRegisterCopy<u8, CTRL2_G::Register> = LocalRegisterCopy::new(0);
302                reg.modify(CTRL2_G::ODR.val(data_rate as u8));
303                reg.modify(CTRL2_G::LPF.val(low_power as u8));
304                reg.modify(CTRL2_G::FS.val(0));
305
306                buf[1] = reg.get();
307                self.i2c.enable();
308                if let Err((error, buf)) = self.i2c.write(buf, 2) {
309                    self.state.set(State::Idle);
310                    self.i2c.disable();
311                    self.buffer.replace(buf);
312                    Err(error.into())
313                } else {
314                    Ok(())
315                }
316            })
317        } else {
318            Err(ErrorCode::BUSY)
319        }
320    }
321
322    pub fn read_acceleration_xyz(&self) -> Result<(), ErrorCode> {
323        if self.state.get() == State::Idle {
324            self.state.set(State::ReadAccelerationXYZ);
325            self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buf| {
326                buf[0] = LSM6DSOXTRAccelRegisters::OUT_X_L_A as u8;
327                self.i2c.enable();
328                if let Err((error, buf)) = self.i2c.write_read(buf, 1, 6) {
329                    self.state.set(State::Idle);
330                    self.buffer.replace(buf);
331                    self.i2c.disable();
332                    Err(error.into())
333                } else {
334                    Ok(())
335                }
336            })
337        } else {
338            Err(ErrorCode::BUSY)
339        }
340    }
341
342    pub fn read_gyroscope_xyz(&self) -> Result<(), ErrorCode> {
343        if self.state.get() == State::Idle {
344            self.state.set(State::ReadGyroscopeXYZ);
345            self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buf| {
346                buf[0] = LSM6DSOXTRGyroRegisters::OUT_X_L_G as u8;
347                self.i2c.enable();
348                if let Err((error, buf)) = self.i2c.write_read(buf, 1, 6) {
349                    self.state.set(State::Idle);
350                    self.buffer.replace(buf);
351                    self.i2c.disable();
352                    Err(error.into())
353                } else {
354                    Ok(())
355                }
356            })
357        } else {
358            Err(ErrorCode::BUSY)
359        }
360    }
361
362    pub fn read_temperature(&self) -> Result<(), ErrorCode> {
363        if self.state.get() == State::Idle {
364            self.state.set(State::ReadTemperature);
365            self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buf| {
366                buf[0] = LSM6DSOXTRTempRegisters::OUT_TEMP_L as u8;
367                self.i2c.enable();
368                if let Err((error, buf)) = self.i2c.write_read(buf, 1, 6) {
369                    self.state.set(State::Idle);
370                    self.buffer.replace(buf);
371                    self.i2c.disable();
372                    Err(error.into())
373                } else {
374                    Ok(())
375                }
376            })
377        } else {
378            Err(ErrorCode::BUSY)
379        }
380    }
381}
382
383impl<I: i2c::I2CDevice> i2c::I2CClient for Lsm6dsoxtrI2C<'_, I> {
384    fn command_complete(&self, buffer: &'static mut [u8], status: Result<(), i2c::Error>) {
385        match self.state.get() {
386            State::IsPresent => {
387                let id = buffer[0];
388                self.buffer.replace(buffer);
389                self.i2c.disable();
390                self.state.set(State::Idle);
391                if status == Ok(()) && id == 108 {
392                    self.is_present.set(true);
393                    if self.config_in_progress.get() {
394                        if let Err(_error) = self.set_accelerometer_power_mode(
395                            self.accel_data_rate.get(),
396                            self.low_power.get(),
397                        ) {
398                            self.config_in_progress.set(false);
399                        }
400                    }
401                } else {
402                    self.is_present.set(false);
403                    self.config_in_progress.set(false);
404                }
405
406                self.syscall_process.take().map(|pid| {
407                    let _res = self.apps.enter(pid, |_app, upcalls| {
408                        upcalls
409                            .schedule_upcall(
410                                0,
411                                (
412                                    into_statuscode(status.map_err(|i2c_error| i2c_error.into())),
413                                    usize::from(self.is_present.get()),
414                                    0,
415                                ),
416                            )
417                            .ok();
418                    });
419                });
420            }
421            State::Idle => {
422                //should never get here
423            }
424            State::ReadAccelerationXYZ => {
425                let mut x: usize = 0;
426                let mut y: usize = 0;
427                let mut z: usize = 0;
428
429                self.nine_dof_client.map(|nine_dof_client| {
430                    if status == Ok(()) {
431                        let scale_factor = self.accel_scale.get() as usize;
432                        x = ((((buffer[0] as u16 + ((buffer[1] as u16) << 8)) as i16) as isize)
433                            * (SCALE_FACTOR_ACCEL[scale_factor] as isize)
434                            / 1000) as usize;
435                        y = ((((buffer[2] as u16 + ((buffer[3] as u16) << 8)) as i16) as isize)
436                            * (SCALE_FACTOR_ACCEL[scale_factor] as isize)
437                            / 1000) as usize;
438
439                        z = ((((buffer[4] as u16 + ((buffer[5] as u16) << 8)) as i16) as isize)
440                            * (SCALE_FACTOR_ACCEL[scale_factor] as isize)
441                            / 1000) as usize;
442                        nine_dof_client.callback(x, y, z)
443                    } else {
444                        nine_dof_client.callback(0, 0, 0)
445                    }
446                });
447                self.buffer.replace(buffer);
448                self.i2c.disable();
449                self.state.set(State::Idle);
450            }
451
452            State::ReadGyroscopeXYZ => {
453                let mut x: usize = 0;
454                let mut y: usize = 0;
455                let mut z: usize = 0;
456                self.nine_dof_client.map(|nine_dof_client| {
457                    if status == Ok(()) {
458                        let scale_factor = self.gyro_range.get() as usize;
459                        x = (((buffer[0] as u16 + ((buffer[1] as u16) << 8)) as i16) as isize
460                            * (SCALE_FACTOR_GYRO[scale_factor] as isize)
461                            / 100) as usize;
462                        y = (((buffer[2] as u16 + ((buffer[3] as u16) << 8)) as i16) as isize
463                            * (SCALE_FACTOR_GYRO[scale_factor] as isize)
464                            / 100) as usize;
465
466                        z = (((buffer[4] as u16 + ((buffer[5] as u16) << 8)) as i16) as isize
467                            * (SCALE_FACTOR_GYRO[scale_factor] as isize)
468                            / 100) as usize;
469                        nine_dof_client.callback(x, y, z)
470                    } else {
471                        nine_dof_client.callback(0, 0, 0)
472                    }
473                });
474                self.buffer.replace(buffer);
475                self.i2c.disable();
476                self.state.set(State::Idle);
477            }
478
479            State::ReadTemperature => {
480                let temperature = match status {
481                    Ok(()) => Ok(((((buffer[0] as u16 + ((buffer[1] as u16) << 8)) as i16)
482                        as isize
483                        / (TEMP_SENSITIVITY_FACTOR as isize)
484                        + 25)
485                        * 100) as i32),
486                    Err(i2c_error) => Err(i2c_error.into()),
487                };
488                self.temperature_client
489                    .map(|client| client.callback(temperature));
490                self.buffer.replace(buffer);
491                self.i2c.disable();
492                self.state.set(State::Idle);
493            }
494
495            State::SetPowerModeAccel => {
496                self.buffer.replace(buffer);
497                self.i2c.disable();
498                self.state.set(State::Idle);
499                if status == Ok(()) {
500                    if self.config_in_progress.get() {
501                        if let Err(_error) = self.set_gyroscope_power_mode(
502                            self.gyro_data_rate.get(),
503                            self.low_power.get(),
504                        ) {
505                            self.config_in_progress.set(false);
506                        }
507                    }
508                } else {
509                    self.config_in_progress.set(false);
510                }
511                self.syscall_process.take().map(|pid| {
512                    let _res = self.apps.enter(pid, |_app, upcalls| {
513                        upcalls
514                            .schedule_upcall(
515                                0,
516                                (
517                                    into_statuscode(status.map_err(|i2c_error| i2c_error.into())),
518                                    usize::from(status == Ok(())),
519                                    0,
520                                ),
521                            )
522                            .ok();
523                    });
524                });
525            }
526
527            State::SetPowerModeGyro => {
528                self.buffer.replace(buffer);
529                self.i2c.disable();
530                self.state.set(State::Idle);
531                self.config_in_progress.set(false);
532                self.syscall_process.take().map(|pid| {
533                    let _res = self.apps.enter(pid, |_app, upcalls| {
534                        upcalls
535                            .schedule_upcall(
536                                0,
537                                (
538                                    into_statuscode(status.map_err(|i2c_error| i2c_error.into())),
539                                    usize::from(status == Ok(())),
540                                    0,
541                                ),
542                            )
543                            .ok();
544                    });
545                });
546            }
547        }
548    }
549}
550
551impl<I: i2c::I2CDevice> SyscallDriver for Lsm6dsoxtrI2C<'_, I> {
552    fn command(
553        &self,
554        command_num: usize,
555        data1: usize,
556        data2: usize,
557        process_id: ProcessId,
558    ) -> CommandReturn {
559        if command_num == 0 {
560            // Handle this first as it should be returned
561            // unconditionally
562            return CommandReturn::success();
563        }
564
565        match command_num {
566            // Check if the sensor is correctly connected
567            1 => {
568                if self.state.get() == State::Idle {
569                    match self.send_is_present() {
570                        Ok(()) => {
571                            self.syscall_process.set(process_id);
572                            CommandReturn::success()
573                        }
574                        Err(error) => CommandReturn::failure(error),
575                    }
576                } else {
577                    CommandReturn::failure(ErrorCode::BUSY)
578                }
579            }
580            // Set Accelerometer Power Mode
581            2 => {
582                if self.state.get() == State::Idle {
583                    if let Some(data_rate) = LSM6DSOXAccelDataRate::from_usize(data1) {
584                        match self.set_accelerometer_power_mode(data_rate, data2 != 0) {
585                            Ok(()) => {
586                                self.syscall_process.set(process_id);
587                                CommandReturn::success()
588                            }
589                            Err(error) => CommandReturn::failure(error),
590                        }
591                    } else {
592                        CommandReturn::failure(ErrorCode::INVAL)
593                    }
594                } else {
595                    CommandReturn::failure(ErrorCode::BUSY)
596                }
597            }
598            // Set Gyroscope Power Mode
599            3 => {
600                if self.state.get() == State::Idle {
601                    if let Some(data_rate) = LSM6DSOXGyroDataRate::from_usize(data1) {
602                        match self.set_gyroscope_power_mode(data_rate, data2 != 0) {
603                            Ok(()) => {
604                                self.syscall_process.set(process_id);
605                                CommandReturn::success()
606                            }
607                            Err(error) => CommandReturn::failure(error),
608                        }
609                    } else {
610                        CommandReturn::failure(ErrorCode::INVAL)
611                    }
612                } else {
613                    CommandReturn::failure(ErrorCode::BUSY)
614                }
615            }
616
617            _ => CommandReturn::failure(ErrorCode::NOSUPPORT),
618        }
619    }
620    fn allocate_grant(&self, processid: ProcessId) -> Result<(), kernel::process::Error> {
621        self.apps.enter(processid, |_, _| {})
622    }
623}
624
625impl<'a, I: i2c::I2CDevice> NineDof<'a> for Lsm6dsoxtrI2C<'a, I> {
626    fn set_client(&self, nine_dof_client: &'a dyn NineDofClient) {
627        self.nine_dof_client.replace(nine_dof_client);
628    }
629
630    fn read_accelerometer(&self) -> Result<(), ErrorCode> {
631        self.read_acceleration_xyz()
632    }
633
634    fn read_gyroscope(&self) -> Result<(), ErrorCode> {
635        self.read_gyroscope_xyz()
636    }
637}
638
639impl<'a, I: i2c::I2CDevice> sensors::TemperatureDriver<'a> for Lsm6dsoxtrI2C<'a, I> {
640    fn set_client(&self, temperature_client: &'a dyn sensors::TemperatureClient) {
641        self.temperature_client.replace(temperature_client);
642    }
643
644    fn read_temperature(&self) -> Result<(), ErrorCode> {
645        self.read_temperature()
646    }
647}