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 create(uint8_t busId,uint8_t devAddr,I2CInterface::InitialState initialState,int maxRetries)533 std::unique_ptr<I2CInterface> create(uint8_t busId, uint8_t devAddr, 534 I2CInterface::InitialState initialState, 535 int maxRetries) 536 { 537 return I2CDevice::create(busId, devAddr, initialState, maxRetries); 538 } 539 540 } // namespace i2c 541