pw_i2c_linux#
Linux userspace implementation for pw_i2c
Stable C++17
pw_i2c_linux
implements the pw_i2c
interface using the Linux userspace
i2c-dev
driver. Transfers are executed using blocking ioctl
calls.
Arbitrary-order read and write messages are supported by one underlying system
call. A retry mechanism is used to support bus arbitration between multiple
controllers.
Support for ten-bit addresses and the no-start flag is enabled but depends on underlying support by the linux-managed device.
API reference#
-
class LinuxInitiator : public pw::i2c::Initiator#
Initiator interface implementation using the Linux userspace i2c-dev driver.
Takes exclusive control of an I2C bus device (ex. “/dev/i2c-0”). The user is responsible to open the device node prior to creating the initiator. The file descriptor is closed when the initiator object is destroyed.
The bus device must support the full I2C functionality. Users of the class are encouraged to use the
OpenI2cBus
helper to ensure the bus is valid.Access to the bus is guarded by an internal mutex, so this initiator can be safely used from multiple threads.
Public Functions
-
LinuxInitiator(int fd)#
Construct an instantiator using an open file descriptor. The file descriptor is closed during destruction.
- Parameters:
fd – [in] Valid file descriptor for an I2C device node.
Public Static Functions
-
static Result<int> OpenI2cBus(const char *bus_path)#
Open an I2C bus and validate that full I2C functionality is supported.
- Parameters:
bus_path – [in] Path to the I2C bus device node.
- Return values:
OK – The device node was opened successfully.
InvalidArgument – Failed to open the device node or to validate I2C functionality.
- Returns:
The open file descriptor on success.
-
LinuxInitiator(int fd)#
Examples#
A simple example illustrating the usage:
#include "pw_i2c/address.h"
#include "pw_i2c/device.h"
#include "pw_i2c_linux/initiator.h"
#include "pw_log/log.h"
#include "pw_result/result.h"
constexpr auto kBusPath = "/dev/i2c-0";
constexpr auto kAddress = pw::i2c::Address::SevenBit<0x42>();
pw::Result<int> result = pw::i2c::LinuxInitiator::OpenI2cBus(kBusPath);
if (!result.ok()) {
PW_LOG_ERROR("Failed to open I2C bus [%s]", kBusPath);
return result.status();
}
pw::i2c::LinuxInitiator initiator(*result);
pw::i2c::Device device(initiator, address);
// Use device to talk to address.
In real-world use cases, you may want to create an initiator singleton. This can be done by initializing a function-local static variable with a lambda:
#include <functional>
#include "pw_i2c/address.h"
#include "pw_i2c/device.h"
#include "pw_i2c/initiator.h"
#include "pw_i2c_linux/initiator.h"
#include "pw_log/log.h"
#include "pw_result/result.h"
#include "pw_status/status.h"
// Open the I2C bus and return an initiator singleton.
pw::i2c::Initiator* GetInitiator() {
static constexpr auto kBusPath = "/dev/i2c-0";
static auto* initiator = std::invoke([]() -> pw::i2c::Initiator* {
pw::Result<int> result = pw::i2c::LinuxInitiator::OpenI2cBus(kBusPath);
if (!result.ok()) {
PW_LOG_ERROR("Failed to open I2C bus [%s]", kBusPath);
return nullptr;
}
return new pw::i2c::Initiator(*result);
});
return initiator;
}
// Use the initiator from anywhere.
constexpr auto kAddress = pw::i2c::Address::SevenBit<0x42>();
auto* initiator = GetInitiator();
if (initiator == nullptr) {
PW_LOG_ERROR("I2C initiator unavailable");
return pw::Status::Internal();
}
pw::i2c::Device device(*initiator, address);
// Use device to talk to address.
Command-line interface#
This module also provides a tool also named pw_i2c_linux_cli
which
provides a basic command-line interface to the library.
Usage:
Usage: pw_i2c_linux_cli -D DEVICE -A|-a ADDR [flags]
Required flags:
-A/--addr10 Target address, 0x prefix allowed (10-bit i2c extension)
-a/--address Target address, 0x prefix allowed (7-bit standard i2c)
-D/--device I2C device path (e.g. /dev/i2c-0)
Optional flags:
-h/--human Human-readable output (default: binary, unless output to stdout tty)
-i/--input Input file, or - for stdin
If not given, no data is sent.
-l/--lsb LSB first (default: MSB first)
-o/--output Output file (default: stdout)
-r/--rx-count Number of bytes to receive (defaults to size of input)
Example:
# Read register 0x0950 (Write two bytes then read one byte)
$ echo -en "\\x9\\x50" | pw_i2c_linux_cli -D /dev/i2c-2 -a 0x09 -i - -r 1