Compare commits
	
		
			4 Commits
		
	
	
		
			ef99d64d08
			...
			d91b903817
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| d91b903817 | |||
| cb6b214e4d | |||
| a33cb94a35 | |||
| 6446310023 | 
@ -35,8 +35,13 @@ embedded-graphics = "0.8.1"
 | 
				
			|||||||
embedded-graphics-profiler-display = { version = "0.1.0", path = "../embedded-graphics-profiler-display" }
 | 
					embedded-graphics-profiler-display = { version = "0.1.0", path = "../embedded-graphics-profiler-display" }
 | 
				
			||||||
embedded-hal = "1.0.0"
 | 
					embedded-hal = "1.0.0"
 | 
				
			||||||
embedded-sdmmc = "0.8.0"
 | 
					embedded-sdmmc = "0.8.0"
 | 
				
			||||||
esp-backtrace    = { version = "0.14.1", features = ["esp32", "println", "exception-handler", "panic-handler"] }
 | 
					esp-backtrace = { version = "0.14.1", features = [
 | 
				
			||||||
esp-hal          = { version = "0.20.1", features = ["esp32", "log", "async"] }
 | 
					    "esp32",
 | 
				
			||||||
 | 
					    "exception-handler",
 | 
				
			||||||
 | 
					    "panic-handler",
 | 
				
			||||||
 | 
					    "println",
 | 
				
			||||||
 | 
					] }
 | 
				
			||||||
 | 
					esp-hal = { version = "0.20.1", features = ["async", "esp32", "log"] }
 | 
				
			||||||
esp-hal-embassy = { version = "0.3.0", features = ["esp32", "log"] }
 | 
					esp-hal-embassy = { version = "0.3.0", features = ["esp32", "log"] }
 | 
				
			||||||
esp-println = { version = "0.11.0", features = ["esp32", "log"] }
 | 
					esp-println = { version = "0.11.0", features = ["esp32", "log"] }
 | 
				
			||||||
format_no_std = "1.2.0"
 | 
					format_no_std = "1.2.0"
 | 
				
			||||||
@ -47,4 +52,3 @@ profont = "0.7.0"
 | 
				
			|||||||
static_cell = { version = "2.1.0", features = ["nightly"] }
 | 
					static_cell = { version = "2.1.0", features = ["nightly"] }
 | 
				
			||||||
ufmt = "0.2.0"
 | 
					ufmt = "0.2.0"
 | 
				
			||||||
xpt2046 = { git = "https://github.com/Yandrik/xpt2046.git", version = "0.3.1" }
 | 
					xpt2046 = { git = "https://github.com/Yandrik/xpt2046.git", version = "0.3.1" }
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,9 @@ name = "embedded-graphics-profiler-display"
 | 
				
			|||||||
version = "0.1.0"
 | 
					version = "0.1.0"
 | 
				
			||||||
edition = "2021"
 | 
					edition = "2021"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[features]
 | 
				
			||||||
 | 
					std = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[dependencies]
 | 
					[dependencies]
 | 
				
			||||||
atomic = "0.6.0"
 | 
					atomic = "0.6.0"
 | 
				
			||||||
embassy-time = "0.3.2"
 | 
					embassy-time = "0.3.2"
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
#![no_std]
 | 
					#![cfg_attr(not(feature = "std"), no_std)]
 | 
				
			||||||
#![no_main]
 | 
					#![no_main]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod profiler;
 | 
					mod profiler;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,7 @@
 | 
				
			|||||||
use atomic::Atomic;
 | 
					use atomic::Atomic;
 | 
				
			||||||
 | 
					#[cfg(feature = "std")]
 | 
				
			||||||
 | 
					use std::time::{Duration, Instant};
 | 
				
			||||||
 | 
					#[cfg(not(feature = "std"))]
 | 
				
			||||||
use embassy_time::{Duration, Instant};
 | 
					use embassy_time::{Duration, Instant};
 | 
				
			||||||
use embedded_graphics::draw_target::DrawTarget;
 | 
					use embedded_graphics::draw_target::DrawTarget;
 | 
				
			||||||
use embedded_graphics::{Drawable, Pixel};
 | 
					use embedded_graphics::{Drawable, Pixel};
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@ target = "xtensa-esp32-espidf"
 | 
				
			|||||||
[target.xtensa-esp32-espidf]
 | 
					[target.xtensa-esp32-espidf]
 | 
				
			||||||
linker = "ldproxy"
 | 
					linker = "ldproxy"
 | 
				
			||||||
# runner = "espflash --monitor" # Select this runner for espflash v1.x.x
 | 
					# runner = "espflash --monitor" # Select this runner for espflash v1.x.x
 | 
				
			||||||
runner = "espflash flash --monitor" # Select this runner for espflash v2.x.x
 | 
					runner = "espflash flash --monitor --baud 921600" # Select this runner for espflash v2.x.x
 | 
				
			||||||
