mirror of
https://fuchsia.googlesource.com/third_party/pigweed.googlesource.com/pigweed/pigweed
synced 2024-09-20 22:00:58 +00:00
pw_i2c: Add Device class
This object will wrap the initiator along with an address. Device is a high level wrapper to be used to stream the reading or writing of arbitrary data to the device. Testing: Host test -- OK Change-Id: I28afd9a956917b28d4db04e8b1be2788981b12c7 Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/41163 Reviewed-by: Ewout van Bekkum <ewout@google.com> Pigweed-Auto-Submit: Ewout van Bekkum <ewout@google.com> Commit-Queue: Kevin Zeng <zengk@google.com>
This commit is contained in:
parent
a1113be66c
commit
6e15a13e9e
26
pw_i2c/BUILD
26
pw_i2c/BUILD
|
@ -49,6 +49,21 @@ pw_cc_library(
|
|||
],
|
||||
)
|
||||
|
||||
pw_cc_library(
|
||||
name = "device",
|
||||
hdrs = [
|
||||
"public/pw_i2c/device.h",
|
||||
],
|
||||
includes = ["public"],
|
||||
deps = [
|
||||
":address",
|
||||
":initiator",
|
||||
"//pw_bytes",
|
||||
"//pw_chrono:system_clock",
|
||||
"//pw_status",
|
||||
],
|
||||
)
|
||||
|
||||
pw_cc_test(
|
||||
name = "address_test",
|
||||
srcs = [
|
||||
|
@ -59,3 +74,14 @@ pw_cc_test(
|
|||
"//pw_unit_test",
|
||||
],
|
||||
)
|
||||
|
||||
pw_cc_test(
|
||||
name = "device_test",
|
||||
srcs = [
|
||||
"device_test.cc",
|
||||
],
|
||||
deps = [
|
||||
":device",
|
||||
"//pw_unit_test",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
import("//build_overrides/pigweed.gni")
|
||||
|
||||
import("$dir_pw_build/target_types.gni")
|
||||
import("$dir_pw_chrono/backend.gni")
|
||||
import("$dir_pw_docgen/docs.gni")
|
||||
import("$dir_pw_unit_test/test.gni")
|
||||
|
||||
|
@ -40,8 +41,22 @@ pw_source_set("initiator") {
|
|||
]
|
||||
}
|
||||
|
||||
pw_source_set("device") {
|
||||
public_configs = [ ":public_include_path" ]
|
||||
public = [ "public/pw_i2c/device.h" ]
|
||||
public_deps = [
|
||||
":address",
|
||||
":initiator",
|
||||
"$dir_pw_bytes",
|
||||
"$dir_pw_chrono:system_clock",
|
||||
"$dir_pw_status",
|
||||
]
|
||||
}
|
||||
pw_test_group("tests") {
|
||||
tests = [ ":address_test" ]
|
||||
tests = [
|
||||
":address_test",
|
||||
":device_test",
|
||||
]
|
||||
}
|
||||
|
||||
pw_test("address_test") {
|
||||
|
@ -49,6 +64,12 @@ pw_test("address_test") {
|
|||
deps = [ ":address" ]
|
||||
}
|
||||
|
||||
pw_test("device_test") {
|
||||
enable_if = pw_chrono_SYSTEM_CLOCK_BACKEND != ""
|
||||
sources = [ "device_test.cc" ]
|
||||
deps = [ ":device" ]
|
||||
}
|
||||
|
||||
pw_doc_group("docs") {
|
||||
sources = [ "docs.rst" ]
|
||||
}
|
||||
|
|
52
pw_i2c/device_test.cc
Normal file
52
pw_i2c/device_test.cc
Normal file
|
@ -0,0 +1,52 @@
|
|||
// Copyright 2021 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.
|
||||
#include "pw_i2c/device.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "pw_bytes/byte_builder.h"
|
||||
|
||||
namespace pw {
|
||||
namespace i2c {
|
||||
namespace {
|
||||
|
||||
// Dummy test initiator that's used for testing.
|
||||
class TestInitiator : public Initiator {
|
||||
public:
|
||||
explicit TestInitiator() {}
|
||||
|
||||
private:
|
||||
Status DoWriteReadFor(Address,
|
||||
ConstByteSpan,
|
||||
ByteSpan,
|
||||
chrono::SystemClock::duration) override {
|
||||
// Empty implementation.
|
||||
return OkStatus();
|
||||
}
|
||||
|
||||
ByteBuffer<10> write_buffer_;
|
||||
ByteBuffer<10> read_buffer_;
|
||||
};
|
||||
|
||||
// This test just checks to make sure the Device object compiles.
|
||||
// TODO(b/185609270): Full test coverage.
|
||||
TEST(DeviceCompilationTest, CompileOk) {
|
||||
constexpr Address kDummyDeviceAddress = Address::SevenBit<0x3F>();
|
||||
|
||||
TestInitiator initiator;
|
||||
Device device = Device(initiator, kDummyDeviceAddress);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace i2c
|
||||
} // namespace pw
|
|
@ -18,3 +18,10 @@ pw::i2c::Initiator
|
|||
The common interface for initiating transactions with devices on an I2C bus.
|
||||
Other documentation sources may call this style of interface an I2C "master",
|
||||
"central" or "controller".
|
||||
|
||||
pw::i2c::Device
|
||||
---------------
|
||||
The common interface for interfacing with generic I2C devices. This object
|
||||
contains ``pw::i2c::Address`` and wraps the ``pw::i2c::Initiator`` API.
|
||||
Common use case includes streaming arbitrary data (Read/Write). Only works
|
||||
with devices with a single device address.
|
||||
|
|
175
pw_i2c/public/pw_i2c/device.h
Normal file
175
pw_i2c/public/pw_i2c/device.h
Normal file
|
@ -0,0 +1,175 @@
|
|||
// Copyright 2021 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_status/status.h"
|
||||
|
||||
namespace pw {
|
||||
namespace i2c {
|
||||
|
||||
// Device is used to write/read arbitrary chunks of data over a bus to a device.
|
||||
// This object essentially just wrap the Initiator API with a fixed I2C device
|
||||
// address.
|
||||
class Device {
|
||||
public:
|
||||
constexpr Device(Initiator& initiator, Address device_address)
|
||||
: initiator_(initiator), device_address_(device_address) {}
|
||||
|
||||
Device(const Device&) = delete;
|
||||
~Device() = default;
|
||||
|
||||
// Write bytes and then read bytes as either one atomic or two independent I2C
|
||||
// transaction.
|
||||
// The signal on the bus should appear as follows:
|
||||
// 1) Write Only:
|
||||
// START + I2C Address + WRITE(0) + TX_BUFFER_BYTES + STOP
|
||||
// 2) Read Only:
|
||||
// START + I2C Address + READ(1) + RX_BUFFER_BYTES + STOP
|
||||
// 3A) Write + Read (atomic):
|
||||
// START + I2C Address + WRITE(0) + TX_BUFFER_BYTES +
|
||||
// START + I2C Address + READ(1) + RX_BUFFER_BYTES + STOP
|
||||
// 3B) Write + Read (separate):
|
||||
// START + I2C Address + WRITE(0) + TX_BUFFER_BYTES + STOP
|
||||
// START + I2C Address + READ(1) + RX_BUFFER_BYTES + STOP
|
||||
//
|
||||
// The timeout defines the minimum duration one may block waiting for both
|
||||
// exclusive bus access and the completion of the I2C transaction.
|
||||
//
|
||||
// Preconditions:
|
||||
// The Address must be supported by the Initiator, i.e. do not use a 10
|
||||
// address if the Initiator only supports 7 bit. This will assert.
|
||||
//
|
||||
// Returns:
|
||||
// Ok - Success.
|
||||
// InvalidArgument - device_address is larger than the 10 bit address space.
|
||||
// DeadlineExceeded - Was unable to acquire exclusive Initiator access
|
||||
// and complete the I2C transaction in time.
|
||||
// Unavailable - NACK condition occurred, meaning the addressed device did
|
||||
// not respond or was unable to process the request.
|
||||
// FailedPrecondition - The interface is not currently initialized and/or
|
||||
// enabled.
|
||||
Status WriteReadFor(ConstByteSpan tx_buffer,
|
||||
ByteSpan rx_buffer,
|
||||
chrono::SystemClock::duration for_at_least) {
|
||||
return initiator_.WriteReadFor(
|
||||
device_address_, tx_buffer, rx_buffer, for_at_least);
|
||||
}
|
||||
Status WriteReadFor(const void* tx_buffer,
|
||||
size_t tx_size_bytes,
|
||||
void* rx_buffer,
|
||||
size_t rx_size_bytes,
|
||||
chrono::SystemClock::duration for_at_least) {
|
||||
return initiator_.WriteReadFor(device_address_,
|
||||
tx_buffer,
|
||||
tx_size_bytes,
|
||||
rx_buffer,
|
||||
rx_size_bytes,
|
||||
for_at_least);
|
||||
}
|
||||
|
||||
// Write bytes. The signal on the bus should appear as follows:
|
||||
// START + I2C Address + WRITE(0) + TX_BUFFER_BYTES + STOP
|
||||
//
|
||||
// The timeout defines the minimum duration one may block waiting for both
|
||||
// exclusive bus access and the completion of the I2C transaction.
|
||||
//
|
||||
// Preconditions:
|
||||
// The Address must be supported by the Initiator, i.e. do not use a 10
|
||||
// address if the Initiator only supports 7 bit. This will assert.
|
||||
//
|
||||
// Returns:
|
||||
// Ok - Success.
|
||||
// InvalidArgument - device_address is larger than the 10 bit address space.
|
||||
// DeadlineExceeded - Was unable to acquire exclusive Initiator access
|
||||
// and complete the I2C transaction in time.
|
||||
// Unavailable - NACK condition occurred, meaning the addressed device did
|
||||
// not respond or was unable to process the request.
|
||||
// FailedPrecondition - The interface is not currently initialized and/or
|
||||
// enabled.
|
||||
Status WriteFor(ConstByteSpan tx_buffer,
|
||||
chrono::SystemClock::duration for_at_least) {
|
||||
return initiator_.WriteFor(device_address_, tx_buffer, for_at_least);
|
||||
}
|
||||
Status WriteFor(const void* tx_buffer,
|
||||
size_t tx_size_bytes,
|
||||
chrono::SystemClock::duration for_at_least) {
|
||||
return initiator_.WriteFor(
|
||||
device_address_, tx_buffer, tx_size_bytes, for_at_least);
|
||||
}
|
||||
|
||||
// Read bytes. The signal on the bus should appear as follows:
|
||||
// START + I2C Address + READ(1) + RX_BUFFER_BYTES + STOP
|
||||
//
|
||||
// The timeout defines the minimum duration one may block waiting for both
|
||||
// exclusive bus access and the completion of the I2C transaction.
|
||||
//
|
||||
// Preconditions:
|
||||
// The Address must be supported by the Initiator, i.e. do not use a 10
|
||||
// address if the Initiator only supports 7 bit. This will assert.
|
||||
//
|
||||
// Returns:
|
||||
// Ok - Success.
|
||||
// InvalidArgument - device_address is larger than the 10 bit address space.
|
||||
// DeadlineExceeded - Was unable to acquire exclusive Initiator access
|
||||
// and complete the I2C transaction in time.
|
||||
// Unavailable - NACK condition occurred, meaning the addressed device did
|
||||
// not respond or was unable to process the request.
|
||||
// FailedPrecondition - The interface is not currently initialized and/or
|
||||
// enabled.
|
||||
Status ReadFor(ByteSpan rx_buffer,
|
||||
chrono::SystemClock::duration for_at_least) {
|
||||
return initiator_.ReadFor(device_address_, rx_buffer, for_at_least);
|
||||
}
|
||||
Status ReadFor(void* rx_buffer,
|
||||
size_t rx_size_bytes,
|
||||
chrono::SystemClock::duration for_at_least) {
|
||||
return initiator_.ReadFor(
|
||||
device_address_, rx_buffer, rx_size_bytes, for_at_least);
|
||||
}
|
||||
|
||||
// Probes the device for an I2C ACK after only writing the address.
|
||||
// This is done by attempting to read a single byte from the specified device.
|
||||
//
|
||||
// The timeout defines the minimum duration one may block waiting for both
|
||||
// exclusive bus access and the completion of the I2C transaction.
|
||||
//
|
||||
// Preconditions:
|
||||
// The Address must be supported by the Initiator, i.e. do not use a 10
|
||||
// address if the Initiator only supports 7 bit. This will assert.
|
||||
//
|
||||
// Returns:
|
||||
// Ok - Success.
|
||||
// InvalidArgument - device_address is larger than the 10 bit address space.
|
||||
// DeadlineExceeded - Was unable to acquire exclusive Initiator access
|
||||
// and complete the I2C transaction in time.
|
||||
// Unavailable - NACK condition occurred, meaning the addressed device did
|
||||
// not respond or was unable to process the request.
|
||||
// FailedPrecondition - The interface is not currently initialized and/or
|
||||
// enabled.
|
||||
Status ProbeFor(chrono::SystemClock::duration for_at_least) {
|
||||
return initiator_.ProbeDeviceFor(device_address_, for_at_least);
|
||||
}
|
||||
|
||||
private:
|
||||
Initiator& initiator_;
|
||||
const Address device_address_;
|
||||
};
|
||||
|
||||
} // namespace i2c
|
||||
} // namespace pw
|
Loading…
Reference in New Issue
Block a user