-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from 0xb-s/feat-allow-user-to-set-number-of-led
Feat: allow user to set number of led
- Loading branch information
Showing
4 changed files
with
246 additions
and
91 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,58 +1,95 @@ | ||
use embedded_hal_async::spi::SpiBus; | ||
use smart_leds::RGB8; | ||
|
||
use crate::drivers::LedDriver; | ||
|
||
pub struct Apa102<SPI: SpiBus<u8>> { | ||
/// APA102 LED Driver supporting an arbitrary number of LEDs. | ||
/// | ||
/// The caller is responsible for providing a buffer of appropriate size. | ||
/// The buffer size should be: | ||
/// `start_frame_size + (num_leds * led_frame_size) + end_frame_size`, | ||
/// where: | ||
/// - `start_frame_size` = 4 bytes (always zero). | ||
/// - `led_frame_size` = 4 bytes per LED (1 for brightness, 3 for RGB data). | ||
/// - `end_frame_size` = `(num_leds + 15) / 16` bytes. | ||
pub struct Apa102<'a, SPI: SpiBus<u8>> { | ||
spi: SPI, | ||
buffer: [u8; MAX_BUFFER_SIZE], | ||
num_leds: usize, | ||
buffer: &'a mut [u8], | ||
} | ||
|
||
const MAX_LEDS: usize = 60; // Adjust as needed | ||
const START_FRAME_SIZE: usize = 4; | ||
const LED_FRAME_SIZE: usize = 4; | ||
const END_FRAME_SIZE: usize = (MAX_LEDS + 15) / 16; | ||
const MAX_BUFFER_SIZE: usize = START_FRAME_SIZE + (MAX_LEDS * LED_FRAME_SIZE) + END_FRAME_SIZE; | ||
impl<'a, SPI: SpiBus<u8>> Apa102<'a, SPI> { | ||
/// Creates a new APA102 driver with the given SPI bus, number of LEDs, and buffer. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `spi` - The SPI bus instance. | ||
/// * `num_leds` - The number of LEDs to control. | ||
/// * `buffer` - A mutable slice that must be large enough to hold the frame data. | ||
/// | ||
/// # Panics | ||
/// | ||
/// This function will panic if the provided buffer is too small to hold all frame data. | ||
pub fn new(spi: SPI, num_leds: usize, buffer: &'a mut [u8]) -> Self { | ||
let start_frame_size = 4; | ||
let led_frame_size = 4; | ||
let end_frame_size = (num_leds + 15) / 16; | ||
let total_size = start_frame_size + (num_leds * led_frame_size) + end_frame_size; | ||
|
||
assert!( | ||
buffer.len() >= total_size, | ||
"Buffer too small: required {}, provided {}", | ||
total_size, | ||
buffer.len() | ||
); | ||
|
||
impl<SPI: SpiBus<u8>> Apa102<SPI> { | ||
/// Creates a new APA102 driver with the given SPI bus. | ||
pub fn new(spi: SPI) -> Self { | ||
Self { | ||
spi, | ||
buffer: [0; MAX_BUFFER_SIZE], | ||
num_leds, | ||
buffer, | ||
} | ||
} | ||
} | ||
|
||
impl<SPI: SpiBus<u8>> LedDriver<RGB8> for Apa102<SPI> { | ||
impl<'a, SPI: SpiBus<u8>> LedDriver<RGB8> for Apa102<'a, SPI> { | ||
type Error = SPI::Error; | ||
|
||
/// Writes the RGB data to the LED strip. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `colors` - A slice of RGB8 colors to write to the strip. This function will write | ||
/// up to the number of LEDs configured at creation time (`num_leds`). | ||
/// | ||
/// # Returns | ||
/// | ||
/// Returns a `Result` indicating whether the write was successful. | ||
async fn write(&mut self, colors: &[RGB8]) -> Result<(), Self::Error> { | ||
let num_leds = core::cmp::min(colors.len(), MAX_LEDS); | ||
let num_leds = core::cmp::min(colors.len(), self.num_leds); | ||
let end_frame_size = (num_leds + 15) / 16; | ||
|
||
// Prepare the buffer. | ||
let buffer = &mut self.buffer[..]; | ||
// Frame sizes | ||
let start_frame_size = 4; | ||
let led_frame_size = 4; | ||
let total_size = start_frame_size + (num_leds * led_frame_size) + end_frame_size; | ||
|
||
// Start frame | ||
buffer[..START_FRAME_SIZE].fill(0x00); | ||
// Start frame: all zeros | ||
self.buffer[..start_frame_size].fill(0x00); | ||
|
||
// LED frames | ||
for (i, &RGB8 { r, g, b }) in colors.iter().enumerate().take(num_leds) { | ||
let offset = START_FRAME_SIZE + i * LED_FRAME_SIZE; | ||
// Data frame: 0xE0 | brightness (set to max 0x1F), then B, G, R. | ||
buffer[offset] = 0xE0 | 0x1F; // Global brightness set to max (0x1F) | ||
buffer[offset + 1] = b; | ||
buffer[offset + 2] = g; | ||
buffer[offset + 3] = r; | ||
let offset = start_frame_size + i * led_frame_size; | ||
// Data frame: 0xE0 | brightness (set to max 0x1F), followed by B, G, R. | ||
self.buffer[offset] = 0xE0 | 0x1F; // Global brightness set to max (0x1F) | ||
self.buffer[offset + 1] = b; // Blue channel | ||
self.buffer[offset + 2] = g; // Green channel | ||
self.buffer[offset + 3] = r; // Red channel | ||
} | ||
|
||
// End frame | ||
let end_frame_offset = START_FRAME_SIZE + num_leds * LED_FRAME_SIZE; | ||
buffer[end_frame_offset..end_frame_offset + end_frame_size].fill(0x00); | ||
// End frame: all zeros | ||
let end_frame_offset = start_frame_size + num_leds * led_frame_size; | ||
self.buffer[end_frame_offset..end_frame_offset + end_frame_size].fill(0x00); | ||
|
||
// Write the data | ||
let total_size = START_FRAME_SIZE + num_leds * LED_FRAME_SIZE + end_frame_size; | ||
self.spi.write(&buffer[..total_size]).await | ||
// Write the data via SPI | ||
self.spi.write(&self.buffer[..total_size]).await | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.