capsules_extra/screen/screen_adapters/
mono_vlsb.rs1use core::cell::Cell;
6
7use kernel::ErrorCode;
8use kernel::hil::screen::{Screen, ScreenClient, ScreenPixelFormat, ScreenRotation};
9use kernel::utilities::cells::OptionalCell;
10use kernel::utilities::leasable_buffer::SubSliceMut;
11
12use super::utils::Frame;
13
14pub struct ScreenARGB8888ToMono8BitPage<'a, S: Screen<'a>> {
52 screen: &'a S,
53 draw_buffer: OptionalCell<SubSliceMut<'static, u8>>,
55 draw_buffer_capacity: usize,
58 client_buffer: OptionalCell<SubSliceMut<'static, u8>>,
61 client: OptionalCell<&'a dyn ScreenClient>,
62
63 display_frame: Cell<Frame>,
65
66 frame_cursor: Cell<usize>,
70 chunk_start: Cell<usize>,
74 chunk_end: Cell<usize>,
77
78 current_op: Cell<Option<Frame>>,
87}
88
89impl<'a, S: Screen<'a>> ScreenARGB8888ToMono8BitPage<'a, S> {
90 pub fn new(screen: &'a S, draw_buffer: &'static mut [u8]) -> Self {
91 assert!(draw_buffer.len().is_multiple_of(4));
93 let capacity = draw_buffer.len();
94 ScreenARGB8888ToMono8BitPage {
95 screen,
96 draw_buffer: OptionalCell::new(SubSliceMut::new(draw_buffer)),
97 draw_buffer_capacity: capacity,
98 client_buffer: OptionalCell::empty(),
99 client: OptionalCell::empty(),
100 display_frame: Cell::new(Frame::default()),
101 frame_cursor: Cell::new(0),
102 chunk_start: Cell::new(0),
103 chunk_end: Cell::new(0),
104 current_op: Cell::new(None),
105 }
106 }
107}
108
109fn convert_mvlsb_sub_rect(src: &[u8], dst: &mut [u8], sub_cols: usize) {
122 let row_bytes = sub_cols * 4;
124 let page_bytes = 8 * row_bytes;
126 for (src_page, dst_page) in src.chunks(sub_cols).zip(dst.chunks_mut(page_bytes)) {
128 for (bit, dst_row) in dst_page.chunks_exact_mut(row_bytes).enumerate() {
131 let src_row_pixels = src_page.iter().map(|b| (b >> bit) & 1 != 0);
133 let dst_row_pixels = dst_row.chunks_exact_mut(4);
135
136 for (src_pixel, dst_pixel) in src_row_pixels.zip(dst_row_pixels) {
137 let color = if src_pixel {
139 [0, 0xFF, 0xFF, 0xFF]
140 } else {
141 [0, 0, 0, 0xFF]
142 };
143 dst_pixel.copy_from_slice(&color);
144 }
145 }
146 }
147}
148
149fn page_rows(page: usize, frame_h: usize) -> usize {
153 core::cmp::min(8, frame_h.saturating_sub(page * 8))
154}
155
156fn sub_op_src_bytes(op: Frame) -> usize {
158 op.width * op.height.div_ceil(8)
159}
160
161fn sub_op_dst_bytes(op: Frame) -> usize {
163 op.width * op.height * 4
164}
165
166fn next_sub_op(
176 display_frame: Frame,
177 cursor: usize,
178 chunk_end: usize,
179 draw_buffer_capacity: usize,
180) -> Option<Frame> {
181 if cursor >= chunk_end {
182 return None;
183 }
184 let start_col = cursor % display_frame.width;
185 let start_page = cursor / display_frame.width;
186 let this_page_rows = page_rows(start_page, display_frame.height);
187 let remaining = chunk_end - cursor;
188
189 if start_col > 0 {
192 let cols = core::cmp::min(display_frame.width - start_col, remaining);
193 return Some(Frame {
194 x: display_frame.x + start_col,
195 y: display_frame.y + start_page * 8,
196 width: cols,
197 height: this_page_rows,
198 });
199 }
200
201 if remaining < display_frame.width {
204 return Some(Frame {
205 x: display_frame.x,
206 y: display_frame.y + start_page * 8,
207 width: remaining,
208 height: this_page_rows,
209 });
210 }
211
212 let pages_available = remaining / display_frame.width;
216 let mut pages_taken = 0;
217 let mut rows_taken = 0;
218 for i in 0..pages_available {
219 let ph = page_rows(start_page + i, display_frame.height);
220 if display_frame.width * (rows_taken + ph) * 4 > draw_buffer_capacity {
221 break;
222 }
223 pages_taken += 1;
224 rows_taken += ph;
225 }
226 debug_assert!(
227 pages_taken >= 1,
228 "draw_buffer_capacity too small to hold one full-width page",
229 );
230 Some(Frame {
231 x: display_frame.x,
232 y: display_frame.y + start_page * 8,
233 width: display_frame.width,
234 height: rows_taken,
235 })
236}
237
238impl<'a, S: Screen<'a>> ScreenARGB8888ToMono8BitPage<'a, S> {
239 fn start_next_sub_op(&self) -> Result<(), ErrorCode> {
244 let cursor = self.frame_cursor.get();
245 let chunk_end = self.chunk_end.get();
246 let op = next_sub_op(
248 self.display_frame.get(),
249 cursor,
250 chunk_end,
251 self.draw_buffer_capacity,
252 )
253 .ok_or(ErrorCode::FAIL)?;
254 let src_bytes = sub_op_src_bytes(op);
255 let dst_bytes = sub_op_dst_bytes(op);
256 let client_offset = cursor - self.chunk_start.get();
257
258 let mut draw_buffer = self.draw_buffer.take().ok_or(ErrorCode::BUSY)?;
259 let client_buffer = match self.client_buffer.take() {
260 Some(cb) => cb,
261 None => {
262 self.draw_buffer.replace(draw_buffer);
263 return Err(ErrorCode::FAIL);
264 }
265 };
266 draw_buffer.reset();
267 convert_mvlsb_sub_rect(
268 &client_buffer.as_slice()[client_offset..client_offset + src_bytes],
269 &mut draw_buffer.as_mut_slice()[..dst_bytes],
270 op.width,
271 );
272 draw_buffer.slice(..dst_bytes);
273 self.draw_buffer.replace(draw_buffer);
274 self.client_buffer.replace(client_buffer);
275
276 self.current_op.set(Some(op));
277 self.screen.set_write_frame(op.x, op.y, op.width, op.height)
278 }
279
280 fn write_current_sub_op(&self) -> Result<(), ErrorCode> {
284 let draw_buffer = self.draw_buffer.take().ok_or(ErrorCode::FAIL)?;
285 self.screen.write(draw_buffer, false)
286 }
287
288 fn finish_chunk(&self, result: Result<(), ErrorCode>) {
291 self.current_op.set(None);
292 if let Some(cb) = self.client_buffer.take() {
293 self.client.map(|c| c.write_complete(cb, result));
294 }
295 }
296}
297
298impl<'a, S: Screen<'a>> Screen<'a> for ScreenARGB8888ToMono8BitPage<'a, S> {
299 fn set_client(&self, client: &'a dyn ScreenClient) {
300 self.client.replace(client);
301 }
302
303 fn get_resolution(&self) -> (usize, usize) {
304 self.screen.get_resolution()
305 }
306
307 fn get_pixel_format(&self) -> ScreenPixelFormat {
308 ScreenPixelFormat::Mono_8BitPage
309 }
310
311 fn get_rotation(&self) -> ScreenRotation {
312 self.screen.get_rotation()
313 }
314
315 fn set_write_frame(
316 &self,
317 x: usize,
318 y: usize,
319 width: usize,
320 height: usize,
321 ) -> Result<(), ErrorCode> {
322 if self.current_op.get().is_some() {
323 return Err(ErrorCode::BUSY);
324 }
325 self.display_frame.set(Frame {
326 x,
327 y,
328 width,
329 height,
330 });
331 self.frame_cursor.set(0);
332
333 self.screen.set_write_frame(x, y, width, height)
334 }
335
336 fn write(
337 &self,
338 buffer: SubSliceMut<'static, u8>,
339 continue_write: bool,
340 ) -> Result<(), ErrorCode> {
341 if self.current_op.get().is_some() {
342 return Err(ErrorCode::BUSY);
343 }
344 let frame = self.display_frame.get();
345 if frame.width == 0 || frame.height == 0 {
346 return Err(ErrorCode::INVAL);
347 }
348
349 if !continue_write {
350 self.frame_cursor.set(0);
351 }
352
353 let cursor = self.frame_cursor.get();
354 let total_frame_bytes = frame.width * frame.height.div_ceil(8);
355 if cursor >= total_frame_bytes {
356 return Err(ErrorCode::SIZE);
357 }
358 let chunk_len = core::cmp::min(buffer.len(), total_frame_bytes - cursor);
359 if chunk_len == 0 {
360 return Err(ErrorCode::SIZE);
361 }
362
363 let mut buffer = buffer;
366 buffer.slice(..chunk_len);
367
368 self.chunk_start.set(cursor);
369 self.chunk_end.set(cursor + chunk_len);
370 assert!(self.client_buffer.replace(buffer).is_none());
371
372 if let Err(e) = self.start_next_sub_op() {
373 self.finish_chunk(Err(e));
374 return Err(e);
375 }
376 Ok(())
377 }
378
379 fn set_brightness(&self, brightness: u16) -> Result<(), ErrorCode> {
380 self.screen.set_brightness(brightness)
381 }
382
383 fn set_power(&self, enabled: bool) -> Result<(), ErrorCode> {
384 self.screen.set_power(enabled)
385 }
386
387 fn set_invert(&self, enabled: bool) -> Result<(), ErrorCode> {
388 self.screen.set_invert(enabled)
389 }
390}
391
392impl<'a, S: Screen<'a>> ScreenClient for ScreenARGB8888ToMono8BitPage<'a, S> {
393 fn screen_is_ready(&self) {
394 self.client.map(|c| c.screen_is_ready());
395 }
396
397 fn command_complete(&self, result: Result<(), ErrorCode>) {
398 if self.current_op.get().is_none() {
399 self.client.map(|c| c.command_complete(result));
400 } else {
401 if result.is_err() {
402 self.finish_chunk(result);
403 return;
404 }
405 if let Err(e) = self.write_current_sub_op() {
406 self.finish_chunk(Err(e));
407 }
408 }
409 }
410
411 fn write_complete(&self, buffer: SubSliceMut<'static, u8>, result: Result<(), ErrorCode>) {
412 self.draw_buffer.replace(buffer);
413
414 if result.is_err() {
415 self.finish_chunk(result);
416 return;
417 }
418
419 let Some(op) = self.current_op.get() else {
421 return;
423 };
424 self.frame_cursor
425 .set(self.frame_cursor.get() + sub_op_src_bytes(op));
426 self.current_op.set(None);
427
428 if self.frame_cursor.get() < self.chunk_end.get() {
431 if let Err(e) = self.start_next_sub_op() {
432 self.finish_chunk(Err(e));
433 }
434 } else {
435 self.finish_chunk(Ok(()));
436 }
437 }
438}