1 // Copyright 2024 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 15 #include "pw_channel/loopback_channel.h" 16 17 #include "pw_multibuf/multibuf.h" 18 19 namespace pw::channel { 20 21 using ::pw::async2::Context; 22 using ::pw::async2::Pending; 23 using ::pw::async2::Poll; 24 using ::pw::async2::Ready; 25 using ::pw::async2::WaitReason; 26 using ::pw::channel::WriteToken; 27 using ::pw::multibuf::MultiBuf; 28 DoPendRead(Context & cx)29Poll<Result<MultiBuf>> LoopbackChannel<DataType::kDatagram>::DoPendRead( 30 Context& cx) { 31 if (!queue_.has_value()) { 32 waker_ = cx.GetWaker(WaitReason::Unspecified()); 33 return Pending(); 34 } 35 MultiBuf data = std::move(*queue_); 36 queue_ = std::nullopt; 37 std::move(waker_).Wake(); 38 return data; 39 } 40 DoPendReadyToWrite(Context & cx)41Poll<Status> LoopbackChannel<DataType::kDatagram>::DoPendReadyToWrite( 42 Context& cx) { 43 if (queue_.has_value()) { 44 waker_ = cx.GetWaker(WaitReason::Unspecified()); 45 return Pending(); 46 } 47 return Ready(OkStatus()); 48 } 49 DoWrite(MultiBuf && data)50Result<WriteToken> LoopbackChannel<DataType::kDatagram>::DoWrite( 51 MultiBuf&& data) { 52 PW_DASSERT(!queue_.has_value()); 53 queue_ = std::move(data); 54 const uint32_t token = ++write_token_; 55 std::move(waker_).Wake(); 56 return CreateWriteToken(token); 57 } 58 59 async2::Poll<Result<channel::WriteToken>> DoPendFlush(async2::Context &)60LoopbackChannel<DataType::kDatagram>::DoPendFlush(async2::Context&) { 61 return async2::Ready(CreateWriteToken(write_token_)); 62 } 63 DoPendClose(async2::Context &)64async2::Poll<Status> LoopbackChannel<DataType::kDatagram>::DoPendClose( 65 async2::Context&) { 66 queue_.reset(); 67 return OkStatus(); 68 } 69 DoPendRead(Context & cx)70Poll<Result<MultiBuf>> LoopbackChannel<DataType::kByte>::DoPendRead( 71 Context& cx) { 72 if (queue_.empty()) { 73 read_waker_ = cx.GetWaker(WaitReason::Unspecified()); 74 return Pending(); 75 } 76 return std::move(queue_); 77 } 78 DoWrite(MultiBuf && data)79Result<WriteToken> LoopbackChannel<DataType::kByte>::DoWrite(MultiBuf&& data) { 80 const uint32_t token = ++write_token_; 81 if (!data.empty()) { 82 bool was_empty = queue_.empty(); 83 queue_.PushSuffix(std::move(data)); 84 if (was_empty) { 85 std::move(read_waker_).Wake(); 86 } 87 } 88 return CreateWriteToken(token); 89 } 90 91 async2::Poll<Result<channel::WriteToken>> DoPendFlush(async2::Context &)92LoopbackChannel<DataType::kByte>::DoPendFlush(async2::Context&) { 93 return async2::Ready(CreateWriteToken(write_token_)); 94 } 95 DoPendClose(async2::Context &)96async2::Poll<Status> LoopbackChannel<DataType::kByte>::DoPendClose( 97 async2::Context&) { 98 queue_.Release(); 99 return OkStatus(); 100 } 101 102 } // namespace pw::channel 103