• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #pragma once
16 
17 #include "pw_bluetooth_proxy/internal/l2cap_channel.h"
18 #include "pw_sync/mutex.h"
19 
20 namespace pw::bluetooth::proxy {
21 
22 /// L2CAP RFCOMM channel that supports writing to and reading
23 /// from a remote peer.
24 /// TODO: https://pwbug.dev/378691959 - Switch to just containing a
25 /// BasicL2capChannel instead of inheritance.
26 ///
27 /// This implementation requires use of RFCOMM credit based flow control.
28 class RfcommChannel final : public L2capChannel {
29  public:
30   /// Parameters for a direction of packet flow in an `RfcommChannel`.
31   struct Config {
32     /// Channel identifier of the endpoint.
33     /// For Rx: Local CID.
34     /// For Tx: Remote CID.
35     uint16_t cid;
36     /// Maximum Information Length.
37     /// For Rx: Specified by local device. Indicates the maximum frame size
38     ///         for an RFCOMM packet we are capable of accepting.
39     /// For Tx: Specified by remote peer. Indicates the maximum frame size for
40     ///         for an RFCOMM packet we are allowed to send.
41     uint16_t max_information_length;
42     /// For Rx: Tracks the number of RFCOMM credits we have currently
43     ///         apportioned to the remote peer for sending us frames.
44     /// For Tx: Currently available credits for sending frames in RFCOMM Credit
45     ///         Based Flow Control mode. This may be different from the initial
46     ///         value if the container has already sent frames and/or received
47     ///         credits.
48     uint16_t credits;
49   };
50 
51   RfcommChannel(const RfcommChannel& other) = delete;
52   RfcommChannel& operator=(const RfcommChannel& other) = delete;
53   RfcommChannel(RfcommChannel&& other);
54   RfcommChannel& operator=(RfcommChannel&& other) = delete;
55   ~RfcommChannel() override;
56 
57   /// Returns an RFCOMM channel that supports writing to and reading from a
58   /// remote peer.
59   ///
60   /// @param[in] l2cap_channel_manager The L2CAP channel manager to register
61   ///                                  with.
62   ///
63   /// @param[in] connection_handle The connection handle of the remote peer.
64   ///
65   /// @param[in] rx_config         Parameters applying to reading packets.
66   ///                              See `rfcomm_channel.h` for details.
67   ///
68   /// @param[in] tx_config         Parameters applying to writing packets.
69   ///                              See `rfcomm_channel.h` for details.
70   ///
71   /// @param[in] channel_number    RFCOMM channel number to use.
72   ///
73   /// @param[in] payload_from_controller_fn        Read callback to be invoked
74   /// on Rx frames.
75   ///
76   /// @returns @rst
77   ///
78   /// .. pw-status-codes::
79   ///  INVALID_ARGUMENT: If arguments are invalid (check logs).
80   ///  UNAVAILABLE: If channel could not be created.
81   /// @endrst
82   static pw::Result<RfcommChannel> Create(
83       L2capChannelManager& l2cap_channel_manager,
84       multibuf::MultiBufAllocator& rx_multibuf_allocator,
85       uint16_t connection_handle,
86       Config rx_config,
87       Config tx_config,
88       uint8_t channel_number,
89       Function<void(multibuf::MultiBuf&& payload)>&& payload_from_controller_fn,
90       ChannelEventCallback&& event_fn);
91 
92   // Overridden here to do additional length checks.
93   StatusWithMultiBuf Write(multibuf::MultiBuf&& payload) override;
94 
rx_config()95   Config rx_config() const { return rx_config_; }
tx_config()96   Config tx_config() const { return tx_config_; }
97 
98  private:
99   static constexpr uint8_t kMinRxCredits = 2;
100 
101   RfcommChannel(
102       L2capChannelManager& l2cap_channel_manager,
103       multibuf::MultiBufAllocator& rx_multibuf_allocator,
104       uint16_t connection_handle,
105       Config rx_config,
106       Config tx_config,
107       uint8_t channel_number,
108       Function<void(multibuf::MultiBuf&& payload)>&& payload_from_controller_fn,
109       ChannelEventCallback&& event_fn);
110 
111   // TODO: https://pwbug.dev/379337272 - Delete this once all channels have
112   // transitioned to payload_queue_.
UsesPayloadQueue()113   bool UsesPayloadQueue() override { return true; }
114 
115   [[nodiscard]] std::optional<H4PacketWithH4> GenerateNextTxPacket()
116       PW_EXCLUSIVE_LOCKS_REQUIRED(send_queue_mutex()) override;
117 
118   // Parses out RFCOMM payload from `l2cap_pdu` and calls
119   // `SendPayloadFromControllerToClient`.
120   bool DoHandlePduFromController(pw::span<uint8_t> l2cap_pdu) override;
121   bool HandlePduFromHost(pw::span<uint8_t> l2cap_pdu) override;
122 
123   // Override: Dequeue a packet only if a credit is able to be subtracted.
124   std::optional<H4PacketWithH4> DequeuePacket() override
125       PW_LOCKS_EXCLUDED(tx_mutex_);
126 
127   // Override: All traffic on this channel goes to client.
128   bool SendPayloadFromControllerToClient(pw::span<uint8_t> payload) override;
129 
DoClose()130   void DoClose() override {}
131 
132   const Config rx_config_;
133   const Config tx_config_;
134   const uint8_t channel_number_;
135   sync::Mutex rx_mutex_;
136   uint8_t rx_credits_ PW_GUARDED_BY(rx_mutex_);
137 
138   sync::Mutex tx_mutex_;
139   uint8_t tx_credits_ PW_GUARDED_BY(tx_mutex_);
140   Function<void(multibuf::MultiBuf&& payload)> payload_from_controller_fn_;
141 };
142 
143 }  // namespace pw::bluetooth::proxy
144