feat: add slint based stuff
This commit is contained in:
		
							
								
								
									
										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