xref: /aosp_15_r20/external/pigweed/pw_bluetooth_proxy/public/pw_bluetooth_proxy/rfcomm_channel.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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_read_channel.h"
18 #include "pw_bluetooth_proxy/internal/l2cap_write_channel.h"
19 #include "pw_sync/mutex.h"
20 
21 namespace pw::bluetooth::proxy {
22 
23 /// L2CAP RFCOMM channel that supports writing to and reading
24 /// from a remote peer.
25 /// TODO: https://pwbug.dev/378691959 - Switch to just containing a
26 /// BasicL2capChannel instead of inheritance.
27 ///
28 /// This implementation requires use of RFCOMM credit based flow control.
29 class RfcommChannel final : public L2capWriteChannel, public L2capReadChannel {
30  public:
31   /// Parameters for a direction of packet flow in an `RfcommChannel`.
32   struct Config {
33     /// Channel identifier of the endpoint.
34     /// For Rx: Local CID.
35     /// For Tx: Remote CID.
36     uint16_t cid;
37     /// Maximum Information Length.
38     /// For Rx: Specified by local device. Indicates the maximum frame size
39     ///         for an RFCOMM packet we are capable of accepting.
40     /// For Tx: Specified by remote peer. Indicates the maximum frame size for
41     ///         for an RFCOMM packet we are allowed to send.
42     uint16_t max_information_length;
43     /// For Rx: Tracks the number of RFCOMM credits we have currently
44     ///         apportioned to the remote peer for sending us frames.
45     /// For Tx: Currently available credits for sending frames in RFCOMM Credit
46     ///         Based Flow Control mode. This may be different from the initial
47     ///         value if the container has already sent frames and/or received
48     ///         credits.
49     uint16_t credits;
50   };
51 
52   RfcommChannel(const RfcommChannel& other) = delete;
53   RfcommChannel& operator=(const RfcommChannel& other) = delete;
54   RfcommChannel(RfcommChannel&& other);
55   RfcommChannel& operator=(RfcommChannel&& other) = delete;
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] receive_fn        Read callback to be invoked on Rx frames.
74   ///
75   /// @returns @rst
76   ///
77   /// .. pw-status-codes::
78   ///  INVALID_ARGUMENT: If arguments are invalid (check logs).
79   ///  UNAVAILABLE: If channel could not be created.
80   /// @endrst
81   static pw::Result<RfcommChannel> Create(
82       L2capChannelManager& l2cap_channel_manager,
83       uint16_t connection_handle,
84       Config rx_config,
85       Config tx_config,
86       uint8_t channel_number,
87       Function<void(pw::span<uint8_t> payload)>&& receive_fn);
88 
89   /// Send an RFCOMM payload to the remote peer.
90   ///
91   /// @param[in] payload The payload to be sent. Payload will be copied
92   ///                    before function completes.
93   ///
94   /// @returns @rst
95   ///
96   /// .. pw-status-codes::
97   ///  OK:                  If packet was successfully queued for send.
98   ///  UNAVAILABLE:         If channel could not acquire the resources to queue
99   ///                       the send at this time (transient error).
100   ///                       TODO: https://pwbug.dev/380299794 - Add more robust
101   ///                       flow control solution.
102   ///  INVALID_ARGUMENT:    If payload is too large.
103   ///  FAILED_PRECONDITION: If channel is `kStopped`.
104   /// @endrst
105   Status Write(pw::span<const uint8_t> payload);
106 
rx_config()107   Config rx_config() const { return rx_config_; }
tx_config()108   Config tx_config() const { return tx_config_; }
109 
110  private:
111   static constexpr uint8_t kMinRxCredits = 2;
112 
113   RfcommChannel(L2capChannelManager& l2cap_channel_manager,
114                 uint16_t connection_handle,
115                 Config rx_config,
116                 Config tx_config,
117                 uint8_t channel_number,
118                 Function<void(pw::span<uint8_t> payload)>&& receive_fn);
119 
120   // Parses out RFCOMM payload from `l2cap_pdu` and calls
121   // `SendPayloadFromControllerToClient`.
122   bool HandlePduFromController(pw::span<uint8_t> l2cap_pdu) override;
123   bool HandlePduFromHost(pw::span<uint8_t> l2cap_pdu) override;
124 
125   void OnFragmentedPduReceived() override;
126 
127   // Override: Dequeue a packet only if a credit is able to be subtracted.
128   std::optional<H4PacketWithH4> DequeuePacket() override
129       PW_LOCKS_EXCLUDED(mutex_);
130 
131   enum class State {
132     kStarted,
133     kStopped,
134   };
135 
136   const Config rx_config_;
137   const Config tx_config_;
138   const uint8_t channel_number_;
139   uint8_t rx_credits_ PW_GUARDED_BY(mutex_);
140   uint8_t tx_credits_ PW_GUARDED_BY(mutex_);
141   sync::Mutex mutex_;
142   State state_;
143 };
144 
145 }  // namespace pw::bluetooth::proxy
146