#![no_std]
#![allow(dead_code)]
mod error;
mod fmt;
use embedded_hal::i2c::I2c;
pub use error::Error;
const ADDR_BASE: u8 = 0x80;
const SLEEP_ENABLE_MASK: u8 = 0;
const SLEEP_DISABLE_MASK: u8 = 0x20;
const OUT_ENABLE_MASK: u8 = 0;
const OUT1_CURRENT_MASK: u8 = 0x1;
const OUT2_CURRENT_MASK: u8 = 0x2;
const OUT3_CURRENT_MASK: u8 = 0x3;
const OUT4_CURRENT_MASK: u8 = 0x4;
const OUT5_CURRENT_MASK: u8 = 0x5;
const OUT1_GRAYSCALE_MASK: u8 = 0x6;
const OUT2_GRAYSCALE_MASK: u8 = 0x8;
const OUT3_GRAYSCALE_MASK: u8 = 0xA;
const OUT4_GRAYSCALE_MASK: u8 = 0xC;
const OUT5_GRAYSCALE_MASK: u8 = 0xE;
const OUT_ALL_ENABLE: u8 = 0x1F;
const OUT_ALL_DISABLE: u8 = 0x00;
pub enum Bp5758dChannel {
OUT1,
OUT2,
OUT3,
OUT4,
OUT5,
}
impl Bp5758dChannel {
const fn get_grayscale_mask(&self) -> u8 {
match self {
Bp5758dChannel::OUT1 => OUT1_GRAYSCALE_MASK,
Bp5758dChannel::OUT2 => OUT2_GRAYSCALE_MASK,
Bp5758dChannel::OUT3 => OUT3_GRAYSCALE_MASK,
Bp5758dChannel::OUT4 => OUT4_GRAYSCALE_MASK,
Bp5758dChannel::OUT5 => OUT5_GRAYSCALE_MASK,
}
}
}
pub struct Bp5758d<T: I2c> {
sleeping: bool,
mapping: [u8; 5], max_current: [u8; 5],
i2c: T,
}
impl<T: I2c> Bp5758d<T> {
pub fn new(
driver: T,
channel_mapping: [u8; 5],
mut max_current: [u8; 5],
) -> Result<Self, Error<T::Error>> {
for i in channel_mapping {
if i > 5 {
return Err(Error::InvalidArg);
}
}
validate_transform_current(&mut max_current)?;
Ok(Self {
sleeping: true,
i2c: driver,
mapping: channel_mapping,
max_current,
})
}
pub fn set_channel(
&mut self,
channel: Bp5758dChannel,
value: u16,
) -> Result<(), Error<T::Error>> {
if value >= 1024 {
return Err(Error::InvalidArg);
}
let mut addr = ADDR_BASE | SLEEP_DISABLE_MASK;
let mut data = [0; 2];
addr |= channel.get_grayscale_mask();
data[0] = (value & 0x1F) as u8;
data[1] = (value >> 5) as u8;
if self.sleeping {
self.set_sleep(false)?;
}
self.write(addr, &data)?;
Ok(())
}
pub fn set_rgbcw(
&mut self,
r: u16,
g: u16,
b: u16,
c: u16,
w: u16,
) -> Result<(), Error<T::Error>> {
let addr = ADDR_BASE | SLEEP_DISABLE_MASK | OUT1_GRAYSCALE_MASK;
let mut data = [0; 10];
let values = [r, g, b, c, w];
for (i, value) in values.iter().enumerate() {
if *value >= 1024 {
return Err(Error::InvalidArg);
}
let chann = self.mapping[i] as usize - 1;
data[2 * chann] = (value & 0x1F) as u8;
data[2 * chann + 1] = (value >> 5) as u8;
}
if self.sleeping {
self.set_sleep(false)?;
}
self.write(addr, &data)?;
Ok(())
}
pub fn set_sleep(&mut self, sleep: bool) -> Result<(), Error<T::Error>> {
let mut addr = ADDR_BASE | OUT_ENABLE_MASK;
let mut data = [0; 6];
if sleep {
addr |= SLEEP_ENABLE_MASK;
data[0] = OUT_ALL_DISABLE;
self.set_shutdown()?;
self.write(addr, &data)?;
self.sleeping = true;
} else {
addr |= SLEEP_DISABLE_MASK;
data[0] = OUT_ALL_ENABLE;
data[1..6].copy_from_slice(&self.max_current);
self.write(addr, &data)?;
self.sleeping = false;
}
Ok(())
}
fn set_shutdown(&mut self) -> Result<(), Error<T::Error>> {
let addr = ADDR_BASE | SLEEP_DISABLE_MASK | OUT1_GRAYSCALE_MASK;
let data = [0; 10];
self.write(addr, &data)?;
Ok(())
}
#[inline(always)]
fn write(&mut self, addr: u8, data: &[u8]) -> Result<(), Error<T::Error>> {
info!("writing: {:x?} at {:x}", data, addr);
self.i2c.write(addr, data)?;
Ok(())
}
}
impl<T: I2c> Drop for Bp5758d<T> {
fn drop(&mut self) {
if !self.sleeping {
if let Err(err) = self.set_sleep(true) {
error!("Failed to set sleep: {}", err);
}
}
}
}
fn validate_transform_current<E: embedded_hal::i2c::Error>(
values: &mut [u8; 5],
) -> Result<(), Error<E>> {
for i in values {
if *i > 90 {
return Err(Error::InvalidArg);
}
if *i > 64 {
*i -= 62;
*i |= 0x60;
}
}
Ok(())
}