diff options
Diffstat (limited to 'pw_i2c_linux/public/pw_i2c_linux/initiator.h')
-rw-r--r-- | pw_i2c_linux/public/pw_i2c_linux/initiator.h | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/pw_i2c_linux/public/pw_i2c_linux/initiator.h b/pw_i2c_linux/public/pw_i2c_linux/initiator.h new file mode 100644 index 000000000..2fe5d6607 --- /dev/null +++ b/pw_i2c_linux/public/pw_i2c_linux/initiator.h @@ -0,0 +1,96 @@ +// Copyright 2023 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +#pragma once + +#include "pw_bytes/span.h" +#include "pw_chrono/system_clock.h" +#include "pw_i2c/address.h" +#include "pw_i2c/initiator.h" +#include "pw_result/result.h" +#include "pw_status/status.h" +#include "pw_sync/lock_annotations.h" +#include "pw_sync/timed_mutex.h" + +namespace pw::i2c { + +/// 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. +/// +class LinuxInitiator final : public Initiator { + public: + /// Open an I2C bus and validate that full I2C functionality is supported. + /// + /// @param[in] bus_path Path to the I2C bus device node. + /// + /// @retval OK The device node was opened successfully. + /// @retval InvalidArgument Failed to open the device node or to validate I2C + /// functionality. + /// + /// @return The open file descriptor on success. + /// + static Result<int> OpenI2cBus(const char* bus_path); + + /// Construct an instantiator using an open file descriptor. + /// The file descriptor is closed during destruction. + /// + /// @param[in] fd Valid file descriptor for an I2C device node. + /// + LinuxInitiator(int fd); + + LinuxInitiator(const LinuxInitiator&) = delete; + LinuxInitiator& operator=(const LinuxInitiator&) = delete; + + ~LinuxInitiator() override; + + private: + /// Implement pw::i2c::Initiator with the following additional requriements: + /// - Asserts that `device_address` is a 7-bit address. + /// - At least one of `tx_buffer` or `rx_buffer` must be not empty. + /// Otherwise, returns InvalidArgument. + /// + /// @note + /// The timeout is used both for getting an exclusive lock on the initiator + /// and for getting exclusive use of a multi-controller bus. If the timeout + /// is zero or negative, the transaction will only execute if there is no + /// contention at either level. + /// + Status DoWriteReadFor(Address device_address, + ConstByteSpan tx_buffer, + ByteSpan rx_buffer, + chrono::SystemClock::duration timeout) override + PW_LOCKS_EXCLUDED(mutex_); + + Status DoWriteReadForLocked(uint8_t address, + ConstByteSpan tx_buffer, + ByteSpan rx_buffer, + chrono::SystemClock::duration timeout) + PW_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + /// The file descriptor for the i2c-dev device representing this bus. + const int fd_; + + /// This mutex is used to synchronize access across multiple retries. + sync::TimedMutex mutex_; +}; + +} // namespace pw::i2c |