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 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 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 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 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 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}