#![no_std]
#![allow(unused)]
use core::marker::PhantomData;
use embedded_hal::blocking::delay::DelayMs;
use embedded_hal::{
blocking::i2c::{Read, Write, WriteRead},
digital::v2::OutputPin,
};
#[derive(Debug)]
pub enum Error<I> {
I2C(I),
Conn,
Address,
Port,
InterfaceConfig,
EnableLine,
ChannelOutOfBounds,
}
pub trait Model {
fn register_value(register: Register) -> u8;
fn channel_count() -> usize;
}
pub struct IS31FL3205;
impl Model for IS31FL3205 {
fn register_value(register: Register) -> u8 {
match register {
Register::PowerControl => 0x00,
Register::Pwm => 0x07,
Register::Update => 0x49,
Register::LedScaling => 0x4D,
Register::GlobalCurrentControl => 0x6E,
Register::PhaseDelayClockPhase => 0x70,
Register::OpenShortDetectEnable => 0x71,
Register::LedOpenShort => 0x72,
Register::TemperatureSensor => 0x77,
Register::SpreadSpectrum => 0x78,
Register::Reset => 0x7F,
}
}
fn channel_count() -> usize {
12
}
}
pub struct IS31FL3237;
impl Model for IS31FL3237 {
fn register_value(register: Register) -> u8 {
match register {
Register::PowerControl => 0x00,
Register::Pwm => 0x01,
Register::Update => 0x49,
Register::LedScaling => 0x4A,
Register::GlobalCurrentControl => 0x6E,
Register::PhaseDelayClockPhase => 0x70,
Register::OpenShortDetectEnable => 0x71,
Register::LedOpenShort => 0x72,
Register::TemperatureSensor => 0x77,
Register::SpreadSpectrum => 0x78,
Register::Reset => 0x7F,
}
}
fn channel_count() -> usize {
36
}
}
#[derive(Copy, Clone)]
pub enum Register {
PowerControl,
Pwm,
Update,
LedScaling,
GlobalCurrentControl,
PhaseDelayClockPhase,
OpenShortDetectEnable,
LedOpenShort,
TemperatureSensor,
SpreadSpectrum,
Reset,
}
pub enum SoftwareShutdownMode {
SoftwareShutdown = 0b0,
Normal = 0b1,
}
pub enum PwmResolution {
Eightbit = 0b00,
Tenbit = 0b01,
TwelveBit = 0b10,
SixteenBit = 0b11,
}
pub enum OscillatorClock {
SixteenMHz = 0b000,
EightMHz = 0b001,
OneMHz = 0b010,
FiveHundredKHz = 0b011,
TwoHundredFiftyKHz = 0b100,
OneHundredTwentyFiveKHz = 0b101,
SixtyTwoKHz = 0b110,
ThirtyOneKHz = 0b111,
}
pub enum OpenShortDetect {
DetectDisable = 0x00,
ShortDetectEnable = 0x02,
OpenDetectEnable = 0x03,
}
pub struct Is31fl32xx<MODEL, I2C, EN> {
interface: Option<I2C>,
transfer_callback: Option<fn(addr: u8, data: &[u8])>,
address: u8,
enable: EN,
model: PhantomData<MODEL>,
}
pub struct Message<MODEL> {
register: Register,
register_offset: u8,
data: [u8; 24],
data_length: usize,
model: PhantomData<MODEL>,
}
impl<MODEL> Message<MODEL>
where
MODEL: Model,
{
fn new(register: Register, raw_data: &[u8]) -> Self {
let mut data = [0u8; 24];
data[0..raw_data.len()].copy_from_slice(raw_data);
Self {
register,
data,
data_length: raw_data.len(),
register_offset: 0,
model: PhantomData,
}
}
pub fn payload(&self) -> ([u8; 25], usize) {
let mut buff = [0u8; 25];
let data = &mut buff[0..self.data_length + 1];
data[0] = self.register_value() + self.register_offset;
data[1..self.data_length + 1].copy_from_slice(&self.data[0..self.data_length]);
(buff, self.data_length + 1)
}
fn register_value(&self) -> u8 {
MODEL::register_value(self.register)
}
fn register_offset(mut self, offset: u8) -> Self {
self.register_offset = offset;
self
}
pub fn power_control(
osc: OscillatorClock,
pms: PwmResolution,
ssd: SoftwareShutdownMode,
) -> Self {
Self::new(
Register::PowerControl,
&[(osc as u8) << 4 | (pms as u8) << 1 | (ssd as u8)],
)
}
pub fn pulse_width_modulation(channel: u8, value: u16) -> Self {
Self::new(Register::Pwm, &value.to_le_bytes()).register_offset(channel * 2)
}
pub fn update() -> Self {
Self::new(Register::Update, &[0x00])
}
pub fn global_current_control(value: u8) -> Self {
Self::new(Register::GlobalCurrentControl, &[value])
}
pub fn led_scaling(channel: u8, value: u8) -> Self {
Self::new(Register::LedScaling, &[value]).register_offset(channel)
}
}
impl<MODEL, I2C, EN, S> Is31fl32xx<MODEL, I2C, EN>
where
MODEL: Model,
I2C: Write<u8, Error = S> + Read<u8, Error = S> + WriteRead<u8, Error = S>,
EN: OutputPin,
{
pub fn init_with_callback(address: u8, en: EN, callback: fn(addr: u8, data: &[u8])) -> Self {
Self {
address,
interface: None,
transfer_callback: Some(callback),
enable: en,
model: PhantomData,
}
}
pub fn init_with_i2c(address: u8, en: EN, i2c: I2C) -> Self {
Self {
address,
interface: Some(i2c),
transfer_callback: None,
enable: en,
model: PhantomData,
}
}
pub fn release(self) -> (EN, Option<I2C>) {
(self.enable, self.interface)
}
fn write(&mut self, message: Message<MODEL>) -> Result<(), Error<S>> {
let mut buff: [u8; 24] = [0u8; 24];
let address = 0x34 | ((self.address & 0x3) << 1);
let data = &mut buff[0..message.data_length + 1];
data[0] = message.register_value() + message.register_offset;
data[1..message.data_length + 1].copy_from_slice(&message.data[0..message.data_length]);
if self.interface.is_some() {
self.interface
.as_mut()
.unwrap()
.write(address, &data[0..message.data_length + 1])
.map_err(Error::I2C)?;
} else if self.transfer_callback.is_some() {
self.transfer_callback.unwrap()(address, &data[0..message.data_length + 1]);
} else {
return Err(Error::InterfaceConfig);
}
Ok(())
}
pub fn enable_device<DEL: DelayMs<u8>>(
&mut self,
delay: &mut DEL,
osc: OscillatorClock,
pms: PwmResolution,
ssd: SoftwareShutdownMode,
) -> Result<(), Error<S>> {
self.enable.set_low().map_err(|_| Error::EnableLine)?;
delay.delay_ms(10_u8);
self.enable.set_high().map_err(|_| Error::EnableLine)?;
delay.delay_ms(10_u8);
self.write(Message::power_control(osc, pms, ssd))
}
pub fn set_global_current(&mut self, value: u8) -> Result<(), Error<S>> {
self.write(Message::global_current_control(value))
}
pub fn set_all_led_scaling(&mut self, value: u8) -> Result<(), Error<S>> {
for i in 0..MODEL::channel_count() {
self.write(Message::led_scaling(i as u8, value))?;
}
Ok(())
}
pub fn set_led_scaling(&mut self, channel: u8, value: u8) -> Result<(), Error<S>> {
self.write(Message::led_scaling(channel, value))
}
pub fn shutdown_device(&mut self) -> Result<(), Error<S>> {
self.write(Message::power_control(
OscillatorClock::FiveHundredKHz,
PwmResolution::Eightbit,
SoftwareShutdownMode::SoftwareShutdown,
))?;
self.enable.set_low().map_err(|_| Error::EnableLine)
}
pub fn set(&mut self, channel: u8, value: u16) -> Result<(), Error<S>> {
if channel as usize > MODEL::channel_count() - 1 {
return Err(Error::ChannelOutOfBounds);
}
self.write(Message::pulse_width_modulation(channel, value))?;
self.write(Message::update())
}
}