WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Re-architect to pre-calculate a buffer for each frame (#90)
👩🔬 🧪 💥
If we can off-load sending bits to the LEDs using hardware, then we can prepare the bits for the next frame while the current frame is being sent.
This change is a big step towards making this possible.
One realization to make this work is that yes [the `generic_const_exprs` feature](https://doc.rust-lang.org/beta/unstable-book/language-features/generic-const-exprs.html) would make no-alloc much nicer, BUT IN THE MEANTIME we can achieve the same outcomes (with a worse user experience) by using generic constants without expressions. Since you can't do constant calculations using generics (e.g. we can't calculate the buffer size needed using other generic types we already have, such as the type of LED which has a constant function for this), the user must calculate them on their side and pass in to your type arguments. We can use all our builder pattern skills to make this as ergonomic as possible.
Changes:
- Change `Driver` (and `DriverAsync`) trait interface
```rust
pub trait Driver {
/// The error type that may be returned by the driver.
type Error;
/// The color type accepted by the driver.
type Color;
/// The word of the frame buffer.
type Word;
/// Encodes an update frame buffer for the LED hardware.
///
/// # Type Parameters
///
/// * `PIXEL_COUNT` - Number of pixels in frame
/// * `FRAME_BUFFER_SIZE` - Length of encoded frame buffer, in words.
/// * `Pixels` - Iterator of colors for each pixel
/// * `Color` - Type of each pixel
///
/// # Arguments
///
/// * `pixels` - Iterator of colors for each pixel
/// * `brightness` - Global brightness scaling factor (0.0 to 1.0)
/// * `correction` - Color correction factors
///
/// # Returns
///
/// Result with frame buffer
fn encode<const PIXEL_COUNT: usize, const FRAME_BUFFER_SIZE: usize, Pixels, Color>(
&mut self,
pixels: Pixels,
brightness: f32,
correction: ColorCorrection,
) -> Vec<Self::Word, FRAME_BUFFER_SIZE>
where
Pixels: IntoIterator<Item = Color>,
Self::Color: FromColor<Color>;
/// Writes frame buffer to the LED hardware.
///
/// # Type Parameters
///
/// * `FRAME_BUFFER_SIZE` - Length of encoded frame buffer, in words.
///
/// # Arguments
///
/// * `frame` - Frame buffer
///
/// # Returns
///
/// Result indicating success or an error
fn write<const FRAME_BUFFER_SIZE: usize>(
&mut self,
frame: Vec<Self::Word, FRAME_BUFFER_SIZE>,
brightness: f32,
correction: ColorCorrection,
) -> Result<(), Self::Error>;
/// Shows a frame on the LED hardware.
///
/// # Type Parameters
///
/// * `PIXEL_COUNT` - Number of pixels in frame
/// * `FRAME_BUFFER_SIZE` - Length of encoded frame buffer, in words.
/// * `Pixels` - Iterator of colors for each pixel
/// * `Color` - Type of each pixel
///
/// # Arguments
///
/// * `pixels` - Iterator of colors for each pixel
/// * `brightness` - Global brightness scaling factor (0.0 to 1.0)
/// * `correction` - Color correction factors
///
/// # Returns
///
/// Result indicating success or an error
fn show<const PIXEL_COUNT: usize, const FRAME_BUFFER_SIZE: usize, I, C>(
&mut self,
pixels: I,
brightness: f32,
correction: ColorCorrection,
) -> Result<(), Self::Error>
where
I: IntoIterator<Item = C>,
Self::Color: FromColor<C>,
{
let frame_buffer =
self.encode::<PIXEL_COUNT, FRAME_BUFFER_SIZE, _, _>(pixels, brightness, correction);
self.write(frame_buffer, brightness, correction)
}
}
```
- Until [the `generic_const_exprs` feature](https://doc.rust-lang.org/beta/unstable-book/language-features/generic-const-exprs.html) is stable, we aren't able to use associated constants, const functions, or expressions in the Blinksy code to calculate constants at compile-time. Instead, we must receive pre-calculated constants from the user as a generic. The best we can do is make it easy as possible by providing good types, traits, and const functions for the user to use.
- To build a `Control`, you now need to provide a `FRAME_BUFFER_SIZE` constant.
- So for example, to build a frame buffer to drive Ws2812 LEDs:
```
.with_frame_buffer_size::<{ Ws2812::frame_buffer_size(Layout::PIXEL_COUNT) }>()
```
- Re-factor clockless and clocked drivers into common pattern
- There is a generic driver for each type: `ClocklessDriver` and `ClockedDriver`.
- You construct the generic driver by combining an Led with a Writer, both of that type.
- All drivers and all writers are made through builders.
- So for example: the clockless RMT driver for a WS2812 LED:
```rust
let driver = ClocklessDriver::default()
.with_led::<Ws2812>()
.with_writer(ClocklessRmt::default()
.with_led::<Ws2812>()
.with_rmt_buffer_size::<{ rmt_buffer_size::<Ws2812>(Layout::PIXEL_COUNT) }>()
.with_channel(/* rmt channel */)
.with_pin(/* rmt pin */)
.build()
);
```
- Another example: the clocked SPI driver for an APA102 LED:
```rust
let driver = ClockedDriver::default()
.with_led::<Apa102>()
.with_writer(/* spi bus */)
```
- Clockless and clocked writers are also constructed through builders.
- Move LED definitions to `crate::leds` module, remove `Led` suffix from structs.
- Until [the `generic_const_exprs` feature](https://doc.rust-lang.org/beta/unstable-book/language-features/generic-const-exprs.html) is stable, we aren't able to use associated constants, const functions, or expressions in the Blinksy code to calculate constants at compile-time. Instead, we must receive pre-calculated constants from the user as a generic. The best we can do is make it easy as possible by providing good types, traits, and const functions for the user to use.
123
+
- Built-in LED drivers have been refactored:
124
+
- There is a generic driver for each type: `ClocklessDriver` and `ClockedDriver`.
125
+
- You construct the generic driver by combining an Led with a Writer, both of that type.
126
+
- All drivers and all writers are made through the builder pattern.
127
+
- So for example: the clockless RMT driver for a WS2812 LED:
0 commit comments