1use core::cell::Cell;
41use kernel::hil::i2c::{self, I2CClient, I2CDevice};
42use kernel::hil::sensors::{NineDof, NineDofClient};
43use kernel::utilities::cells::{OptionalCell, TakeCell};
44use kernel::ErrorCode;
45
46#[allow(dead_code)]
47enum Registers {
48    ChipID = 0x40,
49    DATAxLsb = 0x42,
50    DATAxMsb = 0x43,
51    DATAyLsb = 0x44,
52    DATAyMsb = 0x45,
53    DATAzLsb = 0x46,
54    DATAzMsb = 0x47,
55    RHALLlsb = 0x48,
56    RHALLmsb = 0x49,
57    INTST = 0x4A,
58    CTRL1 = 0x4B,
59    CTRL2 = 0x4C,
60    CTRL3 = 0x4D,
61    CTRL4 = 0x4E,
62    LoThres = 0x4F,
63    HiThres = 0x50,
64    REPXY = 0x51,
65    REPZ = 0x52,
66}
67
68pub struct BMM150<'a, I: I2CDevice> {
69    buffer: TakeCell<'static, [u8]>,
70    i2c: &'a I,
71    ninedof_client: OptionalCell<&'a dyn NineDofClient>,
72    state: Cell<State>,
73}
74
75impl<'a, I: I2CDevice> BMM150<'a, I> {
76    pub fn new(buffer: &'static mut [u8], i2c: &'a I) -> BMM150<'a, I> {
77        BMM150 {
78            buffer: TakeCell::new(buffer),
79            i2c,
80            ninedof_client: OptionalCell::empty(),
81            state: Cell::new(State::Suspend),
82        }
83    }
84
85    pub fn start_measurement(&self) -> Result<(), ErrorCode> {
86        self.buffer
87            .take()
88            .map(|buffer| {
89                self.i2c.enable();
90                match self.state.get() {
91                    State::Suspend => {
92                        buffer[0] = Registers::CTRL1 as u8;
93                        buffer[1] = 0x1_u8;
94
95                        if let Err((_error, buffer)) = self.i2c.write(buffer, 2) {
96                            self.buffer.replace(buffer);
97                            self.i2c.disable();
98                        } else {
99                            self.state.set(State::PowerOn);
100                        }
101                    }
102                    State::Sleep => {
103                        buffer[0] = Registers::CTRL2 as u8;
104                        buffer[1] = 0x3A_u8;
105
106                        if let Err((_error, buffer)) = self.i2c.write(buffer, 2) {
107                            self.buffer.replace(buffer);
108                            self.i2c.disable();
109                        } else {
110                            self.state.set(State::InitializeReading);
111                        }
112                    }
113                    _ => {}
114                }
115            })
116            .ok_or(ErrorCode::FAIL)
117    }
118}
119
120impl<'a, I: i2c::I2CDevice> NineDof<'a> for BMM150<'a, I> {
121    fn set_client(&self, client: &'a dyn NineDofClient) {
122        self.ninedof_client.set(client);
123    }
124
125    fn read_magnetometer(&self) -> Result<(), ErrorCode> {
126        self.start_measurement()
127    }
128}
129
130#[derive(Clone, Copy, Debug)]
131enum State {
132    Suspend,
133    Sleep,
134    PowerOn,
135    InitializeReading,
136    ReadMeasurement,
137    Read,
138}
139
140impl<I: I2CDevice> I2CClient for BMM150<'_, I> {
141    fn command_complete(&self, buffer: &'static mut [u8], status: Result<(), i2c::Error>) {
142        if let Err(i2c_err) = status {
143            self.state.set(State::Sleep);
144            self.buffer.replace(buffer);
145            self.ninedof_client
146                .map(|client| client.callback(i2c_err as usize, 0, 0));
147            return;
148        }
149
150        match self.state.get() {
151            State::PowerOn => {
152                buffer[0] = Registers::CTRL2 as u8;
153                buffer[1] = 0x3A_u8;
154
155                if let Err((error, buffer)) = self.i2c.write(buffer, 2) {
156                    self.buffer.replace(buffer);
157                    self.i2c.disable();
158                    self.ninedof_client
159                        .map(|client| client.callback(error as usize, 0, 0));
160                } else {
161                    self.state.set(State::InitializeReading);
162                }
163            }
164            State::InitializeReading => {
165                buffer[0] = Registers::DATAxLsb as u8;
166
167                if let Err((i2c_err, buffer)) = self.i2c.write(buffer, 1) {
168                    self.state.set(State::Sleep);
169                    self.buffer.replace(buffer);
170                    self.ninedof_client
171                        .map(|client| client.callback(i2c_err as usize, 0, 0));
172                } else {
173                    self.state.set(State::ReadMeasurement);
174                }
175            }
176            State::ReadMeasurement => {
177                if let Err((i2c_err, buffer)) = self.i2c.read(buffer, 8) {
178                    self.state.set(State::Sleep);
179                    self.buffer.replace(buffer);
180                    self.ninedof_client
181                        .map(|client| client.callback(i2c_err as usize, 0, 0));
182                } else {
183                    self.state.set(State::Read);
184                }
185            }
186            State::Read => {
187                let x_axis = ((buffer[1] as i16) << 5) | ((buffer[0] as i16) >> 3);
188                let y_axis = ((buffer[3] as i16) << 5) | ((buffer[2] as i16) >> 3);
189                let z_axis = ((buffer[5] as i16) << 7) | ((buffer[4] as i16) >> 1);
190
191                self.state.set(State::Sleep);
192                self.buffer.replace(buffer);
193                self.i2c.disable();
194                self.ninedof_client.map(|client| {
195                    client.callback(x_axis as usize, y_axis as usize, z_axis as usize)
196                });
197            }
198            State::Sleep => {}   State::Suspend => {} }
201    }
202}