Laelaps  2.3.5
RoadNarrows Robotics Small Outdoor Mobile Robot Project
laeI2CMux.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: Laelaps
4 //
5 // File: laeI2CMux.cxx
6 //
7 /*! \file
8  *
9  * $LastChangedDate: 2016-01-21 16:50:25 -0700 (Thu, 21 Jan 2016) $
10  * $Rev: 4268 $
11  *
12  * \brief Laelaps PCA9548A I2C multiplexer switch implementation.
13  *
14  * The multiplexer allows access to multiple \h_i2c devices including those
15  * that have the same fixed address.
16  *
17  * \author Robin Knight (robin.knight@roadnarrows.com)
18  *
19  * \par Copyright
20  * \h_copy 2015-2017. RoadNarrows LLC.\n
21  * http://www.roadnarrows.com\n
22  * All Rights Reserved
23  */
24 /*
25  * @EulaBegin@
26  *
27  * Unless otherwise stated explicitly, all materials contained are copyrighted
28  * and may not be used without RoadNarrows LLC's written consent,
29  * except as provided in these terms and conditions or in the copyright
30  * notice (documents and software) or other proprietary notice provided with
31  * the relevant materials.
32  *
33  * IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY
34  * MEMBERS/EMPLOYEES/CONTRACTORS OF ROADNARROWS OR DISTRIBUTORS OF THIS SOFTWARE
35  * BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
36  * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
37  * DOCUMENTATION, EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN
38  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39  *
40  * THE AUTHORS AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
41  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
42  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
43  * "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
44  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
45  *
46  * @EulaEnd@
47  */
48 ////////////////////////////////////////////////////////////////////////////////
49 
50 #include <unistd.h>
51 #include <pthread.h>
52 
53 #include "rnr/rnrconfig.h"
54 #include "rnr/log.h"
55 
56 #include "Laelaps/laelaps.h"
57 #include "Laelaps/laeI2C.h"
58 #include "Laelaps/laeI2CMux.h"
59 
60 using namespace std;
61 using namespace laelaps;
62 
63 LaeI2CMux::LaeI2CMux(LaeI2C &i2cBus, uint_t addr) :
64  m_i2cBus(i2cBus), m_addrMux(addr)
65 {
67 
68  pthread_mutex_init(&m_mutex, NULL);
69 }
70 
72 {
73  pthread_mutex_destroy(&m_mutex);
74 }
75 
76 int LaeI2CMux::read(int chan, uint_t addr, byte_t buf[], size_t len)
77 {
78  int n;
79  int rc;
80 
81  lock();
82 
83  if( (rc = setChannel(chan)) == LAE_OK )
84  {
85  if( (n = m_i2cBus.read(addr, buf, len)) < 0 )
86  {
87  LOGDIAG3("I2C Mux: Channel %d I2C device address 0x%02x: "
88  "Failed to read from endpoint device data.",
89  m_chan, addr);
90  rc = -LAE_ECODE_IO;
91  }
92 
93  if( n != (int)len )
94  {
95  LOGWARN("I2C Mux: Channel %d I2C device address 0x%02x: "
96  "Only %d/%d bytes read from endpoint device.",
97  m_chan, addr, n, (int)len);
98  }
99  }
100 
101  unlock();
102 
103  return rc < 0? rc: n;
104 }
105 
106 int LaeI2CMux::write(int chan, uint_t addr, byte_t buf[], size_t len)
107 {
108  int n;
109  int rc;
110 
111  lock();
112 
113  if( (rc = setChannel(chan)) == LAE_OK )
114  {
115  if( (n = m_i2cBus.write(addr, buf, len)) < 0 )
116  {
117  LOGDIAG3("I2C Mux: Channel %d I2C device address 0x%02x: "
118  "Failed to write to device data.",
119  m_chan, addr);
120  rc = -LAE_ECODE_IO;
121  }
122 
123  else if( n != (int)len )
124  {
125  LOGWARN("I2C Mux: Channel %d I2C device address 0x%02x: "
126  "Only %d/%d bytes written to endpoint device.",
127  m_chan, addr, n, (int)len);
128  }
129  }
130 
131  unlock();
132 
133  return rc < 0? rc: n;
134 }
135 
136 int LaeI2CMux::transact(int chan, uint_t addr,
137  const byte_t wbuf[], size_t wlen,
138  byte_t rbuf[], size_t rlen,
139  long usec)
140 {
141  int n;
142  int rc;
143 
144  lock();
145 
146  if( (rc = setChannel(chan)) == LAE_OK )
147  {
148  rc = m_i2cBus.write_read(addr, wbuf, wlen, rbuf, rlen, usec);
149 
150  if( rc != LAE_OK )
151  {
152  LOGDIAG3("I2C Mux: Channel %d I2C device address 0x%02x: "
153  "Failed to write_read to device data.",
154  m_chan, addr);
155  }
156  }
157 
158  unlock();
159 
160  return rc < 0? rc: n;
161 }
162 
163 int LaeI2CMux::readChannelStates(byte_t &chanBits)
164 {
165  int rc;
166 
167  lock();
168 
169  if( m_i2cBus.read(m_addrMux, &chanBits, 1) < 0 )
170  {
171  LOGSYSERROR("I2C Mux: Address 0x%02x: Failed to read channel states.",
172  m_addrMux);
173  rc = -LAE_ECODE_IO;
174  }
175  else
176  {
177  rc = LAE_OK;
178  }
179 
180  unlock();
181 
182  return rc;
183 }
184 
186 {
187  if( (chan < LaeI2CMuxChanMin) || (chan > LaeI2CMuxChanMax) )
188  {
189  LOGERROR("I2C Mux: %d channel: Out-of-range.", chan);
190  return -LAE_ECODE_BAD_VAL;
191  }
192 
193  else if( m_chan != chan )
194  {
195  byte_t ctl = (byte_t)(1 << chan); // control register data
196 
197  if( m_i2cBus.write(m_addrMux, &ctl, 1) < 0 )
198  {
199  LOGSYSERROR("I2C Mux: Address 0x%02x: Failed to select channel.",
200  m_addrMux);
201  return -LAE_ECODE_IO;
202  }
203  else
204  {
205  m_chan = chan;
206  usleep(100);
207  }
208  }
209 
210  return LAE_OK;
211 }
int setChannel(int chan)
Set channel.
Definition: laeI2CMux.cxx:185
virtual int write_read(uint_t addr, const byte_t wbuf[], size_t wlen, byte_t rbuf[], size_t rlen, long usec=0)
Perform a write/read transaction to/from an I2C slave endpoint device.
Definition: laeI2C.cxx:249
static const int LAE_ECODE_IO
I/O error.
Definition: laelaps.h:98
uint_t m_addrMux
I2C multiplexer address.
Definition: laeI2CMux.h:223
const int LaeI2CMuxChanNone
no channel selected
Definition: laeI2CMux.h:86
Laelaps PCA9548A I2C multiplexer switch interface.
Laelaps I2C class interface.
LaeI2C & m_i2cBus
boulnd I2C bus instance
Definition: laeI2CMux.h:222
virtual ~LaeI2CMux()
Destructor.
Definition: laeI2CMux.cxx:71
virtual int write(int chan, uint_t addr, byte_t buf[], size_t len)
Write from an I2C endpoint device.
Definition: laeI2CMux.cxx:106
pthread_mutex_t m_mutex
mutex
Definition: laeI2CMux.h:227
virtual int read(uint_t addr, byte_t buf[], size_t len)
Read from a I2C slave endpoint device.
Definition: laeI2C.cxx:167
The <b><i>Laelaps</i></b> namespace encapsulates all <b><i>Laelaps</i></b> related constructs...
Definition: laeAlarms.h:64
virtual int write(uint_t addr, const byte_t buf[], size_t len)
Write to an I2C slave endpoint device.
Definition: laeI2C.cxx:194
const int LaeI2CMuxChanMax
min channel number
Definition: laeI2CMux.h:85
virtual int read(int chan, uint_t addr, byte_t buf[], size_t len)
Read from a multiplexed I2C slave endpoint device.
Definition: laeI2CMux.cxx:76
int m_chan
current active channel
Definition: laeI2CMux.h:224
const int LaeI2CMuxChanMin
min channel number
Definition: laeI2CMux.h:84
static const int LAE_ECODE_BAD_VAL
bad value general error
Definition: laelaps.h:76
void lock()
Lock the shared resource.
Definition: laeI2CMux.h:237
void unlock()
Unlock the shared resource.
Definition: laeI2CMux.h:248
virtual int transact(int chan, uint_t addr, const byte_t wbuf[], size_t wlen, byte_t rbuf[], size_t rlen, long usec=0)
Perform a write/read transaction to/from an I2C slave endpoint device.
Definition: laeI2CMux.cxx:136
virtual int readChannelStates(byte_t &chanBits)
Read the current I2C multiplexer enable state.
Definition: laeI2CMux.cxx:163
Top-level package include file.
static const int LAE_OK
not an error, success
Definition: laelaps.h:71