Laelaps  2.3.5
RoadNarrows Robotics Small Outdoor Mobile Robot Project
laeI2C.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: Laelaps
4 //
5 // File: laeI2C.cxx
6 //
7 /*! \file
8  *
9  * \brief Laelaps I2C class implementation.
10  *
11  * The I2C class supports safe multi-threading.
12  *
13  * \author Robin Knight (robin.knight@roadnarrows.com)
14  *
15  * \par Copyright
16  * \h_copy 2015-2017. RoadNarrows LLC.\n
17  * http://www.roadnarrows.com\n
18  * All Rights Reserved
19  */
20 /*
21  * @EulaBegin@
22  *
23  * Unless otherwise stated explicitly, all materials contained are copyrighted
24  * and may not be used without RoadNarrows LLC's written consent,
25  * except as provided in these terms and conditions or in the copyright
26  * notice (documents and software) or other proprietary notice provided with
27  * the relevant materials.
28  *
29  * IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY
30  * MEMBERS/EMPLOYEES/CONTRACTORS OF ROADNARROWS OR DISTRIBUTORS OF THIS SOFTWARE
31  * BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
32  * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
33  * DOCUMENTATION, EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN
34  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  *
36  * THE AUTHORS AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
37  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
38  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
39  * "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
40  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
41  *
42  * @EulaEnd@
43  */
44 ////////////////////////////////////////////////////////////////////////////////
45 
46 #include <unistd.h>
47 #include <pthread.h>
48 
49 #include <string>
50 
51 #include "rnr/rnrconfig.h"
52 #include "rnr/i2c.h"
53 #include "rnr/log.h"
54 
55 #include "Laelaps/laelaps.h"
56 #include "Laelaps/laeUtils.h"
57 #include "Laelaps/laeSysDev.h"
58 #include "Laelaps/laeI2C.h"
59 
60 using namespace std;
61 using namespace laelaps;
62 
63 //------------------------------------------------------------------------------
64 // I2C Utilities
65 //------------------------------------------------------------------------------
66 
67 int laelaps::i2cTryOpen(LaeI2C &i2cBus, uint_t addr)
68 {
69  const char *devNames[] = { LaeDevI2C_0, LaeDevI2C_1, LaeDevI2C_2, NULL };
70 
71  int rc;
72 
73  for(int i = 0; devNames[i] != NULL; ++i)
74  {
75  LOGDIAG2("Try I2C device %s.", devNames[i]);
76 
77  if( (rc = i2cBus.open(devNames[i])) == LAE_OK )
78  {
79  if( i2cBus.check(addr) )
80  {
81  LOGDIAG2("Address 0x%02x found on I2C device %s.", addr, devNames[i]);
82  return LAE_OK;
83  }
84  else
85  {
86  LOGDIAG2("No address 0x%02x found on I2C device %s.",
87  addr, devNames[i]);
88  i2cBus.close();
89  }
90  }
91  }
92  rc = -LAE_ECODE_NO_DEV;
93 }
94 
95 //------------------------------------------------------------------------------
96 // LaeI2C Class
97 //------------------------------------------------------------------------------
98 
99 /*! \brief No bound \h_i2c bus. */
100 static i2c_t I2CBusNone = { -1, I2C_ADDR_NONE};
101 
102 LaeI2C::LaeI2C() :
103  m_i2c(I2CBusNone)
104 {
105  pthread_mutex_init(&m_mutex, NULL);
106 }
107 
109 {
110  close();
111  pthread_mutex_destroy(&m_mutex);
112 }
113 
114 int LaeI2C::open(const string &strDevName)
115 {
116  string strDevNameReal;
117  int rc;
118 
119  lock();
120 
121  // Get the real device name, not any symbolic links.
122  strDevNameReal = getRealDeviceName(strDevName);
123 
124  if( i2c_open(&m_i2c, strDevNameReal.c_str()) < 0 )
125  {
126  LOGSYSERROR("%s.", strDevNameReal.c_str());
127  rc = -LAE_ECODE_NO_DEV;
128  }
129 
130  else
131  {
132  m_strDevName = strDevNameReal;
133 
134  LOGDIAG2("I2C device %s opened.", m_strDevName.c_str());
135 
136  rc = LAE_OK;
137  }
138 
139  unlock();
140 
141  return rc;
142 }
143 
145 {
146  lock();
147 
148  if( m_i2c.fd >= 0 )
149  {
150  i2c_close(&m_i2c);
151  LOGDIAG3("I2C device %s closed.", m_strDevName.c_str());
152  }
153 
154  m_strDevName.clear();
155  m_i2c = I2CBusNone;
156 
157  unlock();
158 
159  return LAE_OK;
160 }
161 
162 bool LaeI2C::check(uint_t addr)
163 {
164  return i2c_exists(&m_i2c, (i2c_addr_t)addr) == 1;
165 }
166 
167 int LaeI2C::read(uint_t addr, byte_t buf[], size_t len)
168 {
169  int n;
170 
171  lock();
172 
173  if( (n = i2c_read(&m_i2c, (i2c_addr_t)addr, buf, (uint_t)len)) < 0 )
174  {
175  // LOGSYSERROR
176  LOGDIAG3("I2C: Slave device address 0x%02x: "
177  "Failed to read from endpoint device data.",
178  addr);
179  n = -LAE_ECODE_IO;
180  }
181 
182  else if( n != (int)len )
183  {
184  LOGWARN("I2C: Slave device address 0x%02x: "
185  "Only %d/%d bytes read from endpoint device.",
186  addr, n, (int)len);
187  }
188 
189  unlock();
190 
191  return n;
192 }
193 
194 int LaeI2C::write(uint_t addr, const byte_t buf[], size_t len)
195 {
196  int n;
197 
198  lock();
199 
200  if( (n = i2c_write(&m_i2c, (i2c_addr_t)addr, buf, (uint_t)len)) < 0 )
201  {
202  // LOGSYSERROR
203  LOGDIAG3("I2C: Slave device address 0x%02x: "
204  "Failed to write to device data.",
205  addr);
206  n = -LAE_ECODE_IO;
207  }
208 
209  else if( n != (int)len )
210  {
211  LOGWARN("I2C: Slave device address 0x%02x: "
212  "Only %d/%d bytes written to endpoint device.",
213  addr, n, (int)len);
214  }
215 
216  unlock();
217 
218  return n;
219 }
220 
221 int LaeI2C::transfer(uint_t addr, const byte_t wbuf[], size_t wlen,
222  byte_t rbuf[], size_t rlen)
223 {
224  int rc;
225 
226  lock();
227 
228  rc = i2c_transfer(&m_i2c, (i2c_addr_t)addr, wbuf, (uint_t)wlen,
229  rbuf, (uint_t)rlen);
230 
231  if( rc < 0 )
232  {
233  LOGSYSERROR("I2C: Slave device address 0x%02x: "
234  "Failed to perform write/read transaction.",
235  addr);
236  rc = -LAE_ECODE_IO;
237  }
238 
239  else
240  {
241  rc = LAE_OK;
242  }
243 
244  unlock();
245 
246  return rc;
247 }
248 
249 int LaeI2C::write_read(uint_t addr, const byte_t wbuf[], size_t wlen,
250  byte_t rbuf[], size_t rlen,
251  long usec)
252 {
253  int n;
254  int rc = LAE_OK;
255 
256  lock();
257 
258  //
259  // Write.
260  //
261  if( wlen > 0 )
262  {
263  if( (n = i2c_write(&m_i2c, (i2c_addr_t)addr, wbuf, (uint_t)wlen)) < 0 )
264  {
265  // LOGSYSERROR
266  LOGDIAG3("I2C: Slave device address 0x%02x: "
267  "Failed to write to device data.",
268  addr);
269  rc = -LAE_ECODE_IO;
270  }
271 
272  else if( n != (int)wlen )
273  {
274  LOGERROR("I2C: Slave device address 0x%02x: "
275  "Only %d/%d bytes written to endpoint device.",
276  addr, n, (int)wlen);
277  rc = -LAE_ECODE_IO;
278  }
279  }
280 
281  //
282  // Read.
283  //
284  if( (rlen > 0) && (rc == LAE_OK) )
285  {
286  // delay
287  if( usec > 0 )
288  {
289  usleep(usec);
290  }
291 
292  if( (n = i2c_read(&m_i2c, (i2c_addr_t)addr, rbuf, (uint_t)rlen)) < 0 )
293  {
294  // LOGSYSERROR
295  LOGDIAG3("I2C: Slave device address 0x%02x: "
296  "Failed to read from endpoint device data.",
297  addr);
298  rc = -LAE_ECODE_IO;
299  }
300 
301  else if( n != (int)rlen )
302  {
303  LOGERROR("I2C: Slave device address 0x%02x: "
304  "Only %d/%d bytes read from endpoint device.",
305  addr, n, (int)rlen);
306  rc = -LAE_ECODE_IO;
307  }
308  }
309 
310  unlock();
311 
312  return rc;
313 }
void unlock()
Unlock the I2C bus.
Definition: laeI2C.h:235
std::string m_strDevName
I2C device name.
Definition: laeI2C.h:209
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
virtual int transfer(uint_t addr, const byte_t wbuf[], size_t wlen, byte_t rbuf[], size_t rlen)
Perform a write/read transfer to/from an I2C slave endpoint device.
Definition: laeI2C.cxx:221
i2c_t m_i2c
I2C bus instance.
Definition: laeI2C.h:210
static const int LAE_ECODE_IO
I/O error.
Definition: laelaps.h:98
pthread_mutex_t m_mutex
mutual exclusion
Definition: laeI2C.h:211
Laelaps I2C class interface.
virtual ~LaeI2C()
Destructor.
Definition: laeI2C.cxx:108
virtual int open(const std::string &strDevName)
Open I2C bus device.
Definition: laeI2C.cxx:114
virtual int read(uint_t addr, byte_t buf[], size_t len)
Read from a I2C slave endpoint device.
Definition: laeI2C.cxx:167
void lock()
Lock the I2C bus.
Definition: laeI2C.h:221
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
Laelaps common utilities.
static const int LAE_ECODE_NO_DEV
device not found error
Definition: laelaps.h:82
Laelaps system devices.
static i2c_t I2CBusNone
No bound I2C bus.
Definition: laeI2C.cxx:100
virtual int close()
Close I2C bus device.
Definition: laeI2C.cxx:144
int i2cTryOpen(LaeI2C &i2cBus, uint_t addr)
Try to open a series of I2C devices to fine the required endpoint.
Definition: laeI2C.cxx:67
std::string getRealDeviceName(const std::string &strDevName)
Get real device name.
virtual bool check(uint_t addr)
Check if an I2C slave endpoint exists.
Definition: laeI2C.cxx:162
Top-level package include file.
static const int LAE_OK
not an error, success
Definition: laelaps.h:71