1 #pragma once 2 3 #include "i2c_interface.hpp" 4 5 namespace i2c 6 { 7 8 class I2CDevice : public I2CInterface 9 { 10 private: 11 I2CDevice() = delete; 12 13 /** @brief Constructor 14 * 15 * Construct I2CDevice object from the bus id and device address 16 * 17 * Automatically opens the I2CDevice if initialState is OPEN. 18 * 19 * @param[in] busId - The i2c bus ID 20 * @param[in] devAddr - The device address of the I2C device 21 * @param[in] initialState - Initial state of the I2CDevice object 22 * @param[in] maxRetries - Maximum number of times to retry an I2C operation 23 */ 24 explicit I2CDevice(uint8_t busId, uint8_t devAddr, 25 InitialState initialState = InitialState::OPEN, 26 int maxRetries = 0) : 27 busId(busId), 28 devAddr(devAddr), maxRetries(maxRetries) 29 { 30 busStr = "/dev/i2c-" + std::to_string(busId); 31 if (initialState == InitialState::OPEN) 32 { 33 open(); 34 } 35 } 36 37 /** @brief Invalid file descriptor */ 38 static constexpr int INVALID_FD = -1; 39 40 /** @brief Empty adapter functionality value with no bit flags set */ 41 static constexpr unsigned long NO_FUNCS = 0; 42 43 /** @brief The I2C bus ID */ 44 uint8_t busId; 45 46 /** @brief The i2c device address in the bus */ 47 uint8_t devAddr; 48 49 /** @brief Maximum number of times to retry an I2C operation */ 50 int maxRetries = 0; 51 52 /** @brief The file descriptor of the opened i2c device */ 53 int fd = INVALID_FD; 54 55 /** @brief The i2c bus path in /dev */ 56 std::string busStr; 57 58 /** @brief Cached I2C adapter functionality value */ 59 unsigned long cachedFuncs = NO_FUNCS; 60 61 /** @brief Check that device interface is open 62 * 63 * @throw I2CException if device is not open 64 */ 65 void checkIsOpen() const 66 { 67 if (!isOpen()) 68 { 69 throw I2CException("Device not open", busStr, devAddr); 70 } 71 } 72 73 /** @brief Close device without throwing an exception if an error occurs */ 74 void closeWithoutException() noexcept 75 { 76 try 77 { 78 close(); 79 } 80 catch (...) 81 {} 82 } 83 84 /** @brief Get I2C adapter functionality 85 * 86 * Caches the adapter functionality value since it shouldn't change after 87 * opening the device. 88 * 89 * @throw I2CException on error 90 * @return Adapter functionality value 91 */ 92 unsigned long getFuncs(); 93 94 /** @brief Check i2c adapter read functionality 95 * 96 * Check if the i2c adapter has the functionality specified by the SMBus 97 * transaction type 98 * 99 * @param[in] type - The SMBus transaction type defined in linux/i2c.h 100 * 101 * @throw I2CException if the function is not supported 102 */ 103 void checkReadFuncs(int type); 104 105 /** @brief Check i2c adapter write functionality 106 * 107 * Check if the i2c adapter has the functionality specified by the SMBus 108 * transaction type 109 * 110 * @param[in] type - The SMBus transaction type defined in linux/i2c.h 111 * 112 * @throw I2CException if the function is not supported 113 */ 114 void checkWriteFuncs(int type); 115 116 public: 117 /** @copydoc I2CInterface::~I2CInterface() */ 118 ~I2CDevice() 119 { 120 if (isOpen()) 121 { 122 // Note: destructors must not throw exceptions 123 closeWithoutException(); 124 } 125 } 126 127 /** @copydoc I2CInterface::open() */ 128 void open(); 129 130 /** @copydoc I2CInterface::isOpen() */ 131 bool isOpen() const 132 { 133 return (fd != INVALID_FD); 134 } 135 136 /** @copydoc I2CInterface::close() */ 137 void close(); 138 139 /** @copydoc I2CInterface::read(uint8_t&) */ 140 void read(uint8_t& data) override; 141 142 /** @copydoc I2CInterface::read(uint8_t,uint8_t&) */ 143 void read(uint8_t addr, uint8_t& data) override; 144 145 /** @copydoc I2CInterface::read(uint8_t,uint16_t&) */ 146 void read(uint8_t addr, uint16_t& data) override; 147 148 /** @copydoc I2CInterface::read(uint8_t,uint8_t&,uint8_t*,Mode) */ 149 void read(uint8_t addr, uint8_t& size, uint8_t* data, 150 Mode mode = Mode::SMBUS) override; 151 152 /** @copydoc I2CInterface::write(uint8_t) */ 153 void write(uint8_t data) override; 154 155 /** @copydoc I2CInterface::write(uint8_t,uint8_t) */ 156 void write(uint8_t addr, uint8_t data) override; 157 158 /** @copydoc I2CInterface::write(uint8_t,uint16_t) */ 159 void write(uint8_t addr, uint16_t data) override; 160 161 /** @copydoc I2CInterface::write(uint8_t,uint8_t,const uint8_t*,Mode) */ 162 void write(uint8_t addr, uint8_t size, const uint8_t* data, 163 Mode mode = Mode::SMBUS) override; 164 165 /** @brief Create an I2CInterface instance 166 * 167 * Automatically opens the I2CInterface if initialState is OPEN. 168 * 169 * @param[in] busId - The i2c bus ID 170 * @param[in] devAddr - The device address of the i2c 171 * @param[in] initialState - Initial state of the I2CInterface object 172 * @param[in] maxRetries - Maximum number of times to retry an I2C operation 173 * 174 * @return The unique_ptr holding the I2CInterface 175 */ 176 static std::unique_ptr<I2CInterface> 177 create(uint8_t busId, uint8_t devAddr, 178 InitialState initialState = InitialState::OPEN, 179 int maxRetries = 0); 180 }; 181 182 } // namespace i2c 183