imix/test/
i2c_dummy.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//! A dummy I2C client
6
7use core::cell::Cell;
8use core::ptr::addr_of_mut;
9use kernel::debug;
10use kernel::hil;
11use kernel::hil::i2c::{Error, I2CMaster};
12
13// ===========================================
14// Scan for I2C Slaves
15// ===========================================
16
17struct ScanClient {
18    dev_id: Cell<u8>,
19    i2c_master: &'static dyn I2CMaster<'static>,
20}
21
22impl ScanClient {
23    pub fn new(i2c_master: &'static dyn I2CMaster<'static>) -> Self {
24        Self {
25            dev_id: Cell::new(1),
26            i2c_master,
27        }
28    }
29}
30
31impl hil::i2c::I2CHwMasterClient for ScanClient {
32    fn command_complete(&self, buffer: &'static mut [u8], status: Result<(), Error>) {
33        let mut dev_id = self.dev_id.get();
34
35        if status == Ok(()) {
36            debug!("{:#x}", dev_id);
37        }
38
39        let dev: &dyn I2CMaster<'static> = self.i2c_master;
40        if dev_id < 0x7F {
41            dev_id += 1;
42            self.dev_id.set(dev_id);
43            dev.write(dev_id, buffer, 2).unwrap();
44        } else {
45            debug!(
46                "Done scanning for I2C devices. Buffer len: {}",
47                buffer.len()
48            );
49        }
50    }
51}
52
53/// This test should be called with I2C2, specifically
54pub fn i2c_scan_slaves(i2c_master: &'static dyn I2CMaster<'static>) {
55    static mut DATA: [u8; 255] = [0; 255];
56
57    let dev = i2c_master;
58
59    let i2c_client = unsafe { kernel::static_init!(ScanClient, ScanClient::new(dev)) };
60    dev.set_master_client(i2c_client);
61
62    dev.enable();
63
64    debug!("Scanning for I2C devices...");
65    dev.write(
66        i2c_client.dev_id.get(),
67        unsafe { &mut *addr_of_mut!(DATA) },
68        2,
69    )
70    .unwrap();
71}
72
73// ===========================================
74// Test FXOS8700CQ
75// ===========================================
76
77#[derive(Copy, Clone)]
78enum AccelClientState {
79    ReadingWhoami,
80    Activating,
81    Deactivating,
82    ReadingAccelData,
83}
84
85struct AccelClient {
86    state: Cell<AccelClientState>,
87    i2c_master: &'static dyn I2CMaster<'static>,
88}
89
90impl AccelClient {
91    pub fn new(i2c_master: &'static dyn I2CMaster<'static>) -> Self {
92        Self {
93            state: Cell::new(AccelClientState::ReadingWhoami),
94            i2c_master,
95        }
96    }
97}
98
99impl hil::i2c::I2CHwMasterClient for AccelClient {
100    fn command_complete(&self, buffer: &'static mut [u8], status: Result<(), Error>) {
101        let dev = self.i2c_master;
102
103        match self.state.get() {
104            AccelClientState::ReadingWhoami => {
105                debug!("WHOAMI Register 0x{:x} ({:?})", buffer[0], status);
106                debug!("Activating Sensor...");
107                buffer[0] = 0x2A_u8; // CTRL_REG1
108                buffer[1] = 1; // Bit 1 sets `active`
109                dev.write(0x1e, buffer, 2).unwrap();
110                self.state.set(AccelClientState::Activating);
111            }
112            AccelClientState::Activating => {
113                debug!("Sensor Activated ({:?})", status);
114                buffer[0] = 0x01_u8; // X-MSB register
115                                     // Reading 6 bytes will increment the register pointer through
116                                     // X-MSB, X-LSB, Y-MSB, Y-LSB, Z-MSB, Z-LSB
117                dev.write_read(0x1e, buffer, 1, 6).unwrap();
118                self.state.set(AccelClientState::ReadingAccelData);
119            }
120            AccelClientState::ReadingAccelData => {
121                let x = (((buffer[0] as u16) << 8) | buffer[1] as u16) as usize;
122                let y = (((buffer[2] as u16) << 8) | buffer[3] as u16) as usize;
123                let z = (((buffer[4] as u16) << 8) | buffer[5] as u16) as usize;
124
125                let x = ((x >> 2) * 976) / 1000;
126                let y = ((y >> 2) * 976) / 1000;
127                let z = ((z >> 2) * 976) / 1000;
128
129                debug!(
130                    "Accel data ready x: {}, y: {}, z: {} ({:?})",
131                    x >> 2,
132                    y >> 2,
133                    z >> 2,
134                    status
135                );
136
137                buffer[0] = 0x01_u8; // X-MSB register
138                                     // Reading 6 bytes will increment the register pointer through
139                                     // X-MSB, X-LSB, Y-MSB, Y-LSB, Z-MSB, Z-LSB
140                dev.write_read(0x1e, buffer, 1, 6).unwrap();
141                self.state.set(AccelClientState::ReadingAccelData);
142            }
143            AccelClientState::Deactivating => {
144                debug!("Sensor deactivated ({:?})", status);
145                debug!("Reading Accel's WHOAMI...");
146                buffer[0] = 0x0D_u8; // 0x0D == WHOAMI register
147                dev.write_read(0x1e, buffer, 1, 1).unwrap();
148                self.state.set(AccelClientState::ReadingWhoami);
149            }
150        }
151    }
152}
153
154/// This test should be called with I2C2, specifically
155pub fn i2c_accel_test(i2c_master: &'static dyn I2CMaster<'static>) {
156    static mut DATA: [u8; 255] = [0; 255];
157
158    let dev = i2c_master;
159
160    let i2c_client = unsafe { kernel::static_init!(AccelClient, AccelClient::new(dev)) };
161    dev.set_master_client(i2c_client);
162    dev.enable();
163
164    let buf = unsafe { &mut *addr_of_mut!(DATA) };
165    debug!("Reading Accel's WHOAMI...");
166    buf[0] = 0x0D_u8; // 0x0D == WHOAMI register
167    dev.write_read(0x1e, buf, 1, 1).unwrap();
168    i2c_client.state.set(AccelClientState::ReadingWhoami);
169}
170
171// ===========================================
172// Test LI
173// ===========================================
174
175#[derive(Copy, Clone)]
176enum LiClientState {
177    Enabling,
178    ReadingLI,
179}
180
181struct LiClient {
182    state: Cell<LiClientState>,
183    i2c_master: &'static dyn I2CMaster<'static>,
184}
185
186impl LiClient {
187    pub fn new(i2c_master: &'static dyn I2CMaster<'static>) -> Self {
188        Self {
189            state: Cell::new(LiClientState::Enabling),
190            i2c_master,
191        }
192    }
193}
194
195impl hil::i2c::I2CHwMasterClient for LiClient {
196    fn command_complete(&self, buffer: &'static mut [u8], status: Result<(), Error>) {
197        let dev = self.i2c_master;
198
199        match self.state.get() {
200            LiClientState::Enabling => {
201                debug!("Reading luminance Registers ({:?})", status);
202                buffer[0] = 0x02_u8;
203                buffer[0] = 0;
204                dev.write_read(0x44, buffer, 1, 2).unwrap();
205                self.state.set(LiClientState::ReadingLI);
206            }
207            LiClientState::ReadingLI => {
208                let intensity = ((buffer[1] as usize) << 8) | buffer[0] as usize;
209                debug!(
210                    "Light Intensity: {}% ({:?})",
211                    (intensity * 100) >> 16,
212                    status
213                );
214                buffer[0] = 0x02_u8;
215                dev.write_read(0x44, buffer, 1, 2).unwrap();
216                self.state.set(LiClientState::ReadingLI);
217            }
218        }
219    }
220}
221
222/// This test should be called with I2C2, specifically
223pub fn i2c_li_test(i2c_master: &'static dyn I2CMaster<'static>) {
224    static mut DATA: [u8; 255] = [0; 255];
225
226    let pin = sam4l::gpio::GPIOPin::new(sam4l::gpio::Pin::PA16);
227    pin.enable_output();
228    pin.set();
229
230    let dev = i2c_master;
231
232    let i2c_client = unsafe { kernel::static_init!(LiClient, LiClient::new(dev)) };
233    dev.set_master_client(i2c_client);
234    dev.enable();
235
236    let buf = unsafe { &mut *addr_of_mut!(DATA) };
237    debug!("Enabling LI...");
238    buf[0] = 0;
239    buf[1] = 0b10100000;
240    buf[2] = 0b00000000;
241    dev.write(0x44, buf, 3).unwrap();
242    i2c_client.state.set(LiClientState::Enabling);
243}