SatCat5
i2c_tca9548.cc
1 // Copyright 2023-2024 The Aerospace Corporation.
3 // This file is a part of SatCat5, licensed under CERN-OHL-W v2 or later.
5 
6 #include <hal_devices/i2c_tca9548.h>
7 
13 
14 Tca9548::Tca9548(I2cGeneric* i2c, const I2cAddr& devaddr)
15  : m_parent(i2c)
16  , m_devaddr(devaddr)
17  , m_cb_count(0)
18  , m_cb_rdidx(0)
19 {
20  // Nothing else to initialize.
21 }
22 
23 bool Tca9548::select_mask(u8 mask)
24 {
25  // Issue the "select" command only if bus is idle.
26  if (m_cb_count > 0) return false;
27  return m_parent->write(m_devaddr, 0, 0, 1, &mask);
28 }
29 
31 {
32  return (m_cb_count > 0) || m_parent->busy();
33 }
34 
35 bool Tca9548::read(const I2cAddr& devaddr,
36  u8 regbytes, u32 regaddr, u8 nread,
37  I2cEventListener* callback)
38 {
39  // Reject command if our callback queue is full.
40  if (m_cb_count >= SATCAT5_I2C_MAXCMD) return false;
41 
42  // Otherwise, store the pointer and call parent.
43  m_cb_queue[cb_wridx()] = callback;
44  bool ok = m_parent->read(devaddr, regbytes, regaddr, nread, this);
45 
46  // If the parent succeeds, increment the queue count.
47  if (ok) ++m_cb_count;
48  return ok;
49 }
50 
51 bool Tca9548::write(const I2cAddr& devaddr,
52  u8 regbytes, u32 regaddr, u8 nwrite, const u8* data,
53  I2cEventListener* callback)
54 {
55  // Reject command if our callback queue is full.
56  if (m_cb_count >= SATCAT5_I2C_MAXCMD) return false;
57 
58  // Otherwise, store the pointer and call parent.
59  m_cb_queue[cb_wridx()] = callback;
60  bool ok = m_parent->write(devaddr, regbytes, regaddr, nwrite, data, this);
61 
62  // If the parent succeeds, increment the queue count.
63  if (ok) ++m_cb_count;
64  return ok;
65 }
66 
67 void Tca9548::i2c_done(
68  bool noack, const I2cAddr& devaddr,
69  u32 regaddr, unsigned nread, const u8* rdata)
70 {
71  // Pop callback off the circular buffer.
72  I2cEventListener* cb = m_cb_queue[m_cb_rdidx];
73  m_cb_rdidx = modulo_add_uns(m_cb_rdidx + 1, SATCAT5_I2C_MAXCMD);
74  --m_cb_count;
75 
76  // Forward the callback event if applicable.
77  if (cb) cb->i2c_done(noack, devaddr, regaddr, nread, rdata);
78 }
Callback interface for cfg::I2cGeneric events.
Definition: cfg_i2c.h:78
Polymorphic API for a generic I2C interface.
Definition: cfg_i2c.h:95
virtual bool busy()=0
Is the I2C controller currently busy?
virtual bool read(const satcat5::util::I2cAddr &devaddr, u8 regbytes, u32 regaddr, u8 nread, satcat5::cfg::I2cEventListener *callback=0)=0
Add a read operation to the queue.
virtual bool write(const satcat5::util::I2cAddr &devaddr, u8 regbytes, u32 regaddr, u8 nwrite, const u8 *data, satcat5::cfg::I2cEventListener *callback=0)=0
Add a write operation to the queue.
Device driver for PCA9548A / TCA9548A I2C switches.
Definition: i2c_tca9548.h:31
bool write(const satcat5::util::I2cAddr &devaddr, u8 regbytes, u32 regaddr, u8 nwrite, const u8 *data, satcat5::cfg::I2cEventListener *callback=0) override
Add a write operation to the queue.
Definition: i2c_tca9548.cc:51
bool select_mask(u8 mask)
Select a channel or channel(s).
Definition: i2c_tca9548.cc:23
bool busy() override
Is the I2C controller currently busy?
Definition: i2c_tca9548.cc:30
bool read(const satcat5::util::I2cAddr &devaddr, u8 regbytes, u32 regaddr, u8 nread, satcat5::cfg::I2cEventListener *callback=0) override
Add a read operation to the queue.
Definition: i2c_tca9548.cc:35
Conversion function for I2C device addresses.
Definition: cfg_i2c.h:30
constexpr unsigned modulo_add_uns(unsigned sum, unsigned m)
Modulo addition function.
Definition: utils.h:182