microbit_bsp/display/
types.rs

1use core::ops::{AddAssign, SubAssign};
2// TODO: Use const generic expressions to derive data size when stabilized
3const BITMAP_WIDTH: usize = 1;
4// Using u8 for each word
5const BITMAP_WORD_SIZE: usize = 8;
6
7/// A bitmap with room for 8 bits used by Frame to create a compact frame buffer
8#[derive(Clone, Copy, PartialEq)]
9pub struct Bitmap {
10    data: [u8; BITMAP_WIDTH],
11    nbits: usize,
12}
13
14impl core::fmt::Debug for Bitmap {
15    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
16        for i in 0..self.nbits {
17            if self.is_set(i) {
18                write!(f, "1")?;
19            } else {
20                write!(f, "0")?;
21            }
22        }
23        Ok(())
24    }
25}
26
27#[cfg(feature = "defmt")]
28impl defmt::Format for Bitmap {
29    fn format(&self, f: defmt::Formatter<'_>) {
30        let mut s: heapless::String<32> = heapless::String::new();
31        for i in 0..self.nbits {
32            if self.is_set(i) {
33                s.push('1').unwrap();
34            } else {
35                s.push('0').unwrap();
36            }
37        }
38        defmt::write!(f, "{}", s.as_str());
39    }
40}
41
42impl Bitmap {
43    /// Create a new bitmap with initial input and number of bits
44    // TODO: Change input to array when const generics...
45    pub const fn new(input: u8, nbits: usize) -> Self {
46        let mut data = [0; BITMAP_WIDTH];
47        //for i in 0..input.len() {
48        if nbits < BITMAP_WORD_SIZE {
49            data[0] = input << (BITMAP_WORD_SIZE - nbits);
50        } else {
51            data[0] = input;
52        }
53        //}
54        Self { data, nbits }
55    }
56
57    /// Create an empty bitmap with nbits bits
58    pub const fn empty(nbits: usize) -> Self {
59        Self { data: [0; 1], nbits }
60    }
61
62    /// Set bit n in bitmap
63    pub fn set(&mut self, bit: usize) {
64        assert!(bit < self.nbits);
65        let idx: usize = bit / BITMAP_WORD_SIZE;
66        let p: usize = bit % BITMAP_WORD_SIZE;
67        self.data[idx] |= 1 << ((BITMAP_WORD_SIZE - 1) - p);
68    }
69
70    /// Clear all bits in bitmap
71    pub fn clear_all(&mut self) {
72        for i in 0..self.data.len() {
73            self.data[i] = 0;
74        }
75    }
76
77    /// Clear bit n in bitmap
78    pub fn clear(&mut self, bit: usize) {
79        assert!(bit < self.nbits);
80        let idx: usize = bit / BITMAP_WORD_SIZE;
81        let p: usize = bit % BITMAP_WORD_SIZE;
82        self.data[idx] &= !(1 << ((BITMAP_WORD_SIZE - 1) - p));
83    }
84
85    /// Check if bit n is set in bitmap
86    pub fn is_set(&self, bit: usize) -> bool {
87        assert!(bit < self.nbits);
88        let idx: usize = bit / BITMAP_WORD_SIZE;
89        let p: usize = bit % BITMAP_WORD_SIZE;
90        (self.data[idx] & (1 << ((BITMAP_WORD_SIZE - 1) - p))) != 0
91    }
92
93    /// Shift left by nbits bits
94    pub fn shift_left(&mut self, nbits: usize) {
95        for b in self.data.iter_mut() {
96            *b <<= nbits;
97        }
98    }
99
100    /// Shift right by nbits bits
101    pub fn shift_right(&mut self, nbits: usize) {
102        for b in self.data.iter_mut() {
103            *b >>= nbits;
104        }
105    }
106
107    /// Logical OR with another bitmap
108    pub fn or(&mut self, other: &Bitmap) {
109        for i in 0..self.data.len() {
110            self.data[i] |= other.data[i];
111        }
112    }
113
114    /// Logical AND with another bitmap
115    pub fn and(&mut self, other: &Bitmap) {
116        for i in 0..self.data.len() {
117            self.data[i] &= other.data[i];
118        }
119    }
120}
121
122/// An NxM frame that can be displayed on a LED matrix.
123///
124/// NOTE: Currently restricted to 8 bit width
125#[derive(Clone, Copy, PartialEq)]
126pub struct Frame<const XSIZE: usize, const YSIZE: usize> {
127    bitmap: [Bitmap; YSIZE],
128}
129
130impl<const XSIZE: usize, const YSIZE: usize> core::fmt::Debug for Frame<XSIZE, YSIZE> {
131    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
132        for (i, b) in self.bitmap.iter().enumerate() {
133            for j in 0..b.nbits {
134                if self.bitmap[i].is_set(j) {
135                    write!(f, "1")?;
136                } else {
137                    write!(f, "0")?;
138                }
139            }
140            writeln!(f)?;
141        }
142        Ok(())
143    }
144}
145
146#[cfg(feature = "defmt")]
147impl<const XSIZE: usize, const YSIZE: usize> defmt::Format for Frame<XSIZE, YSIZE> {
148    fn format(&self, f: defmt::Formatter<'_>) {
149        let mut s: heapless::String<1056> = heapless::String::new();
150        for (i, b) in self.bitmap.iter().enumerate() {
151            for j in 0..b.nbits {
152                if self.bitmap[i].is_set(j) {
153                    s.push('1').unwrap();
154                } else {
155                    s.push('0').unwrap();
156                }
157            }
158            s.push('\n').unwrap();
159        }
160        defmt::write!(f, "{}", s.as_str());
161    }
162}
163
164impl<const XSIZE: usize, const YSIZE: usize> Frame<XSIZE, YSIZE> {
165    /// Create an empty frame
166    pub const fn empty() -> Self {
167        Self {
168            bitmap: [Bitmap::empty(XSIZE); YSIZE],
169        }
170    }
171
172    /// Create a frame from a bitmap array
173    pub const fn new(bitmap: [Bitmap; YSIZE]) -> Self {
174        Self { bitmap }
175    }
176
177    /// Clear this frame (empty)
178    pub fn clear(&mut self) {
179        for m in self.bitmap.iter_mut() {
180            m.clear_all();
181        }
182    }
183
184    /// Enable (x, y) on this frame
185    pub fn set(&mut self, x: usize, y: usize) {
186        self.bitmap[y].set(x);
187    }
188
189    /// Disable (x, y) on this frame
190    pub fn unset(&mut self, x: usize, y: usize) {
191        self.bitmap[y].clear(x);
192    }
193
194    /// Check if (x, y) is set on this frame
195    pub fn is_set(&self, x: usize, y: usize) -> bool {
196        self.bitmap[y].is_set(x)
197    }
198
199    /// Logical OR with another frame
200    pub fn or(&mut self, other: &Frame<XSIZE, YSIZE>) {
201        for i in 0..self.bitmap.len() {
202            self.bitmap[i].or(&other.bitmap[i]);
203        }
204    }
205
206    /// Shift all rows left
207    pub fn shift_left(&mut self, nbits: usize) {
208        for i in 0..self.bitmap.len() {
209            self.bitmap[i].shift_left(nbits);
210        }
211    }
212
213    /// Shift all rows right
214    pub fn shift_right(&mut self, nbits: usize) {
215        for i in 0..self.bitmap.len() {
216            self.bitmap[i].shift_right(nbits);
217        }
218    }
219
220    /// Logical AND with another frame
221    pub fn and(&mut self, other: &Frame<XSIZE, YSIZE>) {
222        for i in 0..self.bitmap.len() {
223            self.bitmap[i].and(&other.bitmap[i]);
224        }
225    }
226}
227
228impl<const XSIZE: usize, const YSIZE: usize> Default for Frame<XSIZE, YSIZE> {
229    fn default() -> Self {
230        Frame::empty()
231    }
232}
233
234/// A brightness setting for the display.
235#[derive(Clone, Copy)]
236pub struct Brightness(u8);
237
238impl Brightness {
239    /// Maximum brightness
240    pub const MAX: Brightness = Brightness(10);
241
242    /// Lowest brightness
243    pub const MIN: Brightness = Brightness(0);
244
245    /// Create a new brightness with a custom level
246    pub fn new(level: u8) -> Self {
247        Self(level.clamp(Self::MIN.0, Self::MAX.0))
248    }
249
250    /// Return the level value
251    pub fn level(&self) -> u8 {
252        self.0
253    }
254}
255
256impl Default for Brightness {
257    fn default() -> Self {
258        Self(5)
259    }
260}
261
262impl AddAssign<u8> for Brightness {
263    fn add_assign(&mut self, rhs: u8) {
264        self.0 += core::cmp::min(Self::MAX.level() - self.0, rhs);
265    }
266}
267
268impl SubAssign<u8> for Brightness {
269    fn sub_assign(&mut self, rhs: u8) {
270        self.0 -= core::cmp::min(self.0, rhs);
271    }
272}
273
274/*
275#[cfg(test)]
276mod tests {
277    use super::*;
278
279    #[test]
280    fn test_bitmap() {
281        let mut b: Bitmap = Bitmap::empty(5);
282        b.set(0);
283        b.set(2);
284        b.set(4);
285        assert!(b.is_set(0));
286        assert!(!b.is_set(1));
287        assert!(b.is_set(2));
288        assert!(!b.is_set(3));
289        assert!(b.is_set(4));
290
291        b.clear(2);
292        b.set(3);
293        assert!(b.is_set(0));
294        assert!(!b.is_set(1));
295        assert!(!b.is_set(2));
296        assert!(b.is_set(3));
297        assert!(b.is_set(4));
298
299        /*
300        TODO: When const expressions is allowed
301        let mut b: Bitmap = Bitmap::empty(33);
302        b.set(16);
303        b.set(32);
304        assert!(b.is_set(16));
305        assert!(b.is_set(32));
306        */
307
308        let b: Bitmap = Bitmap::new(0b01000, 5);
309        assert!(!b.is_set(0));
310        assert!(b.is_set(1));
311        assert!(!b.is_set(2));
312        assert!(!b.is_set(3));
313        assert!(!b.is_set(4));
314
315        let b: Bitmap = Bitmap::new(0b11110, 5);
316        assert!(b.is_set(0));
317        assert!(b.is_set(1));
318        assert!(b.is_set(2));
319        assert!(b.is_set(3));
320        assert!(!b.is_set(4));
321
322        let mut b: Bitmap = Bitmap::new(0b01110, 5);
323        b.shift_left(1);
324        assert!(b.is_set(0));
325        assert!(b.is_set(1));
326        assert!(b.is_set(2));
327        assert!(!b.is_set(3));
328        assert!(!b.is_set(4));
329
330        b.shift_right(1);
331        assert!(!b.is_set(0));
332        assert!(b.is_set(1));
333        assert!(b.is_set(2));
334        assert!(b.is_set(3));
335        assert!(!b.is_set(4));
336    }
337}
338*/