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 #include <cstring>
11 #include <format>
12
13 extern "C"
14 {
15 #include <i2c/smbus.h>
16 #include <linux/i2c-dev.h>
17 #include <linux/i2c.h>
18 }
19
20 namespace i2c
21 {
22
23 // Maximum number of data bytes in a block read/block write/block process call
24 // in SMBus 3.0. The maximum was 32 data bytes in SMBus 2.0 and earlier.
25 constexpr uint8_t I2C_SMBUS3_BLOCK_MAX = 255;
26
getFuncs()27 unsigned long I2CDevice::getFuncs()
28 {
29 // If functionality has not been cached
30 if (cachedFuncs == NO_FUNCS)
31 {
32 // Get functionality from adapter
33 int ret = 0, retries = 0;
34 do
35 {
36 ret = ioctl(fd, I2C_FUNCS, &cachedFuncs);
37 } while ((ret < 0) && (++retries <= maxRetries));
38
39 if (ret < 0)
40 {
41 cachedFuncs = NO_FUNCS;
42 throw I2CException("Failed to get funcs", busStr, devAddr, errno);
43 }
44 }
45
46 return cachedFuncs;
47 }
48
checkReadFuncs(int type)49 void I2CDevice::checkReadFuncs(int type)
50 {
51 unsigned long funcs = getFuncs();
52 switch (type)
53 {
54 case I2C_SMBUS_BYTE:
55 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE))
56 {
57 throw I2CException("Missing SMBUS_READ_BYTE", busStr, devAddr);
58 }
59 break;
60 case I2C_SMBUS_BYTE_DATA:
61 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA))
62 {
63 throw I2CException("Missing SMBUS_READ_BYTE_DATA", busStr,
64 devAddr);
65 }
66 break;
67 case I2C_SMBUS_WORD_DATA:
68 if (!(funcs & I2C_FUNC_SMBUS_READ_WORD_DATA))
69 {
70 throw I2CException("Missing SMBUS_READ_WORD_DATA", busStr,
71 devAddr);
72 }
73 break;
74 case I2C_SMBUS_BLOCK_DATA:
75 if (!(funcs & I2C_FUNC_SMBUS_READ_BLOCK_DATA))
76 {
77 throw I2CException("Missing SMBUS_READ_BLOCK_DATA", busStr,
78 devAddr);
79 }
80 break;
81 case I2C_SMBUS_I2C_BLOCK_DATA:
82 if (!(funcs & I2C_FUNC_SMBUS_READ_I2C_BLOCK))
83 {
84 throw I2CException("Missing I2C_FUNC_SMBUS_READ_I2C_BLOCK",
85 busStr, devAddr);
86 }
87 break;
88 default:
89 fprintf(stderr, "Unexpected read size type: %d\n", type);
90 assert(false);
91 break;
92 }
93 }
94
checkWriteFuncs(int type)95 void I2CDevice::checkWriteFuncs(int type)
96 {
97 unsigned long funcs = getFuncs();
98 switch (type)
99 {
100 case I2C_SMBUS_BYTE:
101 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE))
102 {
103 throw I2CException("Missing SMBUS_WRITE_BYTE", busStr, devAddr);
104 }
105 break;
106 case I2C_SMBUS_BYTE_DATA:
107 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
108 {
109 throw I2CException("Missing SMBUS_WRITE_BYTE_DATA", busStr,
110 devAddr);
111 }
112 break;
113 case I2C_SMBUS_WORD_DATA:
114 if (!(funcs & I2C_FUNC_SMBUS_WRITE_WORD_DATA))
115 {
116 throw I2CException("Missing SMBUS_WRITE_WORD_DATA", busStr,
117 devAddr);
118 }
119 break;
120 case I2C_SMBUS_BLOCK_DATA:
121 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BLOCK_DATA))
122 {
123 throw I2CException("Missing SMBUS_WRITE_BLOCK_DATA", busStr,
124 devAddr);
125 }
126 break;
127 case I2C_SMBUS_I2C_BLOCK_DATA:
128 if (!(funcs & I2C_FUNC_SMBUS_WRITE_I2C_BLOCK))
129 {
130 throw I2CException("Missing I2C_FUNC_SMBUS_WRITE_I2C_BLOCK",
131 busStr, devAddr);
132 }
133 break;
134 case I2C_SMBUS_PROC_CALL:
135 if (!(funcs & I2C_FUNC_SMBUS_PROC_CALL))
136 {
137 throw I2CException("Missing I2C_FUNC_SMBUS_PROC_CALL", busStr,
138 devAddr);
139 }
140 break;
141 case I2C_SMBUS_BLOCK_PROC_CALL:
142 if (!(funcs & I2C_FUNC_SMBUS_BLOCK_PROC_CALL))
143 {
144 throw I2CException("Missing I2C_FUNC_SMBUS_BLOCK_PROC_CALL",
145 busStr, devAddr);
146 }
147 break;
148 default:
149 fprintf(stderr, "Unexpected write size type: %d\n", type);
150 assert(false);
151 }
152 }
153
processCallSMBus(uint8_t addr,uint8_t writeSize,const uint8_t * writeData,uint8_t & readSize,uint8_t * readData)154 void I2CDevice::processCallSMBus(uint8_t addr, uint8_t writeSize,
155 const uint8_t* writeData, uint8_t& readSize,
156 uint8_t* readData)
157 {
158 int ret = 0, retries = 0;
159 uint8_t buffer[I2C_SMBUS_BLOCK_MAX];
160 do
161 {
162 // Copy write data to buffer. Buffer is also used by SMBus function to
163 // store the data read from the device.
164 std::memcpy(buffer, writeData, writeSize);
165 ret = i2c_smbus_block_process_call(fd, addr, writeSize, buffer);
166 } while ((ret < 0) && (++retries <= maxRetries));
167
168 if (ret < 0)
169 {
170 throw I2CException("Failed to execute block process call", busStr,
171 devAddr, errno);
172 }
173
174 readSize = static_cast<uint8_t>(ret);
175 std::memcpy(readData, buffer, readSize);
176 }
177
processCallI2C(uint8_t addr,uint8_t writeSize,const uint8_t * writeData,uint8_t & readSize,uint8_t * readData)178 void I2CDevice::processCallI2C(uint8_t addr, uint8_t writeSize,
179 const uint8_t* writeData, uint8_t& readSize,
180 uint8_t* readData)
181 {
182 // Buffer for block write. Linux supports SMBus 3.0 max size for block
183 // write. Buffer will contain register address, byte count, and data bytes.
184 constexpr uint16_t writeBufferSize = I2C_SMBUS3_BLOCK_MAX + 2;
185 uint8_t writeBuffer[writeBufferSize];
186
187 // Buffer for block read. Linux supports smaller SMBus 2.0 max size for
188 // block read. After ioctl() buffer will contain byte count and data bytes.
189 constexpr uint16_t readBufferSize = I2C_SMBUS_BLOCK_MAX + 1;
190 uint8_t readBuffer[readBufferSize];
191
192 // i2c_msg and i2c_rdwr_ioctl_data structs required for ioctl()
193 constexpr unsigned int numMessages = 2;
194 struct i2c_msg messages[numMessages];
195 struct i2c_rdwr_ioctl_data readWriteData;
196 readWriteData.msgs = messages;
197 readWriteData.nmsgs = numMessages;
198
199 int ret = 0, retries = 0;
200 do
201 {
202 // Initialize write buffer with reg addr, byte count, and data bytes
203 writeBuffer[0] = addr;
204 writeBuffer[1] = writeSize;
205 std::memcpy(&(writeBuffer[2]), writeData, writeSize);
206
207 // Initialize first i2c_msg to perform block write
208 messages[0].addr = devAddr;
209 messages[0].flags = 0;
210 messages[0].len = writeSize + 2; // 2 == reg addr + byte count
211 messages[0].buf = writeBuffer;
212
213 // Initialize read buffer. Set first byte to number of "extra bytes"
214 // that will be read in addition to data bytes. Set to 1 since only
215 // extra byte is the byte count.
216 readBuffer[0] = 1;
217
218 // Initialize second i2c_msg to perform block read. Linux requires the
219 // len field to be set to the buffer size.
220 messages[1].addr = devAddr;
221 messages[1].flags = I2C_M_RD | I2C_M_RECV_LEN;
222 messages[1].len = readBufferSize;
223 messages[1].buf = readBuffer;
224
225 // Call ioctl() to send the I2C messages
226 ret = ioctl(fd, I2C_RDWR, &readWriteData);
227 } while ((ret != numMessages) && (++retries <= maxRetries));
228
229 if (ret < 0)
230 {
231 throw I2CException("Failed to execute I2C block process call", busStr,
232 devAddr, errno);
233 }
234 else if (ret != numMessages)
235 {
236 throw I2CException(
237 std::format(
238 "Failed to execute I2C block process call: {} messages sent",
239 ret),
240 busStr, devAddr);
241 }
242
243 // Read size is in first byte; copy remaining data bytes to readData param
244 readSize = readBuffer[0];
245 std::memcpy(readData, &(readBuffer[1]), readSize);
246 }
247
open()248 void I2CDevice::open()
249 {
250 if (isOpen())
251 {
252 throw I2CException("Device already open", busStr, devAddr);
253 }
254
255 int retries = 0;
256 do
257 {
258 fd = ::open(busStr.c_str(), O_RDWR);
259 } while ((fd == -1) && (++retries <= maxRetries));
260
261 if (fd == -1)
262 {
263 throw I2CException("Failed to open", busStr, devAddr, errno);
264 }
265
266 retries = 0;
267 int ret = 0;
268 do
269 {
270 ret = ioctl(fd, I2C_SLAVE, devAddr);
271 } while ((ret < 0) && (++retries <= maxRetries));
272
273 if (ret < 0)
274 {
275 // Close device since setting slave address failed
276 closeWithoutException();
277
278 throw I2CException("Failed to set I2C_SLAVE", busStr, devAddr, errno);
279 }
280 }
281
close()282 void I2CDevice::close()
283 {
284 checkIsOpen();
285
286 int ret = 0, retries = 0;
287 do
288 {
289 ret = ::close(fd);
290 } while ((ret == -1) && (++retries <= maxRetries));
291
292 if (ret == -1)
293 {
294 throw I2CException("Failed to close", busStr, devAddr, errno);
295 }
296
297 fd = INVALID_FD;
298 cachedFuncs = NO_FUNCS;
299 }
300
read(uint8_t & data)301 void I2CDevice::read(uint8_t& data)
302 {
303 checkIsOpen();
304 checkReadFuncs(I2C_SMBUS_BYTE);
305
306 int ret = 0, retries = 0;
307 do
308 {
309 ret = i2c_smbus_read_byte(fd);
310 } while ((ret < 0) && (++retries <= maxRetries));
311
312 if (ret < 0)
313 {
314 throw I2CException("Failed to read byte", busStr, devAddr, errno);
315 }
316
317 data = static_cast<uint8_t>(ret);
318 }
319
read(uint8_t addr,uint8_t & data)320 void I2CDevice::read(uint8_t addr, uint8_t& data)
321 {
322 checkIsOpen();
323 checkReadFuncs(I2C_SMBUS_BYTE_DATA);
324
325 int ret = 0, retries = 0;
326 do
327 {
328 ret = i2c_smbus_read_byte_data(fd, addr);
329 } while ((ret < 0) && (++retries <= maxRetries));
330
331 if (ret < 0)
332 {
333 throw I2CException("Failed to read byte data", busStr, devAddr, errno);
334 }
335
336 data = static_cast<uint8_t>(ret);
337 }
338
read(uint8_t addr,uint16_t & data)339 void I2CDevice::read(uint8_t addr, uint16_t& data)
340 {
341 checkIsOpen();
342 checkReadFuncs(I2C_SMBUS_WORD_DATA);
343
344 int ret = 0, retries = 0;
345 do
346 {
347 ret = i2c_smbus_read_word_data(fd, addr);
348 } while ((ret < 0) && (++retries <= maxRetries));
349
350 if (ret < 0)
351 {
352 throw I2CException("Failed to read word data", busStr, devAddr, errno);
353 }
354
355 data = static_cast<uint16_t>(ret);
356 }
357
read(uint8_t addr,uint8_t & size,uint8_t * data,Mode mode)358 void I2CDevice::read(uint8_t addr, uint8_t& size, uint8_t* data, Mode mode)
359 {
360 checkIsOpen();
361
362 int ret = -1, retries = 0;
363 switch (mode)
364 {
365 case Mode::SMBUS:
366 checkReadFuncs(I2C_SMBUS_BLOCK_DATA);
367 do
368 {
369 ret = i2c_smbus_read_block_data(fd, addr, data);
370 } while ((ret < 0) && (++retries <= maxRetries));
371 break;
372 case Mode::I2C:
373 checkReadFuncs(I2C_SMBUS_I2C_BLOCK_DATA);
374 do
375 {
376 ret = i2c_smbus_read_i2c_block_data(fd, addr, size, data);
377 } while ((ret < 0) && (++retries <= maxRetries));
378 if (ret != size)
379 {
380 throw I2CException("Failed to read i2c block data", busStr,
381 devAddr, errno);
382 }
383 break;
384 }
385
386 if (ret < 0)
387 {
388 throw I2CException("Failed to read block data", busStr, devAddr, errno);
389 }
390
391 size = static_cast<uint8_t>(ret);
392 }
393
write(uint8_t data)394 void I2CDevice::write(uint8_t data)
395 {
396 checkIsOpen();
397 checkWriteFuncs(I2C_SMBUS_BYTE);
398
399 int ret = 0, retries = 0;
400 do
401 {
402 ret = i2c_smbus_write_byte(fd, data);
403 } while ((ret < 0) && (++retries <= maxRetries));
404
405 if (ret < 0)
406 {
407 throw I2CException("Failed to write byte", busStr, devAddr, errno);
408 }
409 }
410
write(uint8_t addr,uint8_t data)411 void I2CDevice::write(uint8_t addr, uint8_t data)
412 {
413 checkIsOpen();
414 checkWriteFuncs(I2C_SMBUS_BYTE_DATA);
415
416 int ret = 0, retries = 0;
417 do
418 {
419 ret = i2c_smbus_write_byte_data(fd, addr, data);
420 } while ((ret < 0) && (++retries <= maxRetries));
421
422 if (ret < 0)
423 {
424 throw I2CException("Failed to write byte data", busStr, devAddr, errno);
425 }
426 }
427
write(uint8_t addr,uint16_t data)428 void I2CDevice::write(uint8_t addr, uint16_t data)
429 {
430 checkIsOpen();
431 checkWriteFuncs(I2C_SMBUS_WORD_DATA);
432
433 int ret = 0, retries = 0;
434 do
435 {
436 ret = i2c_smbus_write_word_data(fd, addr, data);
437 } while ((ret < 0) && (++retries <= maxRetries));
438
439 if (ret < 0)
440 {
441 throw I2CException("Failed to write word data", busStr, devAddr, errno);
442 }
443 }
444
write(uint8_t addr,uint8_t size,const uint8_t * data,Mode mode)445 void I2CDevice::write(uint8_t addr, uint8_t size, const uint8_t* data,
446 Mode mode)
447 {
448 checkIsOpen();
449
450 int ret = -1, retries = 0;
451 switch (mode)
452 {
453 case Mode::SMBUS:
454 checkWriteFuncs(I2C_SMBUS_BLOCK_DATA);
455 do
456 {
457 ret = i2c_smbus_write_block_data(fd, addr, size, data);
458 } while ((ret < 0) && (++retries <= maxRetries));
459 break;
460 case Mode::I2C:
461 checkWriteFuncs(I2C_SMBUS_I2C_BLOCK_DATA);
462 do
463 {
464 ret = i2c_smbus_write_i2c_block_data(fd, addr, size, data);
465 } while ((ret < 0) && (++retries <= maxRetries));
466 break;
467 }
468
469 if (ret < 0)
470 {
471 throw I2CException("Failed to write block data", busStr, devAddr,
472 errno);
473 }
474 }
475
processCall(uint8_t addr,uint16_t writeData,uint16_t & readData)476 void I2CDevice::processCall(uint8_t addr, uint16_t writeData,
477 uint16_t& readData)
478 {
479 checkIsOpen();
480 checkWriteFuncs(I2C_SMBUS_PROC_CALL);
481
482 int ret = 0, retries = 0;
483 do
484 {
485 ret = i2c_smbus_process_call(fd, addr, writeData);
486 } while ((ret < 0) && (++retries <= maxRetries));
487
488 if (ret < 0)
489 {
490 throw I2CException("Failed to execute process call", busStr, devAddr,
491 errno);
492 }
493
494 readData = static_cast<uint16_t>(ret);
495 }
496
processCall(uint8_t addr,uint8_t writeSize,const uint8_t * writeData,uint8_t & readSize,uint8_t * readData)497 void I2CDevice::processCall(uint8_t addr, uint8_t writeSize,
498 const uint8_t* writeData, uint8_t& readSize,
499 uint8_t* readData)
500 {
501 checkIsOpen();
502 unsigned long funcs = getFuncs();
503
504 if ((funcs & I2C_FUNC_SMBUS_BLOCK_PROC_CALL) &&
505 (writeSize <= I2C_SMBUS_BLOCK_MAX))
506 {
507 // Use standard SMBus function which supports smaller SMBus 2.0 maximum
508 processCallSMBus(addr, writeSize, writeData, readSize, readData);
509 }
510 else if (funcs & I2C_FUNC_I2C)
511 {
512 // Use lower level I2C ioctl which supports larger SMBus 3.0 maximum
513 processCallI2C(addr, writeSize, writeData, readSize, readData);
514 }
515 else
516 {
517 throw I2CException(
518 std::format(
519 "Block process call unsupported: writeSize={:d}, funcs={}",
520 writeSize, funcs),
521 busStr, devAddr);
522 }
523 }
524
create(uint8_t busId,uint8_t devAddr,InitialState initialState,int maxRetries)525 std::unique_ptr<I2CInterface> I2CDevice::create(
526 uint8_t busId, uint8_t devAddr, InitialState initialState, int maxRetries)
527 {
528 std::unique_ptr<I2CDevice> dev(
529 new I2CDevice(busId, devAddr, initialState, maxRetries));
530 return dev;
531 }
532
533 std::unique_ptr<I2CInterface>
create(uint8_t busId,uint8_t devAddr,I2CInterface::InitialState initialState,int maxRetries)534 create(uint8_t busId, uint8_t devAddr,
535 I2CInterface::InitialState initialState, int maxRetries)
536 {
537 return I2CDevice::create(busId, devAddr, initialState, maxRetries);
538 }
539
540 } // namespace i2c
541