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}