Skip to content

Commit

Permalink
examples/rust: Add basic Slint example
Browse files Browse the repository at this point in the history
Summary:
- Added a basic Slint example to demonstrate Rust integration with NuttX
- Includes a simple UI with a timer and text display
- Implements a software renderer for Slint targeting the STM32F746G-DISCO board
- Adds touch input handling via FFI to NuttX touchscreen driver

Impact:
- Provides a reference implementation for Rust GUI development on NuttX
- Demonstrates how to integrate Slint's software renderer with NuttX's framebuffer
- Shows FFI usage for hardware interaction (touchscreen)
- Enables future GUI application development using Rust and Slint on NuttX

Signed-off-by: Huang Qi <[email protected]>
  • Loading branch information
no1wudi committed Jan 22, 2025
1 parent dca032a commit 0609f04
Show file tree
Hide file tree
Showing 10 changed files with 448 additions and 0 deletions.
1 change: 1 addition & 0 deletions examples/rust/slint/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
target
31 changes: 31 additions & 0 deletions examples/rust/slint/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# ##############################################################################
# apps/examples/rust/slint/CMakeLists.txt
#
# Licensed to the Apache Software Foundation (ASF) under one or more contributor
# license agreements. See the NOTICE file distributed with this work for
# additional information regarding copyright ownership. The ASF licenses this
# file to you under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
#
# ##############################################################################

if(CONFIG_EXAMPLES_RUST_SLINT)

# Build the Rust crate using nuttx_add_rust
nuttx_add_rust(CRATE_NAME slint CRATE_PATH ${CMAKE_CURRENT_SOURCE_DIR})

nuttx_add_application(
NAME ${CONFIG_EXAMPLES_RUST_SLINT_PROGNAME} STACKSIZE
${CONFIG_EXAMPLES_RUST_SLINT_STACKSIZE} PRIORITY
${CONFIG_EXAMPLES_RUST_SLINT_PRIORITY})

endif() # CONFIG_EXAMPLES_RUST_SLINT
23 changes: 23 additions & 0 deletions examples/rust/slint/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[package]
name = "slint"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["staticlib"]

[profile.dev]
panic = "abort"

[profile.release]
panic = "abort"
lto = true
codegen-units = 1
opt-level = 'z'

[dependencies]
libc = "0.2"
slint = { version = "1.9", default-features = false, features = ["compat-1-2", "renderer-software", "libm", "unsafe-single-threaded"] }

[build-dependencies]
slint-build = { version = "1.9" }
29 changes: 29 additions & 0 deletions examples/rust/slint/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#
# For a description of the syntax of this configuration file,
# see the file kconfig-language.txt in the NuttX tools repository.
#

config EXAMPLES_RUST_SLINT
tristate "Slint Basic Example"
default n
---help---
Enable the basic Slint example.

if EXAMPLES_RUST_SLINT

config EXAMPLES_RUST_SLINT_PROGNAME
string "Program name"
default "slint"
---help---
This is the name of the program that will be used when the
program is installed.

config EXAMPLES_RUST_SLINT_PRIORITY
int "Task priority"
default 100

config EXAMPLES_RUST_SLINT_STACKSIZE
int "Stack size"
default DEFAULT_TASK_STACKSIZE

endif
26 changes: 26 additions & 0 deletions examples/rust/slint/Make.defs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
############################################################################
# apps/examples/rust/slint/Make.defs
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
############################################################################

include $(APPDIR)/tools/Rust.mk

ifneq ($(CONFIG_EXAMPLES_RUST_SLINT),)
CONFIGURED_APPS += $(APPDIR)/examples/rust/slint
EXTRA_LIBS += $(call RUST_GET_BINDIR,slint,$(APPDIR)/examples/rust)
endif
34 changes: 34 additions & 0 deletions examples/rust/slint/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
############################################################################
# apps/examples/rust/slint/Makefile
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
############################################################################

include $(APPDIR)/Make.defs

