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