feat: add lvgl based impl
This commit is contained in:
parent
6446310023
commit
a33cb94a35
@ -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 (*)
|
Loading…
Reference in New Issue
Block a user