i2c.rs
1 //! `describe("I2C Bus Scanner")` 2 //! 3 //! Scans both I2C buses (wired per `config::i2c`) 4 //! for devices in the 7-bit 0x03..=0x77 range and prints each ACKing 5 //! address with a best-guess label via defmt. Flash this test when you 6 //! want to find out which bus a physical sensor is wired to. 7 //! 8 //! Canonical pin assignments come from `firmware/src/config.rs`: 9 //! i2c.0 → sda=GPIO8 scl=GPIO9 10 //! i2c.1 → sda=GPIO17 scl=GPIO18 11 //! 12 //! `#[ignore]` by default (requires hardware); opt in with 13 //! `--include-ignored`. 14 15 #![no_std] 16 #![no_main] 17 18 #[path = "common/mod.rs"] 19 mod common; 20 use common::{Device, tasks}; 21 use defmt::info; 22 23 esp_bootloader_esp_idf::esp_app_desc!(); 24 25 #[cfg(test)] 26 #[embedded_test::setup] 27 fn setup() { 28 rtt_target::rtt_init_defmt!(); 29 } 30 31 #[cfg(test)] 32 #[embedded_test::tests(default_timeout = 15, executor = esp_rtos::embassy::Executor::new())] 33 mod tests { 34 use super::*; 35 36 #[init] 37 fn init() -> Device { 38 info!("=== I2C Bus Scanner — describe block ==="); 39 common::setup::boot_device() 40 } 41 42 /// `it("user scans both buses and sees every wired I2C device")` 43 #[test] 44 async fn user_scans_both_buses_and_sees_every_wired_i2c_device( 45 mut device: Device, 46 ) -> Result<(), &'static str> { 47 common::setup::delay_seconds(1).await; 48 49 let (bus_0, bus_1) = tasks::i2c::scan_both_buses(&mut device)?; 50 let total = bus_0.found_addresses.len() + bus_1.found_addresses.len(); 51 52 info!("BUS ADDR DEVICE"); 53 for addr in bus_0.found_addresses.iter() { 54 info!( 55 "i2c.0 0x{=u8:02x} {=str}", 56 *addr, 57 firmware::hardware::i2c::device_name_at(*addr) 58 ); 59 } 60 for addr in bus_1.found_addresses.iter() { 61 info!( 62 "i2c.1 0x{=u8:02x} {=str}", 63 *addr, 64 firmware::hardware::i2c::device_name_at(*addr) 65 ); 66 } 67 68 info!( 69 "scan summary: bus0={=usize} bus1={=usize} total={=usize}", 70 bus_0.found_addresses.len(), 71 bus_1.found_addresses.len(), 72 total, 73 ); 74 75 defmt::assert!(total > 0, "no I2C devices found on either bus"); 76 Ok(()) 77 } 78 79 /// `it("user probes for TCA9548A mux on bus 1")` 80 #[test] 81 async fn user_probes_mux_on_bus_1( 82 mut device: Device, 83 ) -> Result<(), &'static str> { 84 if !tasks::i2c::is_mux_present(&mut device) { 85 info!("mux not present on this board — skipping"); 86 return Ok(()); 87 } 88 info!("TCA9548A mux detected at 0x70 on i2c.1"); 89 Ok(()) 90 } 91 92 /// `it("user selects a mux channel and verifies the mask")` 93 #[test] 94 async fn user_selects_mux_channel_and_verifies( 95 mut device: Device, 96 ) -> Result<(), &'static str> { 97 if !tasks::i2c::is_mux_present(&mut device) { 98 info!("mux not present — skipping"); 99 return Ok(()); 100 } 101 102 let bus = device.i2c_bus_1.as_mut().ok_or("i2c bus 1 consumed")?; 103 104 tasks::i2c::select_mux_channel(bus, 0)?; 105 let mask = tasks::i2c::access_channel_mask(bus)?; 106 defmt::assert_eq!(mask & (1 << 0), 1, "bit 0 should be set after select(0)"); 107 108 tasks::i2c::select_mux_channel(bus, 3)?; 109 let mask = tasks::i2c::access_channel_mask(bus)?; 110 defmt::assert_eq!(mask & (1 << 3), (1 << 3), "bit 3 should be set after select(3)"); 111 defmt::assert_eq!(mask & (1 << 0), 0, "bit 0 should be clear after select(3)"); 112 113 tasks::i2c::disable_all_channels(bus)?; 114 info!("mux channel select and verify passed"); 115 Ok(()) 116 } 117 118 /// `it("user disables all mux channels and sees mask 0x00")` 119 #[test] 120 async fn user_disables_all_mux_channels( 121 mut device: Device, 122 ) -> Result<(), &'static str> { 123 if !tasks::i2c::is_mux_present(&mut device) { 124 info!("mux not present — skipping"); 125 return Ok(()); 126 } 127 128 let bus = device.i2c_bus_1.as_mut().ok_or("i2c bus 1 consumed")?; 129 130 tasks::i2c::select_mux_channel(bus, 0)?; 131 tasks::i2c::select_mux_channel(bus, 3)?; 132 tasks::i2c::select_mux_channel(bus, 7)?; 133 134 tasks::i2c::disable_all_channels(bus)?; 135 let mask = tasks::i2c::access_channel_mask(bus)?; 136 defmt::assert_eq!(mask, 0x00, "mask should be 0x00 after disable all"); 137 138 info!("disable all channels verified"); 139 Ok(()) 140 } 141 142 /// `it("user enables then disables a single mux channel")` 143 #[test] 144 async fn user_enables_then_disables_single_channel( 145 mut device: Device, 146 ) -> Result<(), &'static str> { 147 if !tasks::i2c::is_mux_present(&mut device) { 148 info!("mux not present — skipping"); 149 return Ok(()); 150 } 151 152 let bus = device.i2c_bus_1.as_mut().ok_or("i2c bus 1 consumed")?; 153 154 tasks::i2c::disable_all_channels(bus)?; 155 156 tasks::i2c::select_mux_channel(bus, 2)?; 157 let mask = tasks::i2c::access_channel_mask(bus)?; 158 defmt::assert_eq!(mask & (1 << 2), (1 << 2), "bit 2 should be set"); 159 160 tasks::i2c::disable_all_channels(bus)?; 161 let mask = tasks::i2c::access_channel_mask(bus)?; 162 defmt::assert_eq!(mask, 0x00, "mask should be 0x00 after disable"); 163 164 info!("enable/disable roundtrip verified"); 165 Ok(()) 166 } 167 }