pw_spi: Introduce SPI HAL
This change introduces a new SPI HAL API, featuring abstractions
enabling a target device to communicate with SPI peripherals in
a portable and consistent fashion.
Change-Id: Idc085c4727abb9247732c40cc84d05ee4113bd78
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/70140
Reviewed-by: Ewout van Bekkum <ewout@google.com>
Reviewed-by: Keir Mierle <keir@google.com>
Commit-Queue: Mark Slevinsky <markslevinsky@google.com>
diff --git a/pw_spi/linux_spi_test.cc b/pw_spi/linux_spi_test.cc
new file mode 100644
index 0000000..23a881b
--- /dev/null
+++ b/pw_spi/linux_spi_test.cc
@@ -0,0 +1,101 @@
+// 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_spi/linux_spi.h"
+
+#include <array>
+#include <optional>
+
+#include "gtest/gtest.h"
+#include "pw_spi/chip_selector.h"
+#include "pw_spi/device.h"
+#include "pw_spi/initiator.h"
+#include "pw_status/status.h"
+#include "pw_sync/borrow.h"
+
+namespace pw::spi {
+namespace {
+
+const pw::spi::Config kConfig = {.polarity = ClockPolarity::kActiveHigh,
+ .phase = ClockPhase::kFallingEdge,
+ .bits_per_word = BitsPerWord(8),
+ .bit_order = BitOrder::kMsbFirst};
+
+class LinuxSpi : public ::testing::Test {
+ public:
+ LinuxSpi()
+ : initiator_(LinuxInitiator("/dev/spidev0.0", 1000000)),
+ chip_selector_(),
+ initiator_lock_(),
+ borrowable_initiator_(initiator_, initiator_lock_),
+ device_(borrowable_initiator_, kConfig, chip_selector_) {}
+
+ Device& device() { return device_; }
+
+ private:
+ LinuxInitiator initiator_;
+ LinuxChipSelector chip_selector_;
+ sync::VirtualMutex initiator_lock_;
+ sync::Borrowable<Initiator> borrowable_initiator_;
+ [[maybe_unused]] Device device_;
+};
+
+TEST_F(LinuxSpi, StartTransaction_Succeeds) {
+ // arrange
+ std::optional<Device::Transaction> transaction =
+ device().StartTransaction(ChipSelectBehavior::kPerWriteRead);
+
+ // act
+
+ // assert
+ EXPECT_TRUE(transaction.has_value());
+}
+
+TEST_F(LinuxSpi, HalfDuplexTransaction_Succeeds) {
+ // arrange
+ std::optional<Device::Transaction> transaction =
+ device().StartTransaction(ChipSelectBehavior::kPerWriteRead);
+
+ // act
+ ASSERT_TRUE(transaction.has_value());
+
+ std::array write_data{std::byte(1), std::byte(2), std::byte(3), std::byte(4)};
+ auto write_status = transaction->Write(ConstByteSpan(write_data));
+
+ std::array read_data{std::byte(1), std::byte(2), std::byte(3), std::byte(4)};
+ auto read_status = transaction->Read(read_data);
+
+ // assert
+ EXPECT_TRUE(write_status.ok());
+ EXPECT_TRUE(read_status.ok());
+}
+
+TEST_F(LinuxSpi, FullDuplexTransaction_Succeeds) {
+ // arrange
+ std::optional<Device::Transaction> transaction =
+ device().StartTransaction(ChipSelectBehavior::kPerWriteRead);
+
+ // act
+ ASSERT_TRUE(transaction.has_value());
+
+ std::array write_data{std::byte(1), std::byte(2), std::byte(3), std::byte(4)};
+ std::array read_data{std::byte(0), std::byte(0), std::byte(0), std::byte(0)};
+ auto wr_status = transaction->WriteRead(ConstByteSpan(write_data), read_data);
+
+ // assert
+ EXPECT_TRUE(wr_status.ok());
+}
+
+} // namespace
+} // namespace pw::spi