mirror of
https://github.com/apache/nuttx-apps.git
synced 2026-08-08 05:57:19 +00:00
Changed the NUTTX dependency branch to 'main' for consistency with repository updates. Updated pixel format check to use FB_FMT_RGB16_565 for better clarity and accuracy. Signed-off-by: Huang Qi <huangqi3@xiaomi.com>
171 lines
5.5 KiB
Rust
171 lines
5.5 KiB
Rust
// ##############################################################################
|
|
// 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::rc::Rc;
|
|
use std::{cell::RefCell, ffi::CStr};
|
|
|
|
use slint::platform::software_renderer::{LineBufferProvider, Rgb565Pixel};
|
|
|
|
use nuttx::input::touchscreen::*;
|
|
use nuttx::video::fb::*;
|
|
use slint::platform::WindowEvent;
|
|
|
|
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 {
|
|
AppWindow::new().expect("Failed to load UI")
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
struct NuttXRenderer {
|
|
frame_buffer: *mut u8,
|
|
line_buffer: Rc<RefCell<Vec<Rgb565Pixel>>>,
|
|
stride: usize,
|
|
lines: usize,
|
|
}
|
|
|
|
impl LineBufferProvider for NuttXRenderer {
|
|
type TargetPixel = Rgb565Pixel;
|
|
fn process_line(
|
|
&mut self,
|
|
line: usize,
|
|
range: std::ops::Range<usize>,
|
|
render_fn: impl FnOnce(&mut [Self::TargetPixel]),
|
|
) {
|
|
let fb_size = self.stride * self.lines;
|
|
let frame = unsafe {
|
|
std::slice::from_raw_parts_mut(self.frame_buffer as *mut Rgb565Pixel, fb_size)
|
|
};
|
|
let mut buffer = self.line_buffer.borrow_mut();
|
|
render_fn(&mut buffer[range.clone()]);
|
|
let offset = line * self.stride;
|
|
frame[offset..offset + range.end - range.start].copy_from_slice(&buffer[range]);
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn slint_main() {
|
|
// Open the framebuffer device and get its information
|
|
let fbdev = match FrameBuffer::new(CStr::from_bytes_with_nul(b"/dev/fb0\0").unwrap()) {
|
|
Ok(fb) => fb,
|
|
Err(_) => {
|
|
println!("Failed to open framebuffer device");
|
|
return;
|
|
}
|
|
};
|
|
|
|
let planeinfo = fbdev.get_plane_info().unwrap();
|
|
let videoinfo = fbdev.get_video_info().unwrap();
|
|
|
|
println!("{:?}", planeinfo);
|
|
println!("{:?}", videoinfo);
|
|
|
|
if videoinfo.fmt != FB_FMT_RGB16_565 as u8 {
|
|
println!("Unsupported pixel format, only RGB565 is supported for now");
|
|
return;
|
|
}
|
|
|
|
// Open the touchscreen device
|
|
let mut tsdev = match TouchScreen::open(CStr::from_bytes_with_nul(b"/dev/input0\0").unwrap()) {
|
|
Ok(ts) => ts,
|
|
Err(_) => {
|
|
println!("Failed to open touchscreen device");
|
|
return;
|
|
}
|
|
};
|
|
|
|
// Setup the Slint backend
|
|
let window = slint::platform::software_renderer::MinimalSoftwareWindow::new(Default::default());
|
|
window.set_size(slint::PhysicalSize::new(
|
|
videoinfo.xres.into(),
|
|
videoinfo.yres.into(),
|
|
));
|
|
|
|
// Set the platform
|
|
slint::platform::set_platform(Box::new(NuttXPlatform {
|
|
window: window.clone(),
|
|
}))
|
|
.unwrap();
|
|
|
|
// Configure the UI
|
|
let _ui = create_slint_app();
|
|
|
|
// Create the renderer for NuttX
|
|
let nxrender = NuttXRenderer {
|
|
frame_buffer: planeinfo.fbmem as *mut u8,
|
|
line_buffer: Rc::new(RefCell::new(vec![
|
|
Rgb565Pixel::default();
|
|
videoinfo.xres as usize
|
|
])),
|
|
stride: videoinfo.xres.into(),
|
|
lines: videoinfo.yres.into(),
|
|
};
|
|
|
|
let button = slint::platform::PointerEventButton::Left;
|
|
let mut last_touch_down = false;
|
|
let mut last_position = Default::default();
|
|
|
|
loop {
|
|
slint::platform::update_timers_and_animations();
|
|
window.draw_if_needed(|renderer| {
|
|
renderer.render_by_line(nxrender.clone());
|
|
});
|
|
|
|
if let Ok(sample) = tsdev.read_sample() {
|
|
if sample.npoints > 0 {
|
|
let point = sample.point[0];
|
|
if point.is_pos_valid() {
|
|
let position = slint::PhysicalPosition::new(point.x.into(), point.y.into())
|
|
.to_logical(window.scale_factor());
|
|
last_position = position;
|
|
if point.is_touch_down() || point.is_touch_move() {
|
|
last_touch_down = true;
|
|
window.dispatch_event(WindowEvent::PointerPressed { position, button });
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if last_touch_down {
|
|
window.dispatch_event(WindowEvent::PointerReleased {
|
|
position: last_position,
|
|
button,
|
|
});
|
|
last_touch_down = false;
|
|
}
|
|
}
|
|
}
|
|
}
|