Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unified LED addressing API #2

Open
blm768 opened this issue Jun 11, 2022 · 0 comments
Open

Unified LED addressing API #2

blm768 opened this issue Jun 11, 2022 · 0 comments

Comments

@blm768
Copy link

blm768 commented Jun 11, 2022

The base IS31FL3731 type assumes a two-dimensional array of monochrome LEDs. This matches many hardware configurations, but some devices us an array of RGB LEDs with three LED control slots per physical array position. The current solution is to provide a wrapper struct with an additional pixel_rgb method. This generally works, but it'd be nice to deal with just one struct, not two.

Additionally, given that the hardware configuration for any device is fixed, the width, height, and calc_pixel fields of IS31FL3731 should not change at runtime. This makes them prime candidates for compile-time, type-level configuration, which could save about six bytes of RAM at runtime.

My proposed solution involves adding another generic parameter to IS31FL3731. This parameter would take a type that implements the MatrixLayout trait, which would look something like the following:

trait MatrixLayout {
    const WIDTH: usize;
    const HEIGHT: usize;
    type Intensity: Intensity;
    fn calc_pixel(x: u8, y: u8) -> [u8; Self::Intensity::COMPONENTS];
}

The Intensity type would, in turn, implement the following trait:

trait Intensity {
    const COMPONENTS; // Either 1 or 3
    fn component(&self, index: u8) -> u8;
}

Intensity would then be implemented for both u8 (for monochrome displays) and an RGB type (probably either struct Rgb { r: u8, g: u8, b: u8 } or [u8; 3]).

The final implementation of pixel would look something like the following:

impl<I2C, I2cError, Layout> IS31FL3731<I2C, Layout>
where
    I2C: Write<Error = I2cError>,
    Layout: MatrixLayout,
{
    pub fn pixel(&mut self, x: u8, y: u8, intensity: Self::Intensity) -> Result<(), Error<I2cError>> {
        if x > Layout::WIDTH {
            return Err(Error::InvalidLocation(x));
        }
        if y > Layout::HEIGHT {
            return Err(Error::InvalidLocation(y));
        }
        let pixels = self.calc_pixel(x, y);
        for (i, address) in pixels.into_iter().enumerate() {
            self.write_register(self.frame, addresses::COLOR_OFFSET + address, intensity.component(i))?;
        }
        Ok(())
    }
}

For monochrome displays, pixel would be called with a plain u8 as in the current API. For RGB displays, it would be called with the RGB intensity type.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant