1 // Copyright 2023 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 #pragma once 16 #include <lib/fit/function.h> 17 18 #include "pw_bluetooth_sapphire/internal/host/common/assert.h" 19 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h" 20 #include "pw_bluetooth_sapphire/internal/host/l2cap/l2cap_defs.h" 21 22 namespace bt::l2cap::internal { 23 24 // The interface between a Channel, and the module implementing the 25 // mode-specific transmit logic. The primary purposes of an TxEngine are a) to 26 // transform SDUs into PDUs, and b) to transmit/retransmit the PDUs at the 27 // appropriate time. See Bluetooth Core Spec v5.0, Volume 3, Part A, Sec 2.4, 28 // "Modes of Operation" for more information about the possible modes. 29 class TxEngine { 30 public: 31 // The interface of a transmission channel, which should be ChannelImpl in 32 // production. The channel is able to send frames over the channel with 33 // SendFrame as well as retrieve SDUs that are queued for sending in the 34 // channel. 35 class TxChannel { 36 public: 37 virtual ~TxChannel() = default; 38 // Callback that a TxEngine uses to deliver a PDU to lower layers. The 39 // callee may assume that the ByteBufferPtr owns an instance of a 40 // DynamicByteBuffer or SlabBuffer. 41 virtual void SendFrame(ByteBufferPtr pdu) = 0; 42 // Callback that a TxEngine uses to retrieve the next SDU queued in the 43 // channel. If the queue is empty, this callback should return 44 // std::nullopt, and the channel must notify the TxEngine when an SDU 45 // becomes available by calling NotifySduQueued(). 46 virtual std::optional<ByteBufferPtr> GetNextQueuedSdu() = 0; 47 }; 48 49 // Creates a transmit engine, which will process SDUs into PDUs for 50 // transmission. 51 // 52 // The engine will invoke the channel's SendFrame() handler when a PDU is 53 // ready for transmission. This callback may be invoked synchronously from 54 // NotifySduQueued(), as well as asynchronously (e.g. when a retransmission 55 // timer expires). 56 // 57 // NOTE(Lifetime): The TxChannel must outlive the TxEngine. 58 // NOTE(Deadlock): The user of this class must ensure that a synchronous 59 // invocation of SendFrame() does not deadlock. E.g., the callback must not 60 // attempt to lock the same mutex as the caller of NotifySduQueued(). TxEngine(ChannelId channel_id,uint16_t max_tx_sdu_size,TxChannel & channel)61 TxEngine(ChannelId channel_id, uint16_t max_tx_sdu_size, TxChannel& channel) 62 : channel_id_(channel_id), 63 max_tx_sdu_size_(max_tx_sdu_size), 64 channel_(channel) { 65 PW_CHECK(max_tx_sdu_size_); 66 } 67 virtual ~TxEngine() = default; 68 69 // Notify the TxEngine that an SDU should be available for it to process. 70 // 71 // NOTE(Deadlock): As noted in the ctor documentation, this _may_ result in 72 // the synchronous invocation of channel_.SendFrame(). 73 virtual void NotifySduQueued() = 0; 74 75 protected: channel_id()76 ChannelId channel_id() const { return channel_id_; } max_tx_sdu_size()77 uint16_t max_tx_sdu_size() const { return max_tx_sdu_size_; } channel()78 const TxChannel& channel() const { return channel_; } channel()79 TxChannel& channel() { return channel_; } 80 81 private: 82 const ChannelId channel_id_; 83 const uint16_t max_tx_sdu_size_; 84 TxChannel& channel_; 85 86 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(TxEngine); 87 }; 88 89 } // namespace bt::l2cap::internal 90