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