PROGNAME = $(CONFIG_EXAMPLES_RUST_SLINT_PROGNAME)
PRIORITY = $(CONFIG_EXAMPLES_RUST_SLINT_PRIORITY)
STACKSIZE = $(CONFIG_EXAMPLES_RUST_SLINT_STACKSIZE)
MODULE = $(CONFIG_EXAMPLES_RUST_SLINT)

context::
$(call RUST_CARGO_BUILD,slint,$(APPDIR)/examples/rust)

clean::
$(call RUST_CARGO_CLEAN,slint,$(APPDIR)/examples/rust)

include $(APPDIR)/Application.mk
28 changes: 28 additions & 0 deletions examples/rust/slint/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// ##############################################################################
// examples/rust/slint/build.rs
//
// Licensed to the Apache Software Foundation (ASF) under one or more contributor
// license agreements. See the NOTICE file distributed with this work for
// additional information regarding copyright ownership. The ASF licenses this
// file to you under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
//
// ##############################################################################

fn main() {
slint_build::compile_with_config(
"ui/app.slint",
slint_build::CompilerConfiguration::new()
.embed_resources(slint_build::EmbedResourcesKind::EmbedForSoftwareRenderer),
)
.unwrap();
}
100 changes: 100 additions & 0 deletions examples/rust/slint/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// ##############################################################################
// examples/rust/slint/src/lib.rs
//
// Licensed to the Apache Software Foundation (ASF) under one or more contributor
// license agreements. See the NOTICE file distributed with this work for
// additional information regarding copyright ownership. The ASF licenses this
// file to you under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
//
// ##############################################################################

use std::boxed::Box;
use std::rc::Rc;

use slint::platform::software_renderer::{LineBufferProvider, Rgb565Pixel};

slint::include_modules!();

struct NuttXPlatform {
window: Rc<slint::platform::software_renderer::MinimalSoftwareWindow>,
}

impl slint::platform::Platform for NuttXPlatform {
fn create_window_adapter(
&self,
) -> Result<Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {
Ok(self.window.clone())
}
fn duration_since_start(&self) -> std::time::Duration {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
}
}

fn create_slint_app() -> AppWindow {
let ui = AppWindow::new().expect("Failed to load UI");

ui
}

#[no_mangle]
pub extern "C" fn slint_main() {
// -------- Setup the Slint backend --------
let window = slint::platform::software_renderer::MinimalSoftwareWindow::new(Default::default());
window.set_size(slint::PhysicalSize::new(480, 272));

slint::platform::set_platform(Box::new(NuttXPlatform {
window: window.clone(),
}))
.unwrap();

// -------- Configure the UI --------
// (need to be done after the call to slint::platform::set_platform)
let _ui = create_slint_app();

// Map framebuffer memory, this is a hardcoded address for the stm32f746g-disco, need to be
// refactored to use a generic way to get the framebuffer address
let fb_ptr = 0xc0000000 as *mut Rgb565Pixel;
let fb_size = (480 * 272) as usize;
let framebuffer = unsafe { std::slice::from_raw_parts_mut(fb_ptr, fb_size) };

loop {
slint::platform::update_timers_and_animations();
window.draw_if_needed(|renderer| {
struct FrameBuffer<'a> {
frame_buffer: &'a mut [Rgb565Pixel],
stride: usize,
}
impl<'a> LineBufferProvider for FrameBuffer<'a> {
type TargetPixel = Rgb565Pixel;
fn process_line(
&mut self,
line: usize,
range: std::ops::Range<usize>,
render_fn: impl FnOnce(&mut [Self::TargetPixel]),
) {
let mut line_buffer = [Rgb565Pixel(0); 480];
render_fn(&mut line_buffer);
let offset = line * self.stride;
self.frame_buffer[offset..offset + range.end - range.start]
.copy_from_slice(&line_buffer[range]);
}
}
renderer.render_by_line(FrameBuffer {
frame_buffer: framebuffer,
stride: 480,
});
});
}
}
Loading

0 comments on commit 0609f04

Please sign in to comment.