Compare commits

..

No commits in common. "256341cd5e744ff8a10aa9e5f753db4786629d53" and "09a920e610cbf4d65995e8075bb0fe31e704e3de" have entirely different histories.

10 changed files with 109 additions and 176 deletions

View File

@ -35,7 +35,5 @@ embedded-graphics = "0.8.1"
ili9341 = "0.6.0" ili9341 = "0.6.0"
display-interface-spi = "0.5.0" display-interface-spi = "0.5.0"
gui = { path="../gui/" }
[profile.release] [profile.release]
debug = 2 debug = 2

1
gui

@ -1 +0,0 @@
Subproject commit 12afc17f90756988b9011240e6884fa0e3fb48ef

View File

@ -1,12 +0,0 @@
[package]
name = "gui-test"
version = "0.1.0"
edition = "2021"
[dependencies]
embedded-graphics = "0.8.1"
embedded-graphics-simulator = "0.7.0"
embedded-layout = "0.4.1"
heapless = "0.8.0"
profont = "0.7.0"
gui = { path = "../gui/" }

View File

@ -1,43 +0,0 @@
use embedded_graphics::{geometry::Size, pixelcolor::Rgb565};
use embedded_graphics_simulator::{
sdl2::Keycode, OutputSettingsBuilder, SimulatorDisplay, SimulatorEvent, Window,
};
use gui::*;
fn main() -> Result<(), core::convert::Infallible> {
let display = SimulatorDisplay::<Rgb565>::new(Size::new(240, 320));
let output_settings = OutputSettingsBuilder::new().scale(1).build();
let mut window = Window::new("Hello World", &output_settings);
let mut gui = Gui::new(display);
'running: loop {
gui.draw()?;
window.update(gui.display_ref());
for event in window.events() {
match event {
SimulatorEvent::Quit => break 'running,
SimulatorEvent::KeyDown { keycode, .. } => {
let action: GuiAction = match keycode {
Keycode::Left => GuiAction::Left,
Keycode::Right => GuiAction::Right,
Keycode::Up => GuiAction::Up,
Keycode::Down => GuiAction::Down,
Keycode::Return => GuiAction::Select,
Keycode::Backspace => GuiAction::Back,
_ => continue,
};
gui = gui.action(action);
gui.fill_black()?;
}
_ => {}
}
}
}
Ok(())
}

View File

