capsules_extra/virtualizers/screen/
virtual_screen_split.rs1use core::cell::Cell;
12use kernel::collections::list::{List, ListLink, ListNode};
13use kernel::deferred_call::{DeferredCall, DeferredCallClient};
14use kernel::hil;
15use kernel::utilities::cells::OptionalCell;
16use kernel::utilities::leasable_buffer::SubSliceMut;
17use kernel::ErrorCode;
18
19enum ScreenSplitOperation {
21 WriteSetFrame,
23 WriteBuffer(SubSliceMut<'static, u8>, bool),
26}
27
28#[derive(Default, Clone, Copy, PartialEq)]
30pub struct Frame {
31 x: usize,
33 y: usize,
35 width: usize,
37 height: usize,
39}
40
41enum ScreenSplitState {
43 SetFrame,
46 WriteSetFrame(SubSliceMut<'static, u8>, bool),
48 WriteBuffer,
51}
52
53pub struct ScreenSplitUser<'a, S: hil::screen::Screen<'a>> {
56 mux: &'a ScreenSplitMux<'a, S>,
58 frame: Frame,
60 write_frame: Cell<Frame>,
63 pending: OptionalCell<ScreenSplitOperation>,
67 client: OptionalCell<&'a dyn hil::screen::ScreenClient>,
69 next: ListLink<'a, ScreenSplitUser<'a, S>>,
71}
72
73impl<'a, S: hil::screen::Screen<'a>> ScreenSplitUser<'a, S> {
74 pub fn new(
75 mux: &'a ScreenSplitMux<'a, S>,
76 x: usize,
77 y: usize,
78 width: usize,
79 height: usize,
80 ) -> Self {
81 let frame = Frame {
82 x,
83 y,
84 width,
85 height,
86 };
87
88 Self {
90 mux,
91 frame,
92 write_frame: Cell::new(Frame {
93 x: 0,
94 y: 0,
95 width,
96 height,
97 }),
98 pending: OptionalCell::empty(),
99 client: OptionalCell::empty(),
100 next: ListLink::empty(),
101 }
102 }
103
104 pub fn add_to_mux(&'a self) {
105 self.mux.splits.push_head(self);
106 }
107}
108
109impl<'a, S: hil::screen::Screen<'a>> ListNode<'a, ScreenSplitUser<'a, S>>
110 for ScreenSplitUser<'a, S>
111{
112 fn next(&'a self) -> &'a ListLink<'a, ScreenSplitUser<'a, S>> {
113 &self.next
114 }
115}
116
117impl<'a, S: hil::screen::Screen<'a>> hil::screen::Screen<'a> for ScreenSplitUser<'a, S> {
118 fn set_client(&self, client: &'a dyn hil::screen::ScreenClient) {
119 self.client.set(client);
120 }
121
122 fn get_resolution(&self) -> (usize, usize) {
123 (self.frame.width, self.frame.height)
124 }
125
126 fn get_pixel_format(&self) -> hil::screen::ScreenPixelFormat {
127 self.mux.screen.get_pixel_format()
128 }
129
130 fn get_rotation(&self) -> hil::screen::ScreenRotation {
131 self.mux.screen.get_rotation()
132 }
133
134 fn set_write_frame(
135 &self,
136 x: usize,
137 y: usize,
138 width: usize,
139 height: usize,
140 ) -> Result<(), ErrorCode> {
141 if self.pending.is_some() {
142 Err(ErrorCode::BUSY)
143 } else {
144 let frame = Frame {
145 x,
146 y,
147 width,
148 height,
149 };
150
151 self.write_frame.set(frame);
152
153 self.pending.set(ScreenSplitOperation::WriteSetFrame);
156 self.mux.request_operation()
157 }
158 }
159
160 fn write(
161 &self,
162 buffer: SubSliceMut<'static, u8>,
163 continue_write: bool,
164 ) -> Result<(), ErrorCode> {
165 if self.pending.is_some() {
166 Err(ErrorCode::BUSY)
167 } else {
168 self.pending
171 .set(ScreenSplitOperation::WriteBuffer(buffer, continue_write));
172 self.mux.request_operation()
173 }
174 }
175
176 fn set_brightness(&self, _brightness: u16) -> Result<(), ErrorCode> {
177 Err(ErrorCode::NOSUPPORT)
178 }
179
180 fn set_power(&self, _enabled: bool) -> Result<(), ErrorCode> {
181 Err(ErrorCode::NOSUPPORT)
182 }
183
184 fn set_invert(&self, _enabled: bool) -> Result<(), ErrorCode> {
185 Err(ErrorCode::NOSUPPORT)
186 }
187}
188
189impl<'a, S: hil::screen::Screen<'a>> hil::screen::ScreenClient for ScreenSplitUser<'a, S> {
190 fn command_complete(&self, r: Result<(), ErrorCode>) {
191 self.pending.take();
192
193 self.client.map(|client| {
194 client.command_complete(r);
195 });
196 }
197
198 fn write_complete(&self, data: SubSliceMut<'static, u8>, r: Result<(), ErrorCode>) {
199 self.pending.take();
200
201 self.client.map(|client| {
202 client.write_complete(data, r);
203 });
204 }
205
206 fn screen_is_ready(&self) {
207 self.client.map(|client| {
208 client.screen_is_ready();
209 });
210 }
211}
212
213pub struct ScreenSplitMux<'a, S: hil::screen::Screen<'a>> {
218 screen: &'a S,
220
221 splits: List<'a, ScreenSplitUser<'a, S>>,
223
224 current_user: OptionalCell<(&'a ScreenSplitUser<'a, S>, ScreenSplitState)>,
226
227 deferred_call: DeferredCall,
229}
230
231impl<'a, S: hil::screen::Screen<'a>> ScreenSplitMux<'a, S> {
232 pub fn new(screen: &'a S) -> Self {
233 Self {
234 screen,
235 splits: List::new(),
236 current_user: OptionalCell::empty(),
237 deferred_call: DeferredCall::new(),
238 }
239 }
240
241 fn request_operation(&self) -> Result<(), ErrorCode> {
242 if self.current_user.is_some() {
245 return Ok(());
246 }
247
248 if let Some(split) = self.splits.iter().find(|split| split.pending.is_some()) {
250 if let Some(operation) = split.pending.take() {
252 self.call_screen(split, operation)
253 } else {
254 Err(ErrorCode::NOMEM)
255 }
256 } else {
257 Err(ErrorCode::NOMEM)
258 }
259 }
260
261 fn call_screen(
262 &self,
263 split: &'a ScreenSplitUser<'a, S>,
264 operation: ScreenSplitOperation,
265 ) -> Result<(), ErrorCode> {
266 match operation {
267 ScreenSplitOperation::WriteSetFrame => {
268 self.current_user.set((split, ScreenSplitState::SetFrame));
271 self.deferred_call.set();
272 Ok(())
273 }
274 ScreenSplitOperation::WriteBuffer(subslice, continue_write) => {
275 let absolute_frame =
277 self.calculate_absolute_frame(split.frame, split.write_frame.get());
278
279 self.screen
280 .set_write_frame(
281 absolute_frame.x,
282 absolute_frame.y,
283 absolute_frame.width,
284 absolute_frame.height,
285 )
286 .inspect(|()| {
287 self.current_user.set((
288 split,
289 ScreenSplitState::WriteSetFrame(subslice, continue_write),
290 ))
291 })
292 }
293 }
294 }
295
296 fn calculate_absolute_frame(&self, split_frame: Frame, active_frame: Frame) -> Frame {
300 let mut absolute_x = split_frame.x + active_frame.x;
302 let mut absolute_y = split_frame.y + active_frame.y;
303 let mut absolute_w = active_frame.width;
305 let mut absolute_h = active_frame.height;
306
307 absolute_x = core::cmp::min(split_frame.x + split_frame.width, absolute_x);
309 absolute_y = core::cmp::min(split_frame.y + split_frame.height, absolute_y);
310 absolute_w = core::cmp::min(split_frame.x + split_frame.width - absolute_x, absolute_w);
311 absolute_h = core::cmp::min(split_frame.y + split_frame.height - absolute_y, absolute_h);
312
313 Frame {
314 x: absolute_x,
315 y: absolute_y,
316 width: absolute_w,
317 height: absolute_h,
318 }
319 }
320}
321
322impl<'a, S: hil::screen::Screen<'a>> hil::screen::ScreenClient for ScreenSplitMux<'a, S> {
323 fn command_complete(&self, _r: Result<(), ErrorCode>) {
324 if let Some((current_user, ScreenSplitState::WriteSetFrame(subslice, continue_write))) =
325 self.current_user.take()
326 {
327 let _ = self.screen.write(subslice, continue_write).inspect(|()| {
328 self.current_user
329 .set((current_user, ScreenSplitState::WriteBuffer))
330 });
331 } else {
332 }
334 }
335
336 fn write_complete(&self, data: SubSliceMut<'static, u8>, r: Result<(), ErrorCode>) {
337 if let Some((current_user, _state)) = self.current_user.take() {
338 current_user.write_complete(data, r);
339 }
340
341 let _ = self.request_operation();
343 }
344
345 fn screen_is_ready(&self) {
346 self.splits.iter().for_each(|split| {
348 split.screen_is_ready();
349 })
350 }
351}
352
353impl<'a, S: hil::screen::Screen<'a>> DeferredCallClient for ScreenSplitMux<'a, S> {
354 fn handle_deferred_call(&self) {
355 if let Some((current_user, _state)) = self.current_user.take() {
357 hil::screen::ScreenClient::command_complete(current_user, Ok(()));
358 }
359 }
360
361 fn register(&'static self) {
362 self.deferred_call.register(self);
363 }
364}