feat: add display UI with splash screen, dashboard, and RSSI sparkline
Implement full SSD1306 OLED display support: - Splash screen on boot (1.5s) with project name, version, board - Dashboard showing radio state, config, counters, RSSI/SNR - RSSI history sparkline (64-sample ring buffer, 2px-wide bars) - DisplayOn/DisplayOff host commands routed via dedicated channel - Pure render functions against generic DrawTarget (no hardware coupling) - Display on/off control bypasses radio task entirely Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
17624 files changed
+4564928
-38
No files matched your search
Vendored
+108
@@ -0,0 +1,108 @@
|
||||
# SSD1306 driver
|
||||
|
||||
[](https://github.com/rust-embedded-community/ssd1306/actions/workflows/ci.yml)
|
||||
[](https://crates.io/crates/ssd1306)
|
||||
[](https://docs.rs/ssd1306)
|
||||
|
||||
[](examples/image_i2c.rs)
|
||||
|
||||
I2C and SPI (4 wire) driver for the SSD1306 OLED display.
|
||||
|
||||
## [Documentation](https://docs.rs/ssd1306)
|
||||
|
||||
## [Changelog](CHANGELOG.md)
|
||||
|
||||
## [Examples](examples)
|
||||
|
||||
This crate uses [`probe-run`](https://crates.io/crates/probe-run) to run the examples. Once set up,
|
||||
it should be as simple as `cargo run --example <example name> --release`.
|
||||
|
||||
From [`examples/image_i2c.rs`](examples/image_i2c.rs):
|
||||
|
||||
```rust
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use cortex_m_rt::{entry, exception, ExceptionFrame};
|
||||
use embedded_graphics::{
|
||||
image::{Image, ImageRaw},
|
||||
pixelcolor::BinaryColor,
|
||||
prelude::*,
|
||||
};
|
||||
use panic_halt as _;
|
||||
use ssd1306::{prelude::*, I2CDisplayInterface, Ssd1306};
|
||||
use stm32f1xx_hal::{
|
||||
i2c::{BlockingI2c, DutyCycle, Mode},
|
||||
prelude::*,
|
||||
stm32,
|
||||
};
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
let dp = stm32::Peripherals::take().unwrap();
|
||||
|
||||
let mut flash = dp.FLASH.constrain();
|
||||
let mut rcc = dp.RCC.constrain();
|
||||
|
||||
let clocks = rcc.cfgr.freeze(&mut flash.acr);
|
||||
|
||||
let mut afio = dp.AFIO.constrain(&mut rcc.apb2);
|
||||
|
||||
let mut gpiob = dp.GPIOB.split(&mut rcc.apb2);
|
||||
|
||||
let scl = gpiob.pb8.into_alternate_open_drain(&mut gpiob.crh);
|
||||
let sda = gpiob.pb9.into_alternate_open_drain(&mut gpiob.crh);
|
||||
|
||||
let i2c = BlockingI2c::i2c1(
|
||||
dp.I2C1,
|
||||
(scl, sda),
|
||||
&mut afio.mapr,
|
||||
Mode::Fast {
|
||||
frequency: 400_000.hz(),
|
||||
duty_cycle: DutyCycle::Ratio2to1,
|
||||
},
|
||||
clocks,
|
||||
&mut rcc.apb1,
|
||||
1000,
|
||||
10,
|
||||
1000,
|
||||
1000,
|
||||
);
|
||||
|
||||
let interface = I2CDisplayInterface::new(i2c);
|
||||
let mut display = Ssd1306::new(interface, DisplaySize128x64, DisplayRotation::Rotate0)
|
||||
.into_buffered_graphics_mode();
|
||||
display.init().unwrap();
|
||||
|
||||
let raw: ImageRaw<BinaryColor> = ImageRaw::new(include_bytes!("./rust.raw"), 64);
|
||||
|
||||
let im = Image::new(&raw, Point::new(32, 0));
|
||||
|
||||
im.draw(&mut display).unwrap();
|
||||
|
||||
display.flush().unwrap();
|
||||
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[exception]
|
||||
fn HardFault(ef: &ExceptionFrame) -> ! {
|
||||
panic!("{:#?}", ef);
|
||||
}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of
|
||||
|
||||
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
|
||||
http://www.apache.org/licenses/LICENSE-2.0)
|
||||
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the
|
||||
work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
|
||||
additional terms or conditions.
|
||||
Reference in new issue
Block a user