@ -2,17 +2,15 @@
#![no_main] #![no_main]
use core::cell::RefCell; use core::cell::RefCell;
use defmt::{error, info};
use display_interface_spi::SPIInterface; use display_interface_spi::SPIInterface;
use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice; use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_nrf::{ use embassy_nrf::{
bind_interrupts, bind_interrupts,
gpio::{AnyPin, Input, Level, Output, OutputDrive, Pin}, gpio::{AnyPin, Level, Output, OutputDrive, Pin},
peripherals, spim, peripherals, spim,
}; };
use embassy_sync::blocking_mutex::{raw::ThreadModeRawMutex, Mutex}; use embassy_sync::blocking_mutex::Mutex;
use embassy_sync::channel::{Channel, Sender};
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
use ili9341::Ili9341; use ili9341::Ili9341;
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
@ -26,7 +24,6 @@ use embedded_graphics::{
}, },
text::{Alignment, Text}, text::{Alignment, Text},
}; };
use gui::*;
// Setup interrupts // Setup interrupts
bind_interrupts!(struct Irqs { bind_interrupts!(struct Irqs {
@ -52,100 +49,77 @@ async fn blink(pin: AnyPin, blink_delay: Duration) -> ! {
} }
} }
static GUI_CHANNEL: Channel<ThreadModeRawMutex, gui::GuiAction, 8> = Channel::new(); /// Create a function to run the demo
///
/// # Arguments
/// This function takes in a variable of a generic type `D`.
/// With the restriction that the generic type `D` implements
/// `DrawTarget`, aka that it is a display.
///
/// I've also said it needs to use a certain colormode, because
/// that is the color mode I use in the demo.
///
/// While this may seem a little clunky this function now accepts _any_
/// display as long as it uses the standard 565 colormode.
///
/// # Returns
/// The function returns a `Result` containing either an empty tuple
/// or the error type associated with the generic type `D`.
fn display_demo<D>(display: &mut D) -> Result<(), D::Error>
where
D: DrawTarget<Color = Rgb565>,
{
display.clear(Rgb565::CSS_DARK_OLIVE_GREEN)?;
#[embassy_executor::task] // Create styles used by the drawing operations.
async fn gui_task( let thin_stroke = PrimitiveStyle::with_stroke(Rgb565::WHITE, 1);
peripheral: embassy_nrf::peripherals::SERIAL3, let thick_stroke = PrimitiveStyle::with_stroke(Rgb565::WHITE, 3);
sck: AnyPin, let border_stroke = PrimitiveStyleBuilder::new()
miso: AnyPin, .stroke_color(Rgb565::WHITE)
mosi: AnyPin, .stroke_width(3)
display_reset_pin: AnyPin, .stroke_alignment(StrokeAlignment::Inside)
cs_pin: AnyPin, .build();
dc_pin: AnyPin, let fill = PrimitiveStyle::with_fill(Rgb565::WHITE);
) -> ! { let character_style = MonoTextStyle::new(&FONT_10X20, Rgb565::WHITE);
///////////////
// Setup SPI //
///////////////
// Create an SPI config with the SPI frequency at 8MHz let yoffset = 10;
let mut spim_config = spim::Config::default();
spim_config.frequency = spim::Frequency::M8;
// Grab the SPI Master peripheral form the nRF60 // Draw a 3px wide outline around the display.
let spim = embassy_nrf::spim::Spim::new(peripheral, Irqs, sck, miso, mosi, spim_config); display
// Use the SPI peripheral to create a shared SPI bus .bounding_box()
let spi_bus: Mutex<embassy_sync::blocking_mutex::raw::NoopRawMutex, _> = .into_styled(border_stroke)
Mutex::new(RefCell::new(spim)); .draw(display)?;
//////////////// // Draw a triangle.
// Setup pins // Triangle::new(
//////////////// Point::new(16, 16 + yoffset),
Point::new(16 + 16, 16 + yoffset),
// Initialize the CS, DC, and display reset pins as outputs Point::new(16 + 8, yoffset),
let chip_select = Output::new(cs_pin, Level::High, OutputDrive::Standard);
let direction_control = Output::new(dc_pin, Level::High, OutputDrive::Standard);
let display_reset = Output::new(display_reset_pin, Level::High, OutputDrive::Standard);
////////////////////////
// Create the display //
////////////////////////
// Use the shared bus to create a SPI Device to use for the display
let spi_display = SpiDevice::new(&spi_bus, chip_select);
// Create a new SPI display interface
let iface = SPIInterface::new(spi_display, direction_control);
// Some options for the display
let display_orientation = ili9341::Orientation::PortraitFlipped;
let display_size = ili9341::DisplaySize240x320;
// Create the display
let display = Ili9341::new(
iface,
display_reset,
&mut embassy_time::Delay,
display_orientation,
display_size,
) )
.unwrap(); .into_styled(thin_stroke)
.draw(display)?;
let mut gui = Gui::new(display); // Draw a filled square
gui.draw().expect("Failed to draw GUI"); Rectangle::new(Point::new(52, yoffset), Size::new(16, 16))
.into_styled(fill)
.draw(display)?;
loop { // Draw a circle with a 3px wide stroke.
info!("Waiting for GUI event"); Circle::new(Point::new(88, yoffset), 17)
// Wait to receive a GUI event .into_styled(thick_stroke)
let gui_action = GUI_CHANNEL.receive().await; .draw(display)?;
// Re-render the GUI
info!("Received event, calculating new screen");
gui = gui.action(gui_action);
// Clear the screen // Draw centered text.
info!("Clearing screen"); let text = "embedded-graphics";
gui.fill_black().expect("Failed to clear screen"); Text::with_alignment(
// Draw the GUI text,
info!("Drawing screen"); display.bounding_box().center() + Point::new(0, 15),
gui.draw().expect("Failed to draw GUI"); character_style,
} Alignment::Center,
} )
.draw(display)?;
#[embassy_executor::task(pool_size = 2)] Ok(())
async fn input_controller(
control: Sender<'static, ThreadModeRawMutex, gui::GuiAction, 8>,
pin: AnyPin,
action: gui::GuiAction,
) -> ! {
let mut button = Input::new(pin, embassy_nrf::gpio::Pull::Up);
loop {
// Wait for the button to be pressed
button.wait_for_falling_edge().await;
// Send the event
if let Err(_e) = control.try_send(action) {
error!("Failed to send input action with error");
}
}
} }
#[embassy_executor::main] #[embassy_executor::main]
@ -163,6 +137,10 @@ async fn main(spawner: Spawner) {
) )
.expect("Failed to start blink task"); .expect("Failed to start blink task");
////////////////
// Setup pins //
////////////////
let mosi = p.P0_13; let mosi = p.P0_13;
let miso = p.P0_12; let miso = p.P0_12;
let sck = p.P0_30; let sck = p.P0_30;
@ -170,38 +148,51 @@ async fn main(spawner: Spawner) {
let dc_pin = p.P0_20; // Data / Command pin for the display let dc_pin = p.P0_20; // Data / Command pin for the display
let disp_rst_pin = p.P0_11; let disp_rst_pin = p.P0_11;
// Create the GUI // Initialize the CS, DC, and display reset pins as outputs
spawner let chip_select = Output::new(cs_pin, Level::High, OutputDrive::Standard);
.spawn(gui_task( let direction_control = Output::new(dc_pin, Level::High, OutputDrive::Standard);
p.SERIAL3, let display_reset = Output::new(disp_rst_pin, Level::High, OutputDrive::Standard);
sck.degrade(),
miso.degrade(),
mosi.degrade(),
disp_rst_pin.degrade(),
cs_pin.degrade(),
dc_pin.degrade(),
))
.expect("Failed to spawn GUI task");
// Create the GUI controllers ///////////////
spawner // Setup SPI //
.spawn(input_controller( ///////////////
GUI_CHANNEL.sender(),
p.P0_06.degrade(), // Create an SPI config with the SPI frequency at 8MHz
gui::GuiAction::Down, let mut spim_config = spim::Config::default();
)) spim_config.frequency = spim::Frequency::M8;
.expect("Failed tp spawn DOWN input controller");
spawner // Grab the SPI Master peripheral form the nRF60
.spawn(input_controller( let spim = embassy_nrf::spim::Spim::new(p.SERIAL3, Irqs, sck, miso, mosi, spim_config);
GUI_CHANNEL.sender(), // Use the SPI peripheral to create a shared SPI bus
p.P0_07.degrade(), let spi_bus: Mutex<embassy_sync::blocking_mutex::raw::NoopRawMutex, _> =
gui::GuiAction::Select, Mutex::new(RefCell::new(spim));
))
.expect("Failed tp spawn Select input controller"); // Use the shared bus to create a SPI Device to use for the display
let spi_display = SpiDevice::new(&spi_bus, chip_select);
// Create a new SPI display interface
let iface = SPIInterface::new(spi_display, direction_control);
////////////////////////
// Create the display //
////////////////////////
// Some options for the display
let display_orientation = ili9341::Orientation::Landscape;
let display_size = ili9341::DisplaySize240x320;
// Create the display
let mut display = Ili9341::new(
iface,
display_reset,
&mut embassy_time::Delay,
display_orientation,
display_size,
)
.unwrap();
// Now loop, re-running the demo every second // Now loop, re-running the demo every second
loop { loop {
info!("Hello, world!"); display_demo(&mut display).expect("Failed to run display demo");
Timer::after_secs(1).await; Timer::after_secs(1).await;
} }
} }