rustflags = [
 | 
					rustflags = [
 | 
				
			||||||
    # Extending time_t for ESP IDF 5: https://github.com/esp-rs/rust/issues/110
 | 
					    # Extending time_t for ESP IDF 5: https://github.com/esp-rs/rust/issues/110
 | 
				
			||||||
    "--cfg",
 | 
					    "--cfg",
 | 
				
			||||||
@ -31,3 +31,6 @@ CROSS_COMPILE = "xtensa-esp32-elf"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# Directory for custom fonts (written in C) that Lvgl can use
 | 
					# Directory for custom fonts (written in C) that Lvgl can use
 | 
				
			||||||
LVGL_FONTS_DIR = {relative = true, value = "custom-fonts"}
 | 
					LVGL_FONTS_DIR = {relative = true, value = "custom-fonts"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PATH="/usr/lib64/ccache:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/var/lib/snapd/snap/bin:/home/yannik/.rustup/toolchains/esp/xtensa-esp32s2-elf/esp-2021r2-patch5-8_4_0/xtensa-esp32s2-elf/bin:/home/yannik/.rustup/toolchains/esp/xtensa-esp32s3-elf/esp-2021r2-patch5-8_4_0/xtensa-esp32s3-elf/bin:/home/yannik/.rustup/toolchains/esp/xtensa-esp32-elf/esp-2021r2-patch5-8_4_0/xtensa-esp32-elf/bin:/home/yannik/.rustup/toolchains/esp/riscv32-esp-elf/esp-2021r2-patch5-8_4_0/riscv32-esp-elf/bin:"
 | 
				
			||||||
 | 
					LIBCLANG_PATH="/home/yannik/.rustup/toolchains/esp/xtensa-esp32-elf-clang/esp-15.0.0-20221201/esp-clang/lib"
 | 
				
			||||||
 | 
				
			|||||||
@ -15,6 +15,12 @@ opt-level = "s"
 | 
				
			|||||||
debug     = true # Symbols are nice and they don't increase the size on Flash
 | 
					debug     = true # Symbols are nice and they don't increase the size on Flash
 | 
				
			||||||
opt-level = "z"
 | 
					opt-level = "z"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[bin]]
 | 
				
			||||||
 | 
					name = "starter"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[bin]]
 | 
				
			||||||
 | 
					name = "timer"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[features]
 | 
					[features]
 | 
				
			||||||
default = ["embassy", "esp-idf-svc/native", "std"]
 | 
					default = ["embassy", "esp-idf-svc/native", "std"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -50,6 +56,12 @@ display-interface-spi = "0.5.0"
 | 
				
			|||||||
mipidsi               = "0.8.0"
 | 
					mipidsi               = "0.8.0"
 | 
				
			||||||
static_cell = "2.1.0"
 | 
					static_cell = "2.1.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					xpt2046 = { git = "https://github.com/Yandrik/xpt2046.git", version = "0.3.1" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					embedded-graphics-profiler-display = { version = "0.1.0", path = "../embedded-graphics-profiler-display", features = ["std"] }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[build-dependencies]
 | 
					[build-dependencies]
 | 
				
			||||||
embuild = "0.32.0"
 | 
					embuild = "0.32.0"
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
# Rust often needs a bit of an extra main task stack size compared to C (the default is 3K)
 | 
					# Rust often needs a bit of an extra main task stack size compared to C (the default is 3K)
 | 
				
			||||||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8000
 | 
					CONFIG_ESP_MAIN_TASK_STACK_SIZE=8000
 | 
				
			||||||
# CONFIG_ESP_MAIN_TASK_STACK_SIZE=16000
 | 
					CONFIG_ESP_MAIN_TASK_STACK_SIZE=48000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Use this to set FreeRTOS kernel tick frequency to 1000 Hz (100 Hz by default).
 | 
					# Use this to set FreeRTOS kernel tick frequency to 1000 Hz (100 Hz by default).
 | 
				
			||||||
# This allows to use 1 ms granuality for thread sleeps (10 ms by default).
 | 
					# This allows to use 1 ms granuality for thread sleeps (10 ms by default).
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										266
									
								
								lvgl-based/src/bin/starter.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										266
									
								
								lvgl-based/src/bin/starter.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,266 @@
 | 
				
			|||||||
 | 
					use std::{
 | 
				
			||||||
 | 
					    cell::RefCell,
 | 
				
			||||||
 | 
					    sync::mpsc::channel,
 | 
				
			||||||
 | 
					    thread,
 | 
				
			||||||
 | 
					    time::{Duration, Instant},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					use std::cmp::min;
 | 
				
			||||||
 | 
					use cstr_core::CString;
 | 
				
			||||||
 | 
					use display_interface_spi::SPIInterface;
 | 
				
			||||||
 | 
					use embedded_graphics_core::{draw_target::DrawTarget, prelude::Point};
 | 
				
			||||||
 | 
					use esp_idf_hal::spi::SpiSingleDeviceDriver;
 | 
				
			||||||
 | 
					use esp_idf_hal::{
 | 
				
			||||||
 | 
					    delay::{self, Delay},
 | 
				
			||||||
 | 
					    gpio::*,
 | 
				
			||||||
 | 
					    peripherals::Peripherals,
 | 
				
			||||||
 | 
					    spi::{config::DriverConfig, Dma, SpiConfig, SpiDeviceDriver},
 | 
				
			||||||
 | 
					    units::FromValueType, // for converting 26MHz to value
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					use lvgl::{
 | 
				
			||||||
 | 
					    font::Font,
 | 
				
			||||||
 | 
					    input_device::{
 | 
				
			||||||
 | 
					        pointer::{Pointer, PointerInputData},
 | 
				
			||||||
 | 
					        InputDriver,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    style::Style,
 | 
				
			||||||
 | 
					    widgets::{Btn, Label},
 | 
				
			||||||
 | 
					    Align,
 | 
				
			||||||
 | 
					    Color,
 | 
				
			||||||
 | 
					    Display,
 | 
				
			||||||
 | 
					    DrawBuffer,
 | 
				
			||||||
 | 
					    LvError,
 | 
				
			||||||
 | 
					    Part,
 | 
				
			||||||
 | 
					    TextAlign,
 | 
				
			||||||
 | 
					    Widget,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					use mipidsi::{
 | 
				
			||||||
 | 
					    models::ILI9486Rgb565,
 | 
				
			||||||
 | 
					    options::{ColorInversion, ColorOrder, Orientation, Rotation},
 | 
				
			||||||
 | 
					    Builder,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					use xpt2046::Xpt2046;
 | 
				
			||||||
 | 
					use embedded_graphics_profiler_display::ProfilerDisplay;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn main() -> Result<(), LvError> {
 | 
				
			||||||
 | 
					    const HOR_RES: u32 = 320;
 | 
				
			||||||
 | 
					    const VER_RES: u32 = 240;
 | 
				
			||||||
 | 
					    const LINES: u32 = 20;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // It is necessary to call this function once. Otherwise some patches to the
 | 
				
			||||||
 | 
					    // runtime implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
 | 
				
			||||||
 | 
					    esp_idf_svc::sys::link_patches();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Initialize lvgl
 | 
				
			||||||
 | 
					    lvgl::init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Bind the log crate to the ESP Logging facilities
 | 
				
			||||||
 | 
					    esp_idf_svc::log::EspLogger::initialize_default();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    log::info!("================= Starting App =======================");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let peripherals = Peripherals::take().unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // #[allow(unused)]
 | 
				
			||||||
 | 
					    let pins = peripherals.pins;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let sclk = pins.gpio14;
 | 
				
			||||||
 | 
					    let miso = pins.gpio12;
 | 
				
			||||||
 | 
					    let mosi = pins.gpio13;
 | 
				
			||||||
 | 
					    let cs = pins.gpio15;
 | 
				
			||||||
 | 
					    let dc = pins.gpio2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let spi = SpiDeviceDriver::new_single(
 | 
				
			||||||
 | 
					        peripherals.spi2,
 | 
				
			||||||
 | 
					        sclk,       // sclk
 | 
				
			||||||
 | 
					        mosi,       // sdo
 | 
				
			||||||
 | 
					        Some(miso), // sdi
 | 
				
			||||||
 | 
					        Some(cs),   // cs
 | 
				
			||||||
 | 
					        &DriverConfig::new().dma(Dma::Channel1(4096)),
 | 
				
			||||||
 | 
					        &SpiConfig::new().write_only(true).baudrate(10.MHz().into()),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    .unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // let rst = PinDriver::output(pins.gpio33).unwrap();
 | 
				
			||||||
 | 
					    let dc = PinDriver::output(dc).unwrap();
 | 
				
			||||||
 | 
					    let di = SPIInterface::new(spi, dc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Turn backlight on
 | 
				
			||||||
 | 
					    let mut bklt = PinDriver::output(pins.gpio21).unwrap();
 | 
				
			||||||
 | 
					    bklt.set_high().unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Configuration for M5Stack Core Development Kit V1.0
 | 
				
			||||||
 | 
					    // Puts display in landscape mode with the three buttons at the bottom of screen
 | 
				
			||||||
 | 
					    // let mut m5stack_display = Builder::ili9342c_rgb565(di)
 | 
				
			||||||
 | 
					    //     .with_display_size(320, 240)
 | 
				
			||||||
 | 
					    //     .with_color_order(ColorOrder::Bgr)
 | 
				
			||||||
 | 
					    //     .with_orientation(Orientation::Portrait(false))
 | 
				
			||||||
 | 
					    //     .with_invert_colors(mipidsi::ColorInversion::Inverted)
 | 
				
			||||||
 | 
					    //     .init(&mut delay::Ets, Some(rst))
 | 
				
			||||||
 | 
					    //     .unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 0.6.0
 | 
				
			||||||
 | 
					    // let mut raw_display = Builder::ili9342c_rgb565(di)
 | 
				
			||||||
 | 
					    //     .with_orientation(Orientation::Portrait(false))
 | 
				
			||||||
 | 
					    //     .with_color_order(ColorOrder::Bgr)
 | 
				
			||||||
 | 
					    //     .with_invert_colors(true)
 | 
				
			||||||
 | 
					    //     .init(&mut Delay::new_default(), None::<PinDriver<AnyOutputPin, Output>>)
 | 
				
			||||||
 | 
					    //     .unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let raw_display = Builder::new(ILI9486Rgb565, di)
 | 
				
			||||||
 | 
					        .orientation(Orientation {
 | 
				
			||||||
 | 
					            rotation: Rotation::Deg90,
 | 
				
			||||||
 | 
					            mirrored: true,
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .color_order(ColorOrder::Bgr)
 | 
				
			||||||
 | 
					        .invert_colors(ColorInversion::Inverted)
 | 
				
			||||||
 | 
					        .init(&mut Delay::new_default())
 | 
				
			||||||
 | 
					        .unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut raw_display = ProfilerDisplay::new(raw_display);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Stack size value - 20,000 for 10 lines,  40,000 for 20 lines
 | 
				
			||||||
 | 
					    // let (touch_send, touch_recv) = channel();
 | 
				
			||||||
 | 
					    let touch_irq = pins.gpio36;
 | 
				
			||||||
 | 
					    let touch_mosi = pins.gpio32;
 | 
				
			||||||
 | 
					    let touch_miso = pins.gpio39;
 | 
				
			||||||
 | 
					    let touch_clk = pins.gpio25;
 | 
				
			||||||
 | 
					    let touch_cs = pins.gpio33;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut touch_driver = Xpt2046::new(
 | 
				
			||||||
 | 
					        SpiDeviceDriver::new_single(
 | 
				
			||||||
 | 
					            peripherals.spi3,
 | 
				
			||||||
 | 
					            touch_clk,
 | 
				
			||||||
 | 
					            touch_mosi,
 | 
				
			||||||
 | 
					            Some(touch_miso),
 | 
				
			||||||
 | 
					            Some(touch_cs),
 | 
				
			||||||
 | 
					            &DriverConfig::new(),
 | 
				
			||||||
 | 
					            &SpiConfig::new().write_only(true).baudrate(2.MHz().into()),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .unwrap(),
 | 
				
			||||||
 | 
					        PinDriver::input(touch_irq).unwrap(),
 | 
				
			||||||
 | 
					        xpt2046::Orientation::LandscapeFlipped,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    touch_driver.set_num_samples(1);
 | 
				
			||||||
 | 
					    touch_driver.init(&mut Delay::new_default()).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let touch_driver = RefCell::new(touch_driver);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let _lvgl_thread = thread::Builder::new()
 | 
				
			||||||
 | 
					        .stack_size(40_000)
 | 
				
			||||||
 | 
					        .spawn(move || {
 | 
				
			||||||
 | 
					            println!("thread started");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let buffer = DrawBuffer::<{ (HOR_RES * LINES) as usize }>::default();
 | 
				
			||||||
 | 
					            let display = Display::register(buffer, HOR_RES, VER_RES, |refresh| {
 | 
				
			||||||
 | 
					                raw_display.draw_iter(refresh.as_pixels()).unwrap();
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Register a new input device that's capable of reading the current state of
 | 
				
			||||||
 | 
					            // the input
 | 
				
			||||||
 | 
					            // let mut last_touch = RefCell::new(None);
 | 
				
			||||||
 | 
					            let _touch_screen = Pointer::register(
 | 
				
			||||||
 | 
					                || {
 | 
				
			||||||
 | 
					                    let mut td_ref = touch_driver.borrow_mut();
 | 
				
			||||||
 | 
					                    td_ref.run().expect("Running Touch driver failed");
 | 
				
			||||||
 | 
					                    if td_ref.is_touched() {
 | 
				
			||||||
 | 
					                        let point = td_ref.get_touch_point();
 | 
				
			||||||
 | 
					                        PointerInputData::Touch(point).pressed().once()
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        PointerInputData::Touch(Point::new(0, 0)).released().once()
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                &display,
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Create screen and widgets
 | 
				
			||||||
 | 
					            let mut screen = display.get_scr_act().unwrap();
 | 
				
			||||||
 | 
					            let mut screen_style = Style::default();
 | 
				
			||||||
 | 
					            screen_style.set_bg_color(Color::from_rgb((0, 0, 0)));
 | 
				
			||||||
 | 
					            screen_style.set_radius(0);
 | 
				
			||||||
 | 
					            screen.add_style(Part::Main, &mut screen_style);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let mut time = Label::new().unwrap();
 | 
				
			||||||
 | 
					            let mut style_time = Style::default();
 | 
				
			||||||
 | 
					            style_time.set_text_color(Color::from_rgb((255, 255, 255))); // white
 | 
				
			||||||
 | 
					            style_time.set_text_align(TextAlign::Center);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Custom font requires lvgl-sys in Cargo.toml and 'use lvgl_sys' in this file
 | 
				
			||||||
 | 
					            style_time.set_text_font(unsafe { Font::new_raw(lvgl_sys::gotham_bold_80) });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            time.add_style(Part::Main, &mut style_time);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Time text will be centered in screen
 | 
				
			||||||
 | 
					            time.set_align(Align::Center, 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let mut button = Btn::create(&mut screen).unwrap();
 | 
				
			||||||
 | 
					            button.set_align(Align::LeftMid, 30, 0);
 | 
				
			||||||
 | 
					            button.set_size(180, 80);
 | 
				
			||||||
 | 
					            let mut btn_lbl = Label::create(&mut button).unwrap();
 | 
				
			||||||
 | 
					            btn_lbl.set_text(CString::new("Click me!").unwrap().as_c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let mut btn_state = false;
 | 
				
			||||||
 | 
					            button.on_event(|_btn, event| {
 | 
				
			||||||
 | 
					                // println!("Button received event: {:?}", event);
 | 
				
			||||||
 | 
					                if let lvgl::Event::Clicked = event {
 | 
				
			||||||
 | 
					                    if btn_state {
 | 
				
			||||||
 | 
					                        let nt = CString::new("Click me!").unwrap();
 | 
				
			||||||
 | 
					                        btn_lbl.set_text(nt.as_c_str()).unwrap();
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        let nt = CString::new("Clicked!").unwrap();
 | 
				
			||||||
 | 
					                        btn_lbl.set_text(nt.as_c_str()).unwrap();
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    btn_state = !btn_state;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let mut i = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            loop {
 | 
				
			||||||
 | 
					                let start_time = Instant::now();
 | 
				
			||||||
 | 
					                if i > 59 {
 | 
				
			||||||
 | 
					                    i = 0;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let val = CString::new(format!("21:{:02}", i)).unwrap();
 | 
				
			||||||
 | 
					                time.set_text(&val).unwrap();
 | 
				
			||||||
 | 
					                i += 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let start_draw_time = Instant::now();
 | 
				
			||||||
 | 
					                lvgl::task_handler();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // Simulate clock - so sleep for one second so time text is incremented in
 | 
				
			||||||
 | 
					                // seconds
 | 
				
			||||||
 | 
					                delay::FreeRtos::delay_ms(10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                lvgl::tick_inc(Instant::now().duration_since(start_time));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let end_time = Instant::now();
 | 
				
			||||||
 | 
					                let draw_time = raw_display.get_time();
 | 
				
			||||||
 | 
					                let prep_time = start_draw_time - start_time;
 | 
				
			||||||
 | 
					                let proc_time = end_time - start_draw_time;
 | 
				
			||||||
 | 
					                let proc_time = proc_time - min(draw_time, proc_time);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if draw_time.as_micros() > 0 {
 | 
				
			||||||
 | 
					                    println!(
 | 
				
			||||||
 | 
					                        "draw time: {}.{:03}ms | prep time: {}.{:03}ms | proc time: {}.{:03}ms | total time: {}.{:03}ms",
 | 
				
			||||||
 | 
					                        draw_time.as_millis(),
 | 
				
			||||||
 | 
					                        draw_time.as_micros() % 100,
 | 
				
			||||||
 | 
					                        prep_time.as_millis(),
 | 
				
			||||||
 | 
					                        prep_time.as_micros() % 100,
 | 
				
			||||||
 | 
					                        proc_time.as_millis(),
 | 
				
			||||||
 | 
					                        proc_time.as_micros() % 100,
 | 
				
			||||||
 | 
					                        (draw_time + prep_time + proc_time).as_millis(),
 | 
				
			||||||
 | 
					                        (draw_time + prep_time + proc_time).as_micros() % 100,            );
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                raw_display.reset_time();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    loop {
 | 
				
			||||||
 | 
					        // Don't exit application
 | 
				
			||||||
 | 
					        delay::FreeRtos::delay_ms(1_000_000);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										432
									
								
								lvgl-based/src/bin/timer.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										432
									
								
								lvgl-based/src/bin/timer.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,432 @@
 | 
				
			|||||||
 | 
					use std::{
 | 
				
			||||||
 | 
					    cell::RefCell,
 | 
				
			||||||
 | 
					    cmp::min,
 | 
				
			||||||
 | 
					    sync::mpsc::channel,
 | 
				
			||||||
 | 
					    thread,
 | 
				
			||||||
 | 
					    time::{Duration, Instant},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use cstr_core::CString;
 | 
				
			||||||
 | 
					use display_interface_spi::SPIInterface;
 | 
				
			||||||
 | 
					use embedded_graphics_core::{draw_target::DrawTarget, prelude::Point};
 | 
				
			||||||
 | 
					use embedded_graphics_profiler_display::ProfilerDisplay;
 | 
				
			||||||
 | 
					use esp_idf_hal::spi::SpiSingleDeviceDriver;
 | 
				
			||||||
 | 
					use esp_idf_hal::{
 | 
				
			||||||
 | 
					    delay::{self, Delay},
 | 
				
			||||||
 | 
					    gpio::*,
 | 
				
			||||||
 | 
					    peripherals::Peripherals,
 | 
				
			||||||
 | 
					    spi::{config::DriverConfig, Dma, SpiConfig, SpiDeviceDriver},
 | 
				
			||||||
 | 
					    units::FromValueType, // for converting 26MHz to value
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					use lvgl::{
 | 
				
			||||||
 | 
					    font::Font,
 | 
				
			||||||
 | 
					    input_device::{
 | 
				
			||||||
 | 
					        pointer::{Pointer, PointerInputData},
 | 
				
			||||||
 | 
					        InputDriver,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    style::Style,
 | 
				
			||||||
 | 
					    widgets::{Btn, Label},
 | 
				
			||||||
 | 
					    Align,
 | 
				
			||||||
 | 
					    Color,
 | 
				
			||||||
 | 
					    Display,
 | 
				
			||||||
 | 
					    DrawBuffer,
 | 
				
			||||||
 | 
					    Event,
 | 
				
			||||||
 | 
					    LvError,
 | 
				
			||||||
 | 
					    Part,
 | 
				
			||||||
 | 
					    TextAlign,
 | 
				
			||||||
 | 
					    Widget,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					use mipidsi::{
 | 
				
			||||||
 | 
					    models::ILI9486Rgb565,
 | 
				
			||||||
 | 
					    options::{ColorInversion, ColorOrder, Orientation, Rotation},
 | 
				
			||||||
 | 
					    Builder,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					use xpt2046::Xpt2046;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct AppData {
 | 
				
			||||||
 | 
					    timer_start: Instant,
 | 
				
			||||||
 | 
					    timer_set_duration: Duration,
 | 
				
			||||||
 | 
					    timer_remaining_duration: Duration,
 | 
				
			||||||
 | 
					    timer_running: bool,
 | 
				
			||||||
 | 
					    timer_paused: bool,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl AppData {
 | 
				
			||||||
 | 
					    fn new() -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            timer_start: Instant::now(),
 | 
				
			||||||
 | 
					            timer_set_duration: Duration::from_secs(10),
 | 
				
			||||||
 | 
					            timer_remaining_duration: Duration::from_secs(10),
 | 
				
			||||||
 | 
					            timer_running: false,
 | 
				
			||||||
 | 
					            timer_paused: false,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn set_timer_duration(&mut self, duration: Duration) {
 | 
				
			||||||
 | 
					        self.timer_set_duration = duration;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn add_secs(&mut self, secs: u64) {
 | 
				
			||||||
 | 
					        self.set_timer_duration(
 | 
				
			||||||
 | 
					            self.timer_set_duration
 | 
				
			||||||
 | 
					                .checked_add(Duration::from_secs(secs))
 | 
				
			||||||
 | 
					                .unwrap_or(Duration::from_secs(5999))
 | 
				
			||||||
 | 
					                .min(Duration::from_secs(5999)),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn sub_secs(&mut self, secs: u64) {
 | 
				
			||||||
 | 
					        self.set_timer_duration(
 | 
				
			||||||
 | 
					            self.timer_set_duration
 | 
				
			||||||
 | 
					                .checked_sub(Duration::from_secs(secs))
 | 
				
			||||||
 | 
					                .unwrap_or(Duration::from_secs(10))
 | 
				
			||||||
 | 
					                .max(Duration::from_secs(10)),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn start_timer(&mut self) {
 | 
				
			||||||
 | 
					        if !self.timer_paused {
 | 
				
			||||||
 | 
					            self.timer_remaining_duration = self.timer_set_duration;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.timer_start = Instant::now();
 | 
				
			||||||
 | 
					        self.timer_running = true;
 | 
				
			||||||
 | 
					        self.timer_paused = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn pause_timer(&mut self) {
 | 
				
			||||||
 | 
					        self.timer_paused = true;
 | 
				
			||||||
 | 
					        self.timer_remaining_duration = self
 | 
				
			||||||
 | 
					            .timer_remaining_duration
 | 
				
			||||||
 | 
					            .checked_sub(self.timer_start.elapsed())
 | 
				
			||||||
 | 
					            .unwrap_or(Duration::from_secs(0));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn reset_timer(&mut self) {
 | 
				
			||||||
 | 
					        self.timer_start = Instant::now();
 | 
				
			||||||
 | 
					        self.timer_paused = false;
 | 
				
			||||||
 | 
					        self.timer_running = false;
 | 
				
			||||||
 | 
					        self.timer_remaining_duration = self.timer_set_duration;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn remaining(&self) -> Duration {
 | 
				
			||||||
 | 
					        if self.timer_stopped() {
 | 
				
			||||||
 | 
					            self.timer_set_duration
 | 
				
			||||||
 | 
					        } else if self.timer_paused() {
 | 
				
			||||||
 | 
					            self.timer_remaining_duration
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            self.timer_remaining_duration
 | 
				
			||||||
 | 
					                .checked_sub(self.timer_start.elapsed())
 | 
				
			||||||
 | 
					                .unwrap_or(Duration::from_secs(0))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn timer_stopped(&self) -> bool {
 | 
				
			||||||
 | 
					        !self.timer_running
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn timer_paused(&self) -> bool {
 | 
				
			||||||
 | 
					        self.timer_running && self.timer_paused
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn timer_running(&self) -> bool {
 | 
				
			||||||
 | 
					        self.timer_running && !self.timer_paused
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn timer_finished(&self) -> bool {
 | 
				
			||||||
 | 
					        self.timer_running && self.remaining() == Duration::from_secs(0)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn main() -> Result<(), LvError> {
 | 
				
			||||||
 | 
					    const HOR_RES: u32 = 320;
 | 
				
			||||||
 | 
					    const VER_RES: u32 = 240;
 | 
				
			||||||
 | 
					    const LINES: u32 = 20;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // It is necessary to call this function once. Otherwise some patches to the
 | 
				
			||||||
 | 
					    // runtime implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
 | 
				
			||||||
 | 
					    esp_idf_svc::sys::link_patches();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Initialize lvgl
 | 
				
			||||||
 | 
					    lvgl::init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Bind the log crate to the ESP Logging facilities
 | 
				
			||||||
 | 
					    esp_idf_svc::log::EspLogger::initialize_default();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    log::info!("================= Starting App =======================");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let peripherals = Peripherals::take().unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // #[allow(unused)]
 | 
				
			||||||
 | 
					    let pins = peripherals.pins;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let sclk = pins.gpio14;
 | 
				
			||||||
 | 
					    let miso = pins.gpio12;
 | 
				
			||||||
 | 
					    let mosi = pins.gpio13;
 | 
				
			||||||
 | 
					    let cs = pins.gpio15;
 | 
				
			||||||
 | 
					    let dc = pins.gpio2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let spi = SpiDeviceDriver::new_single(
 | 
				
			||||||
 | 
					        peripherals.spi2,
 | 
				
			||||||
 | 
					        sclk,       // sclk
 | 
				
			||||||
 | 
					        mosi,       // sdo
 | 
				
			||||||
 | 
					        Some(miso), // sdi
 | 
				
			||||||
 | 
					        Some(cs),   // cs
 | 
				
			||||||
 | 
					        &DriverConfig::new().dma(Dma::Channel1(4096)),
 | 
				
			||||||
 | 
					        &SpiConfig::new().write_only(true).baudrate(10.MHz().into()),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    .unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // let rst = PinDriver::output(pins.gpio33).unwrap();
 | 
				
			||||||
 | 
					    let dc = PinDriver::output(dc).unwrap();
 | 
				
			||||||
 | 
					    let di = SPIInterface::new(spi, dc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Turn backlight on
 | 
				
			||||||
 | 
					    let mut bklt = PinDriver::output(pins.gpio21).unwrap();
 | 
				
			||||||
 | 
					    bklt.set_high().unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Configuration for M5Stack Core Development Kit V1.0
 | 
				
			||||||
 | 
					    // Puts display in landscape mode with the three buttons at the bottom of screen
 | 
				
			||||||
 | 
					    // let mut m5stack_display = Builder::ili9342c_rgb565(di)
 | 
				
			||||||
 | 
					    //     .with_display_size(320, 240)
 | 
				
			||||||
 | 
					    //     .with_color_order(ColorOrder::Bgr)
 | 
				
			||||||
 | 
					    //     .with_orientation(Orientation::Portrait(false))
 | 
				
			||||||
 | 
					    //     .with_invert_colors(mipidsi::ColorInversion::Inverted)
 | 
				
			||||||
 | 
					    //     .init(&mut delay::Ets, Some(rst))
 | 
				
			||||||
 | 
					    //     .unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 0.6.0
 | 
				
			||||||
 | 
					    // let mut raw_display = Builder::ili9342c_rgb565(di)
 | 
				
			||||||
 | 
					    //     .with_orientation(Orientation::Portrait(false))
 | 
				
			||||||
 | 
					    //     .with_color_order(ColorOrder::Bgr)
 | 
				
			||||||
 | 
					    //     .with_invert_colors(true)
 | 
				
			||||||
 | 
					    //     .init(&mut Delay::new_default(), None::<PinDriver<AnyOutputPin, Output>>)
 | 
				
			||||||
 | 
					    //     .unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let raw_display = Builder::new(ILI9486Rgb565, di)
 | 
				
			||||||
 | 
					        .orientation(Orientation {
 | 
				
			||||||
 | 
					            rotation: Rotation::Deg90,
 | 
				
			||||||
 | 
					            mirrored: true,
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .color_order(ColorOrder::Bgr)
 | 
				
			||||||
 | 
					        .invert_colors(ColorInversion::Inverted)
 | 
				
			||||||
 | 
					        .init(&mut Delay::new_default())
 | 
				
			||||||
 | 
					        .unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut raw_display = ProfilerDisplay::new(raw_display);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Stack size value - 20,000 for 10 lines,  40,000 for 20 lines
 | 
				
			||||||
 | 
					    // let (touch_send, touch_recv) = channel();
 | 
				
			||||||
 | 
					    let touch_irq = pins.gpio36;
 | 
				
			||||||
 | 
					    let touch_mosi = pins.gpio32;
 | 
				
			||||||
 | 
					    let touch_miso = pins.gpio39;
 | 
				
			||||||
 | 
					    let touch_clk = pins.gpio25;
 | 
				
			||||||
 | 
					    let touch_cs = pins.gpio33;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut touch_driver = Xpt2046::new(
 | 
				
			||||||
 | 
					        SpiDeviceDriver::new_single(
 | 
				
			||||||
 | 
					            peripherals.spi3,
 | 
				
			||||||
 | 
					            touch_clk,
 | 
				
			||||||
 | 
					            touch_mosi,
 | 
				
			||||||
 | 
					            Some(touch_miso),
 | 
				
			||||||
 | 
					            Some(touch_cs),
 | 
				
			||||||
 | 
					            &DriverConfig::new(),
 | 
				
			||||||
 | 
					            &SpiConfig::new().write_only(true).baudrate(2.MHz().into()),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .unwrap(),
 | 
				
			||||||
 | 
					        PinDriver::input(touch_irq).unwrap(),
 | 
				
			||||||
 | 
					        xpt2046::Orientation::LandscapeFlipped,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    touch_driver.set_num_samples(1);
 | 
				
			||||||
 | 
					    touch_driver.init(&mut Delay::new_default()).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let touch_driver = RefCell::new(touch_driver);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let _lvgl_thread = thread::Builder::new()
 | 
				
			||||||
 | 
					        .stack_size(40_000)
 | 
				
			||||||
 | 
					        .spawn(move || {
 | 
				
			||||||
 | 
					            println!("thread started");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let mut appdata = AppData::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let buffer = DrawBuffer::<{ (HOR_RES * LINES) as usize }>::default();
 | 
				
			||||||
 | 
					            let display = Display::register(buffer, HOR_RES, VER_RES, |refresh| {
 | 
				
			||||||
 | 
					                raw_display.draw_iter(refresh.as_pixels()).unwrap();
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Register a new input device that's capable of reading the current state of
 | 
				
			||||||
 | 
					            // the input
 | 
				
			||||||
 | 
					            // let mut last_touch = RefCell::new(None);
 | 
				
			||||||
 | 
					            let _touch_screen = Pointer::register(
 | 
				
			||||||
 | 
					                || {
 | 
				
			||||||
 | 
					                    let mut td_ref = touch_driver.borrow_mut();
 | 
				
			||||||
 | 
					                    td_ref.run().expect("Running Touch driver failed");
 | 
				
			||||||
 | 
					                    if td_ref.is_touched() {
 | 
				
			||||||
 | 
					                        let point = td_ref.get_touch_point();
 | 
				
			||||||
 | 
					                        // println!("touched {:?}", point);
 | 
				
			||||||
 | 
					                        PointerInputData::Touch(Point::new(point.x + 20, 240 - point.y)).pressed().once()
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        // println!("untouched");
 | 
				
			||||||
 | 
					                        PointerInputData::Touch(Point::new(0, 0)).released().once()
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                &display,
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Create screen and widgets
 | 
				
			||||||
 | 
					            let mut screen = display.get_scr_act().unwrap();
 | 
				
			||||||
 | 
					            let mut screen_style = Style::default();
 | 
				
			||||||
 | 
					            screen_style.set_bg_color(Color::from_rgb((0, 0, 0)));
 | 
				
			||||||
 | 
					            screen_style.set_radius(0);
 | 
				
			||||||
 | 
					            screen.add_style(Part::Main, &mut screen_style);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let mut time = Label::new().unwrap();
 | 
				
			||||||
 | 
					            let mut style_time = Style::default();
 | 
				
			||||||
 | 
					            style_time.set_text_color(Color::from_rgb((255, 255, 255))); // white
 | 
				
			||||||
 | 
					            style_time.set_text_align(TextAlign::Center);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Custom font requires lvgl-sys in Cargo.toml and 'use lvgl_sys' in this file
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            time.add_style(Part::Main, &mut style_time);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Time text will be centered in screen
 | 
				
			||||||
 | 
					            time.set_align(Align::Center, 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let mut button_add = Btn::create(&mut screen).unwrap();
 | 
				
			||||||
 | 
					            // button_add.set_align(Align::Center, -50, -100);
 | 
				
			||||||
 | 
					            button_add.set_pos(130, 150);
 | 
				
			||||||
 | 
					            button_add.set_size(30, 30);
 | 
				
			||||||
 | 
					            let mut btn_lbl1 = Label::create(&mut button_add).unwrap();
 | 
				
			||||||
 | 
					            btn_lbl1.set_text(CString::new(b"+").unwrap().as_c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            button_add.on_event(|_btn, event| {
 | 
				
			||||||
 | 
					                if let Event::Pressed = event {
 | 
				
			||||||
 | 
					                    println!("pressed");
 | 
				
			||||||
 | 
					                    if appdata.timer_stopped() {
 | 
				
			||||||
 | 
					                        appdata.add_secs(10);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                // println!("Button received event: {:?}", event);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let mut button_sub = Btn::create(&mut screen).unwrap();
 | 
				
			||||||
 | 
					            button_sub.set_pos(170, 150);
 | 
				
			||||||
 | 
					            button_sub.set_size(30, 30);
 | 
				
			||||||
 | 
					            let mut btn_lbl2 = Label::create(&mut button_sub).unwrap();
 | 
				
			||||||
 | 
					            btn_lbl2.set_text(CString::new(b"-").unwrap().as_c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            button_sub.on_event(|_btn, event| {
 | 
				
			||||||
 | 
					                if let Event::Pressed = event {
 | 
				
			||||||
 | 
					                    if appdata.timer_stopped() {
 | 
				
			||||||
 | 
					                        appdata.sub_secs(10);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let mut button_reset = Btn::create(&mut screen).unwrap();
 | 
				
			||||||
 | 
					            button_reset.set_pos(123, 190);
 | 
				
			||||||
 | 
					            button_reset.set_size(35, 35);
 | 
				
			||||||
 | 
					            let mut btn_lbl3 = Label::create(&mut button_reset).unwrap();
 | 
				
			||||||
 | 
					            btn_lbl3.set_text(CString::new(b"\xEF\x80\xA1").unwrap().as_c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const PLAY: &'static [u8; 3] = b"\xEF\x81\x8B";
 | 
				
			||||||
 | 
					            const PAUSE: &'static [u8; 3] = b"\xEF\x81\x8C";
 | 
				
			||||||
 | 
					            const STOP: &'static [u8; 3] = b"\xEF\x81\x8D";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let mut button_start_stop = Btn::create(&mut screen).unwrap();
 | 
				
			||||||
 | 
					            button_start_stop.set_pos(173, 190);
 | 
				
			||||||
 | 
					            button_start_stop.set_size(35, 35);
 | 
				
			||||||
 | 
					            let mut btn_lbl4 = Label::create(&mut button_start_stop).unwrap();
 | 
				
			||||||
 | 
					            btn_lbl4.set_text(CString::new(b"\xEF\x81\x8B").unwrap().as_c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            button_reset.on_event(|_btn, event| {
 | 
				
			||||||
 | 
					                if let Event::Pressed = event {
 | 
				
			||||||
 | 
					                    appdata.reset_timer();
 | 
				
			||||||
 | 
					                    btn_lbl4.set_text(CString::new(PLAY).unwrap().as_c_str());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            button_start_stop.on_event(|_btn, event| {
 | 
				
			||||||
 | 
					                if let Event::Pressed = event {
 | 
				
			||||||
 | 
					                    if appdata.timer_finished() {
 | 
				
			||||||
 | 
					                        // println!("Resetting finished timer");
 | 
				
			||||||
 | 
					                        appdata.reset_timer();
 | 
				
			||||||
 | 
					                        btn_lbl4.set_text(CString::new(PLAY).unwrap().as_c_str());
 | 
				
			||||||
 | 
					                    } else if appdata.timer_running() {
 | 
				
			||||||
 | 
					                        // println!("Pausing timer");
 | 
				
			||||||
 | 
					                        appdata.pause_timer();
 | 
				
			||||||
 | 
					                        btn_lbl4.set_text(CString::new(PLAY).unwrap().as_c_str());
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        // println!("Starting timer");
 | 
				
			||||||
 | 
					                        appdata.start_timer();
 | 
				
			||||||
 | 
					                        if appdata.timer_finished() {
 | 
				
			||||||
 | 
					                            // println!("Timer already finished");
 | 
				
			||||||
 | 
					                            btn_lbl4.set_text(CString::new(STOP).unwrap().as_c_str());
 | 
				
			||||||
 | 
					                        } else {
 | 
				
			||||||
 | 
					                            // println!("Timer running");
 | 
				
			||||||
 | 
					                            btn_lbl4.set_text(CString::new(PAUSE).unwrap().as_c_str());
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let mut was_finished = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            loop {
 | 
				
			||||||
 | 
					                let start_time = Instant::now();
 | 
				
			||||||
 | 
					                let rem_time = appdata.remaining();
 | 
				
			||||||
 | 
					                let val = CString::new(format!("{:02}:{:02}:{:03}",
 | 
				
			||||||
 | 
					                                               rem_time.as_secs() / 60,
 | 
				
			||||||
 | 
					                                               rem_time.as_secs() % 60,
 | 
				
			||||||
 | 
					                                               rem_time.as_millis() % 1000)).unwrap();
 | 
				
			||||||
 | 
					                time.set_text(&val).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if !was_finished && appdata.timer_finished() {
 | 
				
			||||||
 | 
					                    was_finished = true;
 | 
				
			||||||
 | 
					                    btn_lbl4.set_text(CString::new(STOP).unwrap().as_c_str());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                was_finished = appdata.timer_finished();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let start_draw_time = Instant::now();
 | 
				
			||||||
 | 
					                lvgl::task_handler();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // Simulate clock - so sleep for one second so time text is incremented in
 | 
				
			||||||
 | 
					                // seconds
 | 
				
			||||||
 | 
					                // delay::FreeRtos::delay_ms(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                lvgl::tick_inc(Instant::now().duration_since(start_time));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let end_time = Instant::now();
 | 
				
			||||||
 | 
					                let draw_time = raw_display.get_time();
 | 
				
			||||||
 | 
					                let prep_time = start_draw_time - start_time;
 | 
				
			||||||
 | 
					                let proc_time = end_time - start_draw_time;
 | 
				
			||||||
 | 
					                let proc_time = proc_time - min(draw_time, proc_time);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if draw_time.as_micros() > 0 {
 | 
				
			||||||
 | 
					                    println!(
 | 
				
			||||||
 | 
					                        "draw time: {}.{:03}ms | prep time: {}.{:03}ms | proc time: {}.{:03}ms | total time: {}.{:03}ms",
 | 
				
			||||||
 | 
					                        draw_time.as_millis(),
 | 
				
			||||||
 | 
					                        draw_time.as_micros() % 100,
 | 
				
			||||||
 | 
					                        prep_time.as_millis(),
 | 
				
			||||||
 | 
					                        prep_time.as_micros() % 100,
 | 
				
			||||||
 | 
					                        proc_time.as_millis(),
 | 
				
			||||||
 | 
					                        proc_time.as_micros() % 100,
 | 
				
			||||||
 | 
					                        (draw_time + prep_time + proc_time).as_millis(),
 | 
				
			||||||
 | 
					                        (draw_time + prep_time + proc_time).as_micros() % 100,            );
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                raw_display.reset_time();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                delay::FreeRtos::delay_ms(1);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    loop {
 | 
				
			||||||
 | 
					        // Don't exit application
 | 
				
			||||||
 | 
					        delay::FreeRtos::delay_ms(1_000_000);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -125,7 +125,6 @@ fn main() -> Result<(), LvError> {
 | 
				
			|||||||
            style_time.set_text_align(TextAlign::Center);
 | 
					            style_time.set_text_align(TextAlign::Center);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Custom font requires lvgl-sys in Cargo.toml and 'use lvgl_sys' in this file
 | 
					            // Custom font requires lvgl-sys in Cargo.toml and 'use lvgl_sys' in this file
 | 
				
			||||||
            style_time.set_text_font(unsafe { Font::new_raw(lvgl_sys::gotham_bold_80) });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            time.add_style(Part::Main, &mut style_time);
 | 
					            time.add_style(Part::Main, &mut style_time);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -148,7 +147,7 @@ fn main() -> Result<(), LvError> {
 | 
				
			|||||||
                lvgl::task_handler();
 | 
					                lvgl::task_handler();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // Simulate clock - so sleep for one second so time text is incremented in seconds
 | 
					                // Simulate clock - so sleep for one second so time text is incremented in seconds
 | 
				
			||||||
                delay::FreeRtos::delay_ms(1000);
 | 
					                delay::FreeRtos::delay_ms(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                lvgl::tick_inc(Instant::now().duration_since(start));
 | 
					                lvgl::tick_inc(Instant::now().duration_since(start));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										322
									
								
								lvgl-based/tree.text
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										322
									
								
								lvgl-based/tree.text
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,322 @@
 | 
				
			|||||||
 | 
					rust-m5stack-lvgl-demo v0.1.0 (/home/yannik/repos/kolibri-cyd-tester-app-embassy/lvgl-based)
 | 
				
			||||||
 | 
					├── cstr_core v0.2.6
 | 
				
			||||||
 | 
					│   ├── cty v0.2.2
 | 
				
			||||||
 | 
					│   └── memchr v2.7.4
 | 
				
			||||||
 | 
					├── display-interface-spi v0.5.0
 | 
				
			||||||
 | 
					│   ├── byte-slice-cast v1.2.2
 | 
				
			||||||
 | 
					│   ├── display-interface v0.5.0
 | 
				
			||||||
 | 
					│   ├── embedded-hal v1.0.0
 | 
				
			||||||
 | 
					│   └── embedded-hal-async v1.0.0
 | 
				
			||||||
 | 
					│       └── embedded-hal v1.0.0
 | 
				
			||||||
 | 
					├── embedded-graphics-core v0.4.0
 | 
				
			||||||
 | 
					│   ├── az v1.2.1
 | 
				
			||||||
 | 
					│   └── byteorder v1.5.0
 | 
				
			||||||
 | 
					├── esp-idf-hal v0.44.1
 | 
				
			||||||
 | 
					│   ├── atomic-waker v1.1.2
 | 
				
			||||||
 | 
					│   ├── critical-section v1.2.0
 | 
				
			||||||
 | 
					│   ├── embassy-sync v0.6.0
 | 
				
			||||||
 | 
					│   │   ├── cfg-if v1.0.0
 | 
				
			||||||
 | 
					│   │   ├── critical-section v1.2.0
 | 
				
			||||||
 | 
					│   │   ├── embedded-io-async v0.6.1
 | 
				
			||||||
 | 
					│   │   │   └── embedded-io v0.6.1
 | 
				
			||||||
 | 
					│   │   ├── futures-util v0.3.31
 | 
				
			||||||
 | 
					│   │   │   ├── futures-core v0.3.31
 | 
				
			||||||
 | 
					│   │   │   ├── futures-task v0.3.31
 | 
				
			||||||
 | 
					│   │   │   ├── pin-project-lite v0.2.15
 | 
				
			||||||
 | 
					│   │   │   └── pin-utils v0.1.0
 | 
				
			||||||
 | 
					│   │   └── heapless v0.8.0
 | 
				
			||||||
 | 
					│   │       ├── hash32 v0.3.1
 | 
				
			||||||
 | 
					│   │       │   └── byteorder v1.5.0
 | 
				
			||||||
 | 
					│   │       └── stable_deref_trait v1.2.0
 | 
				
			||||||
 | 
					│   ├── embedded-can v0.4.1
 | 
				
			||||||
 | 
					│   │   └── nb v1.1.0
 | 
				
			||||||
 | 
					│   ├── embedded-hal v0.2.7
 | 
				
			||||||
 | 
					│   │   ├── nb v0.1.3
 | 
				
			||||||
 | 
					│   │   │   └── nb v1.1.0
 | 
				
			||||||
 | 
					│   │   └── void v1.0.2
 | 
				
			||||||
 | 
					│   ├── embedded-hal v1.0.0
 | 
				
			||||||
 | 
					│   ├── embedded-hal-async v1.0.0 (*)
 | 
				
			||||||
 | 
					│   ├── embedded-hal-nb v1.0.0
 | 
				
			||||||
 | 
					│   │   ├── embedded-hal v1.0.0
 | 
				
			||||||
 | 
					│   │   └── nb v1.1.0
 | 
				
			||||||
 | 
					│   ├── embedded-io v0.6.1
 | 
				
			||||||
 | 
					│   ├── embedded-io-async v0.6.1 (*)
 | 
				
			||||||
 | 
					│   ├── enumset v1.1.5
 | 
				
			||||||
 | 
					│   │   └── enumset_derive v0.10.0 (proc-macro)
 | 
				
			||||||
 | 
					│   │       ├── darling v0.20.10
 | 
				
			||||||
 | 
					│   │       │   ├── darling_core v0.20.10
 | 
				
			||||||
 | 
					│   │       │   │   ├── fnv v1.0.7
 | 
				
			||||||
 | 
					│   │       │   │   ├── ident_case v1.0.1
 | 
				
			||||||
 | 
					│   │       │   │   ├── proc-macro2 v1.0.89
 | 
				
			||||||
 | 
					│   │       │   │   │   └── unicode-ident v1.0.13
 | 
				
			||||||
 | 
					│   │       │   │   ├── quote v1.0.37
 | 
				
			||||||
 | 
					│   │       │   │   │   └── proc-macro2 v1.0.89 (*)
 | 
				
			||||||
 | 
					│   │       │   │   └── syn v2.0.87
 | 
				
			||||||
 | 
					│   │       │   │       ├── proc-macro2 v1.0.89 (*)
 | 
				
			||||||
 | 
					│   │       │   │       ├── quote v1.0.37 (*)
 | 
				
			||||||
 | 
					│   │       │   │       └── unicode-ident v1.0.13
 | 
				
			||||||
 | 
					│   │       │   └── darling_macro v0.20.10 (proc-macro)
 | 
				
			||||||
 | 
					│   │       │       ├── darling_core v0.20.10 (*)
 | 
				
			||||||
 | 
					│   │       │       ├── quote v1.0.37 (*)
 | 
				
			||||||
 | 
					│   │       │       └── syn v2.0.87 (*)
 | 
				
			||||||
 | 
					│   │       ├── proc-macro2 v1.0.89 (*)
 | 
				
			||||||
 | 
					│   │       ├── quote v1.0.37 (*)
 | 
				
			||||||
 | 
					│   │       └── syn v2.0.87 (*)
 | 
				
			||||||
 | 
					│   ├── esp-idf-sys v0.35.0
 | 
				
			||||||
 | 
					│   │   ├── build-time v0.1.3 (proc-macro)
 | 
				
			||||||
 | 
					│   │   │   ├── chrono v0.4.38
 | 
				
			||||||
 | 
					│   │   │   │   ├── iana-time-zone v0.1.61
 | 
				
			||||||
 | 
					│   │   │   │   └── num-traits v0.2.19
 | 
				
			||||||
 | 
					│   │   │   │       [build-dependencies]
 | 
				
			||||||
 | 
					│   │   │   │       └── autocfg v1.4.0
 | 
				
			||||||
 | 
					│   │   │   ├── once_cell v1.20.2
 | 
				
			||||||
 | 
					│   │   │   ├── proc-macro2 v1.0.89 (*)
 | 
				
			||||||
 | 
					│   │   │   ├── quote v1.0.37 (*)
 | 
				
			||||||
 | 
					│   │   │   └── syn v2.0.87 (*)
 | 
				
			||||||
 | 
					│   │   ├── const_format v0.2.33
 | 
				
			||||||
 | 
					│   │   │   └── const_format_proc_macros v0.2.33 (proc-macro)
 | 
				
			||||||
 | 
					│   │   │       ├── proc-macro2 v1.0.89 (*)
 | 
				
			||||||
 | 
					│   │   │       ├── quote v1.0.37 (*)
 | 
				
			||||||
 | 
					│   │   │       └── unicode-xid v0.2.6
 | 
				
			||||||
 | 
					│   │   └── libc v0.2.162
 | 
				
			||||||
 | 
					│   │   [build-dependencies]
 | 
				
			||||||
 | 
					│   │   ├── anyhow v1.0.93
 | 
				
			||||||
 | 
					│   │   ├── bindgen v0.69.5
 | 
				
			||||||
 | 
					│   │   │   ├── bitflags v2.6.0
 | 
				
			||||||
 | 
					│   │   │   ├── cexpr v0.6.0
 | 
				
			||||||
 | 
					│   │   │   │   └── nom v7.1.3
 | 
				
			||||||
 | 
					│   │   │   │       ├── memchr v2.7.4
 | 
				
			||||||
 | 
					│   │   │   │       └── minimal-lexical v0.2.1
 | 
				
			||||||
 | 
					│   │   │   ├── clang-sys v1.8.1
 | 
				
			||||||
 | 
					│   │   │   │   ├── glob v0.3.1
 | 
				
			||||||
 | 
					│   │   │   │   ├── libc v0.2.162
 | 
				
			||||||
 | 
					│   │   │   │   └── libloading v0.8.5
 | 
				
			||||||
 | 
					│   │   │   │       └── cfg-if v1.0.0
 | 
				
			||||||
 | 
					│   │   │   │   [build-dependencies]
 | 
				
			||||||
 | 
					│   │   │   │   └── glob v0.3.1
 | 
				
			||||||
 | 
					│   │   │   ├── itertools v0.12.1
 | 
				
			||||||
 | 
					│   │   │   │   └── either v1.13.0
 | 
				
			||||||
 | 
					│   │   │   ├── lazy_static v1.5.0
 | 
				
			||||||
 | 
					│   │   │   ├── lazycell v1.3.0
 | 
				
			||||||
 | 
					│   │   │   ├── log v0.4.22
 | 
				
			||||||
 | 
					│   │   │   ├── prettyplease v0.2.25
 | 
				
			||||||
 | 
					│   │   │   │   ├── proc-macro2 v1.0.89 (*)
 | 
				
			||||||
 | 
					│   │   │   │   └── syn v2.0.87 (*)
 | 
				
			||||||
 | 
					│   │   │   ├── proc-macro2 v1.0.89 (*)
 | 
				
			||||||
 | 
					│   │   │   ├── quote v1.0.37 (*)
 | 
				
			||||||
 | 
					│   │   │   ├── regex v1.11.1
 | 
				
			||||||
 | 
					│   │   │   │   ├── aho-corasick v1.1.3
 | 
				
			||||||
 | 
					│   │   │   │   │   └── memchr v2.7.4
 | 
				
			||||||
 | 
					│   │   │   │   ├── memchr v2.7.4
 | 
				
			||||||
 | 
					│   │   │   │   ├── regex-automata v0.4.9
 | 
				
			||||||
 | 
					│   │   │   │   │   ├── aho-corasick v1.1.3 (*)
 | 
				
			||||||
 | 
					│   │   │   │   │   ├── memchr v2.7.4
 | 
				
			||||||
 | 
					│   │   │   │   │   └── regex-syntax v0.8.5
 | 
				
			||||||
 | 
					│   │   │   │   └── regex-syntax v0.8.5
 | 
				
			||||||
 | 
					│   │   │   ├── rustc-hash v1.1.0
 | 
				
			||||||
 | 
					│   │   │   ├── shlex v1.3.0
 | 
				
			||||||
 | 
					│   │   │   ├── syn v2.0.87 (*)
 | 
				
			||||||
 | 
					│   │   │   └── which v4.4.2
 | 
				
			||||||
 | 
					│   │   │       ├── either v1.13.0
 | 
				
			||||||
 | 
					│   │   │       ├── home v0.5.9
 | 
				
			||||||
 | 
					│   │   │       └── rustix v0.38.40
 | 
				
			||||||
 | 
					│   │   │           ├── bitflags v2.6.0
 | 
				
			||||||
 | 
					│   │   │           └── linux-raw-sys v0.4.14
 | 
				
			||||||
 | 
					│   │   ├── cargo_metadata v0.18.1
 | 
				
			||||||
 | 
					│   │   │   ├── camino v1.1.9
 | 
				
			||||||
 | 
					│   │   │   │   └── serde v1.0.215
 | 
				
			||||||
 | 
					│   │   │   │       └── serde_derive v1.0.215 (proc-macro)
 | 
				
			||||||
 | 
					│   │   │   │           ├── proc-macro2 v1.0.89 (*)
 | 
				
			||||||
 | 
					│   │   │   │           ├── quote v1.0.37 (*)
 | 
				
			||||||
 | 
					│   │   │   │           └── syn v2.0.87 (*)
 | 
				
			||||||
 | 
					│   │   │   ├── cargo-platform v0.1.8
 | 
				
			||||||
 | 
					│   │   │   │   └── serde v1.0.215 (*)
 | 
				
			||||||
 | 
					│   │   │   ├── semver v1.0.23
 | 
				
			||||||
 | 
					│   │   │   │   └── serde v1.0.215 (*)
 | 
				
			||||||
 | 
					│   │   │   ├── serde v1.0.215 (*)
 | 
				
			||||||
 | 
					│   │   │   ├── serde_json v1.0.132
 | 
				
			||||||
 | 
					│   │   │   │   ├── itoa v1.0.11
 | 
				
			||||||
 | 
					│   │   │   │   ├── memchr v2.7.4
 | 
				
			||||||
 | 
					│   │   │   │   ├── ryu v1.0.18
 | 
				
			||||||
 | 
					│   │   │   │   └── serde v1.0.215 (*)
 | 
				
			||||||
 | 
					│   │   │   └── thiserror v1.0.69
 | 
				
			||||||
 | 
					│   │   │       └── thiserror-impl v1.0.69 (proc-macro)
 | 
				
			||||||
 | 
					│   │   │           ├── proc-macro2 v1.0.89 (*)
 | 
				
			||||||
 | 
					│   │   │           ├── quote v1.0.37 (*)
 | 
				
			||||||
 | 
					│   │   │           └── syn v2.0.87 (*)
 | 
				
			||||||
 | 
					│   │   ├── embuild v0.32.0
 | 
				
			||||||
 | 
					│   │   │   ├── anyhow v1.0.93
 | 
				
			||||||
 | 
					│   │   │   ├── bindgen v0.69.5 (*)
 | 
				
			||||||
 | 
					│   │   │   ├── bitflags v1.3.2
 | 
				
			||||||
 | 
					│   │   │   ├── cmake v0.1.51
 | 
				
			||||||
 | 
					│   │   │   │   └── cc v1.2.1
 | 
				
			||||||
 | 
					│   │   │   │       └── shlex v1.3.0
 | 
				
			||||||
 | 
					│   │   │   ├── filetime v0.2.25
 | 
				
			||||||
 | 
					│   │   │   │   ├── cfg-if v1.0.0
 | 
				
			||||||
 | 
					│   │   │   │   └── libc v0.2.162
 | 
				
			||||||
 | 
					│   │   │   ├── globwalk v0.8.1
 | 
				
			||||||
 | 
					│   │   │   │   ├── bitflags v1.3.2
 | 
				
			||||||
 | 
					│   │   │   │   ├── ignore v0.4.23
 | 
				
			||||||
 | 
					│   │   │   │   │   ├── crossbeam-deque v0.8.5
 | 
				
			||||||
 | 
					│   │   │   │   │   │   ├── crossbeam-epoch v0.9.18
 | 
				
			||||||
 | 
					│   │   │   │   │   │   │   └── crossbeam-utils v0.8.20
 | 
				
			||||||
 | 
					│   │   │   │   │   │   └── crossbeam-utils v0.8.20
 | 
				
			||||||
 | 
					│   │   │   │   │   ├── globset v0.4.15
 | 
				
			||||||
 | 
					│   │   │   │   │   │   ├── aho-corasick v1.1.3 (*)
 | 
				
			||||||
 | 
					│   │   │   │   │   │   ├── bstr v1.11.0
 | 
				
			||||||
 | 
					│   │   │   │   │   │   │   └── memchr v2.7.4
 | 
				
			||||||
 | 
					│   │   │   │   │   │   ├── log v0.4.22
 | 
				
			||||||
 | 
					│   │   │   │   │   │   ├── regex-automata v0.4.9 (*)
 | 
				
			||||||
 | 
					│   │   │   │   │   │   └── regex-syntax v0.8.5
 | 
				
			||||||
 | 
					│   │   │   │   │   ├── log v0.4.22
 | 
				
			||||||
 | 
					│   │   │   │   │   ├── memchr v2.7.4
 | 
				
			||||||
 | 
					│   │   │   │   │   ├── regex-automata v0.4.9 (*)
 | 
				
			||||||
 | 
					│   │   │   │   │   ├── same-file v1.0.6
 | 
				
			||||||
 | 
					│   │   │   │   │   └── walkdir v2.5.0
 | 
				
			||||||
 | 
					│   │   │   │   │       └── same-file v1.0.6
 | 
				
			||||||
 | 
					│   │   │   │   └── walkdir v2.5.0 (*)
 | 
				
			||||||
 | 
					│   │   │   ├── home v0.5.9
 | 
				
			||||||
 | 
					│   │   │   ├── log v0.4.22
 | 
				
			||||||
 | 
					│   │   │   ├── regex v1.11.1 (*)
 | 
				
			||||||
 | 
					│   │   │   ├── remove_dir_all v0.8.4
 | 
				
			||||||
 | 
					│   │   │   │   ├── cfg-if v1.0.0
 | 
				
			||||||
 | 
					│   │   │   │   ├── cvt v0.1.2
 | 
				
			||||||
 | 
					│   │   │   │   │   └── cfg-if v1.0.0
 | 
				
			||||||
 | 
					│   │   │   │   ├── fs_at v0.2.1
 | 
				
			||||||
 | 
					│   │   │   │   │   ├── cfg-if v1.0.0
 | 
				
			||||||
 | 
					│   │   │   │   │   ├── cvt v0.1.2 (*)
 | 
				
			||||||
 | 
					│   │   │   │   │   ├── libc v0.2.162
 | 
				
			||||||
 | 
					│   │   │   │   │   └── nix v0.29.0
 | 
				
			||||||
 | 
					│   │   │   │   │       ├── bitflags v2.6.0
 | 
				
			||||||
 | 
					│   │   │   │   │       ├── cfg-if v1.0.0
 | 
				
			||||||
 | 
					│   │   │   │   │       └── libc v0.2.162
 | 
				
			||||||
 | 
					│   │   │   │   │       [build-dependencies]
 | 
				
			||||||
 | 
					│   │   │   │   │       └── cfg_aliases v0.2.1
 | 
				
			||||||
 | 
					│   │   │   │   ├── libc v0.2.162
 | 
				
			||||||
 | 
					│   │   │   │   └── normpath v1.3.0
 | 
				
			||||||
 | 
					│   │   │   ├── serde v1.0.215 (*)
 | 
				
			||||||
 | 
					│   │   │   ├── serde_json v1.0.132 (*)
 | 
				
			||||||
 | 
					│   │   │   ├── shlex v1.3.0
 | 
				
			||||||
 | 
					│   │   │   ├── strum v0.24.1
 | 
				
			||||||
 | 
					│   │   │   │   └── strum_macros v0.24.3 (proc-macro)
 | 
				
			||||||
 | 
					│   │   │   │       ├── heck v0.4.1
 | 
				
			||||||
 | 
					│   │   │   │       ├── proc-macro2 v1.0.89 (*)
 | 
				
			||||||
 | 
					│   │   │   │       ├── quote v1.0.37 (*)
 | 
				
			||||||
 | 
					│   │   │   │       ├── rustversion v1.0.18 (proc-macro)
 | 
				
			||||||
 | 
					│   │   │   │       └── syn v1.0.109
 | 
				
			||||||
 | 
					│   │   │   │           ├── proc-macro2 v1.0.89 (*)
 | 
				
			||||||
 | 
					│   │   │   │           ├── quote v1.0.37 (*)
 | 
				
			||||||
 | 
					│   │   │   │           └── unicode-ident v1.0.13
 | 
				
			||||||
 | 
					│   │   │   ├── tempfile v3.14.0
 | 
				
			||||||
 | 
					│   │   │   │   ├── cfg-if v1.0.0
 | 
				
			||||||
 | 
					│   │   │   │   ├── fastrand v2.2.0
 | 
				
			||||||
 | 
					│   │   │   │   ├── once_cell v1.20.2
 | 
				
			||||||
 | 
					│   │   │   │   └── rustix v0.38.40 (*)
 | 
				
			||||||
 | 
					│   │   │   ├── thiserror v1.0.69 (*)
 | 
				
			||||||
 | 
					│   │   │   └── which v4.4.2 (*)
 | 
				
			||||||
 | 
					│   │   ├── envy v0.4.2
 | 
				
			||||||
 | 
					│   │   │   └── serde v1.0.215 (*)
 | 
				
			||||||
 | 
					│   │   ├── regex v1.11.1 (*)
 | 
				
			||||||
 | 
					│   │   ├── serde v1.0.215 (*)
 | 
				
			||||||
 | 
					│   │   ├── strum v0.24.1 (*)
 | 
				
			||||||
 | 
					│   │   └── which v4.4.2 (*)
 | 
				
			||||||
 | 
					│   ├── heapless v0.8.0 (*)
 | 
				
			||||||
 | 
					│   ├── log v0.4.22
 | 
				
			||||||
 | 
					│   ├── nb v1.1.0
 | 
				
			||||||
 | 
					│   └── num_enum v0.7.3
 | 
				
			||||||
 | 
					│       └── num_enum_derive v0.7.3 (proc-macro)
 | 
				
			||||||
 | 
					│           ├── proc-macro2 v1.0.89 (*)
 | 
				
			||||||
 | 
					│           ├── quote v1.0.37 (*)
 | 
				
			||||||
 | 
					│           └── syn v2.0.87 (*)
 | 
				
			||||||
 | 
					│   [build-dependencies]
 | 
				
			||||||
 | 
					│   └── embuild v0.32.0 (*)
 | 
				
			||||||
 | 
					├── esp-idf-svc v0.49.1
 | 
				
			||||||
 | 
					│   ├── embassy-futures v0.1.1
 | 
				
			||||||
 | 
					│   ├── embassy-time-driver v0.1.0
 | 
				
			||||||
 | 
					│   │   └── document-features v0.2.10 (proc-macro)
 | 
				
			||||||
 | 
					│   │       └── litrs v0.4.1
 | 
				
			||||||
 | 
					│   ├── embedded-hal-async v1.0.0 (*)
 | 
				
			||||||
 | 
					│   ├── embedded-svc v0.28.0
 | 
				
			||||||
 | 
					│   │   ├── embedded-io v0.6.1
 | 
				
			||||||
 | 
					│   │   ├── embedded-io-async v0.6.1 (*)
 | 
				
			||||||
 | 
					│   │   ├── enumset v1.1.5 (*)
 | 
				
			||||||
 | 
					│   │   ├── heapless v0.8.0 (*)
 | 
				
			||||||
 | 
					│   │   └── serde v1.0.215
 | 
				
			||||||
 | 
					│   │       └── serde_derive v1.0.215 (proc-macro) (*)
 | 
				
			||||||
 | 
					│   ├── enumset v1.1.5 (*)
 | 
				
			||||||
 | 
					│   ├── esp-idf-hal v0.44.1 (*)
 | 
				
			||||||
 | 
					│   ├── heapless v0.8.0 (*)
 | 
				
			||||||
 | 
					│   ├── log v0.4.22
 | 
				
			||||||
 | 
					│   ├── num_enum v0.7.3 (*)
 | 
				
			||||||
 | 
					│   └── uncased v0.9.10
 | 
				
			||||||
 | 
					│       [build-dependencies]
 | 
				
			||||||
 | 
					│       └── version_check v0.9.5
 | 
				
			||||||
 | 
					│   [build-dependencies]
 | 
				
			||||||
 | 
					│   └── embuild v0.32.0 (*)
 | 
				
			||||||
 | 
					├── esp-idf-sys v0.35.0 (*)
 | 
				
			||||||
 | 
					├── log v0.4.22
 | 
				
			||||||
 | 
					├── lvgl v0.6.2 (https://github.com/enelson1001/lv_binding_rust#723ad383)
 | 
				
			||||||
 | 
					│   ├── bitflags v2.6.0
 | 
				
			||||||
 | 
					│   ├── cstr_core v0.2.6 (*)
 | 
				
			||||||
 | 
					│   ├── ctor v0.2.8 (proc-macro)
 | 
				
			||||||
 | 
					│   │   ├── quote v1.0.37 (*)
 | 
				
			||||||
 | 
					│   │   └── syn v2.0.87 (*)
 | 
				
			||||||
 | 
					│   ├── cty v0.2.2
 | 
				
			||||||
 | 
					│   ├── embedded-graphics v0.8.1
 | 
				
			||||||
 | 
					│   │   ├── az v1.2.1
 | 
				
			||||||
 | 
					│   │   ├── byteorder v1.5.0
 | 
				
			||||||
 | 
					│   │   ├── embedded-graphics-core v0.4.0 (*)
 | 
				
			||||||
 | 
					│   │   ├── float-cmp v0.9.0
 | 
				
			||||||
 | 
					│   │   │   └── num-traits v0.2.19
 | 
				
			||||||
 | 
					│   │   │       [build-dependencies]
 | 
				
			||||||
 | 
					│   │   │       └── autocfg v1.4.0
 | 
				
			||||||
 | 
					│   │   └── micromath v2.1.0
 | 
				
			||||||
 | 
					│   ├── lvgl-sys v0.6.2 (https://github.com/enelson1001/lv_binding_rust#723ad383)
 | 
				
			||||||
 | 
					│   │   └── cty v0.2.2
 | 
				
			||||||
 | 
					│   │   [build-dependencies]
 | 
				
			||||||
 | 
					│   │   ├── bindgen v0.65.1
 | 
				
			||||||
 | 
					│   │   │   ├── bitflags v1.3.2
 | 
				
			||||||
 | 
					│   │   │   ├── cexpr v0.6.0 (*)
 | 
				
			||||||
 | 
					│   │   │   ├── clang-sys v1.8.1 (*)
 | 
				
			||||||
 | 
					│   │   │   ├── lazy_static v1.5.0
 | 
				
			||||||
 | 
					│   │   │   ├── lazycell v1.3.0
 | 
				
			||||||
 | 
					│   │   │   ├── log v0.4.22
 | 
				
			||||||
 | 
					│   │   │   ├── peeking_take_while v0.1.2
 | 
				
			||||||
 | 
					│   │   │   ├── prettyplease v0.2.25 (*)
 | 
				
			||||||
 | 
					│   │   │   ├── proc-macro2 v1.0.89 (*)
 | 
				
			||||||
 | 
					│   │   │   ├── quote v1.0.37 (*)
 | 
				
			||||||
 | 
					│   │   │   ├── regex v1.11.1 (*)
 | 
				
			||||||
 | 
					│   │   │   ├── rustc-hash v1.1.0
 | 
				
			||||||
 | 
					│   │   │   ├── shlex v1.3.0
 | 
				
			||||||
 | 
					│   │   │   ├── syn v2.0.87 (*)
 | 
				
			||||||
 | 
					│   │   │   └── which v4.4.2 (*)
 | 
				
			||||||
 | 
					│   │   └── cc v1.2.1 (*)
 | 
				
			||||||
 | 
					│   └── paste v1.0.15 (proc-macro)
 | 
				
			||||||
 | 
					│   [build-dependencies]
 | 
				
			||||||
 | 
					│   ├── lvgl-codegen v0.6.2 (https://github.com/enelson1001/lv_binding_rust#723ad383)
 | 
				
			||||||
 | 
					│   │   ├── Inflector v0.11.4
 | 
				
			||||||
 | 
					│   │   │   ├── lazy_static v1.5.0
 | 
				
			||||||
 | 
					│   │   │   └── regex v1.11.1 (*)
 | 
				
			||||||
 | 
					│   │   ├── lazy_static v1.5.0
 | 
				
			||||||
 | 
					│   │   ├── proc-macro2 v1.0.89 (*)
 | 
				
			||||||
 | 
					│   │   ├── quote v1.0.37 (*)
 | 
				
			||||||
 | 
					│   │   ├── regex v1.11.1 (*)
 | 
				
			||||||
 | 
					│   │   └── syn v2.0.87 (*)
 | 
				
			||||||
 | 
					│   ├── lvgl-sys v0.6.2 (https://github.com/enelson1001/lv_binding_rust#723ad383)
 | 
				
			||||||
 | 
					│   │   └── cty v0.2.2
 | 
				
			||||||
 | 
					│   │   [build-dependencies]
 | 
				
			||||||
 | 
					│   │   ├── bindgen v0.65.1 (*)
 | 
				
			||||||
 | 
					│   │   └── cc v1.2.1 (*)
 | 
				
			||||||
 | 
					│   ├── proc-macro2 v1.0.89 (*)
 | 
				
			||||||
 | 
					│   └── quote v1.0.37 (*)
 | 
				
			||||||
 | 
					├── lvgl-sys v0.6.2 (https://github.com/enelson1001/lv_binding_rust#723ad383) (*)
 | 
				
			||||||
 | 
					├── mipidsi v0.8.0
 | 
				
			||||||
 | 
					│   ├── display-interface v0.5.0
 | 
				
			||||||
 | 
					│   ├── embedded-graphics-core v0.4.0 (*)
 | 
				
			||||||
 | 
					│   ├── embedded-hal v1.0.0
 | 
				
			||||||
 | 
					│   ├── heapless v0.8.0 (*)
 | 
				
			||||||
 | 
					│   └── nb v1.1.0
 | 
				
			||||||
 | 
					└── static_cell v2.1.0
 | 
				
			||||||
 | 
					    └── portable-atomic v1.9.0
 | 
				
			||||||
 | 
					[build-dependencies]
 | 
				
			||||||
 | 
					└── embuild v0.32.0 (*)
 | 
				
			||||||
							
								
								
									
										42
									
								
								slint-based/.cargo/config.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								slint-based/.cargo/config.toml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,42 @@
 | 
				
			|||||||
 | 
					#
 | 
				
			||||||
 | 
					# Cargo Configuration for the https://github.com/rp-rs/rp-hal.git repository.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Copyright (c) The RP-RS Developers, 2021
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# You might want to make a similar file in your own repository if you are
 | 
				
			||||||
 | 
					# writing programs for Raspberry Silicon microcontrollers.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This file is MIT or Apache-2.0 as per the repository README.md file
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[target.xtensa-esp32-none]
 | 
				
			||||||
 | 
					# runner = "espflash --monitor" # Select this runner for espflash v1.x.x
 | 
				
			||||||
 | 
					runner = "espflash flash --monitor --baud 921600" # Select this runner for espflash v2.x.x
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Target specific options
 | 
				
			||||||
 | 
					[target.thumbv6m-none-eabi]
 | 
				
			||||||
 | 
					# Pass some extra options to rustc, some of which get passed on to the linker.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# * linker argument --nmagic turns off page alignment of sections (which saves
 | 
				
			||||||
 | 
					#   flash space)
 | 
				
			||||||
 | 
					# * linker argument -Tlink.x tells the linker to use link.x as the linker
 | 
				
			||||||
 | 
					#   script. This is usually provided by the cortex-m-rt crate, and by default
 | 
				
			||||||
 | 
					#   the version in that crate will include a file called `memory.x` which
 | 
				
			||||||
 | 
					#   describes the particular memory layout for your specific chip. 
 | 
				
			||||||
 | 
					# * inline-threshold=5 makes the compiler more aggressive and inlining functions
 | 
				
			||||||
 | 
					# * no-vectorize-loops turns off the loop vectorizer (seeing as the M0+ doesn't
 | 
				
			||||||
 | 
					#   have SIMD)
 | 
				
			||||||
 | 
					rustflags = [
 | 
				
			||||||
 | 
					    "-C", "link-arg=--nmagic",
 | 
				
			||||||
 | 
					    "-C", "link-arg=-Tlink.x",
 | 
				
			||||||
 | 
					    "-C", "llvm-args=--inline-threshold=5",
 | 
				
			||||||
 | 
					    "-C", "no-vectorize-loops",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# This runner will make a UF2 file and then copy it to a mounted RP2040 in USB
 | 
				
			||||||
 | 
					# Bootloader mode:
 | 
				
			||||||
 | 
					# runner = "elf2uf2-rs -d"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# This runner will find a supported SWD debug probe and flash your RP2040 over
 | 
				
			||||||
 | 
					# SWD:
 | 
				
			||||||
 | 
					# runner = "probe-run --chip RP2040"
 | 
				
			||||||
							
								
								
									
										6
									
								
								slint-based/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								slint-based/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					# Generated by Cargo
 | 
				
			||||||
 | 
					# will have compiled files and executables
 | 
				
			||||||
 | 
					/target/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# These are backup files generated by rustfmt
 | 
				
			||||||
 | 
					**/*.rs.bk
 | 
				
			||||||
							
								
								
									
										7
									
								
								slint-based/.vscode/extensions.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								slint-based/.vscode/extensions.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "recommendations": [
 | 
				
			||||||
 | 
					    "rust-lang.rust-analyzer",
 | 
				
			||||||
 | 
					    "vadimcn.vscode-lldb",
 | 
				
			||||||
 | 
					    "Slint.slint"
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										5186
									
								
								slint-based/Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										5186
									
								
								slint-based/Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										69
									
								
								slint-based/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								slint-based/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,69 @@
 | 
				
			|||||||
 | 
					[workspace]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[package]
 | 
				
			||||||
 | 
					name = "slint-mcu-rust-template"
 | 
				
			||||||
 | 
					version = "0.1.0"
 | 
				
			||||||
 | 
					edition = "2021"
 | 
				
			||||||
 | 
					build = "build.rs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# [[bin]]
 | 
				
			||||||
 | 
					# name = "main"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[bin]]
 | 
				
			||||||
 | 
					name = "starter"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies]
 | 
				
			||||||
 | 
					slint = { version = "1.8", default-features = false, features = ["compat-1-2", "renderer-software", "libm", "unsafe-single-threaded"] }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					embassy-embedded-hal = "0.2.0"
 | 
				
			||||||
 | 
					embassy-executor = { version = "0.6.0", features = ["log"] }
 | 
				
			||||||
 | 
					embassy-sync = "0.6.0"
 | 
				
			||||||
 | 
					embassy-time = { version = "0.3.1", features = ["generic-queue-8"] }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					esp-hal = { version = "0.20.1", features = ["async", "esp32", "log"] }
 | 
				
			||||||
 | 
					esp-hal-embassy = { version = "0.3.0", features = ["esp32", "log"] }
 | 
				
			||||||
 | 
					esp-println = { version = "0.12.0", features = ["esp32", "log"] }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cortex-m = { version = "0.7.6" }
 | 
				
			||||||
 | 
					cortex-m-rt = { version = "0.7.1" }
 | 
				
			||||||
 | 
					embedded-alloc = { version = "0.6.0" }
 | 
				
			||||||
 | 
					shared-bus = { version = "0.3.1" }
 | 
				
			||||||
 | 
					panic-halt = { version = "1.0.0" }
 | 
				
			||||||
 | 
					display-interface-spi = { version = "0.5.0" }
 | 
				
			||||||
 | 
					mipidsi = "0.8.0"
 | 
				
			||||||
 | 
					embedded-graphics-core = { version = "0.4.0" }
 | 
				
			||||||
 | 
					embedded-hal = { version = "1.0.0" }
 | 
				
			||||||
 | 
					fugit = { version = "0.3.6" }
 | 
				
			||||||
 | 
					esp-alloc = "0.5.0"
 | 
				
			||||||
 | 
					embedded-graphics-profiler-display = { version = "0.1.0", path = "../embedded-graphics-profiler-display" }
 | 
				
			||||||
 | 
					xpt2046 = { git = "https://github.com/Yandrik/xpt2046.git", version = "0.3.1" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					esp-backtrace = { version = "0.14.2", features = ["esp32", "println"] }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static_cell = { version = "2.1.0", features = ["nightly"] }
 | 
				
			||||||
 | 
					embedded-hal-bus = "0.2.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[build-dependencies]
 | 
				
			||||||
 | 
					slint-build = { version = "1.8" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[features]
 | 
				
			||||||
 | 
					simulator = ["slint/backend-winit"]
 | 
				
			||||||
 | 
					# pico = [
 | 
				
			||||||
 | 
					#     "slint/unsafe-single-threaded",
 | 
				
			||||||
 | 
					#     "slint/libm",
 | 
				
			||||||
 | 
					#     "cortex-m",
 | 
				
			||||||
 | 
					#     "cortex-m-rt",
 | 
				
			||||||
 | 
					#     "embedded-alloc",
 | 
				
			||||||
 | 
					#     "embedded-hal",
 | 
				
			||||||
 | 
					#     "fugit",
 | 
				
			||||||
 | 
					#     "display-interface-spi",
 | 
				
			||||||
 | 
					#     "embedded-graphics-core",
 | 
				
			||||||
 | 
					#     "shared-bus",
 | 
				
			||||||
 | 
					#     "panic-halt"
 | 
				
			||||||
 | 
					# ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										45
									
								
								slint-based/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								slint-based/README.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,45 @@
 | 
				
			|||||||
 | 
					# Slint Bare Metal Microcontroller Rust Template
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A template for a Rust Microcontroller(MCU) application that's using [Slint](https://slint-ui.com) for the user interface.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## About
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This template helps you get started developing a bare metal MCU Rust application with Slint as toolkit for the user interface.
 | 
				
			||||||
 | 
					It shows how to implement the `slint::platform::Platform` trait, and displays a simple `.slint` design on the screen.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For a template about using Slint with an operating system (Desktop, or Embedded Linux), check out the
 | 
				
			||||||
 | 
					classic template at https://github.com/slint-ui/slint-rust-template.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Usage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. Download and extract the [ZIP archive of this repository](https://github.com/slint-ui/slint-mcu-rust-template/archive/refs/heads/main.zip).
 | 
				
			||||||
 | 
					2. Rename the extracted directory and change into it:
 | 
				
			||||||
 | 
					    ```
 | 
				
			||||||
 | 
					    mv slint-mcu-rust-template-main my-project
 | 
				
			||||||
 | 
					    cd my-project
 | 
				
			||||||
 | 
					    ```
 | 
				
			||||||
 | 
					3. Run on the Desktop (Simulator)
 | 
				
			||||||
 | 
					    ```
 | 
				
			||||||
 | 
					    cargo run --features simulator
 | 
				
			||||||
 | 
					    ```
 | 
				
			||||||
 | 
					4. If you have a [RaspberryPi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/) with a [2.8 inch Waveshare Touch Screen](https://www.waveshare.com/pico-restouch-lcd-2.8.htm):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   a. Install the cargo extension to create UF2 images for the RP2040 USB Bootloader
 | 
				
			||||||
 | 
					      ```
 | 
				
			||||||
 | 
					      cargo install elf2uf2-rs --locked
 | 
				
			||||||
 | 
					      ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   b. Run on the device
 | 
				
			||||||
 | 
					      ```
 | 
				
			||||||
 | 
					      cargo run --target=thumbv6m-none-eabi --features=pico --release
 | 
				
			||||||
 | 
					      ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In order to port to your device, you will have to replace all the code that is specific to the RaspberryPi Pico.
 | 
				
			||||||
 | 
					See also the instructions on https://slint-ui.com/snapshots/master/docs/rust/slint/docs/mcu/index.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Next Steps
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					We hope that this template helps you get started and you enjoy exploring making user interfaces with Slint. To learn more
 | 
				
			||||||
 | 
					about the Slint APIs and the `.slint` markup language check out our [online documentation](https://slint-ui.com/docs/rust/slint/).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Don't forget to edit this readme to replace it by yours, and edit the `name =` field in `Cargo.toml` to match the name of your project.
 | 
				
			||||||
							
								
								
									
										8
									
								
								slint-based/build.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								slint-based/build.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					fn main() {
 | 
				
			||||||
 | 
					    slint_build::compile_with_config(
 | 
				
			||||||
 | 
					        "ui/app-window.slint",
 | 
				
			||||||
 | 
					        slint_build::CompilerConfiguration::new()
 | 
				
			||||||
 | 
					            .embed_resources(slint_build::EmbedResourcesKind::EmbedForSoftwareRenderer),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    .unwrap();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										2
									
								
								slint-based/rust-toolchain.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								slint-based/rust-toolchain.toml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					[toolchain]
 | 
				
			||||||
 | 
					channel = "esp"
 | 
				
			||||||
							
								
								
									
										1
									
								
								slint-based/rustfmt.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								slint-based/rustfmt.toml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					use_small_heuristics = "Max"
 | 
				
			||||||
							
								
								
									
										450
									
								
								slint-based/src/bin/starter.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										450
									
								
								slint-based/src/bin/starter.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,450 @@
 | 
				
			|||||||
 | 
					#![no_std]
 | 
				
			||||||
 | 
					#![no_main]
 | 
				
			||||||
 | 
					extern crate alloc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use alloc::boxed::Box;
 | 
				
			||||||
 | 
					use alloc::rc::Rc;
 | 
				
			||||||
 | 
					use core::mem::MaybeUninit;
 | 
				
			||||||
 | 
					use core::{cell::RefCell, cmp::min, fmt};
 | 
				
			||||||
 | 
					use display_interface_spi::SPIInterface;
 | 
				
			||||||
 | 
					use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice;
 | 
				
			||||||
 | 
					use embassy_executor::Spawner;
 | 
				
			||||||
 | 
					use embassy_sync::{
 | 
				
			||||||
 | 
					    blocking_mutex::{raw::NoopRawMutex, NoopMutex},
 | 
				
			||||||
 | 
					    signal::Signal,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					use embassy_time::Delay;
 | 
				
			||||||
 | 
					use embassy_time::{Duration, Instant, Timer};
 | 
				
			||||||
 | 
					use embedded_graphics_core::pixelcolor::Rgb565;
 | 
				
			||||||
 | 
					use embedded_graphics_core::prelude::*;
 | 
				
			||||||
 | 
					use embedded_graphics_core::primitives::Rectangle;
 | 
				
			||||||
 | 
					use embedded_graphics_profiler_display::ProfilerDisplay;
 | 
				
			||||||
 | 
					use embedded_hal::digital::OutputPin;
 | 
				
			||||||
 | 
					use embedded_hal_bus::spi::ExclusiveDevice;
 | 
				
			||||||
 | 
					use esp_backtrace as _;
 | 
				
			||||||
 | 
					use esp_hal::interrupt::Priority;
 | 
				
			||||||
 | 
					use esp_hal::{self, prelude::*};
 | 
				
			||||||
 | 
					use esp_hal::{
 | 
				
			||||||
 | 
					    clock::ClockControl,
 | 
				
			||||||
 | 
					    gpio::{GpioPin, Input, Io, Level, Output, Pull, NO_PIN},
 | 
				
			||||||
 | 
					    peripherals::{Peripherals, SPI2, SPI3},
 | 
				
			||||||
 | 
					    prelude::*,
 | 
				
			||||||
 | 
					    rtc_cntl::Rtc,
 | 
				
			||||||
 | 
					    spi::{master::Spi, FullDuplexMode, SpiMode},
 | 
				
			||||||
 | 
					    system::SystemControl,
 | 
				
			||||||
 | 
					    timer::timg::TimerGroup,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					use esp_hal_embassy::InterruptExecutor;
 | 
				
			||||||
 | 
					use esp_println::println;
 | 
				
			||||||
 | 
					use mipidsi::{
 | 
				
			||||||
 | 
					    models::ILI9486Rgb565,
 | 
				
			||||||
 | 
					    options::{ColorInversion, ColorOrder, Orientation, Rotation},
 | 
				
			||||||
 | 
					    Builder, Display,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					use panic_halt as _;
 | 
				
			||||||
 | 
					use slint::platform::software_renderer::MinimalSoftwareWindow;
 | 
				
			||||||
 | 
					use slint::platform::{Platform, PointerEventButton, WindowEvent};
 | 
				
			||||||
 | 
					use slint::private_unstable_api::re_exports::LogicalPoint;
 | 
				
			||||||
 | 
					use slint::LogicalPosition;
 | 
				
			||||||
 | 
					use static_cell::StaticCell;
 | 
				
			||||||
 | 
					use xpt2046::Xpt2046;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use esp_alloc as _;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// slint::slint!{ export MyUI := Window {} }
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					slint::include_modules!();
 | 
				
			||||||
 | 
					# */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					slint::include_modules!();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn init_heap() {
 | 
				
			||||||
 | 
					    const HEAP_SIZE: usize = 32 * 1024;
 | 
				
			||||||
 | 
					    static mut HEAP: MaybeUninit<[u8; HEAP_SIZE]> = MaybeUninit::uninit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unsafe {
 | 
				
			||||||
 | 
					        esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new(
 | 
				
			||||||
 | 
					            HEAP.as_mut_ptr() as *mut u8,
 | 
				
			||||||
 | 
					            HEAP_SIZE,
 | 
				
			||||||
 | 
					            esp_alloc::MemoryCapability::Internal.into(),
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[embassy_executor::task]
 | 
				
			||||||
 | 
					async fn touch_task(
 | 
				
			||||||
 | 
					    touch_irq: GpioPin<36>,
 | 
				
			||||||
 | 
					    spi: ExclusiveDevice<
 | 
				
			||||||
 | 
					        Spi<'static, SPI3, FullDuplexMode>,
 | 
				
			||||||
 | 
					        Output<'static, GpioPin<33>>,
 | 
				
			||||||
 | 
					        &'static mut Delay,
 | 
				
			||||||
 | 
					    >,
 | 
				
			||||||
 | 
					    touch_signal: &'static Signal<NoopRawMutex, Option<Point>>,
 | 
				
			||||||
 | 
					) -> ! {
 | 
				
			||||||
 | 
					    let mut touch_driver =
 | 
				
			||||||
 | 
					        Xpt2046::new(spi, Input::new(touch_irq, Pull::Up), xpt2046::Orientation::LandscapeFlipped);
 | 
				
			||||||
 | 
					    touch_driver.set_num_samples(16);
 | 
				
			||||||
 | 
					    touch_driver.init(&mut embassy_time::Delay).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    esp_println::println!("touch task");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    loop {
 | 
				
			||||||
 | 
					        touch_driver.run().expect("Running Touch driver failed");
 | 
				
			||||||
 | 
					        if touch_driver.is_touched() {
 | 
				
			||||||
 | 
					            let point = touch_driver.get_touch_point();
 | 
				
			||||||
 | 
					            touch_signal.signal(Some(Point::new(point.x + 25, 240 - point.y)));
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            touch_signal.signal(None);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Timer::after(Duration::from_millis(1)).await; // 100 a second
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Your touch handling logic here
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn point_to_logical_pos(point: Point) -> LogicalPosition {
 | 
				
			||||||
 | 
					    LogicalPosition::new(point.x as f32, point.y as f32)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct CYDPlatform {
 | 
				
			||||||
 | 
					    window: Rc<slint::platform::software_renderer::MinimalSoftwareWindow>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Platform for CYDPlatform {
 | 
				
			||||||
 | 
					    fn create_window_adapter(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					    ) -> Result<Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {
 | 
				
			||||||
 | 
					        Ok(self.window.clone())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn duration_since_start(&self) -> core::time::Duration {
 | 
				
			||||||
 | 
					        embassy_time::Instant::from_millis(0).elapsed().into()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //noinspection DuplicatedCode
 | 
				
			||||||
 | 
					    fn run_event_loop(&self) -> Result<(), slint::PlatformError> {
 | 
				
			||||||
 | 
					        todo!();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct AppData {
 | 
				
			||||||
 | 
					    timer_start: Instant,
 | 
				
			||||||
 | 
					    timer_set_duration: Duration,
 | 
				
			||||||
 | 
					    timer_remaining_duration: Duration,
 | 
				
			||||||
 | 
					    timer_running: bool,
 | 
				
			||||||
 | 
					    timer_paused: bool,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl AppData {
 | 
				
			||||||
 | 
					    fn new() -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            timer_start: Instant::now(),
 | 
				
			||||||
 | 
					            timer_set_duration: Duration::from_secs(10),
 | 
				
			||||||
 | 
					            timer_remaining_duration: Duration::from_secs(10),
 | 
				
			||||||
 | 
					            timer_running: false,
 | 
				
			||||||
 | 
					            timer_paused: false,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn set_timer_duration(&mut self, duration: Duration) {
 | 
				
			||||||
 | 
					        self.timer_set_duration = duration;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn add_secs(&mut self, secs: u64) {
 | 
				
			||||||
 | 
					        self.set_timer_duration(
 | 
				
			||||||
 | 
					            self.timer_set_duration
 | 
				
			||||||
 | 
					                .checked_add(Duration::from_secs(secs))
 | 
				
			||||||
 | 
					                .unwrap_or(Duration::from_secs(5999))
 | 
				
			||||||
 | 
					                .min(Duration::from_secs(5999)),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn sub_secs(&mut self, secs: u64) {
 | 
				
			||||||
 | 
					        self.set_timer_duration(
 | 
				
			||||||
 | 
					            self.timer_set_duration
 | 
				
			||||||
 | 
					                .checked_sub(Duration::from_secs(secs))
 | 
				
			||||||
 | 
					                .unwrap_or(Duration::from_secs(10))
 | 
				
			||||||
 | 
					                .max(Duration::from_secs(10)),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn start_timer(&mut self) {
 | 
				
			||||||
 | 
					        if !self.timer_paused {
 | 
				
			||||||
 | 
					            self.timer_remaining_duration = self.timer_set_duration;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.timer_start = Instant::now();
 | 
				
			||||||
 | 
					        self.timer_running = true;
 | 
				
			||||||
 | 
					        self.timer_paused = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn pause_timer(&mut self) {
 | 
				
			||||||
 | 
					        self.timer_paused = true;
 | 
				
			||||||
 | 
					        self.timer_remaining_duration = self
 | 
				
			||||||
 | 
					            .timer_remaining_duration
 | 
				
			||||||
 | 
					            .checked_sub(self.timer_start.elapsed())
 | 
				
			||||||
 | 
					            .unwrap_or(Duration::from_secs(0));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn reset_timer(&mut self) {
 | 
				
			||||||
 | 
					        self.timer_start = Instant::now();
 | 
				
			||||||
 | 
					        self.timer_paused = false;
 | 
				
			||||||
 | 
					        self.timer_running = false;
 | 
				
			||||||
 | 
					        self.timer_remaining_duration = self.timer_set_duration;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn remaining(&self) -> Duration {
 | 
				
			||||||
 | 
					        if self.timer_stopped() {
 | 
				
			||||||
 | 
					            self.timer_set_duration
 | 
				
			||||||
 | 
					        } else if self.timer_paused() {
 | 
				
			||||||
 | 
					            self.timer_remaining_duration
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            self.timer_remaining_duration
 | 
				
			||||||
 | 
					                .checked_sub(self.timer_start.elapsed())
 | 
				
			||||||
 | 
					                .unwrap_or(Duration::from_secs(0))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn timer_stopped(&self) -> bool {
 | 
				
			||||||
 | 
					        !self.timer_running
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn timer_paused(&self) -> bool {
 | 
				
			||||||
 | 
					        self.timer_running && self.timer_paused
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn timer_running(&self) -> bool {
 | 
				
			||||||
 | 
					        self.timer_running && !self.timer_paused
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn timer_finished(&self) -> bool {
 | 
				
			||||||
 | 
					        self.timer_running && self.remaining() == Duration::from_secs(0)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[main]
 | 
				
			||||||
 | 
					async fn main(spawner: Spawner) {
 | 
				
			||||||
 | 
					    init_heap();
 | 
				
			||||||
 | 
					    let peripherals = Peripherals::take();
 | 
				
			||||||
 | 
					    let system = SystemControl::new(peripherals.SYSTEM);
 | 
				
			||||||
 | 
					    let mut clocks = ClockControl::boot_defaults(system.clock_control).freeze();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut rtc = Rtc::new(peripherals.LPWR);
 | 
				
			||||||
 | 
					    rtc.rwdt.disable();
 | 
				
			||||||
 | 
					    let mut timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
 | 
				
			||||||
 | 
					    timer_group0.wdt.disable();
 | 
				
			||||||
 | 
					    let mut timer_group1 = TimerGroup::new(peripherals.TIMG1, &clocks);
 | 
				
			||||||
 | 
					    timer_group1.wdt.disable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    esp_hal_embassy::init(&clocks, timer_group0.timer0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let touch_irq = io.pins.gpio36;
 | 
				
			||||||
 | 
					    let touch_mosi = io.pins.gpio32;
 | 
				
			||||||
 | 
					    let touch_miso = io.pins.gpio39;
 | 
				
			||||||
 | 
					    let touch_clk = io.pins.gpio25;
 | 
				
			||||||
 | 
					    let touch_cs = io.pins.gpio33;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 2MHz is the MAX! DO NOT DECREASE! This is really important.
 | 
				
			||||||
 | 
					    let mut touch_spi = Spi::new(peripherals.SPI3, 2.MHz(), SpiMode::Mode0, &mut clocks).with_pins(
 | 
				
			||||||
 | 
					        Some(touch_clk),
 | 
				
			||||||
 | 
					        Some(touch_mosi),
 | 
				
			||||||
 | 
					        Some(touch_miso),
 | 
				
			||||||
 | 
					        NO_PIN,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static TOUCH_DELAY_STATICCELL: StaticCell<Delay> = StaticCell::new();
 | 
				
			||||||
 | 
					    let mut delay = TOUCH_DELAY_STATICCELL.init(Delay);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let touch_spi =
 | 
				
			||||||
 | 
					        ExclusiveDevice::new(touch_spi, Output::new(touch_cs, Level::Low), delay).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let touch_signal = Signal::new();
 | 
				
			||||||
 | 
					    static TOUCH_SIGNAL: StaticCell<Signal<NoopRawMutex, Option<Point>>> = StaticCell::new();
 | 
				
			||||||
 | 
					    let touch_signal = &*TOUCH_SIGNAL.init(touch_signal);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // let sw_int = system.software_interrupt_control.software_interrupt2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // static EXECUTOR: StaticCell<InterruptExecutor<2>> = StaticCell::new();
 | 
				
			||||||
 | 
					    // let executor = InterruptExecutor::<2>::new(sw_int);
 | 
				
			||||||
 | 
					    // let executor = EXECUTOR.init(executor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    spawner.spawn(touch_task(touch_irq, touch_spi, touch_signal)).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // executor.start(Priority::Priority1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Display setup
 | 
				
			||||||
 | 
					    let sclk = io.pins.gpio14;
 | 
				
			||||||
 | 
					    let miso = io.pins.gpio12;
 | 
				
			||||||
 | 
					    let mosi = io.pins.gpio13;
 | 
				
			||||||
 | 
					    let cs = io.pins.gpio15;
 | 
				
			||||||
 | 
					    let dc = io.pins.gpio2;
 | 
				
			||||||
 | 
					    let mut backlight = Output::new(io.pins.gpio21, Level::Low);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut spi = Spi::new(peripherals.SPI2, 10u32.MHz(), SpiMode::Mode0, &clocks).with_pins(
 | 
				
			||||||
 | 
					        Some(sclk),
 | 
				
			||||||
 | 
					        Some(mosi),
 | 
				
			||||||
 | 
					        Some(miso),
 | 
				
			||||||
 | 
					        esp_hal::gpio::NO_PIN,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // static DISP_SPI_BUS:  StaticCell<NoopMutex<RefCell<Spi<SPI2, FullDuplexMode>>>> = StaticCell::new();
 | 
				
			||||||
 | 
					    // let spi_bus = NoopMutex::new(RefCell::new(spi));
 | 
				
			||||||
 | 
					    // let spi_bus = DISP_SPI_BUS.init(spi_bus);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static spi_delay_staticcell: StaticCell<Delay> = StaticCell::new();
 | 
				
			||||||
 | 
					    let mut delay = spi_delay_staticcell.init(Delay);
 | 
				
			||||||
 | 
					    let spi = ExclusiveDevice::new(spi, Output::new(cs, Level::Low), delay).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let di = SPIInterface::new(spi, Output::new(dc, Level::Low));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let display = Builder::new(ILI9486Rgb565, di)
 | 
				
			||||||
 | 
					        .orientation(Orientation { rotation: Rotation::Deg90, mirrored: true })
 | 
				
			||||||
 | 
					        .color_order(ColorOrder::Bgr)
 | 
				
			||||||
 | 
					        .invert_colors(ColorInversion::Inverted)
 | 
				
			||||||
 | 
					        .init(&mut embassy_time::Delay)
 | 
				
			||||||
 | 
					        .unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut display = ProfilerDisplay::new(display);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    backlight.set_high();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let size = display.bounding_box().size;
 | 
				
			||||||
 | 
					    let size = slint::PhysicalSize::new(size.width as u32, size.height as u32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let window = MinimalSoftwareWindow::new(Default::default());
 | 
				
			||||||
 | 
					    slint::platform::set_platform(Box::new(CYDPlatform { window: window.clone() })).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let ui = create_slint_app();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    window.set_size(slint::PhysicalSize::new(320, 240));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut buffer_provider = DrawBuffer {
 | 
				
			||||||
 | 
					        display,
 | 
				
			||||||
 | 
					        buffer: &mut [slint::platform::software_renderer::Rgb565Pixel(0); 320],
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut last_touch = None;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    loop {
 | 
				
			||||||
 | 
					        let start_time = Instant::now();
 | 
				
			||||||
 | 
					        if let Some(touch) = touch_signal.try_take() {
 | 
				
			||||||
 | 
					            // println!("touch: {:?}, last_touch: {:?}", touch, last_touch);
 | 
				
			||||||
 | 
					            let button = PointerEventButton::Left;
 | 
				
			||||||
 | 
					            let interact = match (touch, last_touch) {
 | 
				
			||||||
 | 
					                (Some(point), Some(_)) => {
 | 
				
			||||||
 | 
					                    Some(WindowEvent::PointerMoved { position: point_to_logical_pos(point) })
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                (Some(point), None) => Some(WindowEvent::PointerPressed {
 | 
				
			||||||
 | 
					                    position: point_to_logical_pos(point),
 | 
				
			||||||
 | 
					                    button,
 | 
				
			||||||
 | 
					                }),
 | 
				
			||||||
 | 
					                (None, Some(point)) => Some(WindowEvent::PointerReleased {
 | 
				
			||||||
 | 
					                    position: point_to_logical_pos(point),
 | 
				
			||||||
 | 
					                    button,
 | 
				
			||||||
 | 
					                }),
 | 
				
			||||||
 | 
					                (None, None) => None,
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            if let Some(event) = interact {
 | 
				
			||||||
 | 
					                // println!("event: {:?}", event);
 | 
				
			||||||
 | 
					                window.dispatch_event(event);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            last_touch = touch;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        slint::platform::update_timers_and_animations();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // let window = window.clone();
 | 
				
			||||||
 | 
					        let start_draw_time = Instant::now();
 | 
				
			||||||
 | 
					        window.draw_if_needed(|renderer| {
 | 
				
			||||||
 | 
					            renderer.render_by_line(&mut buffer_provider);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let button = PointerEventButton::Left;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if window.has_active_animations() {
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let display = &mut buffer_provider.display;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let end_time = embassy_time::Instant::now();
 | 
				
			||||||
 | 
					        let draw_time = display.get_time();
 | 
				
			||||||
 | 
					        let prep_time = start_draw_time - start_time;
 | 
				
			||||||
 | 
					        let proc_time = end_time - start_draw_time;
 | 
				
			||||||
 | 
					        let proc_time = proc_time - min(draw_time, proc_time);
 | 
				
			||||||
 | 
					        rtc.rwdt.feed();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if draw_time.as_micros() > 0 {
 | 
				
			||||||
 | 
					            println!(
 | 
				
			||||||
 | 
					                "draw time: {}.{:03}ms | prep time: {}.{:03}ms | proc time: {}.{:03}ms | total time: {}.{:03}ms",
 | 
				
			||||||
 | 
					                draw_time.as_millis(),
 | 
				
			||||||
 | 
					                draw_time.as_micros() % 100,
 | 
				
			||||||
 | 
					                prep_time.as_millis(),
 | 
				
			||||||
 | 
					                prep_time.as_micros() % 100,
 | 
				
			||||||
 | 
					                proc_time.as_millis(),
 | 
				
			||||||
 | 
					                proc_time.as_micros() % 100,
 | 
				
			||||||
 | 
					                (draw_time + prep_time + proc_time).as_millis(),
 | 
				
			||||||
 | 
					                (draw_time + prep_time + proc_time).as_micros() % 100,            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        display.reset_time();
 | 
				
			||||||
 | 
					        Timer::after(Duration::from_millis(1)).await; // 60 a second
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn create_slint_app() -> AppWindow {
 | 
				
			||||||
 | 
					    let ui = AppWindow::new().unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let ui_handle = ui.as_weak();
 | 
				
			||||||
 | 
					    ui.on_request_increase_value(move || {
 | 
				
			||||||
 | 
					        let ui = ui_handle.unwrap();
 | 
				
			||||||
 | 
					        ui.set_counter(ui.get_counter() + 1);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ui
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct DrawBuffer<'a, DT> {
 | 
				
			||||||
 | 
					    display: DT,
 | 
				
			||||||
 | 
					    buffer: &'a mut [slint::platform::software_renderer::Rgb565Pixel],
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<
 | 
				
			||||||
 | 
					        // DI: display_interface_spi::WriteOnlyDataCommand,
 | 
				
			||||||
 | 
					        E: core::fmt::Debug,
 | 
				
			||||||
 | 
					        DT: DrawTarget<Color = Rgb565, Error = E>,
 | 
				
			||||||
 | 
					        // RST: OutputPin<Error = core::convert::Infallible>,
 | 
				
			||||||
 | 
					    > slint::platform::software_renderer::LineBufferProvider for &mut DrawBuffer<'_, DT>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    type TargetPixel = slint::platform::software_renderer::Rgb565Pixel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn process_line(
 | 
				
			||||||
 | 
					        &mut self,
 | 
				
			||||||
 | 
					        line: usize,
 | 
				
			||||||
 | 
					        range: core::ops::Range<usize>,
 | 
				
			||||||
 | 
					        render_fn: impl FnOnce(&mut [slint::platform::software_renderer::Rgb565Pixel]),
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        let buffer = &mut self.buffer[range.clone()];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        render_fn(buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // We send empty data just to get the device in the right window
 | 
				
			||||||
 | 
					        self.display
 | 
				
			||||||
 | 
					            .fill_contiguous(
 | 
				
			||||||
 | 
					                &Rectangle::new(
 | 
				
			||||||
 | 
					                    Point::new(range.start as i32, line as i32),
 | 
				
			||||||
 | 
					                    Size::new((range.end - range.start) as u32, 1),
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					                // range.start as u16,
 | 
				
			||||||
 | 
					                // line as _,
 | 
				
			||||||
 | 
					                // range.end as u16,
 | 
				
			||||||
 | 
					                // line as u16,
 | 
				
			||||||
 | 
					                buffer
 | 
				
			||||||
 | 
					                    .iter()
 | 
				
			||||||
 | 
					                    .map(|x| embedded_graphics_core::pixelcolor::raw::RawU16::new(x.0).into()),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            .unwrap();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										260
									
								
								slint-based/src/cyd.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										260
									
								
								slint-based/src/cyd.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,260 @@
 | 
				
			|||||||
 | 
					use alloc::boxed::Box;
 | 
				
			||||||
 | 
					use alloc::rc::Rc;
 | 
				
			||||||
 | 
					use core::cell::RefCell;
 | 
				
			||||||
 | 
					use core::mem::MaybeUninit;
 | 
				
			||||||
 | 
					use display_interface_spi::SPIInterface;
 | 
				
			||||||
 | 
					use embassy_sync::blocking_mutex::raw::NoopRawMutex;
 | 
				
			||||||
 | 
					use embassy_sync::signal::Signal;
 | 
				
			||||||
 | 
					use embassy_time::{Duration, Timer};
 | 
				
			||||||
 | 
					use embedded_graphics_core::geometry::{OriginDimensions, Point};
 | 
				
			||||||
 | 
					use embedded_graphics_profiler_display::ProfilerDisplay;
 | 
				
			||||||
 | 
					use embedded_hal::digital::OutputPin;
 | 
				
			||||||
 | 
					use embedded_hal_bus::spi::ExclusiveDevice;
 | 
				
			||||||
 | 
					use esp_hal::clock::ClockControl;
 | 
				
			||||||
 | 
					use esp_hal::delay::Delay;
 | 
				
			||||||
 | 
					pub use esp_hal::entry;
 | 
				
			||||||
 | 
					use esp_hal::gpio::{GpioPin, Input, Io, Level, Output, Pull, NO_PIN};
 | 
				
			||||||
 | 
					use esp_hal::interrupt::Priority;
 | 
				
			||||||
 | 
					use esp_hal::peripherals::{Peripherals, SPI3};
 | 
				
			||||||
 | 
					use esp_hal::prelude::*;
 | 
				
			||||||
 | 
					use esp_hal::rtc_cntl::Rtc;
 | 
				
			||||||
 | 
					use esp_hal::spi::{master::Spi, FullDuplexMode, SpiMode};
 | 
				
			||||||
 | 
					use esp_hal::system::SystemControl;
 | 
				
			||||||
 | 
					use esp_hal::timer::timg::TimerGroup;
 | 
				
			||||||
 | 
					use esp_hal_embassy::InterruptExecutor;
 | 
				
			||||||
 | 
					use mipidsi::models::ILI9486Rgb565;
 | 
				
			||||||
 | 
					use mipidsi::options::{ColorInversion, ColorOrder, Rotation};
 | 
				
			||||||
 | 
					use mipidsi::{options::Orientation, Builder, Display};
 | 
				
			||||||
 | 
					use xpt2046::Xpt2046;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[embassy_executor::task]
 | 
				
			||||||
 | 
					async fn touch_task(
 | 
				
			||||||
 | 
					    touch_irq: GpioPin<36>,
 | 
				
			||||||
 | 
					    spi: ExclusiveDevice<
 | 
				
			||||||
 | 
					        Spi<'static, SPI3, FullDuplexMode>,
 | 
				
			||||||
 | 
					        Output<'static, GpioPin<33>>,
 | 
				
			||||||
 | 
					        &'static mut Delay,
 | 
				
			||||||
 | 
					    >,
 | 
				
			||||||
 | 
					    touch_signal: &'static Signal<NoopRawMutex, Option<Point>>,
 | 
				
			||||||
 | 
					) -> ! {
 | 
				
			||||||
 | 
					    let mut touch_driver = Xpt2046::new(
 | 
				
			||||||
 | 
					        spi,
 | 
				
			||||||
 | 
					        Input::new(touch_irq, Pull::Up),
 | 
				
			||||||
 | 
					        xpt2046::Orientation::LandscapeFlipped,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    touch_driver.set_num_samples(16);
 | 
				
			||||||
 | 
					    touch_driver.init(&mut embassy_time::Delay).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    esp_println::println!("touch task");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    loop {
 | 
				
			||||||
 | 
					        touch_driver.run().expect("Running Touch driver failed");
 | 
				
			||||||
 | 
					        if touch_driver.is_touched() {
 | 
				
			||||||
 | 
					            let point = touch_driver.get_touch_point();
 | 
				
			||||||
 | 
					            touch_signal.signal(Some(Point::new(point.x + 25, 240 - point.y)));
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            touch_signal.signal(None);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Timer::after(Duration::from_millis(1)).await; // 100 a second
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Your touch handling logic here
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn init() {
 | 
				
			||||||
 | 
					    const HEAP_SIZE: usize = 250 * 1024;
 | 
				
			||||||
 | 
					    static mut HEAP: MaybeUninit<[u8; HEAP_SIZE]> = MaybeUninit::uninit();
 | 
				
			||||||
 | 
					    unsafe {
 | 
				
			||||||
 | 
					        esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new(
 | 
				
			||||||
 | 
					            HEAP.as_mut_ptr() as *mut u8,
 | 
				
			||||||
 | 
					            HEAP_SIZE,
 | 
				
			||||||
 | 
					            esp_alloc::MemoryCapability::Internal.into(),
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    slint::platform::set_platform(Box::new(EspBackend::default()))
 | 
				
			||||||
 | 
					        .expect("backend already initialized");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Default)]
 | 
				
			||||||
 | 
					struct EspBackend {
 | 
				
			||||||
 | 
					    window: RefCell<Option<Rc<slint::platform::software_renderer::MinimalSoftwareWindow>>>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl slint::platform::Platform for EspBackend {
 | 
				
			||||||
 | 
					    fn create_window_adapter(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					    ) -> Result<Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {
 | 
				
			||||||
 | 
					        let window = slint::platform::software_renderer::MinimalSoftwareWindow::new(
 | 
				
			||||||
 | 
					            slint::platform::software_renderer::RepaintBufferType::ReusedBuffer,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        self.window.replace(Some(window.clone()));
 | 
				
			||||||
 | 
					        Ok(window)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn duration_since_start(&self) -> core::time::Duration {
 | 
				
			||||||
 | 
					        embassy_time::Instant::from_millis(0).elapsed().into()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //noinspection DuplicatedCode
 | 
				
			||||||
 | 
					    fn run_event_loop(&self) -> Result<(), slint::PlatformError> {
 | 
				
			||||||
 | 
					        use display_interface_spi::SPIInterface;
 | 
				
			||||||
 | 
					        use embedded_hal_bus::spi::ExclusiveDevice;
 | 
				
			||||||
 | 
					        use esp_hal::delay::Delay;
 | 
				
			||||||
 | 
					        use esp_hal::gpio::{Io, Level, Output};
 | 
				
			||||||
 | 
					        use esp_hal::rtc_cntl::Rtc;
 | 
				
			||||||
 | 
					        use esp_hal::spi::{master::Spi, SpiMode};
 | 
				
			||||||
 | 
					        use esp_hal::timer::timg::TimerGroup;
 | 
				
			||||||
 | 
					        use esp_hal::{self, prelude::*};
 | 
				
			||||||
 | 
					        use mipidsi::{
 | 
				
			||||||
 | 
					            options::{ColorInversion, ColorOrder, Orientation, Rotation},
 | 
				
			||||||
 | 
					            Builder,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        use static_cell::StaticCell;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let peripherals = Peripherals::take();
 | 
				
			||||||
 | 
					        let system = SystemControl::new(peripherals.SYSTEM);
 | 
				
			||||||
 | 
					        let mut clocks = ClockControl::boot_defaults(system.clock_control).freeze();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut rtc = Rtc::new(peripherals.LPWR);
 | 
				
			||||||
 | 
					        rtc.rwdt.disable();
 | 
				
			||||||
 | 
					        let mut timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
 | 
				
			||||||
 | 
					        timer_group0.wdt.disable();
 | 
				
			||||||
 | 
					        let mut timer_group1 = TimerGroup::new(peripherals.TIMG1, &clocks);
 | 
				
			||||||
 | 
					        timer_group1.wdt.disable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        esp_hal_embassy::init(&clocks, timer_group0.timer0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let touch_irq = io.pins.gpio36;
 | 
				
			||||||
 | 
					        let touch_mosi = io.pins.gpio32;
 | 
				
			||||||
 | 
					        let touch_miso = io.pins.gpio39;
 | 
				
			||||||
 | 
					        let touch_clk = io.pins.gpio25;
 | 
				
			||||||
 | 
					        let touch_cs = io.pins.gpio33;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 2MHz is the MAX! DO NOT DECREASE! This is really important.
 | 
				
			||||||
 | 
					        let mut touch_spi = Spi::new(peripherals.SPI3, 2.MHz(), SpiMode::Mode0, &mut clocks)
 | 
				
			||||||
 | 
					            .with_pins(Some(touch_clk), Some(touch_mosi), Some(touch_miso), NO_PIN);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let touch_spi =
 | 
				
			||||||
 | 
					            ExclusiveDevice::new(touch_spi, Output::new(touch_cs, Level::Low), &mut Delay).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let touch_signal = Signal::new();
 | 
				
			||||||
 | 
					        static TOUCH_SIGNAL: StaticCell<Signal<NoopRawMutex, Option<Point>>> = StaticCell::new();
 | 
				
			||||||
 | 
					        let touch_signal = &*TOUCH_SIGNAL.init(touch_signal);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let sw_int = system.software_interrupt_control.software_interrupt2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static EXECUTOR: StaticCell<InterruptExecutor<2>> = StaticCell::new();
 | 
				
			||||||
 | 
					        let executor = InterruptExecutor::<2>::new(sw_int);
 | 
				
			||||||
 | 
					        let executor = EXECUTOR.init(executor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        executor.spawner().unwrap()
 | 
				
			||||||
 | 
					            .spawn(touch_task(touch_irq, touch_spi, touch_signal))
 | 
				
			||||||
 | 
					            .unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        executor.start(Priority::Priority1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Display setup
 | 
				
			||||||
 | 
					        let sclk = io.pins.gpio14;
 | 
				
			||||||
 | 
					        let miso = io.pins.gpio12;
 | 
				
			||||||
 | 
					        let mosi = io.pins.gpio13;
 | 
				
			||||||
 | 
					        let cs = io.pins.gpio15;
 | 
				
			||||||
 | 
					        let dc = io.pins.gpio2;
 | 
				
			||||||
 | 
					        let mut backlight = Output::new(io.pins.gpio21, Level::Low);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut spi = Spi::new(peripherals.SPI2, 10u32.MHz(), SpiMode::Mode0, &clocks).with_pins(
 | 
				
			||||||
 | 
					            Some(sclk),
 | 
				
			||||||
 | 
					            Some(mosi),
 | 
				
			||||||
 | 
					            Some(miso),
 | 
				
			||||||
 | 
					            esp_hal::gpio::NO_PIN,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // static DISP_SPI_BUS:  StaticCell<NoopMutex<RefCell<Spi<SPI2, FullDuplexMode>>>> = StaticCell::new();
 | 
				
			||||||
 | 
					        // let spi_bus = NoopMutex::new(RefCell::new(spi));
 | 
				
			||||||
 | 
					        // let spi_bus = DISP_SPI_BUS.init(spi_bus);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let spi = ExclusiveDevice::new(spi, Output::new(cs, Level::Low), &mut Delay).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let di = SPIInterface::new(spi, Output::new(dc, Level::Low));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let display = Builder::new(ILI9486Rgb565, di)
 | 
				
			||||||
 | 
					            .orientation(Orientation { rotation: Rotation::Deg90, mirrored: true })
 | 
				
			||||||
 | 
					            .color_order(ColorOrder::Bgr)
 | 
				
			||||||
 | 
					            .invert_colors(ColorInversion::Inverted)
 | 
				
			||||||
 | 
					            .init(&mut embassy_time::Delay)
 | 
				
			||||||
 | 
					            .unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut display = ProfilerDisplay::new(display);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        backlight.set_high().unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let size = display.size();
 | 
				
			||||||
 | 
					        let size = slint::PhysicalSize::new(size.width as u32, size.height as u32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.window.borrow().as_ref().unwrap().set_size(size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut buffer_provider = DrawBuffer {
 | 
				
			||||||
 | 
					            display,
 | 
				
			||||||
 | 
					            buffer: &mut [slint::platform::software_renderer::Rgb565Pixel(0); 320],
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        loop {
 | 
				
			||||||
 | 
					            slint::platform::update_timers_and_animations();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if let Some(window) = self.window.borrow().clone() {
 | 
				
			||||||
 | 
					                window.draw_if_needed(|renderer| {
 | 
				
			||||||
 | 
					                    renderer.render_by_line(&mut buffer_provider);
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					                if window.has_active_animations() {
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            // TODO: Implement touch handling
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn debug_log(&self, arguments: core::fmt::Arguments) {
 | 
				
			||||||
 | 
					        esp_println::println!("{}", arguments);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct DrawBuffer<'a, Display> {
 | 
				
			||||||
 | 
					    display: Display,
 | 
				
			||||||
 | 
					    buffer: &'a mut [slint::platform::software_renderer::Rgb565Pixel],
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<
 | 
				
			||||||
 | 
					        DI: display_interface_spi::WriteOnlyDataCommand,
 | 
				
			||||||
 | 
					        RST: OutputPin<Error = core::convert::Infallible>,
 | 
				
			||||||
 | 
					    > slint::platform::software_renderer::LineBufferProvider
 | 
				
			||||||
 | 
					    for &mut DrawBuffer<'_, Display<DI, mipidsi::models::ILI9342CRgb565, RST>>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    type TargetPixel = slint::platform::software_renderer::Rgb565Pixel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn process_line(
 | 
				
			||||||
 | 
					        &mut self,
 | 
				
			||||||
 | 
					        line: usize,
 | 
				
			||||||
 | 
					        range: core::ops::Range<usize>,
 | 
				
			||||||
 | 
					        render_fn: impl FnOnce(&mut [slint::platform::software_renderer::Rgb565Pixel]),
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        let buffer = &mut self.buffer[range.clone()];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        render_fn(buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // We send empty data just to get the device in the right window
 | 
				
			||||||
 | 
					        self.display
 | 
				
			||||||
 | 
					            .set_pixels(
 | 
				
			||||||
 | 
					                range.start as u16,
 | 
				
			||||||
 | 
					                line as _,
 | 
				
			||||||
 | 
					                range.end as u16,
 | 
				
			||||||
 | 
					                line as u16,
 | 
				
			||||||
 | 
					                buffer
 | 
				
			||||||
 | 
					                    .iter()
 | 
				
			||||||
 | 
					                    .map(|x| embedded_graphics_core::pixelcolor::raw::RawU16::new(x.0).into()),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            .unwrap();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										8
									
								
								slint-based/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								slint-based/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					#![no_std]
 | 
				
			||||||
 | 
					#![no_main]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern crate alloc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// mod cyd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// pub use cyd::*;
 | 
				
			||||||
							
								
								
									
										36
									
								
								slint-based/ui/app-window.slint
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								slint-based/ui/app-window.slint
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					import { Button, VerticalBox , AboutSlint } from "std-widgets.slint";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export component AppWindow inherits Window {
 | 
				
			||||||
 | 
					    width: 320px;
 | 
				
			||||||
 | 
					    height: 240px;
 | 
				
			||||||
 | 
					    in-out property <int> counter: 42;
 | 
				
			||||||
 | 
					    callback request-increase-value();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    VerticalBox {
 | 
				
			||||||
 | 
					        alignment: start;
 | 
				
			||||||
 | 
					        Text {
 | 
				
			||||||
 | 
					            text: "Hello World!";
 | 
				
			||||||
 | 
					            font-size: 24px;
 | 
				
			||||||
 | 
					            horizontal-alignment: center;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Text {
 | 
				
			||||||
 | 
					        text: "Counter App (Slint)";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    VerticalBox {
 | 
				
			||||||
 | 
					        Text {
 | 
				
			||||||
 | 
					            text: "Counter: \{root.counter}";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Button {
 | 
				
			||||||
 | 
					            text: "Increase value";
 | 
				
			||||||
 | 
					            clicked => {
 | 
				
			||||||
 | 
					                root.request-increase-value();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // AboutSlint { }
 | 
				
			||||||
 | 
					     }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user