A personal rust firmware for the Badger 2040 W

We got real time temps homie

Changed files
+69 -34
src
badge_display
+10
Cargo.lock
··· 906 906 "reqwless", 907 907 "serde", 908 908 "serde-json-core", 909 + "shtcx", 909 910 "smart-leds", 910 911 "st7789", 911 912 "static_cell", ··· 2130 2131 version = "0.1.0" 2131 2132 source = "registry+https://github.com/rust-lang/crates.io-index" 2132 2133 checksum = "5f179d4e11094a893b82fff208f74d448a7512f99f5a0acbd5c679b705f83ed9" 2134 + 2135 + [[package]] 2136 + name = "shtcx" 2137 + version = "1.0.0" 2138 + source = "registry+https://github.com/rust-lang/crates.io-index" 2139 + checksum = "2c25d66e6c78c6e19160a5b528cebe6f54d5737f091a2b90b08dbd7e63a9269f" 2140 + dependencies = [ 2141 + "embedded-hal 1.0.0", 2142 + ] 2133 2143 2134 2144 [[package]] 2135 2145 name = "siphasher"
+1
Cargo.toml
··· 104 104 ] } 105 105 embedded-text = "0.7.0" 106 106 tinybmp = "0.5.0" 107 + shtcx = "1.0.0" 107 108 108 109 [profile.release] 109 110 debug = 2
+12 -16
src/badge_display/mod.rs
··· 4 4 cell::RefCell, 5 5 sync::atomic::{AtomicBool, AtomicU32, AtomicU8}, 6 6 }; 7 - use cortex_m::interrupt::CriticalSection; 8 7 use defmt::*; 9 8 use display_image::get_current_image; 10 9 use embassy_embedded_hal::shared_bus::asynch::spi::SpiDevice; ··· 42 41 pub static CURRENT_IMAGE: AtomicU8 = AtomicU8::new(0); 43 42 pub static CHANGE_IMAGE: AtomicBool = AtomicBool::new(true); 44 43 pub static WIFI_COUNT: AtomicU32 = AtomicU32::new(0); 45 - 46 44 pub static RTC_TIME_STRING: blocking_mutex::Mutex<CriticalSectionRawMutex, RefCell<String<8>>> = 47 45 blocking_mutex::Mutex::new(RefCell::new(String::<8>::new())); 48 - 46 + pub static TEMP: AtomicU8 = AtomicU8::new(0); 47 + pub static HUMIDITY: AtomicU8 = AtomicU8::new(0); 49 48 pub static HOUR: AtomicU8 = AtomicU8::new(10); 50 49 pub static MINUTE: AtomicU8 = AtomicU8::new(57); 51 50 pub static SECOND: AtomicU8 = AtomicU8::new(0); ··· 122 121 //Runs every 30 cycles/15 seconds and first run 123 122 if cycles_since_last_clear % 30 == 0 || first_run { 124 123 let count = WIFI_COUNT.load(core::sync::atomic::Ordering::Relaxed); 125 - let count_text: String<16> = easy_format::<16>(format_args!("Count: {}", count)); 126 - let count_bounds = Rectangle::new(Point::new(0, 0), Size::new(WIDTH, 24)); 127 - count_bounds 124 + let temp = TEMP.load(core::sync::atomic::Ordering::Relaxed); 125 + let humidity = HUMIDITY.load(core::sync::atomic::Ordering::Relaxed); 126 + let top_text: String<64> = 127 + easy_format::<64>(format_args!("{}F {}% Count: {}", temp, humidity, count)); 128 + let top_bounds = Rectangle::new(Point::new(0, 0), Size::new(WIDTH, 24)); 129 + top_bounds 128 130 .into_styled( 129 131 PrimitiveStyleBuilder::default() 130 132 .stroke_color(BinaryColor::Off) ··· 135 137 .draw(&mut display) 136 138 .unwrap(); 137 139 138 - Text::new(count_text.as_str(), Point::new(8, 16), character_style) 140 + Text::new(top_text.as_str(), Point::new(8, 16), character_style) 139 141 .draw(&mut display) 140 142 .unwrap(); 141 143 142 - // // Draw the text box. 143 - let result = display 144 - .partial_update(count_bounds.try_into().unwrap()) 145 - .await; 144 + // Draw the text box. 145 + let result = display.partial_update(top_bounds.try_into().unwrap()).await; 146 146 match result { 147 147 Ok(_) => {} 148 148 Err(_) => { 149 149 info!("Error updating display"); 150 150 } 151 151 } 152 - // let _ = display.clear(Rgb565::WHITE.into()); 153 - // let _ = display.update().await; 152 + 154 153 WIFI_COUNT.store(count + 1, core::sync::atomic::Ordering::Relaxed); 155 154 } 156 155 ··· 207 206 let tga: Bmp<BinaryColor> = Bmp::from_slice(&current_image.image()).unwrap(); 208 207 let image = Image::new(&tga, current_image.image_location()); 209 208 //clear image location by writing a white rectangle over previous image location 210 - let image_bounds = Size::new(160, 140); 211 209 let clear_rectangle = Rectangle::new( 212 210 current_image.previous().image_location(), 213 211 Size::new(157, 101), ··· 219 217 220 218 let _ = image.draw(&mut display); 221 219 //TODO need to look up the reginal area display 222 - // let update_region = UpdateRegion::new(192, 32, 160, 144).unwrap(); 223 - // let result = display.partial_update(update_region).await; 224 220 let _ = display.update().await; 225 221 CHANGE_IMAGE.store(false, core::sync::atomic::Ordering::Relaxed); 226 222 }
+8 -18
src/main.rs
··· 16 16 use embassy_rp::spi::{self}; 17 17 use embassy_sync::blocking_mutex::raw::NoopRawMutex; 18 18 use embassy_sync::mutex::Mutex; 19 - use embassy_time::{Delay, Duration, Timer}; 20 - use embedded_graphics::{ 21 - image::Image, 22 - mono_font::{ascii::*, MonoTextStyle}, 23 - pixelcolor::BinaryColor, 24 - prelude::*, 25 - primitives::{PrimitiveStyle, Rectangle}, 26 - }; 27 - use embedded_text::{ 28 - alignment::HorizontalAlignment, 29 - style::{HeightMode, TextBoxStyleBuilder}, 30 - TextBox, 31 - }; 19 + use embassy_time::{Duration, Timer}; 32 20 use gpio::{Level, Output, Pull}; 33 21 use helpers::easy_format; 34 22 use static_cell::StaticCell; 23 + use temp_sensor::run_the_temp_sensor; 35 24 use {defmt_rtt as _, panic_probe as _}; 36 25 37 26 mod badge_display; 38 27 mod cyw43_driver; 39 28 mod env; 40 29 mod helpers; 30 + mod temp_sensor; 41 31 42 32 type Spi0Bus = Mutex<NoopRawMutex, Spi<'static, SPI0, spi::Async>>; 43 33 ··· 73 63 let _btn_b = Input::new(p.PIN_13, Pull::Down); 74 64 let btn_c = Input::new(p.PIN_14, Pull::Down); 75 65 76 - // let mut btn_c: Debouncer<'_> = Debouncer::new(Input::new(btn_c, Pull::Up), Duration::from_millis(20)); 77 - 78 66 let spi = Spi::new( 79 67 p.SPI0, 80 68 clk, ··· 84 72 p.DMA_CH2, 85 73 spi::Config::default(), 86 74 ); 87 - // let spi_bus: Mutex<NoopRawMutex, _> = Mutex::new(spi); 75 + 76 + //SPI Bus setup to run the e-ink display 88 77 static SPI_BUS: StaticCell<Spi0Bus> = StaticCell::new(); 89 78 let spi_bus = SPI_BUS.init(Mutex::new(spi)); 90 79 91 80 info!("led on!"); 92 81 // control.gpio_set(0, true).await; 82 + spawner.must_spawn(run_the_temp_sensor(p.I2C0, p.PIN_5, p.PIN_4)); 93 83 spawner.must_spawn(run_the_display(spi_bus, cs, dc, busy, reset)); 94 84 95 85 //rtc setup ··· 101 91 month: 1, 102 92 day: 1, 103 93 day_of_week: DayOfWeek::Saturday, 104 - hour: 0, 105 - minute: 0, 94 + hour: 18, 95 + minute: 31, 106 96 second: 0, 107 97 }; 108 98 rtc.set_datetime(now).unwrap();
+38
src/temp_sensor.rs
··· 1 + use bt_hci::cmd::info; 2 + use defmt::*; 3 + use embassy_rp::i2c::{I2c, SclPin, SdaPin}; 4 + use embassy_rp::peripherals::I2C0; 5 + use embassy_rp::{i2c, Peripheral}; 6 + use embassy_time::Timer; 7 + use shtcx::{self, PowerMode}; 8 + 9 + use crate::badge_display::{HUMIDITY, TEMP}; // Import the necessary items from shtcx 10 + 11 + #[embassy_executor::task] 12 + pub async fn run_the_temp_sensor( 13 + i2c0: I2C0, 14 + scl: impl Peripheral<P = impl SclPin<I2C0>> + 'static, 15 + sda: impl Peripheral<P = impl SdaPin<I2C0>> + 'static, 16 + ) { 17 + let i2c = I2c::new_blocking(i2c0, scl, sda, i2c::Config::default()); 18 + 19 + let mut sht = shtcx::shtc3(i2c); 20 + let mut sht_delay = embassy_time::Delay; // Create a delay instance 21 + 22 + loop { 23 + let combined = sht.measure(PowerMode::NormalMode, &mut sht_delay).unwrap(); 24 + let celsius = combined.temperature.as_degrees_celsius(); 25 + let fahrenheit = (celsius * 9.0 / 5.0) + 32.0; 26 + info!( 27 + "Temperature: {}°F, Humidity: {}%", 28 + fahrenheit, 29 + combined.humidity.as_percent() 30 + ); 31 + TEMP.store(fahrenheit as u8, core::sync::atomic::Ordering::Relaxed); 32 + HUMIDITY.store( 33 + combined.humidity.as_percent() as u8, 34 + core::sync::atomic::Ordering::Relaxed, 35 + ); 36 + Timer::after_secs(120).await; 37 + } 38 + }