use embedded_hal::spi::SpiBus;
use crate::transport::neopixel::NeoPixelTransport;
pub const MAX_PIXELS: usize = 256;
const MAX_BUF: usize = MAX_PIXELS * 4;
pub struct Sk6812RgbwMinimal<SPI> {
transport: NeoPixelTransport<SPI>,
n: usize,
buf: heapless::Vec<u8, MAX_BUF>,
}
impl<SPI: SpiBus> Sk6812RgbwMinimal<SPI> {
pub fn new(spi: SPI, n: usize) -> Self {
let n = n.min(MAX_PIXELS);
let mut buf = heapless::Vec::new();
buf.resize_default(n * 4).ok();
Self {
transport: NeoPixelTransport::new(spi),
n,
buf,
}
}
pub fn fill(&mut self, r: u8, g: u8, b: u8, w: u8) -> Result<(), SPI::Error> {
for i in 0..self.n {
self.buf[i * 4] = g;
self.buf[i * 4 + 1] = r;
self.buf[i * 4 + 2] = b;
self.buf[i * 4 + 3] = w;
}
self.transport.write(&self.buf[..self.n * 4])
}
pub fn off(&mut self) -> Result<(), SPI::Error> {
self.fill(0, 0, 0, 0)
}
}
pub struct Sk6812RgbwFull<SPI> {
inner: Sk6812RgbwMinimal<SPI>,
brightness: u8,
}
impl<SPI: SpiBus> Sk6812RgbwFull<SPI> {
pub fn new(spi: SPI, n: usize) -> Self {
Self {
inner: Sk6812RgbwMinimal::new(spi, n),
brightness: 255,
}
}
pub fn fill(&mut self, r: u8, g: u8, b: u8, w: u8) -> Result<(), SPI::Error> {
self.inner.fill(r, g, b, w)
}
pub fn off(&mut self) -> Result<(), SPI::Error> {
self.inner.off()
}
pub fn set_pixel(&mut self, index: usize, r: u8, g: u8, b: u8, w: u8) {
let index = index.min(self.inner.n.saturating_sub(1));
self.inner.buf[index * 4] = g;
self.inner.buf[index * 4 + 1] = r;
self.inner.buf[index * 4 + 2] = b;
self.inner.buf[index * 4 + 3] = w;
}
pub fn show(&mut self) -> Result<(), SPI::Error> {
let bri = self.brightness;
let n4 = self.inner.n * 4;
if bri == 255 {
return self.inner.transport.write(&self.inner.buf[..n4]);
}
let mut scaled: heapless::Vec<u8, MAX_BUF> = heapless::Vec::new();
scaled.resize_default(n4).ok();
for i in 0..n4 {
scaled[i] = (self.inner.buf[i] as u16 * bri as u16 / 255) as u8;
}
self.inner.transport.write(&scaled[..n4])
}
pub fn get_brightness(&self) -> u8 {
self.brightness
}
pub fn set_brightness(&mut self, value: u8) {
self.brightness = value;
}
pub fn rotate(&mut self, steps: usize) {
let n = self.inner.n;
if n == 0 { return; }
let steps = steps % n;
if steps == 0 { return; }
let bytes = steps * 4;
let n4 = n * 4;
let mut tmp: heapless::Vec<u8, MAX_BUF> = heapless::Vec::new();
tmp.extend_from_slice(&self.inner.buf[..bytes]).ok();
self.inner.buf.copy_within(bytes..n4, 0);
for (i, &v) in tmp.iter().enumerate() {
self.inner.buf[n4 - bytes + i] = v;
}
}
pub fn fill_hsv(&mut self, h: f32, s: f32, v: f32) -> Result<(), SPI::Error> {
let (r, g, b) = hsv_to_rgb(h, s, v);
self.fill(r, g, b, 0)
}
}
use super::color::hsv_to_rgb;