Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Added
- Add a `reset_single_transaction` feature for the `prerendered` version, which uses a single SPI transaction for a `write` call. Can be useful if using a DMA-approach or you're experiencing glitches due to the SPI peripheral turning high between the data and the reset.
- Add `pixel_order` to allow for non-standard pixel orders

### Changed
- Using the `mosi_idle_high` feature with the `prerendered` version now sends out the first reset together with the data, thus requiring a larger data buffer (but avoids potentially long dead-time between the first reset and the data being sent).
Expand Down
34 changes: 22 additions & 12 deletions src/hosted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! This dynamically allocates an output buffer and writes out the data in a single call.
//! Much better suited for linux or similar environments, but may not always work
//!
//! Intendded for use with rppal or linux-embedded-hal
//! Intended for use with rppal or linux-embedded-hal

use embedded_hal as hal;

Expand All @@ -16,6 +16,9 @@ use smart_leds_trait::{SmartLedsWrite, RGB8, RGBW};
use std::vec;
use std::vec::Vec;

use crate::pixel_order;
use crate::OrderedColors;

/// SPI mode that can be used for this crate
///
/// Provided for convenience
Expand All @@ -30,15 +33,17 @@ pub mod devices {
pub struct Sk6812w;
}

pub struct Ws2812<SPI, DEVICE = devices::Ws2812> {
pub struct Ws2812<SPI, DEVICE = devices::Ws2812, PIXELORDER = pixel_order::GRB> {
spi: SPI,
data: Vec<u8>,
device: PhantomData<DEVICE>,
_device: PhantomData<DEVICE>,
_pixel_order: PhantomData<PIXELORDER>,
}

impl<SPI, E> Ws2812<SPI>
impl<SPI, E, PO> Ws2812<SPI, devices::Ws2812, PO>
where
SPI: SpiBus<u8, Error = E>,
PO: OrderedColors,
{
/// Use ws2812 devices via spi
///
Expand All @@ -52,7 +57,8 @@ where
Self {
spi,
data,
device: PhantomData {},
_device: PhantomData {},
_pixel_order: PhantomData {},
}
}
}
Expand All @@ -75,12 +81,13 @@ where
Self {
spi,
data,
device: PhantomData {},
_device: PhantomData {},
_pixel_order: PhantomData {},
}
}
}

impl<SPI, D, E> Ws2812<SPI, D>
impl<SPI, D, E> Ws2812<SPI, D, PO>
where
SPI: SpiBus<u8, Error = E>,
{
Expand All @@ -105,9 +112,10 @@ where
}
}

