1*61c4878aSAndroid Build Coastguard Worker // Copyright 2024 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker
15*61c4878aSAndroid Build Coastguard Worker #include "pw_uart/blocking_adapter.h"
16*61c4878aSAndroid Build Coastguard Worker
17*61c4878aSAndroid Build Coastguard Worker #include <array>
18*61c4878aSAndroid Build Coastguard Worker #include <memory>
19*61c4878aSAndroid Build Coastguard Worker #include <mutex>
20*61c4878aSAndroid Build Coastguard Worker #include <optional>
21*61c4878aSAndroid Build Coastguard Worker #include <utility>
22*61c4878aSAndroid Build Coastguard Worker
23*61c4878aSAndroid Build Coastguard Worker #include "pw_assert/check.h"
24*61c4878aSAndroid Build Coastguard Worker #include "pw_bytes/array.h"
25*61c4878aSAndroid Build Coastguard Worker #include "pw_log/log.h"
26*61c4878aSAndroid Build Coastguard Worker #include "pw_sync/lock_annotations.h"
27*61c4878aSAndroid Build Coastguard Worker #include "pw_sync/mutex.h"
28*61c4878aSAndroid Build Coastguard Worker #include "pw_sync/timed_thread_notification.h"
29*61c4878aSAndroid Build Coastguard Worker #include "pw_thread/test_thread_context.h"
30*61c4878aSAndroid Build Coastguard Worker #include "pw_unit_test/framework.h"
31*61c4878aSAndroid Build Coastguard Worker #include "pw_work_queue/work_queue.h"
32*61c4878aSAndroid Build Coastguard Worker
33*61c4878aSAndroid Build Coastguard Worker // Waits for something critical for test execution.
34*61c4878aSAndroid Build Coastguard Worker // We use PW_CHECK to ensure we crash on timeout instead of hanging forever.
35*61c4878aSAndroid Build Coastguard Worker // This is a macro so the crash points to the invocation site.
36*61c4878aSAndroid Build Coastguard Worker #define ASSERT_WAIT(waitable) PW_CHECK(waitable.try_acquire_for(1000ms))
37*61c4878aSAndroid Build Coastguard Worker
38*61c4878aSAndroid Build Coastguard Worker namespace pw::uart {
39*61c4878aSAndroid Build Coastguard Worker namespace {
40*61c4878aSAndroid Build Coastguard Worker
41*61c4878aSAndroid Build Coastguard Worker using namespace std::chrono_literals;
42*61c4878aSAndroid Build Coastguard Worker
43*61c4878aSAndroid Build Coastguard Worker // A mock UartNonBlocking for testing the blocking adapter.
44*61c4878aSAndroid Build Coastguard Worker class UartNonBlockingMock : public UartNonBlocking {
45*61c4878aSAndroid Build Coastguard Worker public:
enabled() const46*61c4878aSAndroid Build Coastguard Worker bool enabled() const { return enabled_; }
47*61c4878aSAndroid Build Coastguard Worker
WaitAndCompleteRead(Status status,ConstByteSpan data)48*61c4878aSAndroid Build Coastguard Worker void WaitAndCompleteRead(Status status, ConstByteSpan data) {
49*61c4878aSAndroid Build Coastguard Worker // Wait for a read to start.
50*61c4878aSAndroid Build Coastguard Worker ASSERT_WAIT(read_started_);
51*61c4878aSAndroid Build Coastguard Worker
52*61c4878aSAndroid Build Coastguard Worker std::optional<ReadTransaction> read = ConsumeCurrentRead();
53*61c4878aSAndroid Build Coastguard Worker PW_CHECK(read.has_value());
54*61c4878aSAndroid Build Coastguard Worker
55*61c4878aSAndroid Build Coastguard Worker // Copy data into rx buffer;
56*61c4878aSAndroid Build Coastguard Worker PW_CHECK_UINT_GE(read->rx_buffer.size(), data.size());
57*61c4878aSAndroid Build Coastguard Worker std::copy(data.begin(), data.end(), read->rx_buffer.begin());
58*61c4878aSAndroid Build Coastguard Worker
59*61c4878aSAndroid Build Coastguard Worker read->Complete(status, data.size());
60*61c4878aSAndroid Build Coastguard Worker }
61*61c4878aSAndroid Build Coastguard Worker
WaitForWrite()62*61c4878aSAndroid Build Coastguard Worker ConstByteSpan WaitForWrite() PW_LOCKS_EXCLUDED(mutex_) {
63*61c4878aSAndroid Build Coastguard Worker // Wait for a write to start.
64*61c4878aSAndroid Build Coastguard Worker ASSERT_WAIT(write_started_);
65*61c4878aSAndroid Build Coastguard Worker
66*61c4878aSAndroid Build Coastguard Worker std::lock_guard lock(mutex_);
67*61c4878aSAndroid Build Coastguard Worker PW_CHECK(current_write_.has_value());
68*61c4878aSAndroid Build Coastguard Worker return current_write_->tx_buffer;
69*61c4878aSAndroid Build Coastguard Worker }
70*61c4878aSAndroid Build Coastguard Worker
CompleteWrite(StatusWithSize status_size)71*61c4878aSAndroid Build Coastguard Worker void CompleteWrite(StatusWithSize status_size) {
72*61c4878aSAndroid Build Coastguard Worker std::optional<WriteTransaction> write = ConsumeCurrentWrite();
73*61c4878aSAndroid Build Coastguard Worker PW_CHECK(write.has_value());
74*61c4878aSAndroid Build Coastguard Worker write->Complete(status_size);
75*61c4878aSAndroid Build Coastguard Worker }
76*61c4878aSAndroid Build Coastguard Worker
WaitAndCompleteFlush(Status status)77*61c4878aSAndroid Build Coastguard Worker void WaitAndCompleteFlush(Status status) {
78*61c4878aSAndroid Build Coastguard Worker // Wait for a flush to start.
79*61c4878aSAndroid Build Coastguard Worker ASSERT_WAIT(flush_started_);
80*61c4878aSAndroid Build Coastguard Worker
81*61c4878aSAndroid Build Coastguard Worker std::optional<FlushTransaction> flush = ConsumeCurrentFlush();
82*61c4878aSAndroid Build Coastguard Worker PW_CHECK(flush.has_value());
83*61c4878aSAndroid Build Coastguard Worker
84*61c4878aSAndroid Build Coastguard Worker flush->Complete(status);
85*61c4878aSAndroid Build Coastguard Worker }
86*61c4878aSAndroid Build Coastguard Worker
87*61c4878aSAndroid Build Coastguard Worker private:
88*61c4878aSAndroid Build Coastguard Worker sync::Mutex mutex_;
89*61c4878aSAndroid Build Coastguard Worker bool enabled_ = false;
90*61c4878aSAndroid Build Coastguard Worker
91*61c4878aSAndroid Build Coastguard Worker //
92*61c4878aSAndroid Build Coastguard Worker // UartNonBlocking impl.
93*61c4878aSAndroid Build Coastguard Worker //
DoEnable(bool enabled)94*61c4878aSAndroid Build Coastguard Worker Status DoEnable(bool enabled) override {
95*61c4878aSAndroid Build Coastguard Worker enabled_ = enabled;
96*61c4878aSAndroid Build Coastguard Worker return OkStatus();
97*61c4878aSAndroid Build Coastguard Worker }
98*61c4878aSAndroid Build Coastguard Worker
DoSetBaudRate(uint32_t)99*61c4878aSAndroid Build Coastguard Worker Status DoSetBaudRate(uint32_t) override { return OkStatus(); }
DoConservativeReadAvailable()100*61c4878aSAndroid Build Coastguard Worker size_t DoConservativeReadAvailable() override { return 0; }
DoClearPendingReceiveBytes()101*61c4878aSAndroid Build Coastguard Worker Status DoClearPendingReceiveBytes() override { return OkStatus(); }
102*61c4878aSAndroid Build Coastguard Worker
103*61c4878aSAndroid Build Coastguard Worker // Read
104*61c4878aSAndroid Build Coastguard Worker struct ReadTransaction {
105*61c4878aSAndroid Build Coastguard Worker ByteSpan rx_buffer;
106*61c4878aSAndroid Build Coastguard Worker size_t min_bytes;
107*61c4878aSAndroid Build Coastguard Worker Function<void(Status, ConstByteSpan buffer)> callback;
108*61c4878aSAndroid Build Coastguard Worker
Completepw::uart::__anonea452bc80111::UartNonBlockingMock::ReadTransaction109*61c4878aSAndroid Build Coastguard Worker void Complete(Status status, size_t num_bytes) {
110*61c4878aSAndroid Build Coastguard Worker callback(status, rx_buffer.first(num_bytes));
111*61c4878aSAndroid Build Coastguard Worker }
112*61c4878aSAndroid Build Coastguard Worker };
113*61c4878aSAndroid Build Coastguard Worker std::optional<ReadTransaction> current_read_ PW_GUARDED_BY(mutex_);
114*61c4878aSAndroid Build Coastguard Worker sync::TimedThreadNotification read_started_;
115*61c4878aSAndroid Build Coastguard Worker
ConsumeCurrentRead()116*61c4878aSAndroid Build Coastguard Worker std::optional<ReadTransaction> ConsumeCurrentRead()
117*61c4878aSAndroid Build Coastguard Worker PW_LOCKS_EXCLUDED(mutex_) {
118*61c4878aSAndroid Build Coastguard Worker std::lock_guard lock(mutex_);
119*61c4878aSAndroid Build Coastguard Worker return std::exchange(current_read_, std::nullopt);
120*61c4878aSAndroid Build Coastguard Worker }
121*61c4878aSAndroid Build Coastguard Worker
DoRead(ByteSpan rx_buffer,size_t min_bytes,Function<void (Status,ConstByteSpan buffer)> && callback)122*61c4878aSAndroid Build Coastguard Worker Status DoRead(ByteSpan rx_buffer,
123*61c4878aSAndroid Build Coastguard Worker size_t min_bytes,
124*61c4878aSAndroid Build Coastguard Worker Function<void(Status, ConstByteSpan buffer)>&& callback)
125*61c4878aSAndroid Build Coastguard Worker override PW_LOCKS_EXCLUDED(mutex_) {
126*61c4878aSAndroid Build Coastguard Worker {
127*61c4878aSAndroid Build Coastguard Worker std::lock_guard lock(mutex_);
128*61c4878aSAndroid Build Coastguard Worker
129*61c4878aSAndroid Build Coastguard Worker if (current_read_) {
130*61c4878aSAndroid Build Coastguard Worker return Status::Unavailable();
131*61c4878aSAndroid Build Coastguard Worker }
132*61c4878aSAndroid Build Coastguard Worker
133*61c4878aSAndroid Build Coastguard Worker current_read_.emplace(ReadTransaction{
134*61c4878aSAndroid Build Coastguard Worker .rx_buffer = rx_buffer,
135*61c4878aSAndroid Build Coastguard Worker .min_bytes = min_bytes,
136*61c4878aSAndroid Build Coastguard Worker .callback = std::move(callback),
137*61c4878aSAndroid Build Coastguard Worker });
138*61c4878aSAndroid Build Coastguard Worker }
139*61c4878aSAndroid Build Coastguard Worker
140*61c4878aSAndroid Build Coastguard Worker read_started_.release();
141*61c4878aSAndroid Build Coastguard Worker return OkStatus();
142*61c4878aSAndroid Build Coastguard Worker }
143*61c4878aSAndroid Build Coastguard Worker
DoCancelRead()144*61c4878aSAndroid Build Coastguard Worker bool DoCancelRead() override {
145*61c4878aSAndroid Build Coastguard Worker std::optional<ReadTransaction> read = ConsumeCurrentRead();
146*61c4878aSAndroid Build Coastguard Worker if (!read.has_value()) {
147*61c4878aSAndroid Build Coastguard Worker return false;
148*61c4878aSAndroid Build Coastguard Worker }
149*61c4878aSAndroid Build Coastguard Worker read->Complete(Status::Cancelled(), 0);
150*61c4878aSAndroid Build Coastguard Worker return true;
151*61c4878aSAndroid Build Coastguard Worker }
152*61c4878aSAndroid Build Coastguard Worker
153*61c4878aSAndroid Build Coastguard Worker // Write
154*61c4878aSAndroid Build Coastguard Worker struct WriteTransaction {
155*61c4878aSAndroid Build Coastguard Worker ConstByteSpan tx_buffer;
156*61c4878aSAndroid Build Coastguard Worker Function<void(StatusWithSize)> callback;
157*61c4878aSAndroid Build Coastguard Worker
Completepw::uart::__anonea452bc80111::UartNonBlockingMock::WriteTransaction158*61c4878aSAndroid Build Coastguard Worker void Complete(StatusWithSize status_size) { callback(status_size); }
159*61c4878aSAndroid Build Coastguard Worker };
160*61c4878aSAndroid Build Coastguard Worker std::optional<WriteTransaction> current_write_ PW_GUARDED_BY(mutex_);
161*61c4878aSAndroid Build Coastguard Worker sync::TimedThreadNotification write_started_;
162*61c4878aSAndroid Build Coastguard Worker
ConsumeCurrentWrite()163*61c4878aSAndroid Build Coastguard Worker std::optional<WriteTransaction> ConsumeCurrentWrite()
164*61c4878aSAndroid Build Coastguard Worker PW_LOCKS_EXCLUDED(mutex_) {
165*61c4878aSAndroid Build Coastguard Worker std::lock_guard lock(mutex_);
166*61c4878aSAndroid Build Coastguard Worker return std::exchange(current_write_, std::nullopt);
167*61c4878aSAndroid Build Coastguard Worker }
168*61c4878aSAndroid Build Coastguard Worker
DoWrite(ConstByteSpan tx_buffer,Function<void (StatusWithSize status)> && callback)169*61c4878aSAndroid Build Coastguard Worker Status DoWrite(ConstByteSpan tx_buffer,
170*61c4878aSAndroid Build Coastguard Worker Function<void(StatusWithSize status)>&& callback) override
171*61c4878aSAndroid Build Coastguard Worker PW_LOCKS_EXCLUDED(mutex_) {
172*61c4878aSAndroid Build Coastguard Worker {
173*61c4878aSAndroid Build Coastguard Worker std::lock_guard lock(mutex_);
174*61c4878aSAndroid Build Coastguard Worker
175*61c4878aSAndroid Build Coastguard Worker if (current_write_) {
176*61c4878aSAndroid Build Coastguard Worker return Status::Unavailable();
177*61c4878aSAndroid Build Coastguard Worker }
178*61c4878aSAndroid Build Coastguard Worker
179*61c4878aSAndroid Build Coastguard Worker current_write_.emplace(WriteTransaction{
180*61c4878aSAndroid Build Coastguard Worker .tx_buffer = tx_buffer,
181*61c4878aSAndroid Build Coastguard Worker .callback = std::move(callback),
182*61c4878aSAndroid Build Coastguard Worker });
183*61c4878aSAndroid Build Coastguard Worker }
184*61c4878aSAndroid Build Coastguard Worker
185*61c4878aSAndroid Build Coastguard Worker write_started_.release();
186*61c4878aSAndroid Build Coastguard Worker return OkStatus();
187*61c4878aSAndroid Build Coastguard Worker }
188*61c4878aSAndroid Build Coastguard Worker
DoCancelWrite()189*61c4878aSAndroid Build Coastguard Worker bool DoCancelWrite() override {
190*61c4878aSAndroid Build Coastguard Worker std::optional<WriteTransaction> write = ConsumeCurrentWrite();
191*61c4878aSAndroid Build Coastguard Worker if (!write.has_value()) {
192*61c4878aSAndroid Build Coastguard Worker return false;
193*61c4878aSAndroid Build Coastguard Worker }
194*61c4878aSAndroid Build Coastguard Worker write->Complete(StatusWithSize::Cancelled(0));
195*61c4878aSAndroid Build Coastguard Worker return true;
196*61c4878aSAndroid Build Coastguard Worker }
197*61c4878aSAndroid Build Coastguard Worker
198*61c4878aSAndroid Build Coastguard Worker // Flush
199*61c4878aSAndroid Build Coastguard Worker struct FlushTransaction {
200*61c4878aSAndroid Build Coastguard Worker Function<void(Status)> callback;
201*61c4878aSAndroid Build Coastguard Worker
Completepw::uart::__anonea452bc80111::UartNonBlockingMock::FlushTransaction202*61c4878aSAndroid Build Coastguard Worker void Complete(Status status) { callback(status); }
203*61c4878aSAndroid Build Coastguard Worker };
204*61c4878aSAndroid Build Coastguard Worker std::optional<FlushTransaction> current_flush_ PW_GUARDED_BY(mutex_);
205*61c4878aSAndroid Build Coastguard Worker sync::TimedThreadNotification flush_started_;
206*61c4878aSAndroid Build Coastguard Worker
ConsumeCurrentFlush()207*61c4878aSAndroid Build Coastguard Worker std::optional<FlushTransaction> ConsumeCurrentFlush()
208*61c4878aSAndroid Build Coastguard Worker PW_LOCKS_EXCLUDED(mutex_) {
209*61c4878aSAndroid Build Coastguard Worker std::lock_guard lock(mutex_);
210*61c4878aSAndroid Build Coastguard Worker return std::exchange(current_flush_, std::nullopt);
211*61c4878aSAndroid Build Coastguard Worker }
212*61c4878aSAndroid Build Coastguard Worker
DoFlushOutput(Function<void (Status status)> && callback)213*61c4878aSAndroid Build Coastguard Worker Status DoFlushOutput(Function<void(Status status)>&& callback) override
214*61c4878aSAndroid Build Coastguard Worker PW_LOCKS_EXCLUDED(mutex_) {
215*61c4878aSAndroid Build Coastguard Worker {
216*61c4878aSAndroid Build Coastguard Worker std::lock_guard lock(mutex_);
217*61c4878aSAndroid Build Coastguard Worker
218*61c4878aSAndroid Build Coastguard Worker if (current_flush_) {
219*61c4878aSAndroid Build Coastguard Worker return Status::Unavailable();
220*61c4878aSAndroid Build Coastguard Worker }
221*61c4878aSAndroid Build Coastguard Worker
222*61c4878aSAndroid Build Coastguard Worker current_flush_.emplace(FlushTransaction{
223*61c4878aSAndroid Build Coastguard Worker .callback = std::move(callback),
224*61c4878aSAndroid Build Coastguard Worker });
225*61c4878aSAndroid Build Coastguard Worker }
226*61c4878aSAndroid Build Coastguard Worker
227*61c4878aSAndroid Build Coastguard Worker flush_started_.release();
228*61c4878aSAndroid Build Coastguard Worker return OkStatus();
229*61c4878aSAndroid Build Coastguard Worker }
230*61c4878aSAndroid Build Coastguard Worker
DoCancelFlushOutput()231*61c4878aSAndroid Build Coastguard Worker bool DoCancelFlushOutput() override {
232*61c4878aSAndroid Build Coastguard Worker std::optional<FlushTransaction> flush = ConsumeCurrentFlush();
233*61c4878aSAndroid Build Coastguard Worker if (!flush.has_value()) {
234*61c4878aSAndroid Build Coastguard Worker return false;
235*61c4878aSAndroid Build Coastguard Worker }
236*61c4878aSAndroid Build Coastguard Worker flush->Complete(Status::Cancelled());
237*61c4878aSAndroid Build Coastguard Worker return true;
238*61c4878aSAndroid Build Coastguard Worker }
239*61c4878aSAndroid Build Coastguard Worker };
240*61c4878aSAndroid Build Coastguard Worker
241*61c4878aSAndroid Build Coastguard Worker // Test fixture
242*61c4878aSAndroid Build Coastguard Worker class BlockingAdapterTest : public ::testing::Test {
243*61c4878aSAndroid Build Coastguard Worker protected:
BlockingAdapterTest()244*61c4878aSAndroid Build Coastguard Worker BlockingAdapterTest() : adapter(underlying) {}
245*61c4878aSAndroid Build Coastguard Worker
246*61c4878aSAndroid Build Coastguard Worker UartNonBlockingMock underlying;
247*61c4878aSAndroid Build Coastguard Worker UartBlockingAdapter adapter;
248*61c4878aSAndroid Build Coastguard Worker
249*61c4878aSAndroid Build Coastguard Worker work_queue::WorkQueueWithBuffer<2> work_queue;
250*61c4878aSAndroid Build Coastguard Worker
251*61c4878aSAndroid Build Coastguard Worker // State used by tests.
252*61c4878aSAndroid Build Coastguard Worker // Ideally these would be locals, but that would require capturing more than
253*61c4878aSAndroid Build Coastguard Worker // one pointer worth of data, exceeding PW_FUNCTION_INLINE_CALLABLE_SIZE.
254*61c4878aSAndroid Build Coastguard Worker sync::TimedThreadNotification blocking_action_complete;
255*61c4878aSAndroid Build Coastguard Worker static constexpr auto kReadBufferSize = 16;
256*61c4878aSAndroid Build Coastguard Worker std::array<std::byte, kReadBufferSize> read_buffer;
257*61c4878aSAndroid Build Coastguard Worker StatusWithSize read_result;
258*61c4878aSAndroid Build Coastguard Worker Status write_result;
259*61c4878aSAndroid Build Coastguard Worker
SetUp()260*61c4878aSAndroid Build Coastguard Worker void SetUp() override { StartWorkQueueThread(); }
261*61c4878aSAndroid Build Coastguard Worker
TearDown()262*61c4878aSAndroid Build Coastguard Worker void TearDown() override { StopWorkQueueThread(); }
263*61c4878aSAndroid Build Coastguard Worker
StartWorkQueueThread()264*61c4878aSAndroid Build Coastguard Worker void StartWorkQueueThread() {
265*61c4878aSAndroid Build Coastguard Worker PW_CHECK(!work_queue_thread_, "WorkQueue thread already started");
266*61c4878aSAndroid Build Coastguard Worker work_queue_thread_context_ =
267*61c4878aSAndroid Build Coastguard Worker std::make_unique<thread::test::TestThreadContext>();
268*61c4878aSAndroid Build Coastguard Worker work_queue_thread_.emplace(work_queue_thread_context_->options(),
269*61c4878aSAndroid Build Coastguard Worker work_queue);
270*61c4878aSAndroid Build Coastguard Worker }
271*61c4878aSAndroid Build Coastguard Worker
StopWorkQueueThread()272*61c4878aSAndroid Build Coastguard Worker void StopWorkQueueThread() {
273*61c4878aSAndroid Build Coastguard Worker if (work_queue_thread_) {
274*61c4878aSAndroid Build Coastguard Worker PW_LOG_DEBUG("Stopping work queue...");
275*61c4878aSAndroid Build Coastguard Worker work_queue.RequestStop();
276*61c4878aSAndroid Build Coastguard Worker #if PW_THREAD_JOINING_ENABLED
277*61c4878aSAndroid Build Coastguard Worker work_queue_thread_->join();
278*61c4878aSAndroid Build Coastguard Worker #else
279*61c4878aSAndroid Build Coastguard Worker work_queue_thread_->detach();
280*61c4878aSAndroid Build Coastguard Worker #endif
281*61c4878aSAndroid Build Coastguard Worker // Once stopped, the WorkQueue cannot be started again (stop_requested_
282*61c4878aSAndroid Build Coastguard Worker // latches), so we don't set work_queue_thread_ to std::nullopt here.
283*61c4878aSAndroid Build Coastguard Worker // work_queue_thread_ = std::nullopt;
284*61c4878aSAndroid Build Coastguard Worker }
285*61c4878aSAndroid Build Coastguard Worker }
286*61c4878aSAndroid Build Coastguard Worker
287*61c4878aSAndroid Build Coastguard Worker private:
288*61c4878aSAndroid Build Coastguard Worker std::unique_ptr<thread::test::TestThreadContext> work_queue_thread_context_;
289*61c4878aSAndroid Build Coastguard Worker std::optional<thread::Thread> work_queue_thread_;
290*61c4878aSAndroid Build Coastguard Worker };
291*61c4878aSAndroid Build Coastguard Worker
292*61c4878aSAndroid Build Coastguard Worker //
293*61c4878aSAndroid Build Coastguard Worker // Enable
294*61c4878aSAndroid Build Coastguard Worker //
295*61c4878aSAndroid Build Coastguard Worker
TEST_F(BlockingAdapterTest,EnableWorks)296*61c4878aSAndroid Build Coastguard Worker TEST_F(BlockingAdapterTest, EnableWorks) {
297*61c4878aSAndroid Build Coastguard Worker // Start out disabled
298*61c4878aSAndroid Build Coastguard Worker ASSERT_FALSE(underlying.enabled());
299*61c4878aSAndroid Build Coastguard Worker
300*61c4878aSAndroid Build Coastguard Worker // Can enable
301*61c4878aSAndroid Build Coastguard Worker PW_TEST_EXPECT_OK(adapter.Enable());
302*61c4878aSAndroid Build Coastguard Worker EXPECT_TRUE(underlying.enabled());
303*61c4878aSAndroid Build Coastguard Worker }
304*61c4878aSAndroid Build Coastguard Worker
TEST_F(BlockingAdapterTest,DisableWorks)305*61c4878aSAndroid Build Coastguard Worker TEST_F(BlockingAdapterTest, DisableWorks) {
306*61c4878aSAndroid Build Coastguard Worker // Start out enabled
307*61c4878aSAndroid Build Coastguard Worker PW_TEST_ASSERT_OK(underlying.Enable());
308*61c4878aSAndroid Build Coastguard Worker ASSERT_TRUE(underlying.enabled());
309*61c4878aSAndroid Build Coastguard Worker
310*61c4878aSAndroid Build Coastguard Worker // Can disable
311*61c4878aSAndroid Build Coastguard Worker PW_TEST_EXPECT_OK(adapter.Disable());
312*61c4878aSAndroid Build Coastguard Worker EXPECT_FALSE(underlying.enabled());
313*61c4878aSAndroid Build Coastguard Worker }
314*61c4878aSAndroid Build Coastguard Worker
315*61c4878aSAndroid Build Coastguard Worker //
316*61c4878aSAndroid Build Coastguard Worker // Read
317*61c4878aSAndroid Build Coastguard Worker //
318*61c4878aSAndroid Build Coastguard Worker
TEST_F(BlockingAdapterTest,ReadWorks)319*61c4878aSAndroid Build Coastguard Worker TEST_F(BlockingAdapterTest, ReadWorks) {
320*61c4878aSAndroid Build Coastguard Worker // Call blocking ReadExactly on the work queue.
321*61c4878aSAndroid Build Coastguard Worker work_queue.CheckPushWork([this]() {
322*61c4878aSAndroid Build Coastguard Worker PW_LOG_DEBUG("Calling adapter.ReadExactly()...");
323*61c4878aSAndroid Build Coastguard Worker read_result = adapter.ReadExactly(read_buffer);
324*61c4878aSAndroid Build Coastguard Worker blocking_action_complete.release();
325*61c4878aSAndroid Build Coastguard Worker });
326*61c4878aSAndroid Build Coastguard Worker
327*61c4878aSAndroid Build Coastguard Worker constexpr auto kRxData = bytes::Array<0x12, 0x34, 0x56>();
328*61c4878aSAndroid Build Coastguard Worker static_assert(kRxData.size() <= kReadBufferSize);
329*61c4878aSAndroid Build Coastguard Worker
330*61c4878aSAndroid Build Coastguard Worker underlying.WaitAndCompleteRead(OkStatus(), kRxData);
331*61c4878aSAndroid Build Coastguard Worker
332*61c4878aSAndroid Build Coastguard Worker // Wait for the read to complete.
333*61c4878aSAndroid Build Coastguard Worker ASSERT_WAIT(blocking_action_complete);
334*61c4878aSAndroid Build Coastguard Worker
335*61c4878aSAndroid Build Coastguard Worker PW_TEST_EXPECT_OK(read_result.status());
336*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(read_result.size(), kRxData.size());
337*61c4878aSAndroid Build Coastguard Worker EXPECT_TRUE(std::equal(kRxData.begin(), kRxData.end(), read_buffer.begin()));
338*61c4878aSAndroid Build Coastguard Worker }
339*61c4878aSAndroid Build Coastguard Worker
TEST_F(BlockingAdapterTest,ReadHandlesTimeouts)340*61c4878aSAndroid Build Coastguard Worker TEST_F(BlockingAdapterTest, ReadHandlesTimeouts) {
341*61c4878aSAndroid Build Coastguard Worker // Call blocking TryReadExactlyFor on the work queue.
342*61c4878aSAndroid Build Coastguard Worker work_queue.CheckPushWork([this]() {
343*61c4878aSAndroid Build Coastguard Worker PW_LOG_DEBUG("Calling adapter.TryReadExactlyFor()...");
344*61c4878aSAndroid Build Coastguard Worker read_result = adapter.TryReadExactlyFor(read_buffer, 100ms);
345*61c4878aSAndroid Build Coastguard Worker blocking_action_complete.release();
346*61c4878aSAndroid Build Coastguard Worker });
347*61c4878aSAndroid Build Coastguard Worker
348*61c4878aSAndroid Build Coastguard Worker // Don't complete the transaction; let it time out.
349*61c4878aSAndroid Build Coastguard Worker
350*61c4878aSAndroid Build Coastguard Worker // Wait for the read to complete.
351*61c4878aSAndroid Build Coastguard Worker ASSERT_WAIT(blocking_action_complete);
352*61c4878aSAndroid Build Coastguard Worker
353*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(read_result.status(), Status::DeadlineExceeded());
354*61c4878aSAndroid Build Coastguard Worker }
355*61c4878aSAndroid Build Coastguard Worker
356*61c4878aSAndroid Build Coastguard Worker //
357*61c4878aSAndroid Build Coastguard Worker // Write
358*61c4878aSAndroid Build Coastguard Worker //
TEST_F(BlockingAdapterTest,WriteWorks)359*61c4878aSAndroid Build Coastguard Worker TEST_F(BlockingAdapterTest, WriteWorks) {
360*61c4878aSAndroid Build Coastguard Worker static constexpr auto kTxData = bytes::Array<0x12, 0x34, 0x56>();
361*61c4878aSAndroid Build Coastguard Worker
362*61c4878aSAndroid Build Coastguard Worker // Call blocking Write on the work queue.
363*61c4878aSAndroid Build Coastguard Worker work_queue.CheckPushWork([this]() {
364*61c4878aSAndroid Build Coastguard Worker PW_LOG_DEBUG("Calling adapter.Write()...");
365*61c4878aSAndroid Build Coastguard Worker write_result = adapter.Write(kTxData);
366*61c4878aSAndroid Build Coastguard Worker blocking_action_complete.release();
367*61c4878aSAndroid Build Coastguard Worker });
368*61c4878aSAndroid Build Coastguard Worker
369*61c4878aSAndroid Build Coastguard Worker ConstByteSpan tx_buffer = underlying.WaitForWrite();
370*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(tx_buffer.size(), kTxData.size());
371*61c4878aSAndroid Build Coastguard Worker EXPECT_TRUE(std::equal(tx_buffer.begin(), tx_buffer.end(), kTxData.begin()));
372*61c4878aSAndroid Build Coastguard Worker
373*61c4878aSAndroid Build Coastguard Worker underlying.CompleteWrite(StatusWithSize(tx_buffer.size()));
374*61c4878aSAndroid Build Coastguard Worker
375*61c4878aSAndroid Build Coastguard Worker // Wait for the write to complete.
376*61c4878aSAndroid Build Coastguard Worker ASSERT_WAIT(blocking_action_complete);
377*61c4878aSAndroid Build Coastguard Worker PW_TEST_EXPECT_OK(write_result);
378*61c4878aSAndroid Build Coastguard Worker }
379*61c4878aSAndroid Build Coastguard Worker
TEST_F(BlockingAdapterTest,WriteHandlesTimeouts)380*61c4878aSAndroid Build Coastguard Worker TEST_F(BlockingAdapterTest, WriteHandlesTimeouts) {
381*61c4878aSAndroid Build Coastguard Worker static constexpr auto kTxData = bytes::Array<0x12, 0x34, 0x56>();
382*61c4878aSAndroid Build Coastguard Worker
383*61c4878aSAndroid Build Coastguard Worker // Call blocking TryWriteFor on the work queue.
384*61c4878aSAndroid Build Coastguard Worker work_queue.CheckPushWork([this]() {
385*61c4878aSAndroid Build Coastguard Worker PW_LOG_DEBUG("Calling adapter.TryWriteFor()...");
386*61c4878aSAndroid Build Coastguard Worker write_result = adapter.TryWriteFor(kTxData, 100ms).status();
387*61c4878aSAndroid Build Coastguard Worker blocking_action_complete.release();
388*61c4878aSAndroid Build Coastguard Worker });
389*61c4878aSAndroid Build Coastguard Worker
390*61c4878aSAndroid Build Coastguard Worker // Don't complete the transaction; let it time out.
391*61c4878aSAndroid Build Coastguard Worker
392*61c4878aSAndroid Build Coastguard Worker // Wait for the write to complete.
393*61c4878aSAndroid Build Coastguard Worker ASSERT_WAIT(blocking_action_complete);
394*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(write_result, Status::DeadlineExceeded());
395*61c4878aSAndroid Build Coastguard Worker }
396*61c4878aSAndroid Build Coastguard Worker
397*61c4878aSAndroid Build Coastguard Worker //
398*61c4878aSAndroid Build Coastguard Worker // FlushOutput
399*61c4878aSAndroid Build Coastguard Worker //
TEST_F(BlockingAdapterTest,FlushOutputWorks)400*61c4878aSAndroid Build Coastguard Worker TEST_F(BlockingAdapterTest, FlushOutputWorks) {
401*61c4878aSAndroid Build Coastguard Worker // Call blocking FlushOutput on the work queue.
402*61c4878aSAndroid Build Coastguard Worker work_queue.CheckPushWork([this]() {
403*61c4878aSAndroid Build Coastguard Worker PW_LOG_DEBUG("Calling adapter.FlushOutput()...");
404*61c4878aSAndroid Build Coastguard Worker write_result = adapter.FlushOutput();
405*61c4878aSAndroid Build Coastguard Worker blocking_action_complete.release();
406*61c4878aSAndroid Build Coastguard Worker });
407*61c4878aSAndroid Build Coastguard Worker
408*61c4878aSAndroid Build Coastguard Worker underlying.WaitAndCompleteFlush(OkStatus());
409*61c4878aSAndroid Build Coastguard Worker
410*61c4878aSAndroid Build Coastguard Worker // Wait for the flush to complete.
411*61c4878aSAndroid Build Coastguard Worker ASSERT_WAIT(blocking_action_complete);
412*61c4878aSAndroid Build Coastguard Worker PW_TEST_EXPECT_OK(write_result);
413*61c4878aSAndroid Build Coastguard Worker }
414*61c4878aSAndroid Build Coastguard Worker
415*61c4878aSAndroid Build Coastguard Worker // FlushOutput does not provide a variant with timeout.
416*61c4878aSAndroid Build Coastguard Worker
417*61c4878aSAndroid Build Coastguard Worker } // namespace
418*61c4878aSAndroid Build Coastguard Worker } // namespace pw::uart
419