1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
//! LP55231
//!
//! This is a driver for the [TI LP55231](http://www.ti.com/product/LP55231) RGB LED controller IC
//! using the [`embedded_hal`](https://github.com/rust-embedded/embedded-hal/) traits.
//!
//! NOTE that this driver is not yet platform agnostic, as it relies on `cortex_m` for a delay.
//!
//! This driver optionally takes a [digital output
//! pin](https://docs.rs/embedded-hal/0.2.1/embedded_hal/digital/trait.OutputPin.html) to control
//! power to the LP55231. It will drive the pin (digital) high on power-on, and (digital) low on
//! power-off.
#![no_std]
#![deny(missing_docs)]

extern crate embedded_hal as hal;
#[macro_use]
extern crate bitflags;

use core::fmt::Debug;
use hal::blocking::i2c::{Write, WriteRead};
use hal::digital::OutputPin;

pub mod registers;
use registers as reg;

#[derive(Debug)]
/// Error conditions returned by the LP55231
pub enum Error<I> {
    /// The LP is not currently enabled
    NotEnabled,
    /// Generic I2c error
    I2cError(I),
}

#[derive(Copy, Clone)]
/// Available I2C addresses for the part
pub enum Addr {
    /// ASEL1=GND, ASEL2=GND
    _0x32,
    /// ASEL1=GND, ASEL2=VEN
    _0x33,
    /// ASEL1=VEN, ASEL2=GND
    _0x34,
    /// ASEL1=VEN, ASEL2=VEN
    _0x35,
}

impl From<Addr> for u8 {
    fn from(a: Addr) -> Self {
        match a {
            Addr::_0x32 => 0x32_u8,
            Addr::_0x33 => 0x33_u8,
            Addr::_0x34 => 0x34_u8,
            Addr::_0x35 => 0x35_u8,
        }
    }
}

#[derive(Debug, Copy, Clone)]
/// Enumeration of the 9 LED lines from the chip
pub enum D {
    /// LED line D1
    D1,
    /// LED line D2
    D2,
    /// LED line D3
    D3,
    /// LED line D4
    D4,
    /// LED line D5
    D5,
    /// LED line D6
    D6,
    /// LED line D7
    D7,
    /// LED line D8
    D8,
    /// LED line D9
    D9,
}

impl From<D> for u8 {
    fn from(d: D) -> Self {
        match d {
            D::D1 => 0,
            D::D2 => 1,
            D::D3 => 2,
            D::D4 => 3,
            D::D5 => 4,
            D::D6 => 5,
            D::D7 => 6,
            D::D8 => 7,
            D::D9 => 8,
        }
    }
}

/// The LP55231 device
pub struct Lp55231<I, P> {
    /// The owned I2C bus
    i2c: I,
    /// The owned enable pin
    en_pin: Option<P>,
    /// The I2C address of this device
    addr: u8,
    /// Has the LP55231 been enabled
    en: bool,
}

impl<E, I, P> Lp55231<I, P>
where
    E: Debug,
    I: Write<Error = E> + WriteRead<Error = E>,
    P: OutputPin,
{

    /// Create a new instance of an LP55231 that exclusively owns its I2C bus. Optionally takes a
    /// power control pin.
    pub fn new(i2c: I, en_pin: Option<P>, addr: Addr) -> Self {
        Lp55231 {
            i2c,
            en_pin,
            addr: u8::from(addr) << 1,
            en: false,
        }
    }

    /// Convenience method to call `self.i2c.write` with `self.addr`
    fn send(&mut self, bytes: &[u8]) -> Result<(), Error<E>> {
        if self.en {
            self.i2c.write(self.addr, bytes).map_err(|e| Error::I2cError(e))
        } else {
            Err(Error::NotEnabled)
        }
    }

    /// Enable the device for use
    ///
    /// Sets the enable line high, then sends an enable command, waits 500us, and then configures
    /// to device to use its internal clock, enable the charge pump at 1.5x boost, and
    /// auto-increment on writes.
    pub fn enable(&mut self) -> Result<(), Error<E>> {
        if let Some(p) = self.en_pin.as_mut() {
            p.set_high();
        }
        // TODO there should be a 500us delay here, but the chip appears to mostly work without it,
        // so I'm not going to worry about it now. Ideally, this function should take a
        // `embedded_hal::delay::Delay` and wait.
        self.en = true;
        self.send(&[reg::CNTRL1, (reg::Cntrl1::CHIP_EN).bits()])?;
        self.send(&[
                  reg::MISC,
                  (reg::Misc::INT_CLK_EN
                   | reg::Misc::CLK_DET_EN
                   | reg::Misc::CP_MODE_1_5x
                   | reg::Misc::EN_AUTO_INCR)
                  .bits(),
        ])?;
        Ok(())
    }

    /// Soft-reset the device NOW
    pub fn reset(&mut self) -> Result<(), Error<E>> {
        self.send(&[reg::Reset::RESET_NOW.bits()])?;
        Ok(())
    }

    /// Turn off the device NOW
    pub fn disable(&mut self) {
        if let Some(p) = self.en_pin.as_mut() {
            p.set_low();
        }
        self.en = false;
    }

    /// Set the D line to the provided PWM value
    pub fn set_pwm(&mut self, d: D, pwm: u8) -> Result<(), Error<E>> {
        self.send(&[reg::D_PWM_BASE + u8::from(d), pwm])?;
        Ok(())
    }
}