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