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