graphics/
display.rs

1use alloc::boxed::Box;
2use file_system::{ControlCommand, DirectCharacterDevice};
3use shared::AnyByLayout;
4
5use core::{ffi::c_void, ptr::null_mut, slice};
6
7use crate::{
8    Area, GET_RESOLUTION, Point, RenderingColor, Result, SET_DRAWING_AREA, WAS_RESIZED,
9    draw_buffer::Buffer,
10};
11
12use super::lvgl;
13
14struct UserData {
15    device: &'static dyn DirectCharacterDevice,
16}
17
18pub struct Display {
19    display: *mut lvgl::lv_display_t,
20    _buffer_1: Buffer,
21    _buffer_2: Option<Buffer>,
22}
23
24unsafe impl Send for Display {}
25
26unsafe impl Sync for Display {}
27
28unsafe extern "C" fn binding_callback_function(
29    display: *mut lvgl::lv_disp_t,
30    area: *const lvgl::lv_area_t,
31    data: *mut u8,
32) {
33    let mut area: Area = unsafe { *area }.into();
34
35    let buffer_size: usize =
36        (area.get_width()) as usize * (area.get_height()) as usize * size_of::<RenderingColor>();
37
38    let buffer = unsafe { slice::from_raw_parts(data as *const u8, buffer_size) };
39
40    let user_data = unsafe { &mut *(lvgl::lv_display_get_user_data(display) as *mut UserData) };
41
42    let device = &user_data.device;
43
44    device
45        .control(
46            SET_DRAWING_AREA::IDENTIFIER,
47            AnyByLayout::from_mutable(&mut area),
48            AnyByLayout::NONE,
49        )
50        .expect("Error setting drawing area");
51
52    device.write(buffer, 0).expect("Error writing to display");
53
54    unsafe { lvgl::lv_display_flush_ready(display) };
55}
56
57impl Drop for Display {
58    fn drop(&mut self) {
59        unsafe {
60            lvgl::lv_display_delete(self.display);
61        }
62    }
63}
64
65impl Display {
66    pub fn new(
67        device: &'static dyn DirectCharacterDevice,
68        buffer_size: usize,
69        double_buffered: bool,
70    ) -> Result<Self> {
71        // Get the resolution from the device.
72        let mut resolution = Point::new(0, 0);
73        device
74            .control(
75                GET_RESOLUTION::IDENTIFIER,
76                AnyByLayout::NONE,
77                AnyByLayout::from_mutable(&mut resolution),
78            )
79            .expect("Error getting resolution");
80
81        // Create the display.
82        let lvgl_display: *mut lvgl_rust_sys::_lv_display_t = unsafe {
83            lvgl::lv_display_create(resolution.get_x() as i32, resolution.get_y() as i32)
84        };
85
86        // Set the buffer(s) and the render mode.
87        let buffer_1 = Buffer::new(buffer_size);
88
89        let buffer_2 = if double_buffered {
90            Some(Buffer::new(buffer_size))
91        } else {
92            None
93        };
94
95        unsafe {
96            lvgl::lv_display_set_buffers(
97                lvgl_display,
98                buffer_1.as_ref().as_ptr() as *mut c_void,
99                buffer_2
100                    .as_ref()
101                    .map_or(null_mut(), |buffer| buffer.as_ref().as_ptr() as *mut c_void),
102                buffer_size as u32,
103                lvgl::lv_display_render_mode_t_LV_DISPLAY_RENDER_MODE_PARTIAL,
104            )
105        }
106
107        // Set the user data.
108        let user_data = Box::new(UserData { device });
109
110        unsafe {
111            lvgl::lv_display_set_user_data(lvgl_display, Box::into_raw(user_data) as *mut c_void)
112        };
113
114        // Set the flush callback.
115        unsafe { lvgl::lv_display_set_flush_cb(lvgl_display, Some(binding_callback_function)) }
116
117        Ok(Self {
118            display: lvgl_display,
119            _buffer_1: buffer_1,
120            _buffer_2: buffer_2,
121        })
122    }
123
124    pub fn check_for_resizing(&self) {
125        let user_data =
126            unsafe { &mut *(lvgl::lv_display_get_user_data(self.display) as *mut UserData) };
127
128        let mut was_resize = false;
129
130        user_data
131            .device
132            .control(
133                WAS_RESIZED::IDENTIFIER,
134                AnyByLayout::NONE,
135                AnyByLayout::from_mutable(&mut was_resize),
136            )
137            .expect("Error checking if display was resized");
138
139        if !was_resize {
140            return;
141        }
142
143        let mut resolution = Point::new(0, 0);
144
145        user_data
146            .device
147            .control(
148                GET_RESOLUTION::IDENTIFIER,
149                AnyByLayout::NONE,
150                AnyByLayout::from_mutable(&mut resolution),
151            )
152            .expect("Error getting resolution");
153
154        unsafe {
155            lvgl::lv_display_set_resolution(
156                self.display,
157                resolution.get_x() as i32,
158                resolution.get_y() as i32,
159            );
160        }
161    }
162
163    pub fn get_lvgl_display(&self) -> *mut lvgl::lv_display_t {
164        self.display
165    }
166
167    pub fn get_object(&self) -> *mut lvgl::lv_obj_t {
168        unsafe { lvgl::lv_display_get_screen_active(self.display) }
169    }
170}