rpi_led_matrix/
matrix.rs

1use crate::ffi;
2use crate::{LedCanvas, LedMatrixOptions, LedRuntimeOptions};
3#[cfg(feature = "embeddedgraphics")]
4use embedded_graphics_core::{
5    draw_target::DrawTarget,
6    geometry::{Dimensions, Point, Size},
7    pixelcolor::Rgb888,
8    primitives::Rectangle,
9    Pixel,
10};
11
12/// The Rust handle for the RGB matrix.
13///
14/// ```
15/// use rpi_led_matrix::{LedMatrix, LedColor};
16/// let matrix = LedMatrix::new(None, None).unwrap();
17/// ```
18pub struct LedMatrix {
19    handle: *mut ffi::CLedMatrix,
20    _options: LedMatrixOptions,
21}
22
23impl LedMatrix {
24    /// Creates the rust handle for the RGB matrix, given the optional options.
25    ///
26    /// ```
27    /// use rpi_led_matrix::{LedMatrix, LedColor, LedMatrixOptions};
28    /// let mut options = LedMatrixOptions::new();
29    /// options.set_hardware_mapping("adafruit-hat-pwm");
30    /// let matrix = LedMatrix::new(Some(options), None).unwrap();
31    /// ```
32    ///
33    /// # Errors
34    /// If the underlying C++ library returns a null pointer when trying to create
35    /// the [`CLedMatrix`](ffi::CLedMatrix).
36    pub fn new(
37        options: Option<LedMatrixOptions>,
38        rt_options: Option<LedRuntimeOptions>,
39    ) -> Result<Self, &'static str> {
40        let mut options = options.unwrap_or_default();
41        let mut rt_options = rt_options.unwrap_or_default();
42
43        let handle = unsafe {
44            ffi::led_matrix_create_from_options_and_rt_options(
45                &mut options.0 as *mut ffi::CLedMatrixOptions,
46                &mut rt_options.0 as *mut ffi::CLedRuntimeOptions,
47            )
48        };
49
50        if handle.is_null() {
51            Err("Couldn't create LedMatrix")
52        } else {
53            Ok(Self {
54                handle,
55                _options: options,
56            })
57        }
58    }
59
60    /// Retrieves the on screen canvas.
61    #[must_use]
62    pub fn canvas(&self) -> LedCanvas {
63        let handle = unsafe { ffi::led_matrix_get_canvas(self.handle) };
64
65        LedCanvas { handle }
66    }
67
68    /// Retrieves the offscreen canvas. Used in conjunction with [swap](LedMatrix.swap).
69    #[must_use]
70    pub fn offscreen_canvas(&self) -> LedCanvas {
71        let handle = unsafe { ffi::led_matrix_create_offscreen_canvas(self.handle) };
72
73        LedCanvas { handle }
74    }
75
76    /// Cleanly swaps the canvas on v-sync, returning the off-screen canvas for updating.
77    ///
78    /// ```
79    /// use rpi_led_matrix::{LedMatrix, LedColor};
80    /// let matrix = LedMatrix::new(None, None).unwrap();
81    /// let mut canvas = matrix.offscreen_canvas();
82    /// let mut color = LedColor { red: 0, green: 0, blue: 0 };
83    /// while(color.red < 255) {
84    ///     canvas.fill(&color);
85    ///     canvas = matrix.swap(canvas);
86    ///     color.red += 1;
87    /// }
88    /// ```
89    #[must_use]
90    #[allow(clippy::needless_pass_by_value)]
91    pub fn swap(&self, canvas: LedCanvas) -> LedCanvas {
92        let handle = unsafe { ffi::led_matrix_swap_on_vsync(self.handle, canvas.handle) };
93
94        LedCanvas { handle }
95    }
96}
97
98impl Drop for LedMatrix {
99    fn drop(&mut self) {
100        unsafe {
101            ffi::led_matrix_delete(self.handle);
102        }
103    }
104}
105
106#[cfg(feature = "embeddedgraphics")]
107impl DrawTarget for LedCanvas {
108    type Color = Rgb888;
109    type Error = core::convert::Infallible;
110
111    fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
112    where
113        I: IntoIterator<Item = Pixel<Self::Color>>,
114    {
115        for px in pixels {
116            self.set(px.0.x, px.0.y, &px.1.into());
117        }
118        Ok(())
119    }
120
121    fn clear(&mut self, color: Self::Color) -> Result<(), Self::Error> {
122        self.fill(&color.into());
123        Ok(())
124    }
125}
126
127#[cfg(feature = "embeddedgraphics")]
128impl Dimensions for LedCanvas {
129    fn bounding_box(&self) -> Rectangle {
130        let size = self.canvas_size();
131        Rectangle::new(Point::new(0, 0), Size::new(size.0 as u32, size.1 as u32))
132    }
133}
134
135#[cfg(test)]
136mod tests {
137    use super::*;
138
139    fn led_matrix() -> LedMatrix {
140        let mut options = LedMatrixOptions::new();
141        let mut rt_options = LedRuntimeOptions::new();
142        options.set_hardware_mapping("adafruit-hat-pwm");
143        options.set_chain_length(2);
144        options.set_hardware_pulsing(false);
145        options.set_refresh_rate(true);
146        options.set_brightness(10).unwrap();
147        rt_options.set_gpio_slowdown(2);
148        LedMatrix::new(Some(options), Some(rt_options)).unwrap()
149    }
150
151    #[test]
152    #[serial_test::serial]
153    fn matrix_create() {
154        let _matrix = led_matrix();
155    }
156}