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 #include <i2c/smbus.h> 13 #include <linux/i2c-dev.h> 14 #include <linux/i2c.h> 15 } 16 17 namespace i2c 18 { 19 20 void I2CDevice::checkReadFuncs(int type) 21 { 22 unsigned long funcs; 23 24 /* Check adapter functionality */ 25 if (ioctl(fd, I2C_FUNCS, &funcs) < 0) 26 { 27 throw I2CException("Failed to get funcs", busStr, devAddr, errno); 28 } 29 30 switch (type) 31 { 32 case I2C_SMBUS_BYTE: 33 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE)) 34 { 35 throw I2CException("Missing SMBUS_READ_BYTE", busStr, devAddr); 36 } 37 break; 38 case I2C_SMBUS_BYTE_DATA: 39 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA)) 40 { 41 throw I2CException("Missing SMBUS_READ_BYTE_DATA", busStr, 42 devAddr); 43 } 44 break; 45 46 case I2C_SMBUS_WORD_DATA: 47 if (!(funcs & I2C_FUNC_SMBUS_READ_WORD_DATA)) 48 { 49 throw I2CException("Missing SMBUS_READ_WORD_DATA", busStr, 50 devAddr); 51 } 52 break; 53 case I2C_SMBUS_BLOCK_DATA: 54 if (!(funcs & I2C_FUNC_SMBUS_READ_BLOCK_DATA)) 55 { 56 throw I2CException("Missing SMBUS_READ_BLOCK_DATA", busStr, 57 devAddr); 58 } 59 break; 60 case I2C_SMBUS_I2C_BLOCK_DATA: 61 if (!(funcs & I2C_FUNC_SMBUS_READ_I2C_BLOCK)) 62 { 63 throw I2CException("Missing I2C_FUNC_SMBUS_READ_I2C_BLOCK", 64 busStr, devAddr); 65 } 66 break; 67 default: 68 fprintf(stderr, "Unexpected read size type: %d\n", type); 69 assert(false); 70 break; 71 } 72 } 73 74 void I2CDevice::checkWriteFuncs(int type) 75 { 76 unsigned long funcs; 77 78 /* Check adapter functionality */ 79 if (ioctl(fd, I2C_FUNCS, &funcs) < 0) 80 { 81 throw I2CException("Failed to get funcs", busStr, devAddr, errno); 82 } 83 84 switch (type) 85 { 86 case I2C_SMBUS_BYTE: 87 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE)) 88 { 89 throw I2CException("Missing SMBUS_WRITE_BYTE", busStr, devAddr); 90 } 91 break; 92 case I2C_SMBUS_BYTE_DATA: 93 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) 94 { 95 throw I2CException("Missing SMBUS_WRITE_BYTE_DATA", busStr, 96 devAddr); 97 } 98 break; 99 100 case I2C_SMBUS_WORD_DATA: 101 if (!(funcs & I2C_FUNC_SMBUS_WRITE_WORD_DATA)) 102 { 103 throw I2CException("Missing SMBUS_WRITE_WORD_DATA", busStr, 104 devAddr); 105 } 106 break; 107 case I2C_SMBUS_BLOCK_DATA: 108 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BLOCK_DATA)) 109 { 110 throw I2CException("Missing SMBUS_WRITE_BLOCK_DATA", busStr, 111 devAddr); 112 } 113 break; 114 case I2C_SMBUS_I2C_BLOCK_DATA: 115 if (!(funcs & I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) 116 { 117 throw I2CException("Missing I2C_FUNC_SMBUS_WRITE_I2C_BLOCK", 118 busStr, devAddr); 119 } 120 break; 121 default: 122 fprintf(stderr, "Unexpected read size type: %d\n", type); 123 assert(false); 124 } 125 } 126 127 void I2CDevice::open() 128 { 129 if (isOpen()) 130 { 131 throw I2CException("Device already open", busStr, devAddr); 132 } 133 134 fd = ::open(busStr.c_str(), O_RDWR); 135 if (fd == -1) 136 { 137 throw I2CException("Failed to open", busStr, devAddr, errno); 138 } 139 140 if (ioctl(fd, I2C_SLAVE, devAddr) < 0) 141 { 142 // Close device since setting slave address failed 143 closeWithoutException(); 144 145 throw I2CException("Failed to set I2C_SLAVE", busStr, devAddr, errno); 146 } 147 } 148 149 void I2CDevice::close() 150 { 151 checkIsOpen(); 152 if (::close(fd) == -1) 153 { 154 throw I2CException("Failed to close", busStr, devAddr, errno); 155 } 156 fd = INVALID_FD; 157 } 158 159 void I2CDevice::read(uint8_t& data) 160 { 161 checkIsOpen(); 162 checkReadFuncs(I2C_SMBUS_BYTE); 163 164 int ret = i2c_smbus_read_byte(fd); 165 if (ret < 0) 166 { 167 throw I2CException("Failed to read byte", busStr, devAddr, errno); 168 } 169 data = static_cast<uint8_t>(ret); 170 } 171 172 void I2CDevice::read(uint8_t addr, uint8_t& data) 173 { 174 checkIsOpen(); 175 checkReadFuncs(I2C_SMBUS_BYTE_DATA); 176 177 int ret = i2c_smbus_read_byte_data(fd, addr); 178 if (ret < 0) 179 { 180 throw I2CException("Failed to read byte data", busStr, devAddr, errno); 181 } 182 data = static_cast<uint8_t>(ret); 183 } 184 185 void I2CDevice::read(uint8_t addr, uint16_t& data) 186 { 187 checkIsOpen(); 188 checkReadFuncs(I2C_SMBUS_WORD_DATA); 189 int ret = i2c_smbus_read_word_data(fd, addr); 190 if (ret < 0) 191 { 192 throw I2CException("Failed to read word data", busStr, devAddr, errno); 193 } 194 data = static_cast<uint16_t>(ret); 195 } 196 197 void I2CDevice::read(uint8_t addr, uint8_t& size, uint8_t* data, Mode mode) 198 { 199 checkIsOpen(); 200 int ret; 201 switch (mode) 202 { 203 case Mode::SMBUS: 204 checkReadFuncs(I2C_SMBUS_BLOCK_DATA); 205 ret = i2c_smbus_read_block_data(fd, addr, data); 206 break; 207 case Mode::I2C: 208 checkReadFuncs(I2C_SMBUS_I2C_BLOCK_DATA); 209 ret = i2c_smbus_read_i2c_block_data(fd, addr, size, data); 210 if (ret != size) 211 { 212 throw I2CException("Failed to read i2c block data", busStr, 213 devAddr, errno); 214 } 215 break; 216 } 217 if (ret < 0) 218 { 219 throw I2CException("Failed to read block data", busStr, devAddr, errno); 220 } 221 size = static_cast<uint8_t>(ret); 222 } 223 224 void I2CDevice::write(uint8_t data) 225 { 226 checkIsOpen(); 227 checkWriteFuncs(I2C_SMBUS_BYTE); 228 229 if (i2c_smbus_write_byte(fd, data) < 0) 230 { 231 throw I2CException("Failed to write byte", busStr, devAddr, errno); 232 } 233 } 234 235 void I2CDevice::write(uint8_t addr, uint8_t data) 236 { 237 checkIsOpen(); 238 checkWriteFuncs(I2C_SMBUS_BYTE_DATA); 239 240 if (i2c_smbus_write_byte_data(fd, addr, data) < 0) 241 { 242 throw I2CException("Failed to write byte data", busStr, devAddr, errno); 243 } 244 } 245 246 void I2CDevice::write(uint8_t addr, uint16_t data) 247 { 248 checkIsOpen(); 249 checkWriteFuncs(I2C_SMBUS_WORD_DATA); 250 251 if (i2c_smbus_write_word_data(fd, addr, data) < 0) 252 { 253 throw I2CException("Failed to write word data", busStr, devAddr, errno); 254 } 255 } 256 257 void I2CDevice::write(uint8_t addr, uint8_t size, const uint8_t* data, 258 Mode mode) 259 { 260 checkIsOpen(); 261 int ret; 262 switch (mode) 263 { 264 case Mode::SMBUS: 265 checkWriteFuncs(I2C_SMBUS_BLOCK_DATA); 266 ret = i2c_smbus_write_block_data(fd, addr, size, data); 267 break; 268 case Mode::I2C: 269 checkWriteFuncs(I2C_SMBUS_I2C_BLOCK_DATA); 270 ret = i2c_smbus_write_i2c_block_data(fd, addr, size, data); 271 break; 272 } 273 if (ret < 0) 274 { 275 throw I2CException("Failed to write block data", busStr, devAddr, 276 errno); 277 } 278 } 279 280 std::unique_ptr<I2CInterface> I2CDevice::create(uint8_t busId, uint8_t devAddr, 281 InitialState initialState) 282 { 283 std::unique_ptr<I2CDevice> dev(new I2CDevice(busId, devAddr, initialState)); 284 return dev; 285 } 286 287 std::unique_ptr<I2CInterface> create(uint8_t busId, uint8_t devAddr, 288 I2CInterface::InitialState initialState) 289 { 290 return I2CDevice::create(busId, devAddr, initialState); 291 } 292 293 } // namespace i2c 294