stusb4500/
lib.rs

1#![no_std]
2
3extern crate bitflags;
4extern crate byteorder;
5extern crate embedded_hal as hal;
6
7use byteorder::{ByteOrder, LittleEndian};
8use hal::blocking::i2c;
9
10pub mod pdo;
11pub mod rdo;
12pub mod registers;
13
14use pdo::*;
15use rdo::*;
16use registers::*;
17
18pub const STUSB4500_ADDR: u8 = 0x28;
19
20/// Address enum for STUSB4500
21pub enum Address {
22    /// Default address with all address pins tied low
23    Default,
24    /// Address determined by A1 and A0 pins. True = tied high, low = tied low.
25    Strap(bool, bool),
26    /// Custom address from config file etc
27    Custom(u8),
28}
29
30impl Address {
31    pub(crate) fn addr(&self) -> u8 {
32        match self {
33            Address::Default => STUSB4500_ADDR,
34            Address::Strap(a1, a0) => STUSB4500_ADDR | (*a1 as u8) << 1 | (*a0 as u8) << 0,
35            Address::Custom(addr) => *addr,
36        }
37    }
38}
39
40impl Default for Address {
41    fn default() -> Self {
42        Address::Default
43    }
44}
45
46#[derive(Debug)]
47pub enum Error<I2C> {
48    I2CError(I2C),
49    InvalidPdo,
50    OutaRangePdo,
51}
52
53pub enum PdoChannel {
54    PDO1,
55    PDO2,
56    PDO3,
57}
58
59pub struct STUSB4500<I2C> {
60    i2c: I2C,
61    address: u8,
62}
63
64impl<I2C, E> STUSB4500<I2C>
65where
66    I2C: i2c::Write<Error = E> + i2c::Read<Error = E>,
67{
68    pub fn new(i2c: I2C, address: Address) -> Self {
69        STUSB4500 {
70            i2c,
71            address: address.addr(),
72        }
73    }
74
75    /// Read all interrupt registers to clear them
76    pub fn clear_interrupts(&mut self) -> Result<(), Error<E>> {
77        // Read all interrupt registers
78        let mut _buf = [0x00; 10];
79        self.i2c
80            .write(self.address, &[Register::PortStatus0 as u8])
81            .map_err(|err| Error::I2CError(err))?;
82        self.i2c
83            .read(self.address, &mut _buf)
84            .map_err(|err| Error::I2CError(err))
85    }
86
87    /// Set interrupt mask
88    pub fn set_alerts_mask(&mut self, alerts: AlertMask) -> Result<(), Error<E>> {
89        self.write(Register::AlertStatus1Mask, alerts.bits())
90    }
91
92    /// Get active interrupt flags
93    pub fn get_alerts(&mut self) -> Result<Alert, Error<E>> {
94        Ok(Alert::from_bits_truncate(
95            self.read(Register::AlertStatus1)?,
96        ))
97    }
98
99    /// Perform a soft reset
100    /// Triggers re-negotiation of PDO's.
101    pub fn soft_reset(&mut self) -> Result<(), Error<E>> {
102        self.write(Register::TXHeaderL, 0x0D)?;
103        self.write(Register::PDCommandCtrl, 0x26)?;
104        Ok(())
105    }
106
107    pub fn set_pdo(&mut self, pdo: PdoChannel, data: &Pdo) -> Result<(), Error<E>> {
108        if let Pdo::Fixed { .. } = data {
109            self.write_word(
110                match pdo {
111                    PdoChannel::PDO1 => Register::DPMSNKPDO1,
112                    PdoChannel::PDO2 => Register::DPMSNKPDO2,
113                    PdoChannel::PDO3 => Register::DPMSNKPDO3,
114                },
115                data.bits(),
116            )
117        } else {
118            // Can only advertise fixed PDOs
119            Err(Error::InvalidPdo)
120        }
121    }
122
123    pub fn get_pdo(&mut self, pdo: PdoChannel) -> Result<Pdo, Error<E>> {
124        Pdo::from_bits(self.read_word(match pdo {
125            PdoChannel::PDO1 => Register::DPMSNKPDO1,
126            PdoChannel::PDO2 => Register::DPMSNKPDO2,
127            PdoChannel::PDO3 => Register::DPMSNKPDO3,
128        })?)
129        .ok_or(Error::InvalidPdo)
130    }
131
132    pub fn get_current_rdo(&mut self) -> Result<Rdo, Error<E>> {
133        Ok(Rdo(self.read_word(Register::RDORegStatus)?))
134    }
135
136    pub fn set_num_pdo(&mut self, num: u8) -> Result<(), Error<E>> {
137        match num {
138            1..=3 => self.write(Register::DPMPDONumb, num),
139            _ => Err(Error::OutaRangePdo),
140        }
141    }
142
143    /// Unlock the NVM for reading and writing
144    pub fn unlock_nvm(&mut self) -> Result<STUSB4500Nvm<I2C>, Error<E>> {
145        STUSB4500Nvm::unlock(self)
146    }
147
148    // *****************************************************************
149    // Raw access functions
150
151    /// Write a byte register
152    pub(crate) fn write(&mut self, register: Register, value: u8) -> Result<(), Error<E>> {
153        let buf = [register as u8, value];
154        self.i2c
155            .write(self.address, &buf)
156            .map_err(|err| Error::I2CError(err))
157    }
158
159    /// Write a word register
160    pub(crate) fn write_word(&mut self, register: Register, word: u32) -> Result<(), Error<E>> {
161        let mut buf = [0x00; 5];
162        buf[0] = register as u8;
163        LittleEndian::write_u32(&mut buf[1..], word);
164        self.i2c
165            .write(self.address, &buf)
166            .map_err(|err| Error::I2CError(err))
167    }
168
169    /// Read a byte register
170    pub(crate) fn read(&mut self, register: Register) -> Result<u8, Error<E>> {
171        let mut buf = [0x00; 1];
172        self.i2c
173            .write(self.address, &[register as u8])
174            .map_err(|err| Error::I2CError(err))?;
175        self.i2c
176            .read(self.address, &mut buf)
177            .map_err(|err| Error::I2CError(err))?;
178        Ok(buf[0])
179    }
180
181    /// Read a word register
182    pub(crate) fn read_word(&mut self, register: Register) -> Result<u32, Error<E>> {
183        let mut buf = [0x00; 4];
184        self.i2c
185            .write(self.address, &[register as u8])
186            .map_err(|err| Error::I2CError(err))?;
187        self.i2c
188            .read(self.address, &mut buf)
189            .map_err(|err| Error::I2CError(err))?;
190        Ok(LittleEndian::read_u32(&buf))
191    }
192}
193
194pub struct STUSB4500Nvm<'a, I2C> {
195    inner: &'a mut STUSB4500<I2C>,
196}
197
198impl<I2C, E> STUSB4500Nvm<'_, I2C>
199where
200    I2C: i2c::Write<Error = E> + i2c::Read<Error = E>,
201{
202    const DEFAULT_PASSWORD: u8 = 0x47;
203
204    pub(crate) fn unlock(inner: &mut STUSB4500<I2C>) -> Result<STUSB4500Nvm<I2C>, Error<E>> {
205        inner.write(Register::NvmPassword, STUSB4500Nvm::<I2C>::DEFAULT_PASSWORD)?;
206        inner.write(Register::NvmCtrl0, 0x00)?;
207        inner.write(
208            Register::NvmCtrl0,
209            (NvmCtrl0::Power | NvmCtrl0::Enable).bits(),
210        )?;
211
212        Ok(STUSB4500Nvm { inner })
213    }
214
215    /// Lock the NVM
216    pub fn lock(self) -> Result<(), Error<E>> {
217        self.inner
218            .write(Register::NvmCtrl0, NvmCtrl0::Enable.bits())?;
219        self.inner.write(Register::NvmCtrl1, 0x00)?;
220        self.inner.write(Register::NvmPassword, 0x00)
221    }
222
223    /// Read the NVM data (all five sectors)
224    ///
225    /// The NVM data is used to set the configuration on power-up. It can be decoded by the [GUI
226    /// application][gui].
227    ///
228    /// [gui]: https://www.st.com/en/embedded-software/stsw-stusb002.html
229    pub fn read_sectors(&mut self) -> Result<[[u8; 8]; 5], Error<E>> {
230        let mut buf = [[0x00; 8]; 5];
231        for (i, sector) in buf.iter_mut().enumerate() {
232            *sector = self.read_sector(i as u8)?;
233        }
234        Ok(buf)
235    }
236
237    /// Write the NVM data (all five sectors)
238    ///
239    /// The NVM data is used to set the configuration on power-up. It can be generated by the [GUI
240    /// application][gui].
241    ///
242    /// [gui]: https://www.st.com/en/embedded-software/stsw-stusb002.html
243    pub fn write_sectors(&mut self, sectors: [[u8; 8]; 5]) -> Result<(), Error<E>> {
244        self.erase_sectors()?;
245        for (i, sector) in sectors.iter().enumerate() {
246            self.write_sector(i as u8, sector)?;
247        }
248        Ok(())
249    }
250
251    fn issue_request(&mut self) -> Result<(), Error<E>> {
252        self.issue_request_with_sector(0)
253    }
254
255    fn issue_request_with_sector(&mut self, sector: u8) -> Result<(), Error<E>> {
256        self.inner.write(
257            Register::NvmCtrl0,
258            sector | (NvmCtrl0::Power | NvmCtrl0::Enable | NvmCtrl0::Request).bits(),
259        )?;
260
261        while NvmCtrl0::from_bits_truncate(self.inner.read(Register::NvmCtrl0)?)
262            .contains(NvmCtrl0::Request)
263        {}
264
265        Ok(())
266    }
267
268    fn read_sector(&mut self, sector: u8) -> Result<[u8; 8], Error<E>> {
269        self.inner
270            .write(Register::NvmCtrl1, NvmCtrl1Opcode::ReadSector as u8)?;
271        self.issue_request_with_sector(sector)?;
272
273        let mut buf = [0x00; 8];
274        self.inner
275            .i2c
276            .write(self.inner.address, &[Register::RWBuffer as u8])
277            .map_err(|err| Error::I2CError(err))?;
278        self.inner
279            .i2c
280            .read(self.inner.address, &mut buf)
281            .map_err(|err| Error::I2CError(err))?;
282        Ok(buf)
283    }
284
285    fn write_sector(&mut self, sector: u8, data: &[u8; 8]) -> Result<(), Error<E>> {
286        let mut buf = [0x00; 9];
287        buf[0] = Register::RWBuffer as u8;
288        buf[1..].copy_from_slice(data);
289
290        self.inner
291            .i2c
292            .write(self.inner.address, &buf)
293            .map_err(|err| Error::I2CError(err))?;
294        self.inner
295            .write(Register::NvmCtrl1, NvmCtrl1Opcode::LoadPlr as u8)?;
296        self.issue_request()?;
297
298        self.inner
299            .write(Register::NvmCtrl1, NvmCtrl1Opcode::WriteSector as u8)?;
300        self.issue_request_with_sector(sector)
301    }
302
303    fn erase_sectors(&mut self) -> Result<(), Error<E>> {
304        self.inner.write(
305            Register::NvmCtrl1,
306            NvmCtrl1Opcode::LoadSer as u8
307                | (NvmCtrl1::EraseSector0
308                    | NvmCtrl1::EraseSector1
309                    | NvmCtrl1::EraseSector2
310                    | NvmCtrl1::EraseSector3
311                    | NvmCtrl1::EraseSector4)
312                    .bits(),
313        )?;
314        self.issue_request()?;
315
316        self.inner
317            .write(Register::NvmCtrl1, NvmCtrl1Opcode::EraseSectors as u8)?;
318        self.issue_request()
319    }
320}