1use core::cell::Cell;
23use kernel::hil;
24use kernel::utilities::cells::MapCell;
25use kernel::utilities::leasable_buffer::SubSliceMut;
26use kernel::ErrorCode;
27
28const LEFT_RIGTH_PADDING: usize = 2;
30const TOP_BOTTOM_PADDING: usize = 2;
32const TEXT_LEDS_PADDING: usize = 2;
34const TEXT_SPACING: usize = 2;
36const TEXT_TOP_BOTTOM_PADDING: usize = 4;
38
39pub trait LedIndexed {
44 fn init(&self, index: usize);
45 fn on(&self, index: usize);
46 fn off(&self, index: usize);
47 fn toggle(&self, index: usize);
48 fn read(&self, index: usize) -> bool;
49}
50
51pub struct ScreenOnLedSingle<'a, L: LedIndexed> {
56 led_controller: &'a L,
58 index: usize,
60}
61
62impl<'a, L: LedIndexed> ScreenOnLedSingle<'a, L> {
63 pub fn new(led_controller: &'a L, index: usize) -> Self {
64 Self {
65 led_controller,
66 index,
67 }
68 }
69}
70
71impl<L: LedIndexed> hil::led::Led for ScreenOnLedSingle<'_, L> {
72 fn init(&self) {
73 self.led_controller.init(self.index);
74 }
75
76 fn on(&self) {
77 self.led_controller.on(self.index);
78 }
79
80 fn off(&self) {
81 self.led_controller.off(self.index);
82 }
83
84 fn toggle(&self) {
85 self.led_controller.toggle(self.index);
86 }
87
88 fn read(&self) -> bool {
89 self.led_controller.read(self.index)
90 }
91}
92
93pub struct ScreenOnLed<
94 'a,
95 S: hil::screen::Screen<'a>,
96 const NUM_LEDS: usize,
97 const SCREEN_WIDTH: usize,
98 const SCREEN_HEIGHT: usize,
99> {
100 screen: &'a S,
102
103 leds: Cell<[bool; NUM_LEDS]>,
105
106 buffer: MapCell<&'static mut [u8]>,
108
109 initialized: Cell<bool>,
111
112 dirty: Cell<bool>,
115}
116
117impl<
118 'a,
119 S: hil::screen::Screen<'a>,
120 const NUM_LEDS: usize,
121 const SCREEN_WIDTH: usize,
122 const SCREEN_HEIGHT: usize,
123 > ScreenOnLed<'a, S, NUM_LEDS, SCREEN_WIDTH, SCREEN_HEIGHT>
124{
125 pub const fn new(screen: &'a S, buffer: &'static mut [u8]) -> Self {
126 Self {
127 screen,
128 leds: Cell::new([false; NUM_LEDS]),
129 buffer: MapCell::new(buffer),
130 initialized: Cell::new(false),
131 dirty: Cell::new(false),
132 }
133 }
134
135 fn initialize_leds(&self) {
137 self.buffer.take().map(|buffer| {
138 self.render(buffer);
139 let data = SubSliceMut::new(buffer);
140 let _ = self.screen.write(data, false);
141 });
142 }
143
144 fn show_leds(&self) {
151 if !self.initialized.get() {
152 return;
153 }
154
155 self.buffer.take().map_or_else(
156 || {
157 self.dirty.set(true);
161 },
162 |buffer| {
163 let leds = self.leds.get();
164 for (i, led_state) in leds.iter().enumerate() {
165 self.render_led_state(buffer, i, *led_state);
166 }
167 let data = SubSliceMut::new(buffer);
168 let _ = self.screen.write(data, false);
169 },
170 );
171 }
172
173 fn get_led_offset(&self, led_index: usize) -> usize {
174 let led_dimension = self.get_size().1;
175
176 LEFT_RIGTH_PADDING
177 + self.get_led_width(led_dimension)
178 + TEXT_LEDS_PADDING
179 + ((led_dimension + 1) * led_index)
180 }
181
182 fn render(&self, buffer: &mut [u8]) {
183 self.render_led_text(buffer, LEFT_RIGTH_PADDING);
184 for i in 0..NUM_LEDS {
185 self.render_led(buffer, i);
186 }
187 }
188
189 fn render_led_text(&self, buffer: &mut [u8], x_offset: usize) {
190 let y_offset = self.get_size().2;
191
192 let y_top = TOP_BOTTOM_PADDING + TEXT_TOP_BOTTOM_PADDING + y_offset;
193 let y_bottom = SCREEN_HEIGHT - TOP_BOTTOM_PADDING - TEXT_TOP_BOTTOM_PADDING - y_offset;
194 let height = y_bottom - y_top;
195
196 let l_offset = x_offset;
198 let l_width = self.get_char_width(height, 'l');
199 self.write_vertical_line(buffer, l_offset, y_top, height, 1);
200 self.write_horizontal_line(buffer, l_offset, y_bottom, l_width, 1);
201
202 let e_offset = x_offset + l_width + TEXT_SPACING;
204 let e_width = self.get_char_width(height, 'e');
205 self.write_vertical_line(buffer, e_offset, y_top, height, 1);
206 self.write_horizontal_line(buffer, e_offset, y_top, e_width, 1);
207 self.write_horizontal_line(buffer, e_offset, y_bottom, e_width, 1);
208 self.write_horizontal_line(
209 buffer,
210 e_offset,
211 usize::midpoint(y_top, y_bottom),
212 e_width / 2,
213 1,
214 );
215
216 let d_offset = e_offset + e_width + TEXT_SPACING;
218 let d_width = self.get_char_width(height, 'd');
219 self.write_vertical_line(buffer, d_offset, y_top, height, 1);
220 self.write_vertical_line(buffer, d_offset + d_width, y_top, height, 1);
221 self.write_horizontal_line(buffer, d_offset, y_top, d_width, 1);
222 self.write_horizontal_line(buffer, d_offset, y_bottom, d_width, 1);
223 }
224
225 fn render_led(&self, buffer: &mut [u8], led_index: usize) {
226 let (_width, led_dimension, y_offset) = self.get_size();
229 let x_offset: usize = self.get_led_offset(led_index);
230
231 self.write_square(
233 buffer.as_mut(),
234 x_offset,
235 TOP_BOTTOM_PADDING + y_offset,
236 led_dimension,
237 1,
238 );
239 self.write_square(
241 buffer.as_mut(),
242 x_offset + 1,
243 TOP_BOTTOM_PADDING + y_offset + 1,
244 led_dimension - 2,
245 0,
246 );
247 }
248
249 fn render_led_state(&self, buffer: &mut [u8], led_index: usize, on: bool) {
250 let (_width, led_dimension, y_offset) = self.get_size();
251 let x_offset: usize = self.get_led_offset(led_index);
252
253 self.write_square(
255 buffer.as_mut(),
256 x_offset + 1,
257 TOP_BOTTOM_PADDING + y_offset + 1,
258 led_dimension - 2,
259 0,
260 );
261
262 if on {
263 self.write_square(
265 buffer.as_mut(),
266 x_offset + 2,
267 TOP_BOTTOM_PADDING + y_offset + 2,
268 led_dimension - 4,
269 1,
270 );
271 }
272 }
273
274 fn write_square(&self, buffer: &mut [u8], x: usize, y: usize, dimension: usize, val: usize) {
275 for i in 0..dimension {
276 for j in 0..dimension {
277 let pixel_x = i + x;
278 let pixel_y = j + y;
279 let byte = ((pixel_y / 8) * SCREEN_WIDTH) + pixel_x;
280 let bit = pixel_y % 8;
281 if val & 0x1 == 0x1 {
282 buffer[byte] |= 1 << bit;
283 } else {
284 buffer[byte] &= !(1 << bit);
285 }
286 }
287 }
288 }
289
290 fn write_horizontal_line(
291 &self,
292 buffer: &mut [u8],
293 x: usize,
294 y: usize,
295 length: usize,
296 val: usize,
297 ) {
298 for i in 0..length {
299 let pixel_x = i + x;
300 let byte = ((y / 8) * SCREEN_WIDTH) + pixel_x;
301 let bit = y % 8;
302 if val & 0x1 == 0x1 {
303 buffer[byte] |= 1 << bit;
304 } else {
305 buffer[byte] &= !(1 << bit);
306 }
307 }
308 }
309
310 fn write_vertical_line(
311 &self,
312 buffer: &mut [u8],
313 x: usize,
314 y: usize,
315 length: usize,
316 val: usize,
317 ) {
318 for i in 0..length {
319 let pixel_y = i + y;
320 let byte = ((pixel_y / 8) * SCREEN_WIDTH) + x;
321 let bit = pixel_y % 8;
322 if val & 0x1 == 0x1 {
323 buffer[byte] |= 1 << bit;
324 } else {
325 buffer[byte] &= !(1 << bit);
326 }
327 }
328 }
329
330 pub const fn get_size(&self) -> (usize, usize, usize) {
333 let mut width = SCREEN_WIDTH + 1;
334 let mut led_dimension = SCREEN_HEIGHT - (TOP_BOTTOM_PADDING * 2);
335
336 while width > SCREEN_WIDTH {
337 led_dimension -= 1;
339
340 let leds_width: usize = (led_dimension * NUM_LEDS) + (NUM_LEDS - 1);
341 width = LEFT_RIGTH_PADDING
342 + self.get_led_width(led_dimension)
343 + TEXT_LEDS_PADDING
344 + leds_width
345 + LEFT_RIGTH_PADDING;
346 }
347
348 let y_offset = (SCREEN_HEIGHT - (TOP_BOTTOM_PADDING * 2) - led_dimension) / 2;
349
350 (width, led_dimension, y_offset)
351 }
352
353 pub const fn get_char_width(&self, height: usize, c: char) -> usize {
354 match c {
355 'l' => (height * 3) / 5,
356 'e' => (height * 3) / 5,
357 'd' => (height * 2) / 4,
358 _ => 0,
359 }
360 }
361
362 pub const fn get_led_width(&self, height: usize) -> usize {
363 let height = height - (TEXT_TOP_BOTTOM_PADDING * 2);
364
365 let l_width = self.get_char_width(height, 'l');
366 let e_width = self.get_char_width(height, 'e');
367 let d_width = self.get_char_width(height, 'd');
368 l_width + TEXT_SPACING + e_width + TEXT_SPACING + d_width
369 }
370}
371
372impl<
373 'a,
374 S: hil::screen::Screen<'a>,
375 const NUM_LEDS: usize,
376 const SCREEN_WIDTH: usize,
377 const SCREEN_HEIGHT: usize,
378 > LedIndexed for ScreenOnLed<'a, S, NUM_LEDS, SCREEN_WIDTH, SCREEN_HEIGHT>
379{
380 fn init(&self, _index: usize) {}
381
382 fn on(&self, index: usize) {
383 let mut leds = self.leds.get();
384 leds[index] = true;
385 self.leds.set(leds);
386 self.show_leds();
387 }
388
389 fn off(&self, index: usize) {
390 let mut leds = self.leds.get();
391 leds[index] = false;
392 self.leds.set(leds);
393 self.show_leds();
394 }
395
396 fn toggle(&self, index: usize) {
397 let mut leds = self.leds.get();
398 let updated = !leds[index];
399 leds[index] = updated;
400 self.leds.set(leds);
401 self.show_leds();
402 }
403
404 fn read(&self, index: usize) -> bool {
405 self.leds.get()[index]
406 }
407}
408
409impl<
410 'a,
411 S: hil::screen::Screen<'a>,
412 const NUM_LEDS: usize,
413 const SCREEN_WIDTH: usize,
414 const SCREEN_HEIGHT: usize,
415 > hil::screen::ScreenClient for ScreenOnLed<'a, S, NUM_LEDS, SCREEN_WIDTH, SCREEN_HEIGHT>
416{
417 fn command_complete(&self, _r: Result<(), ErrorCode>) {}
418
419 fn write_complete(&self, data: SubSliceMut<'static, u8>, _r: Result<(), ErrorCode>) {
420 self.buffer.replace(data.take());
421
422 if self.dirty.get() {
425 self.dirty.set(false);
426 self.show_leds();
427 }
428 }
429
430 fn screen_is_ready(&self) {
431 if !self.initialized.get() {
432 self.initialized.set(true);
433 self.initialize_leds();
434 }
435 }
436}