xref: /aosp_15_r20/external/pigweed/pw_bluetooth_proxy/public/pw_bluetooth_proxy/h4_packet.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 <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