1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15
16 #include <array>
17 #include <cstddef>
18 #include <optional>
19
20 #include "pw_bytes/span.h"
21 #include "pw_containers/to_array.h"
22 #include "pw_i2c/initiator.h"
23
24 namespace pw::i2c {
25
26 // Represents a complete parameter set for the Initiator::DoWriteReadFor().
27 class Transaction {
28 public:
29 // Same set of parameters as Initiator::DoWriteReadFor(), with the exception
30 // of optional parameter timeout.
31 constexpr Transaction(
32 Status expected_return_value,
33 Address device_address,
34 ConstByteSpan write_buffer,
35 ConstByteSpan read_buffer,
36 std::optional<chrono::SystemClock::duration> timeout = std::nullopt)
return_value_(expected_return_value)37 : return_value_(expected_return_value),
38 read_buffer_(read_buffer),
39 write_buffer_(write_buffer),
40 address_(device_address),
41 timeout_(timeout) {}
42
43 // Alternate Transaction constructor for use in ProbeTransaction.
44 constexpr Transaction(
45 Status expected_return_value,
46 Address device_address,
47 std::optional<chrono::SystemClock::duration> timeout = std::nullopt)
Transaction(expected_return_value,device_address,ConstByteSpan (),ignored_buffer_,timeout)48 : Transaction(expected_return_value,
49 device_address,
50 ConstByteSpan(),
51 ignored_buffer_,
52 timeout) {}
53
54 // Gets the buffer that is virtually read.
read_buffer()55 ConstByteSpan read_buffer() const { return read_buffer_; }
56
57 // Gets the buffer that should be written by the driver.
write_buffer()58 ConstByteSpan write_buffer() const { return write_buffer_; }
59
60 // Gets the min duration for a blocking i2c transaction.
timeout()61 std::optional<chrono::SystemClock::duration> timeout() const {
62 return timeout_;
63 }
64
65 // Gets the i2c address that the i2c transaction is targetting.
address()66 Address address() const { return address_; }
67
68 // Gets the expected return value.
return_value()69 Status return_value() const { return return_value_; }
70
71 private:
72 const Status return_value_;
73 const ConstByteSpan read_buffer_;
74 const ConstByteSpan write_buffer_;
75 static constexpr std::array<std::byte, 1> ignored_buffer_ = {};
76 const Address address_;
77 const std::optional<chrono::SystemClock::duration> timeout_;
78 };
79
80 // Read transaction is a helper that constructs a read only transaction.
81 constexpr Transaction ReadTransaction(
82 Status expected_return_value,
83 Address device_address,
84 ConstByteSpan read_buffer,
85 std::optional<chrono::SystemClock::duration> timeout = std::nullopt) {
86 return Transaction(expected_return_value,
87 device_address,
88 ConstByteSpan(),
89 read_buffer,
90 timeout);
91 }
92
93 // WriteTransaction is a helper that constructs a write only transaction.
94 constexpr Transaction WriteTransaction(
95 Status expected_return_value,
96 Address device_address,
97 ConstByteSpan write_buffer,
98 std::optional<chrono::SystemClock::duration> timeout = std::nullopt) {
99 return Transaction(expected_return_value,
100 device_address,
101 write_buffer,
102 ConstByteSpan(),
103 timeout);
104 }
105
106 // ProbeTransaction is a helper that constructs a one-byte read transaction.
107 // For use in testing Probe transactions with the Mock Initiator.
108 constexpr Transaction ProbeTransaction(
109 Status expected_return_value,
110 Address device_address,
111 std::optional<chrono::SystemClock::duration> timeout = std::nullopt) {
112 return Transaction(expected_return_value, device_address, timeout);
113 }
114
115 // MockInitiator takes a series of read and/or write transactions and
116 // compares them against user/driver input.
117 //
118 // This mock uses Gtest to ensure that the transactions instantiated meet
119 // expectations. This MockedInitiator should be instantiated inside a Gtest test
120 // frame.
121 class MockInitiator : public Initiator {
122 public:
MockInitiator(span<Transaction> transaction_list)123 explicit constexpr MockInitiator(span<Transaction> transaction_list)
124 : expected_transactions_(transaction_list),
125 expected_transaction_index_(0) {}
126
127 // Should be called at the end of the test to ensure that all expected
128 // transactions have been met.
129 // Returns:
130 // Ok - Success.
131 // OutOfRange - The mocked set of transactions has not been exhausted.
Finalize()132 Status Finalize() const {
133 if (expected_transaction_index_ != expected_transactions_.size()) {
134 return Status::OutOfRange();
135 }
136 return Status();
137 }
138
139 // Runs Finalize() regardless of whether it was already optionally finalized.
140 ~MockInitiator() override;
141
142 private:
143 // Implements a mocked backend for the i2c initiator.
144 //
145 // Expects (via Gtest):
146 // tx_buffer == expected_transaction_tx_buffer
147 // tx_buffer.size() == expected_transaction_tx_buffer.size()
148 // rx_buffer.size() == expected_transaction_rx_buffer.size()
149 //
150 // Asserts:
151 // When the number of calls to this method exceed the number of expected
152 // transactions.
153 //
154 // Returns:
155 // Specified transaction return type
156 Status DoWriteReadFor(Address device_address,
157 ConstByteSpan tx_buffer,
158 ByteSpan rx_buffer,
159 chrono::SystemClock::duration timeout) override;
160
161 span<Transaction> expected_transactions_;
162 size_t expected_transaction_index_;
163 };
164
165 // Makes a new i2c transactions list.
166 template <size_t kSize>
MakeExpectedTransactionArray(const Transaction (& transactions)[kSize])167 constexpr std::array<Transaction, kSize> MakeExpectedTransactionArray(
168 const Transaction (&transactions)[kSize]) {
169 return containers::to_array(transactions);
170 }
171
172 } // namespace pw::i2c
173