#![cfg_attr(not(test), no_std)]
use embedded_hal::blocking::i2c::{Read, Write, WriteRead};
const DEVICE_ADDRESS: u8 = 0x54;
#[derive(Debug)]
pub enum Error<I> {
I2C(I),
Conn,
Address,
Port,
}
pub struct Is31Fl3218<I2C> {
i2c: I2C,
cmd_buf: [u8; 23],
}
impl<I2C, S> Is31Fl3218<I2C>
where
I2C: Write<u8, Error = S> + Read<u8, Error = S> + WriteRead<u8, Error = S>,
{
pub fn new(i2c: I2C) -> Self {
Self {
i2c,
cmd_buf: [0; 23],
}
}
fn write_raw(&mut self, len: usize) -> Result<(), Error<S>> {
self.i2c
.write(DEVICE_ADDRESS, &self.cmd_buf[..=len])
.map_err(Error::I2C)?;
Ok(())
}
fn write(&mut self, register: u8, values: &[u8]) -> Result<(), Error<S>> {
let len = values.len();
if len > 23 {
return Err(Error::Address);
}
self.cmd_buf[0x0] = register;
self.cmd_buf[0x1..=len].copy_from_slice(values);
self.write_raw(len)?;
Ok(())
}
pub fn enable_device(&mut self) -> Result<(), Error<S>> {
self.write(0x0, &[0x1])?;
Ok(())
}
pub fn shutdown_device(&mut self) -> Result<(), Error<S>> {
self.write(0x0, &[0])?;
Ok(())
}
pub fn enable_channel(&mut self, led: usize) -> Result<(), Error<S>> {
if led > 0x11 {
return Err(Error::Address);
}
let register: u8 = 0x13 + led as u8 / 6;
let bit: u8 = (led as u8 - 1) % 6;
self.write(register, &[1 << bit])?;
self.write(0x16, &[0])?;
Ok(())
}
pub fn enable_all(&mut self) -> Result<(), Error<S>> {
self.write(0x13, &[0x3f; 3])?;
self.write(0x16, &[0])?;
Ok(())
}
pub fn set(&mut self, led: usize, brightness: u8) -> Result<(), Error<S>> {
if led > 0x11 {
return Err(Error::Address);
}
self.write(0x1 + led as u8, &[brightness])?;
self.write(0x16, &[0])?;
Ok(())
}
pub fn set_many(&mut self, start_led: usize, values: &[u8]) -> Result<(), Error<S>> {
let len = values.len();
if start_led + len > 0x12 {
return Err(Error::Address);
}
self.write(0x1 + start_led as u8, values)?;
self.write(0x16, &[0])?;
Ok(())
}
pub fn set_all(&mut self, values: &[u8; 18]) -> Result<(), Error<S>> {
self.cmd_buf[0] = 0x1;
self.cmd_buf[0x1..=0x12].copy_from_slice(values);
self.cmd_buf[0x13..=0x15].copy_from_slice(&[0x3f; 3]);
self.cmd_buf[0x16] = 0x0;
self.write_raw(22)?;
Ok(())
}
pub fn reset(&mut self) -> Result<(), Error<S>> {
self.write(0x17, &[0])?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use embedded_hal_mock::i2c::{Mock as I2cMock, Transaction as I2cTransaction};
#[test]
fn init() {
let mut i2c = I2cMock::new([]);
i2c.expect(&[
I2cTransaction::write(DEVICE_ADDRESS, vec![0, 1]),
I2cTransaction::write(DEVICE_ADDRESS, vec![21, 4]),
I2cTransaction::write(DEVICE_ADDRESS, vec![22, 0]),
I2cTransaction::write(
DEVICE_ADDRESS,
vec![
1, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 63, 63, 63, 0, ],
),
]);
let mut led_driver = Is31Fl3218::new(i2c);
led_driver.enable_device().unwrap();
led_driver.enable_channel(15).unwrap();
led_driver.set_all(&[255; 18]).unwrap();
}
}