Implementing I2C_TIMEOUT to prevent blocking

Hi! I’m working on getting I2C_TIMEOUT to work, but am struggling. I can consistently get the errno of ETIMEDOUT to trigger with a faulty I2C device of mine, but I want to shorten that timeout to 10-20 ms.

However, no matter what I set the I2C_TIMEOUT to, it never changes the timeout in the print. I’m getting timeouts of about one second (1036498619 nanoseconds was my last run using a timeout of 500 ms)

BeagleBone Information

debian@BeagleBone:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description:    Debian GNU/Linux 11 (bullseye)
Release:    11
Codename:   bullseye
debian@BeagleBone:~$ uname -r
5.10.168-ti-r77

General class implementation

#include <fcntl.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include <stdbool.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>

#define MACRO_TO_CHECK_ERRNO(foo) {};

// Set in constructor
std::string bus_name_;
uint8_t addr_;
int fd_;

Opening and configuring the driver

bool I2cDriver::open()
{
    MACRO_TO_CHECK_ERRNO(fd_ = ::open(bus_name_.c_str(), O_RDWR | O_NONBLOCK));
    MACRO_TO_CHECK_ERRNO(ioctl(fd_, I2C_SLAVE, addr_));
    MACRO_TO_CHECK_ERRNO(ioctl(fd_, I2C_PEC, 0));
    MACRO_TO_CHECK_ERRNO(ioctl(fd_, I2C_TIMEOUT, 50)); // 50 = 500 ms as the units is 10 ms
    return true;
}

Writing a message to the device

bool I2cDriver::write_handler(std::vector<uint8_t> &write_data) const
{
    pseudo_validate_data();

    const uint32_t num_msgs = 1;
    struct i2c_msg msgs[num_msgs]; // i2c_ms is from i2c.h

    // Prepare the write message.
    msgs[0].addr = addr_;
    msgs[0].flags = 0;
    msgs[0].len = (uint16_t)write_data.size();
    msgs[0].buf = write_data.data();

    // Build the write transaction.
    struct i2c_rdwr_ioctl_data ioctl_data;
    ioctl_data.msgs = msgs;
    ioctl_data.nmsgs = num_msgs;

    // Perform the write operation    
    double start = pseudo_get_time();
    if (ioctl(fd_, I2C_RDWR, &ioctl_data) < 0)
    {
        double end = pseudo_get_time();
        i2c_timeout_log << "WRITE " << errnoname(errno) << ": " << end - start
                        << ": " << dev_name_.c_str() << std::endl;        
        return false;
    }

    return true;
}