| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // ====================================================================== | ||
| 2 | // \title LinuxI2cDriverComponentImpl.cpp | ||
| 3 | // \author tcanham | ||
| 4 | // \brief cpp file for LinuxI2cDriver component implementation class | ||
| 5 | // | ||
| 6 | // \copyright | ||
| 7 | // Copyright 2009-2015, by the California Institute of Technology. | ||
| 8 | // ALL RIGHTS RESERVED. United States Government Sponsorship | ||
| 9 | // acknowledged. | ||
| 10 | // | ||
| 11 | // ====================================================================== | ||
| 12 | |||
| 13 | #include <Drv/LinuxI2cDriver/LinuxI2cDriver.hpp> | ||
| 14 | #include <Fw/FPrimeBasicTypes.hpp> | ||
| 15 | #include <Fw/Logger/Logger.hpp> | ||
| 16 | #include "Fw/Types/Assert.hpp" | ||
| 17 | |||
| 18 | #include <fcntl.h> // required for I2C device configuration | ||
| 19 | #include <linux/i2c-dev.h> // required for constant definitions | ||
| 20 | #include <linux/i2c.h> // required for struct / constant definitions | ||
| 21 | #include <sys/ioctl.h> // required for I2C device usage | ||
| 22 | #include <unistd.h> // required for I2C device access | ||
| 23 | #include <cerrno> | ||
| 24 | |||
| 25 | namespace Drv { | ||
| 26 | |||
| 27 | // ---------------------------------------------------------------------- | ||
| 28 | // Construction, initialization, and destruction | ||
| 29 | // ---------------------------------------------------------------------- | ||
| 30 | |||
| 31 | ✗ | LinuxI2cDriver ::LinuxI2cDriver(const char* const compName) : LinuxI2cDriverComponentBase(compName), m_fd(-1) {} | |
| 32 | |||
| 33 | ✗ | LinuxI2cDriver::~LinuxI2cDriver() { | |
| 34 | ✗ | if (-1 != this->m_fd) { // check if file is open | |
| 35 | ✗ | (void)::close(this->m_fd); | |
| 36 | } | ||
| 37 | ✗ | } | |
| 38 | |||
| 39 | ✗ | bool LinuxI2cDriver::open(const char* device) { | |
| 40 | ✗ | FW_ASSERT(device != nullptr); | |
| 41 | ✗ | this->m_fd = ::open(device, O_RDWR); | |
| 42 | ✗ | return (-1 != this->m_fd); | |
| 43 | } | ||
| 44 | |||
| 45 | // ---------------------------------------------------------------------- | ||
| 46 | // Handler implementations for user-defined typed input ports | ||
| 47 | // ---------------------------------------------------------------------- | ||
| 48 | |||
| 49 | // Note this port handler is guarded, so we can make the ioctl call | ||
| 50 | |||
| 51 | ✗ | Drv::I2cStatus LinuxI2cDriver ::write_handler(const FwIndexType portNum, U32 addr, Fw::Buffer& serBuffer) { | |
| 52 | // Make sure file has been opened | ||
| 53 | ✗ | if (-1 == this->m_fd) { | |
| 54 | ✗ | return I2cStatus::I2C_OPEN_ERR; | |
| 55 | } | ||
| 56 | |||
| 57 | // select slave address | ||
| 58 | ✗ | int stat = ioctl(this->m_fd, I2C_SLAVE, addr); | |
| 59 | ✗ | if (stat == -1) { | |
| 60 | ✗ | return I2cStatus::I2C_ADDRESS_ERR; | |
| 61 | } | ||
| 62 | // make sure it isn't a null pointer | ||
| 63 | ✗ | FW_ASSERT(serBuffer.getData() != nullptr); | |
| 64 | ✗ | FW_ASSERT_NO_OVERFLOW(serBuffer.getSize(), size_t); | |
| 65 | // write data | ||
| 66 | ✗ | ssize_t status_write = write(this->m_fd, serBuffer.getData(), static_cast<size_t>(serBuffer.getSize())); | |
| 67 | ✗ | if ((status_write == -1) || (static_cast<FwSizeType>(status_write) != serBuffer.getSize())) { | |
| 68 | ✗ | return I2cStatus::I2C_WRITE_ERR; | |
| 69 | } | ||
| 70 | ✗ | return I2cStatus::I2C_OK; | |
| 71 | } | ||
| 72 | |||
| 73 | ✗ | Drv::I2cStatus LinuxI2cDriver ::read_handler(const FwIndexType portNum, U32 addr, Fw::Buffer& serBuffer) { | |
| 74 | // Make sure file has been opened | ||
| 75 | ✗ | if (-1 == this->m_fd) { | |
| 76 | ✗ | return I2cStatus::I2C_OPEN_ERR; | |
| 77 | } | ||
| 78 | |||
| 79 | // select slave address | ||
| 80 | ✗ | int stat = ioctl(this->m_fd, I2C_SLAVE, addr); | |
| 81 | ✗ | if (stat == -1) { | |
| 82 | ✗ | return I2cStatus::I2C_ADDRESS_ERR; | |
| 83 | } | ||
| 84 | // make sure it isn't a null pointer | ||
| 85 | ✗ | FW_ASSERT(serBuffer.getData() != nullptr); | |
| 86 | // read data | ||
| 87 | ✗ | FW_ASSERT_NO_OVERFLOW(serBuffer.getSize(), size_t); | |
| 88 | ✗ | ssize_t status_read = read(this->m_fd, serBuffer.getData(), static_cast<size_t>(serBuffer.getSize())); | |
| 89 | ✗ | if ((status_read == -1) || (static_cast<FwSizeType>(status_read) != serBuffer.getSize())) { | |
| 90 | ✗ | return I2cStatus::I2C_READ_ERR; | |
| 91 | } | ||
| 92 | ✗ | return I2cStatus::I2C_OK; | |
| 93 | } | ||
| 94 | |||
| 95 | ✗ | Drv::I2cStatus LinuxI2cDriver ::writeRead_handler(const FwIndexType portNum, /*!< The port number*/ | |
| 96 | U32 addr, | ||
| 97 | Fw::Buffer& writeBuffer, | ||
| 98 | Fw::Buffer& readBuffer) { | ||
| 99 | // Make sure file has been opened | ||
| 100 | ✗ | if (-1 == this->m_fd) { | |
| 101 | ✗ | return I2cStatus::I2C_OPEN_ERR; | |
| 102 | } | ||
| 103 | ✗ | FW_ASSERT(-1 != this->m_fd); | |
| 104 | |||
| 105 | // make sure they are not null pointers | ||
| 106 | ✗ | FW_ASSERT(writeBuffer.getData() != nullptr); | |
| 107 | ✗ | FW_ASSERT(readBuffer.getData() != nullptr); | |
| 108 | // make sure downcasts are safe | ||
| 109 | ✗ | FW_ASSERT_NO_OVERFLOW(addr, U16); | |
| 110 | ✗ | FW_ASSERT_NO_OVERFLOW(writeBuffer.getSize(), U16); | |
| 111 | ✗ | FW_ASSERT_NO_OVERFLOW(readBuffer.getSize(), U16); | |
| 112 | |||
| 113 | ✗ | struct i2c_msg rdwr_msgs[2]; | |
| 114 | |||
| 115 | // Start address | ||
| 116 | ✗ | rdwr_msgs[0].addr = static_cast<U16>(addr); | |
| 117 | ✗ | rdwr_msgs[0].flags = 0; // write | |
| 118 | ✗ | rdwr_msgs[0].len = static_cast<U16>(writeBuffer.getSize()); | |
| 119 | ✗ | rdwr_msgs[0].buf = writeBuffer.getData(); | |
| 120 | |||
| 121 | // Read buffer | ||
| 122 | ✗ | rdwr_msgs[1].addr = static_cast<U16>(addr); | |
| 123 | ✗ | rdwr_msgs[1].flags = I2C_M_RD; // read | |
| 124 | ✗ | rdwr_msgs[1].len = static_cast<U16>(readBuffer.getSize()); | |
| 125 | ✗ | rdwr_msgs[1].buf = readBuffer.getData(); | |
| 126 | |||
| 127 | ✗ | struct i2c_rdwr_ioctl_data rdwr_data; | |
| 128 | ✗ | rdwr_data.msgs = rdwr_msgs; | |
| 129 | ✗ | rdwr_data.nmsgs = 2; | |
| 130 | |||
| 131 | // Use ioctl to perform the combined write/read transaction | ||
| 132 | ✗ | int stat = ioctl(this->m_fd, I2C_RDWR, &rdwr_data); | |
| 133 | |||
| 134 | ✗ | if (stat == -1) { | |
| 135 | // Because we're using ioctl to perform the transaction we dont know exactly the type of error that occurred | ||
| 136 | ✗ | return I2cStatus::I2C_OTHER_ERR; | |
| 137 | } | ||
| 138 | |||
| 139 | ✗ | return I2cStatus::I2C_OK; | |
| 140 | } | ||
| 141 | |||
| 142 | } // end namespace Drv | ||
| 143 |