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 <cstdint> 18 19 #include "lib/stdcompat/utility.h" 20 #include "pw_bluetooth/hci_h4.emb.h" 21 #include "pw_function/function.h" 22 #include "pw_span/span.h" 23 24 namespace pw::bluetooth::proxy { 25 26 /// H4PacketInterface is an abstract interface for an H4 HCI packet. 27 /// 28 /// Concrete subclasses are used directly in code so their functions will be 29 /// properly inlined. This abstract superclass just ensures a common interface 30 /// across the concrete subclasses 31 class H4PacketInterface { 32 public: 33 H4PacketInterface() = default; 34 35 H4PacketInterface(const H4PacketInterface& other) = delete; 36 37 H4PacketInterface(H4PacketInterface&& other) = default; 38 H4PacketInterface& operator=(H4PacketInterface&& other) = default; 39 40 virtual ~H4PacketInterface() = default; 41 42 /// Returns HCI packet type indicator as defined in BT Core Spec Version 5.4 | 43 /// Vol 4, Part A, Section 2. 44 virtual emboss::H4PacketType GetH4Type() = 0; 45 46 /// Sets HCI packet type indicator. 47 virtual void SetH4Type(emboss::H4PacketType) = 0; 48 49 /// Returns pw::span of HCI packet as defined in BT Core Spec Version 5.4 | 50 /// Vol 4, Part E, Section 5.4. 51 virtual pw::span<uint8_t> GetHciSpan() = 0; 52 53 protected: 54 H4PacketInterface& operator=(const H4PacketInterface& other) = default; 55 }; 56 57 /// H4PacketWithHci is an H4Packet backed by an HCI buffer. 58 class H4PacketWithHci final : public H4PacketInterface { 59 public: H4PacketWithHci(emboss::H4PacketType h4_type,pw::span<uint8_t> hci_span)60 H4PacketWithHci(emboss::H4PacketType h4_type, pw::span<uint8_t> hci_span) 61 : hci_span_(hci_span), h4_type_(h4_type) {} 62 63 H4PacketWithHci(const H4PacketWithHci& other) = delete; 64 65 H4PacketWithHci(H4PacketWithHci&& other) = default; 66 H4PacketWithHci& operator=(H4PacketWithHci&& other) = default; 67 68 ~H4PacketWithHci() final = default; 69 GetH4Type()70 emboss::H4PacketType GetH4Type() final { return h4_type_; } 71 SetH4Type(emboss::H4PacketType h4_type)72 void SetH4Type(emboss::H4PacketType h4_type) final { h4_type_ = h4_type; } 73 GetHciSpan()74 pw::span<uint8_t> GetHciSpan() final { return hci_span_; } 75 76 private: 77 H4PacketWithHci& operator=(const H4PacketWithHci& other) = default; 78 79 pw::span<uint8_t> hci_span_; 80 81 emboss::H4PacketType h4_type_; 82 }; 83 84 /// H4PacketWithHci is an H4Packet backed by an H4 buffer. 85 class H4PacketWithH4 final : public H4PacketInterface { 86 public: 87 H4PacketWithH4() = default; H4PacketWithH4(pw::span<uint8_t> h4_span)88 H4PacketWithH4(pw::span<uint8_t> h4_span) : h4_span_(h4_span) {} 89 90 /// release_fn (if callable) will be called when H4PacketWithH4 is destructed. H4PacketWithH4(pw::span<uint8_t> h4_span,pw::Function<void (const uint8_t * buffer)> && release_fn)91 H4PacketWithH4(pw::span<uint8_t> h4_span, 92 pw::Function<void(const uint8_t* buffer)>&& release_fn) 93 : h4_span_(h4_span), release_fn_(std::move(release_fn)) {} 94 H4PacketWithH4(emboss::H4PacketType h4_type,pw::span<uint8_t> h4_span)95 H4PacketWithH4(emboss::H4PacketType h4_type, pw::span<uint8_t> h4_span) 96 : H4PacketWithH4(h4_span) { 97 SetH4Type(h4_type); 98 } 99 100 H4PacketWithH4(const H4PacketWithH4& other) = delete; 101 H4PacketWithH4& operator=(const H4PacketWithH4& other) = delete; 102 H4PacketWithH4(H4PacketWithH4 && other)103 H4PacketWithH4(H4PacketWithH4&& other) 104 : h4_span_(other.h4_span_), release_fn_(std::move(other.release_fn_)) { 105 other.Reset(); 106 } 107 108 H4PacketWithH4& operator=(H4PacketWithH4&& other) { 109 h4_span_ = other.h4_span_; 110 release_fn_ = std::move(other.release_fn_); 111 other.Reset(); 112 return *this; 113 } 114 ~H4PacketWithH4()115 ~H4PacketWithH4() final { 116 if (release_fn_) { 117 release_fn_(h4_span_.data()); 118 } 119 } 120 GetH4Type()121 emboss::H4PacketType GetH4Type() final { 122 if (h4_span_.empty()) { 123 return emboss::H4PacketType::UNKNOWN; 124 } 125 126 return emboss::H4PacketType(h4_span_[0]); 127 } 128 SetH4Type(emboss::H4PacketType h4_type)129 void SetH4Type(emboss::H4PacketType h4_type) final { 130 if (!h4_span_.empty()) { 131 h4_span_.data()[0] = cpp23::to_underlying(h4_type); 132 } 133 } 134 HasReleaseFn()135 bool HasReleaseFn() { 136 // pw::Function bool returns true if not-empty 137 return bool{release_fn_}; 138 } 139 140 // Returns the release function (which could be empty) and resets the packet. 141 // Essentially it moves ownership of the buffer to the caller (who should have 142 // already stored `GetH4Span()` since packet's span will be reset by this 143 // call). ResetAndReturnReleaseFn()144 pw::Function<void(const uint8_t*)> ResetAndReturnReleaseFn() { 145 pw::Function<void(const uint8_t* packet)> fn = std::move(release_fn_); 146 Reset(); 147 return fn; 148 } 149 GetHciSpan()150 pw::span<uint8_t> GetHciSpan() final { 151 // If h4_span is empty, then return an empty span for hci also. 152 if (h4_span_.empty()) { 153 return {}; 154 } 155 return pw::span(h4_span_.data() + 1, h4_span_.size() - 1); 156 } 157 GetH4Span()158 pw::span<uint8_t> GetH4Span() { 159 if (h4_span_.empty()) { 160 return {}; 161 } 162 return h4_span_; 163 } 164 165 private: Reset()166 void Reset() { 167 h4_span_ = pw::span<uint8_t>(); 168 release_fn_ = nullptr; 169 } 170 171 pw::span<uint8_t> h4_span_; 172 173 pw::Function<void(const uint8_t* packet)> release_fn_{}; 174 }; 175 176 } // namespace pw::bluetooth::proxy 177