1 #include "i2c.hpp"
2
3 #include <fcntl.h>
4 #include <sys/ioctl.h>
5 #include <sys/stat.h>
6 #include <unistd.h>
7
8 #include <cassert>
9 #include <cerrno>
10
11 extern "C"
12 {
13 #include <i2c/smbus.h>
14 #include <linux/i2c-dev.h>
15 #include <linux/i2c.h>
16 }
17
18 namespace i2c
19 {
20
getFuncs()21 unsigned long I2CDevice::getFuncs()
22 {
23 // If functionality has not been cached
24 if (cachedFuncs == NO_FUNCS)
25 {
26 // Get functionality from adapter
27 int ret = 0, retries = 0;
28 do
29 {
30 ret = ioctl(fd, I2C_FUNCS, &cachedFuncs);
31 } while ((ret < 0) && (++retries <= maxRetries));
32
33 if (ret < 0)
34 {
35 throw I2CException("Failed to get funcs", busStr, devAddr, errno);
36 }
37 }
38
39 return cachedFuncs;
40 }
41
checkReadFuncs(int type)42 void I2CDevice::checkReadFuncs(int type)
43 {
44 unsigned long funcs = getFuncs();
45 switch (type)
46 {
47 case I2C_SMBUS_BYTE:
48 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE))
49 {
50 throw I2CException("Missing SMBUS_READ_BYTE", busStr, devAddr);
51 }
52 break;
53 case I2C_SMBUS_BYTE_DATA:
54 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA))
55 {
56 throw I2CException("Missing SMBUS_READ_BYTE_DATA", busStr,
57 devAddr);
58 }
59 break;
60 case I2C_SMBUS_WORD_DATA:
61 if (!(funcs & I2C_FUNC_SMBUS_READ_WORD_DATA))
62 {
63 throw I2CException("Missing SMBUS_READ_WORD_DATA", busStr,
64 devAddr);
65 }
66 break;
67 case I2C_SMBUS_BLOCK_DATA:
68 if (!(funcs & I2C_FUNC_SMBUS_READ_BLOCK_DATA))
69 {
70 throw I2CException("Missing SMBUS_READ_BLOCK_DATA", busStr,
71 devAddr);
72 }
73 break;
74 case I2C_SMBUS_I2C_BLOCK_DATA:
75 if (!(funcs & I2C_FUNC_SMBUS_READ_I2C_BLOCK))
76 {
77 throw I2CException("Missing I2C_FUNC_SMBUS_READ_I2C_BLOCK",
78 busStr, devAddr);
79 }
80 break;
81 default:
82 fprintf(stderr, "Unexpected read size type: %d\n", type);
83 assert(false);
84 break;
85 }
86 }
87
checkWriteFuncs(int type)88 void I2CDevice::checkWriteFuncs(int type)
89 {
90 unsigned long funcs = getFuncs();
91 switch (type)
92 {
93 case I2C_SMBUS_BYTE:
94 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE))
95 {
96 throw I2CException("Missing SMBUS_WRITE_BYTE", busStr, devAddr);
97 }
98 break;
99 case I2C_SMBUS_BYTE_DATA:
100 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
101 {
102 throw I2CException("Missing SMBUS_WRITE_BYTE_DATA", busStr,
103 devAddr);
104 }
105 break;
106 case I2C_SMBUS_WORD_DATA:
107 if (!(funcs & I2C_FUNC_SMBUS_WRITE_WORD_DATA))
108 {
109 throw I2CException("Missing SMBUS_WRITE_WORD_DATA", busStr,
110 devAddr);
111 }
112 break;
113 case I2C_SMBUS_BLOCK_DATA:
114 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BLOCK_DATA))
115 {
116 throw I2CException("Missing SMBUS_WRITE_BLOCK_DATA", busStr,
117 devAddr);
118 }
119 break;
120 case I2C_SMBUS_I2C_BLOCK_DATA:
121 if (!(funcs & I2C_FUNC_SMBUS_WRITE_I2C_BLOCK))
122 {
123 throw I2CException("Missing I2C_FUNC_SMBUS_WRITE_I2C_BLOCK",
124 busStr, devAddr);
125 }
126 break;
127 default:
128 fprintf(stderr, "Unexpected write size type: %d\n", type);
129 assert(false);
130 }
131 }
132
open()133 void I2CDevice::open()
134 {
135 if (isOpen())
136 {
137 throw I2CException("Device already open", busStr, devAddr);
138 }
139
140 int retries = 0;
141 do
142 {
143 fd = ::open(busStr.c_str(), O_RDWR);
144 } while ((fd == -1) && (++retries <= maxRetries));
145
146 if (fd == -1)
147 {
148 throw I2CException("Failed to open", busStr, devAddr, errno);
149 }
150
151 retries = 0;
152 int ret = 0;
153 do
154 {
155 ret = ioctl(fd, I2C_SLAVE, devAddr);
156 } while ((ret < 0) && (++retries <= maxRetries));
157
158 if (ret < 0)
159 {
160 // Close device since setting slave address failed
161 closeWithoutException();
162
163 throw I2CException("Failed to set I2C_SLAVE", busStr, devAddr, errno);
164 }
165 }
166
close()167 void I2CDevice::close()
168 {
169 checkIsOpen();
170
171 int ret = 0, retries = 0;
172 do
173 {
174 ret = ::close(fd);
175 } while ((ret == -1) && (++retries <= maxRetries));
176
177 if (ret == -1)
178 {
179 throw I2CException("Failed to close", busStr, devAddr, errno);
180 }
181
182 fd = INVALID_FD;
183 cachedFuncs = NO_FUNCS;
184 }
185
read(uint8_t & data)186 void I2CDevice::read(uint8_t& data)
187 {
188 checkIsOpen();
189 checkReadFuncs(I2C_SMBUS_BYTE);
190
191 int ret = 0, retries = 0;
192 do
193 {
194 ret = i2c_smbus_read_byte(fd);
195 } while ((ret < 0) && (++retries <= maxRetries));
196
197 if (ret < 0)
198 {
199 throw I2CException("Failed to read byte", busStr, devAddr, errno);
200 }
201
202 data = static_cast<uint8_t>(ret);
203 }
204
read(uint8_t addr,uint8_t & data)205 void I2CDevice::read(uint8_t addr, uint8_t& data)
206 {
207 checkIsOpen();
208 checkReadFuncs(I2C_SMBUS_BYTE_DATA);
209
210 int ret = 0, retries = 0;
211 do
212 {
213 ret = i2c_smbus_read_byte_data(fd, addr);
214 } while ((ret < 0) && (++retries <= maxRetries));
215
216 if (ret < 0)
217 {
218 throw I2CException("Failed to read byte data", busStr, devAddr, errno);
219 }
220
221 data = static_cast<uint8_t>(ret);
222 }
223
read(uint8_t addr,uint16_t & data)224 void I2CDevice::read(uint8_t addr, uint16_t& data)
225 {
226 checkIsOpen();
227 checkReadFuncs(I2C_SMBUS_WORD_DATA);
228
229 int ret = 0, retries = 0;
230 do
231 {
232 ret = i2c_smbus_read_word_data(fd, addr);
233 } while ((ret < 0) && (++retries <= maxRetries));
234
235 if (ret < 0)
236 {
237 throw I2CException("Failed to read word data", busStr, devAddr, errno);
238 }
239
240 data = static_cast<uint16_t>(ret);
241 }
242
read(uint8_t addr,uint8_t & size,uint8_t * data,Mode mode)243 void I2CDevice::read(uint8_t addr, uint8_t& size, uint8_t* data, Mode mode)
244 {
245 checkIsOpen();
246
247 int ret = -1, retries = 0;
248 switch (mode)
249 {
250 case Mode::SMBUS:
251 checkReadFuncs(I2C_SMBUS_BLOCK_DATA);
252 do
253 {
254 ret = i2c_smbus_read_block_data(fd, addr, data);
255 } while ((ret < 0) && (++retries <= maxRetries));
256 break;
257 case Mode::I2C:
258 checkReadFuncs(I2C_SMBUS_I2C_BLOCK_DATA);
259 do
260 {
261 ret = i2c_smbus_read_i2c_block_data(fd, addr, size, data);
262 } while ((ret < 0) && (++retries <= maxRetries));
263 if (ret != size)
264 {
265 throw I2CException("Failed to read i2c block data", busStr,
266 devAddr, errno);
267 }
268 break;
269 }
270
271 if (ret < 0)
272 {
273 throw I2CException("Failed to read block data", busStr, devAddr, errno);
274 }
275
276 size = static_cast<uint8_t>(ret);
277 }
278
write(uint8_t data)279 void I2CDevice::write(uint8_t data)
280 {
281 checkIsOpen();
282 checkWriteFuncs(I2C_SMBUS_BYTE);
283
284 int ret = 0, retries = 0;
285 do
286 {
287 ret = i2c_smbus_write_byte(fd, data);
288 } while ((ret < 0) && (++retries <= maxRetries));
289
290 if (ret < 0)
291 {
292 throw I2CException("Failed to write byte", busStr, devAddr, errno);
293 }
294 }
295
write(uint8_t addr,uint8_t data)296 void I2CDevice::write(uint8_t addr, uint8_t data)
297 {
298 checkIsOpen();
299 checkWriteFuncs(I2C_SMBUS_BYTE_DATA);
300
301 int ret = 0, retries = 0;
302 do
303 {
304 ret = i2c_smbus_write_byte_data(fd, addr, data);
305 } while ((ret < 0) && (++retries <= maxRetries));
306
307 if (ret < 0)
308 {
309 throw I2CException("Failed to write byte data", busStr, devAddr, errno);
310 }
311 }
312
write(uint8_t addr,uint16_t data)313 void I2CDevice::write(uint8_t addr, uint16_t data)
314 {
315 checkIsOpen();
316 checkWriteFuncs(I2C_SMBUS_WORD_DATA);
317
318 int ret = 0, retries = 0;
319 do
320 {
321 ret = i2c_smbus_write_word_data(fd, addr, data);
322 } while ((ret < 0) && (++retries <= maxRetries));
323
324 if (ret < 0)
325 {
326 throw I2CException("Failed to write word data", busStr, devAddr, errno);
327 }
328 }
329
write(uint8_t addr,uint8_t size,const uint8_t * data,Mode mode)330 void I2CDevice::write(uint8_t addr, uint8_t size, const uint8_t* data,
331 Mode mode)
332 {
333 checkIsOpen();
334
335 int ret = -1, retries = 0;
336 switch (mode)
337 {
338 case Mode::SMBUS:
339 checkWriteFuncs(I2C_SMBUS_BLOCK_DATA);
340 do
341 {
342 ret = i2c_smbus_write_block_data(fd, addr, size, data);
343 } while ((ret < 0) && (++retries <= maxRetries));
344 break;
345 case Mode::I2C:
346 checkWriteFuncs(I2C_SMBUS_I2C_BLOCK_DATA);
347 do
348 {
349 ret = i2c_smbus_write_i2c_block_data(fd, addr, size, data);
350 } while ((ret < 0) && (++retries <= maxRetries));
351 break;
352 }
353
354 if (ret < 0)
355 {
356 throw I2CException("Failed to write block data", busStr, devAddr,
357 errno);
358 }
359 }
360
create(uint8_t busId,uint8_t devAddr,InitialState initialState,int maxRetries)361 std::unique_ptr<I2CInterface> I2CDevice::create(uint8_t busId, uint8_t devAddr,
362 InitialState initialState,
363 int maxRetries)
364 {
365 std::unique_ptr<I2CDevice> dev(
366 new I2CDevice(busId, devAddr, initialState, maxRetries));
367 return dev;
368 }
369
create(uint8_t busId,uint8_t devAddr,I2CInterface::InitialState initialState,int maxRetries)370 std::unique_ptr<I2CInterface> create(uint8_t busId, uint8_t devAddr,
371 I2CInterface::InitialState initialState,
372 int maxRetries)
373 {
374 return I2CDevice::create(busId, devAddr, initialState, maxRetries);
375 }
376
377 } // namespace i2c
378