ws2818_rgb_led_spi_driver/
adapter_gen.rs

1//! Generic Hardware Abstraction Layer, no_std-compatible.
2
3use crate::encoding::encode_rgb_slice;
4use alloc::boxed::Box;
5use alloc::string::String;
6
7/// SPI-device abstraction.
8pub trait HardwareDev {
9    fn write_all(&mut self, encoded_data: &[u8]) -> Result<(), String>;
10}
11
12pub trait WS28xxAdapter {
13    /// Returns a reference to the hardware device.
14    /// This function only needs to be implemented once in the generic adapter.
15    fn get_hw_dev(&mut self) -> &mut Box<dyn HardwareDev>;
16
17    /// Encodes RGB values and write them via the hardware device to the LEDs. The length of the vector
18    /// is the number of LEDs you want to write to. *Note* that if you have performance critical
19    /// applications (like you need a signal on the LEDS on a given time) it's a better idea
20    /// to encode the data earlier by yourself using `crate::encoding`-module and calling
21    /// `WS28xxAdapter::write_encoded_rgb`. Otherwise and if your device is slow the encoding
22    /// could cost a few microseconds to milliseconds - depending on your amount of data and machine.
23    fn write_rgb(&mut self, rgb_data: &[(u8, u8, u8)]) -> Result<(), String> {
24        let encoded_data = encode_rgb_slice(rgb_data);
25        self.write_encoded_rgb(&encoded_data)
26    }
27
28    /// Clears all LEDs. Sets each to (0, 0, 0).
29    fn clear(&mut self, num_leds: usize) {
30        let data = vec![(0, 0, 0); num_leds];
31        self.write_rgb(&data).unwrap();
32    }
33
34    /// Directly writes encoded RGB values via hardware device to the LEDs. This method and the encoded data
35    /// must fulfill the restrictions given by [`crate::timings`] and [`crate::encoding`] if the hardware
36    /// device uses the specified frequency in [`crate::timings::PI_SPI_HZ`].
37    fn write_encoded_rgb(&mut self, encoded_data: &[u8]) -> Result<(), String> {
38        self.get_hw_dev().write_all(&encoded_data)
39            .map_err(|_| {
40                format!(
41                    "Failed to send {} bytes via the specified hardware device. If you use SPI on Linux Perhaps your SPI buffer is too small!\
42                     Check https://www.raspberrypi.org/forums/viewtopic.php?p=309582#p309582 for example.",
43                    encoded_data.len()
44                )}
45            )
46    }
47}
48
49/// Platform agnostic (generic) adapter that connects your application via your specified
50/// hardware interface to your WS28xx LEDs. *Handle this as something like an abstract class
51/// for concrete implementations!* This works in `#[no-std]`-environments.
52pub struct WS28xxGenAdapter {
53    hw: Box<dyn HardwareDev>,
54}
55
56impl WS28xxGenAdapter {
57    /// Constructor that stores the hardware device in the adapter.
58    pub fn new(hw: Box<dyn HardwareDev>) -> Self {
59        Self { hw }
60    }
61}
62
63// Implement the getter for the hardware device.
64impl WS28xxAdapter for WS28xxGenAdapter {
65    fn get_hw_dev(&mut self) -> &mut Box<dyn HardwareDev> {
66        &mut self.hw
67    }
68}