impl<SPI, E> SmartLedsWrite for Ws2812<SPI>
impl<SPI, E, PO> SmartLedsWrite for Ws2812<SPI, devices::Ws2812, PO>
where
SPI: SpiBus<u8, Error = E>,
PO: OrderedColors,
{
type Error = E;
type Color = RGB8;
Expand All @@ -118,10 +126,11 @@ where
I: Into<Self::Color>,
{
for item in iterator {
let item = item.into();
self.write_byte(item.g);
self.write_byte(item.r);
self.write_byte(item.b);
let color: RGB8 = item.into();
let ordered_color = PO::order(color);
self.write_byte(ordered_color[0]);
self.write_byte(ordered_color[1]);
self.write_byte(ordered_color[2]);
}
self.send_data()
}
Expand All @@ -141,6 +150,7 @@ where
{
for item in iterator {
let item = item.into();
// SK6812W always expects GRBW order
self.write_byte(item.g);
self.write_byte(item.r);
self.write_byte(item.b);
Expand Down
67 changes: 54 additions & 13 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,51 @@ pub mod devices {
pub struct Sk6812w;
}

pub struct Ws2812<SPI, DEVICE = devices::Ws2812> {
/// The color order the WS2812-like device expects. In most cases, this is GRB
/// and doesn't need to be specified separately.
///
/// For SK6812W devices (with a separate white channel) this is unused
pub mod pixel_order {
pub struct RGB;
pub struct RBG;
pub struct GRB;
pub struct GBR;
pub struct BRG;
pub struct BGR;
}

/// Used to define the pixel order, refer to the pixel_order module
pub trait OrderedColors {
fn order(color: RGB8) -> [u8; 3];
}

macro_rules! impl_ordered_colors {
($struct_name:ident, $r_field:ident, $g_field:ident, $b_field:ident) => {
impl OrderedColors for pixel_order::$struct_name {
fn order(color: RGB8) -> [u8; 3] {
[color.$r_field, color.$g_field, color.$b_field]
}
}
};
}

impl_ordered_colors!(RGB, r, g, b);
impl_ordered_colors!(RBG, r, b, g);
impl_ordered_colors!(GRB, g, r, b);
impl_ordered_colors!(GBR, g, b, r);
impl_ordered_colors!(BRG, b, r, g);
impl_ordered_colors!(BGR, b, g, r);

pub struct Ws2812<SPI, DEVICE = devices::Ws2812, PIXELORDER = pixel_order::GRB> {
spi: SPI,
device: PhantomData<DEVICE>,
_device: PhantomData<DEVICE>,
_pixel_order: PhantomData<PIXELORDER>,
}

impl<SPI, E> Ws2812<SPI>
impl<SPI, E, PO> Ws2812<SPI, devices::Ws2812, PO>
where
SPI: SpiBus<u8, Error = E>,
PO: OrderedColors,
{
/// Use ws2812 devices via spi
///
Expand All @@ -59,12 +96,13 @@ where
pub fn new(spi: SPI) -> Self {
Self {
spi,
device: PhantomData {},
_device: PhantomData {},
_pixel_order: PhantomData {},
}
}
}

impl<SPI, E> Ws2812<SPI, devices::Sk6812w>
impl<SPI, E, PO> Ws2812<SPI, devices::Sk6812w, PO>
where
SPI: SpiBus<u8, Error = E>,
{
Expand All @@ -81,12 +119,13 @@ where
pub fn new_sk6812w(spi: SPI) -> Self {
Self {
spi,
device: PhantomData {},
_device: PhantomData {},
_pixel_order: PhantomData {},
}
}
}

impl<SPI, D, E> Ws2812<SPI, D>
impl<SPI, D, E, PO> Ws2812<SPI, D, PO>
where
SPI: SpiBus<u8, Error = E>,
{
Expand All @@ -113,7 +152,7 @@ where
}
}

impl<SPI, E> SmartLedsWrite for Ws2812<SPI>
impl<SPI, E, PO: OrderedColors> SmartLedsWrite for Ws2812<SPI, devices::Ws2812, PO>
where
SPI: SpiBus<u8, Error = E>,
{
Expand All @@ -130,17 +169,18 @@ where
}

for item in iterator {
let item = item.into();
self.write_byte(item.g)?;
self.write_byte(item.r)?;
self.write_byte(item.b)?;
let color: RGB8 = item.into();
let ordered_color = PO::order(color);
self.write_byte(ordered_color[0])?;
self.write_byte(ordered_color[1])?;
self.write_byte(ordered_color[2])?;
}
self.reset()?;
Ok(())
}
}

impl<SPI, E> SmartLedsWrite for Ws2812<SPI, devices::Sk6812w>
impl<SPI, E, PO> SmartLedsWrite for Ws2812<SPI, devices::Sk6812w, PO>
where
SPI: SpiBus<u8, Error = E>,
{
Expand All @@ -158,6 +198,7 @@ where

for item in iterator {
let item = item.into();
// SK6812W always expects GRBW order
self.write_byte(item.g)?;
self.write_byte(item.r)?;
self.write_byte(item.b)?;
Expand Down
36 changes: 23 additions & 13 deletions src/prerendered.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ use smart_leds_trait::{SmartLedsWrite, RGB8, RGBW};

const RESET_DATA_LEN: usize = 140;

use crate::pixel_order;
use crate::OrderedColors;

/// SPI mode that can be used for this crate
///
/// Provided for convenience
Expand All @@ -33,16 +36,18 @@ pub mod devices {
pub struct Sk6812w;
}

pub struct Ws2812<'a, SPI, DEVICE = devices::Ws2812> {
pub struct Ws2812<'a, SPI, DEVICE = devices::Ws2812, PIXELORDER = pixel_order::GRB> {
spi: SPI,
data: &'a mut [u8],
index: usize,
device: PhantomData<DEVICE>,
_device: PhantomData<DEVICE>,
_pixel_order: PhantomData<PIXELORDER>,
}

impl<'a, SPI, E> Ws2812<'a, SPI>
impl<'a, SPI, E, PO> Ws2812<'a, SPI, devices::Ws2812, PO>
where
SPI: SpiBus<u8, Error = E>,
PO: OrderedColors,
{
/// Use WS2812 devices via SPI
///
Expand All @@ -63,12 +68,13 @@ where
spi,
data,
index: 0,
device: PhantomData {},
_device: PhantomData {},
_pixel_order: PhantomData {},
}
}
}

impl<'a, SPI, E> Ws2812<'a, SPI, devices::Sk6812w>
impl<'a, SPI, E, PO> Ws2812<'a, SPI, devices::Sk6812w, PO>
where
SPI: SpiBus<u8, Error = E>,
{
Expand All @@ -93,12 +99,13 @@ where
spi,
data,
index: 0,
device: PhantomData {},
_device: PhantomData {},
_pixel_order: PhantomData {},
}
}
}

impl<'a, SPI, D, E> Ws2812<'a, SPI, D>
impl<SPI, D, E, PO> Ws2812<'_, SPI, D, PO>
where
SPI: SpiBus<u8, Error = E>,
{
Expand Down Expand Up @@ -148,9 +155,10 @@ where
}
}

impl<'a, SPI, E> SmartLedsWrite for Ws2812<'a, SPI>
impl<SPI, E, PO> SmartLedsWrite for Ws2812<'_, SPI, devices::Ws2812, PO>
where
SPI: SpiBus<u8, Error = E>,
PO: OrderedColors,
{
type Error = Error<E>;
type Color = RGB8;
Expand All @@ -167,10 +175,11 @@ where
}

for item in iterator {
let item = item.into();
self.write_byte(item.g)?;
self.write_byte(item.r)?;
self.write_byte(item.b)?;
let color: RGB8 = item.into();
let ordered_color = PO::order(color);
self.write_byte(ordered_color[0])?;
self.write_byte(ordered_color[1])?;
self.write_byte(ordered_color[2])?;
}

if cfg!(feature = "reset_single_transaction") {
Expand All @@ -186,7 +195,7 @@ where
}
}

impl<'a, SPI, E> SmartLedsWrite for Ws2812<'a, SPI, devices::Sk6812w>
impl<SPI, E, PO> SmartLedsWrite for Ws2812<'_, SPI, devices::Sk6812w, PO>
where
SPI: SpiBus<u8, Error = E>,
{
Expand All @@ -206,6 +215,7 @@ where

for item in iterator {
let item = item.into();
// SK6812W always expects GRBW order
self.write_byte(item.g)?;
self.write_byte(item.r)?;
self.write_byte(item.b)?;
Expand Down