mirror of
https://github.com/LegitCamper/picocalc-os-rs.git
synced 2025-12-28 00:05:28 +00:00
add status bar to console
This commit is contained in:
7
Cargo.lock
generated
7
Cargo.lock
generated
@@ -1006,9 +1006,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.9.0"
|
version = "2.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
|
checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
@@ -1730,10 +1730,11 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "st7365p-lcd"
|
name = "st7365p-lcd"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
source = "git+https://github.com/legitcamper/st7365p-lcd-rs#d751e8d30f1a3f964ffe05e4bb16f82112fbefce"
|
source = "git+https://github.com/legitcamper/st7365p-lcd-rs?branch=async#9f8da568ff695a00afb6b8b8cf9573fad408a66f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"embedded-graphics-core",
|
"embedded-graphics-core",
|
||||||
"embedded-hal 1.0.0",
|
"embedded-hal 1.0.0",
|
||||||
|
"embedded-hal-async",
|
||||||
"nb 1.1.0",
|
"nb 1.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ defmt-rtt = "0.4.2"
|
|||||||
|
|
||||||
embedded-graphics = { version = "0.8.1" }
|
embedded-graphics = { version = "0.8.1" }
|
||||||
embedded-sdmmc = { git = "https://github.com/Be-ing/embedded-sdmmc-rs", branch = "bisync", default-features = false }
|
embedded-sdmmc = { git = "https://github.com/Be-ing/embedded-sdmmc-rs", branch = "bisync", default-features = false }
|
||||||
st7365p-lcd = { git = "https://github.com/legitcamper/st7365p-lcd-rs" }
|
st7365p-lcd = { git = "https://github.com/legitcamper/st7365p-lcd-rs", branch = "async" }
|
||||||
|
|
||||||
static_cell = "2.1.1"
|
static_cell = "2.1.1"
|
||||||
bitflags = "2.9.1"
|
bitflags = "2.9.1"
|
||||||
|
|||||||
157
src/display.rs
157
src/display.rs
@@ -1,27 +1,42 @@
|
|||||||
use embassy_rp::{
|
use embassy_rp::{
|
||||||
gpio::{Level, Output},
|
gpio::{Level, Output},
|
||||||
peripherals::{PIN_13, PIN_14, PIN_15, SPI1},
|
peripherals::{PIN_13, PIN_14, PIN_15, SPI1},
|
||||||
spi::{Blocking, Spi},
|
spi::{Async, Spi},
|
||||||
};
|
};
|
||||||
use embassy_time::{Delay, Timer};
|
use embassy_time::{Delay, Timer};
|
||||||
use embedded_graphics::{
|
|
||||||
Drawable, Pixel,
|
|
||||||
pixelcolor::{Rgb565, raw::RawU16},
|
|
||||||
prelude::{DrawTarget, OriginDimensions, Point, Primitive, RawData, RgbColor, Size},
|
|
||||||
primitives::{PrimitiveStyle, Rectangle},
|
|
||||||
};
|
|
||||||
use embedded_hal_bus::spi::ExclusiveDevice;
|
use embedded_hal_bus::spi::ExclusiveDevice;
|
||||||
use st7365p_lcd::{Orientation, ST7365P};
|
use st7365p_lcd::{FrameBuffer, Orientation, ST7365P};
|
||||||
|
|
||||||
|
use arrform::{ArrForm, arrform};
|
||||||
|
use embedded_graphics::{
|
||||||
|
Drawable,
|
||||||
|
draw_target::DrawTarget,
|
||||||
|
mono_font::{
|
||||||
|
MonoTextStyle,
|
||||||
|
ascii::{FONT_6X10, FONT_9X15, FONT_10X20},
|
||||||
|
},
|
||||||
|
object_chain::Chain,
|
||||||
|
pixelcolor::Rgb565,
|
||||||
|
prelude::{Point, RgbColor, Size},
|
||||||
|
primitives::Rectangle,
|
||||||
|
text::Text,
|
||||||
|
};
|
||||||
|
use embedded_layout::{
|
||||||
|
align::{horizontal, vertical},
|
||||||
|
layout::linear::LinearLayout,
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const SCREEN_WIDTH: usize = 320;
|
||||||
|
pub const SCREEN_HEIGHT: usize = 320;
|
||||||
|
|
||||||
|
pub const STATUS_BAR_WIDTH: usize = 320;
|
||||||
|
pub const STATUS_BAR_HEIGHT: usize = 40;
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
pub async fn display_task(
|
pub async fn display_task(spi: Spi<'static, SPI1, Async>, cs: PIN_13, data: PIN_14, reset: PIN_15) {
|
||||||
spi: Spi<'static, SPI1, Blocking>,
|
|
||||||
cs: PIN_13,
|
|
||||||
data: PIN_14,
|
|
||||||
reset: PIN_15,
|
|
||||||
) {
|
|
||||||
let spi_device = ExclusiveDevice::new(spi, Output::new(cs, Level::Low), Delay).unwrap();
|
let spi_device = ExclusiveDevice::new(spi, Output::new(cs, Level::Low), Delay).unwrap();
|
||||||
let mut display = ST7365P::new(
|
let display = ST7365P::new(
|
||||||
spi_device,
|
spi_device,
|
||||||
Output::new(data, Level::Low),
|
Output::new(data, Level::Low),
|
||||||
Some(Output::new(reset, Level::High)),
|
Some(Output::new(reset, Level::High)),
|
||||||
@@ -30,84 +45,70 @@ pub async fn display_task(
|
|||||||
320,
|
320,
|
||||||
320,
|
320,
|
||||||
);
|
);
|
||||||
display.init(&mut Delay).unwrap();
|
display.init(&mut Delay).await.unwrap();
|
||||||
display.set_orientation(&Orientation::Landscape).unwrap();
|
display
|
||||||
let mut virtual_display = VirtualDisplay::new(display, 320 / 2, 320 / 2);
|
.set_orientation(&Orientation::Landscape)
|
||||||
|
.await
|
||||||
let thin_stroke = PrimitiveStyle::with_stroke(Rgb565::RED, 20);
|
|
||||||
|
|
||||||
Rectangle::new(Point::new(10, 10), Size::new(100, 100))
|
|
||||||
.into_styled(thin_stroke)
|
|
||||||
.draw(&mut virtual_display)
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let mut framebuffer = FrameBuffer::new(display);
|
||||||
|
|
||||||
|
let mut ui = UI::new();
|
||||||
|
ui.draw_status_bar(&mut framebuffer);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
framebuffer.draw().await.unwrap();
|
||||||
Timer::after_millis(500).await;
|
Timer::after_millis(500).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// simple abstraction over real display & resolution to reduce frame buffer size
|
pub struct UI {
|
||||||
/// by cutting the resolution by 1/4
|
pub status_bar: StatusBar,
|
||||||
struct VirtualDisplay {
|
|
||||||
display: ST7365P<
|
|
||||||
ExclusiveDevice<Spi<'static, SPI1, Blocking>, Output<'static>, Delay>,
|
|
||||||
Output<'static>,
|
|
||||||
Output<'static>,
|
|
||||||
>,
|
|
||||||
width: u32,
|
|
||||||
height: u32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VirtualDisplay {
|
impl UI {
|
||||||
pub fn new(
|
pub fn new() -> Self {
|
||||||
display: ST7365P<
|
|
||||||
ExclusiveDevice<Spi<'static, SPI1, Blocking>, Output<'static>, Delay>,
|
|
||||||
Output<'static>,
|
|
||||||
Output<'static>,
|
|
||||||
>,
|
|
||||||
new_width: u32,
|
|
||||||
new_height: u32,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
display,
|
status_bar: StatusBar {
|
||||||
width: new_width,
|
battery: 100,
|
||||||
height: new_height,
|
backlight: 100,
|
||||||
|
volume: 100,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl DrawTarget for VirtualDisplay {
|
pub fn draw_status_bar<D: DrawTarget<Color = Rgb565>>(&mut self, target: &mut D) {
|
||||||
type Color = Rgb565;
|
let text_style = MonoTextStyle::new(&FONT_9X15, Rgb565::WHITE);
|
||||||
type Error = ();
|
|
||||||
|
|
||||||
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
|
let status_bar = Rectangle::new(
|
||||||
where
|
Point::new(0, 0),
|
||||||
I: IntoIterator<Item = Pixel<Self::Color>>,
|
Size::new(STATUS_BAR_WIDTH as u32, STATUS_BAR_HEIGHT as u32),
|
||||||
{
|
);
|
||||||
for Pixel(coord, color) in pixels.into_iter() {
|
let _ = LinearLayout::horizontal(
|
||||||
// Check bounds on the *virtual* (already reduced) resolution
|
Chain::new(Text::new(
|
||||||
if coord.x >= 0
|
arrform!(20, "Bat: {}", self.status_bar.battery).as_str(),
|
||||||
&& coord.y >= 0
|
Point::zero(),
|
||||||
&& coord.x < self.width as i32
|
text_style,
|
||||||
&& coord.y < self.height as i32
|
))
|
||||||
{
|
.append(Text::new(
|
||||||
let px = coord.x as u16 * 2;
|
arrform!(20, "Lght: {}", self.status_bar.backlight).as_str(),
|
||||||
let py = coord.y as u16 * 2;
|
Point::zero(),
|
||||||
let raw_color = RawU16::from(color).into_inner();
|
text_style,
|
||||||
|
))
|
||||||
// Draw the 2x2 block on the underlying hardware
|
.append(Text::new(
|
||||||
self.display.set_pixel(px, py, raw_color)?;
|
arrform!(20, "Vol: {}", self.status_bar.volume).as_str(),
|
||||||
self.display.set_pixel(px + 1, py, raw_color)?;
|
Point::zero(),
|
||||||
self.display.set_pixel(px, py + 1, raw_color)?;
|
text_style,
|
||||||
self.display.set_pixel(px + 1, py + 1, raw_color)?;
|
)),
|
||||||
}
|
)
|
||||||
}
|
.arrange()
|
||||||
Ok(())
|
.align_to(&status_bar, horizontal::Center, vertical::Center)
|
||||||
|
.draw(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OriginDimensions for VirtualDisplay {
|
pub struct StatusBar {
|
||||||
fn size(&self) -> Size {
|
pub battery: u8,
|
||||||
Size::new(self.width, self.height)
|
pub backlight: u8,
|
||||||
}
|
pub volume: u8,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user