Skip to content

Latest commit

History

History
306 lines (234 loc) 路 10.8 KB

File metadata and controls

306 lines (234 loc) 路 10.8 KB

Changelog

UNRELEASED

0.11

A step towards more efficient LED output.

Now on each frame, the driver has two separate steps:

  1. Encode the next frame into a buffer.
  2. Get all the colors for the next frame from the Pattern.
  3. Do any processing (e.g. convert color to linear sRGB, brightness, color corrections, etc)
  4. Format colors into words (bytes) that will be sent to the LEDs.
  5. Add any other words (bytes), depending on the LED type. (e.g. a start header, an end trailer, etc)
  6. Send the encoded frame buffer to the LEDs.

The purpose of separating these steps is to:

  • Minimize the work required to send chunks of the encoded frame buffer to the LEDs, thus minimizing the timing gap in between these chunks.
  • Open up the possibility of pre-encoding the next frame into a buffer, while sending the current frame to the LEDs.

Migration guide (0.10 -> 0.11)

  • defmt is now optional across all crates, defaults to enabled in gledopto.
  • alloc is now optional in gledopto crate.
  • ControlBuilder::with_layout generic type signature changes from <Layout> to <Layout, const PIXEL_COUNT: usize>
    • If your layout is Layout, then change .with_layout<Layout>() to .with_layout::<Layout, { Layout::PIXEL_COUNT }>()
-  .with_layout::<Layout>()
+  .with_layout::<Layout, { Layout::PIXEL_COUNT }>()
  • ControlBuilder now has a with_frame_buffer_size 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) }>()

If using the gledopto high-level helper macros, this should be all you need to change.

Below are changes for lower-level interfaces:

  • Change Driver (and DriverAsync) traits:
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 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.
  • Built-in LED drivers have been refactored:
    • 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 the builder pattern.
    • So for example: the clockless RMT driver for a WS2812 LED:
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:
let driver = ClockedDriver::default()
    .with_led::<Apa102>()
    .with_writer(/* spi bus */)
  • Clockless and clocked writers are also constructed through the builder pattern.
  • Move LED definitions to blinksy::leds module, remove Led suffix from structs.
  • blinksy-esp RMT driver expects RMT_BUFFER_SIZE.
    • Each memory block on the RMT driver has a size of 64, with a max of 8 memory blocks.
    • If async, you should use 64.
    • If blocking and not too many LEDs, you should use rmt_buffer_size::<Led>(Layout::PIXEL_COUNT).
    • If blocking and too many LEDs, you should use 64.

Changes

  • #96: Gledopto clockless led macros default to using buffered RMT
  • #94: Upgrade to esp-hal@1.0.0-rc.1
  • #93: Make more features optional
  • #92: Document and enforce generic constants in ControlBuilder
  • #90: Re-architect to pre-calculate a buffer for each frame
  • #85: Pin RMT driver in RAM for examples
  • #82: Use pixels buffer
    • Write all colors from Pattern iterator to pixel buffer, then write pixel buffer to LEDs with Driver.
  • #87: Refactor clocked LED drivers

0.10

Yee haw blinksy now supports async!

Migration guide (0.9 -> 0.10)

  • You can now add the async feature and use async drivers.
    • For gledopto, add the embassy feature and use the embassy_main entry.
    • See examples for async usage.
  • For projects using gledopto macros: no known breaking changes.
  • For projects using blinksy-esp: create_rmt_buffer! macro no longer needs $num_leds.
  • For projects using blinksy internals, changes:
    • Renamed dimensions module to markers
      • dimension::Dim1d -> markers::Dim1d
      • dimension::Dim2d -> markers::Dim2d
    • Move dimension::LayoutForDim to layout::LayoutForDim
    • Un-pub-ify internal functions within drivers

Breaking changes

  • #54: Add async drivers

Bug fixes

  • #73: Fix APA102 color correction
  • #74: Remove extranaeous docstring
  • #75: Fix color temperature

0.9

Migration guide (0.8 -> 0.9)

fn main() {
    Desktop::new_1d::<Layout>().start(|driver| {
        let mut control = ControlBuilder::new_1d()
            .with_layout::<Layout>()
            .with_pattern::<Pattern>(PatternParams::default())
            .with_driver(driver)
            .build();

        loop {
            // ...
        }
    });
}

Breaking changes

  • #72: Fix desktop simulator on macOS

0.8

Migration guide (0.7 -> 0.8)

  • rust-version has been increased to 1.88, to follow esp-hal.
  • You should upgrade to espflash@4, which will also require adding bootloader metadata via a macro.
    • See gledopto library and examples for bootloader!() on how to easily do this.
    • See esp-hal-1.0.0-rc.0 release for "Special migration note" about this.

Breaking changes

  • #66: Upgrade to esp-hal-1.0.0-rc.0

0.7

Migration guide (0.6 -> 0.7)

No known breaking changes.

Feature additions

  • #59: Add example of 3D volumetric cube
  • #65: Add support for GL-C-017WL-D
  • #63: Add arc shape

Bug fixes

  • #61: Fix points step of Shape::Line

Visual improvements

  • #64: Change rainbow pattern so is not just over x, but over all available dimensions

0.6

Woo hoo blinksy now supports 3D!

Migration guide (0.5 -> 0.6):

No known breaking changes.

Feature additions

  • #57: Add support for 3D layouts and animations
  • #58: Add 3D to desktop simulator

Minor changes

  • #56: Refactor layout code into separate files

Thanks @ahdinosaur for their contributions.

0.5

Migration guide (0.4 -> 0.5):

No known breaking changes.

Changes

  • #50: Use bluurryy/noise-functions instead of Razaekel/noise-rs
  • #45: Add support for SK6812

Thanks @not-jan, @nazo6, and @ahdinosaur for their contributions.