C/C++ API Reference
Loading...
Searching...
No Matches
h4_packet.h
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#include <cstring>
19
20#include "lib/stdcompat/utility.h"
21#include "pw_allocator/allocator.h"
22#include "pw_bluetooth/hci_h4.emb.h"
23#include "pw_function/function.h"
24#include "pw_result/result.h"
25#include "pw_span/span.h"
26
28
30
37 public:
38 using ReleaseFn = Function<void(const uint8_t*)>;
39
40 constexpr H4PacketInterface() = default;
42 size_t hci_offset,
43 ReleaseFn&& release_fn)
44 : buffer_(buffer),
45 hci_offset_(hci_offset),
46 release_fn_(std::move(release_fn)) {}
47
48 H4PacketInterface(const H4PacketInterface& other) = delete;
49 H4PacketInterface& operator=(const H4PacketInterface& other) = delete;
50
51 H4PacketInterface(H4PacketInterface&& other) { *this = std::move(other); }
52 H4PacketInterface& operator=(H4PacketInterface&& other) {
53 if (this != &other) {
54 buffer_ = other.buffer_;
55 hci_offset_ = other.hci_offset_;
56 release_fn_ = std::move(other.release_fn_);
57 other.Reset();
58 }
59 return *this;
60 }
61
62 virtual ~H4PacketInterface() {
63 if (!buffer_.empty() && HasReleaseFn()) {
64 release_fn_(buffer_.data());
65 }
66 }
67
70 emboss::H4PacketType GetH4Type() const { return DoGetH4Type(); }
71
73 void SetH4Type(emboss::H4PacketType type) { DoSetH4Type(type); }
74
78 return buffer_.empty() ? buffer_ : buffer_.subspan(hci_offset_);
79 }
80 constexpr span<const uint8_t> GetHciSpan() const {
81 return buffer_.empty() ? buffer_ : buffer_.subspan(hci_offset_);
82 }
83
84 bool HasReleaseFn() { return bool{release_fn_}; }
85
86 // Returns the release function (which could be empty) and resets the packet.
87 // The caller takes ownership of the buffer and should already have stored it.
88 ReleaseFn ResetAndReturnReleaseFn() {
89 ReleaseFn fn = std::move(release_fn_);
90 Reset();
91 return fn;
92 }
93
94 protected:
95 static constexpr std::uint8_t kH4PacketIndicatorSize = 1;
96
97 constexpr span<uint8_t> buffer() { return buffer_; }
98 constexpr span<const uint8_t> buffer() const { return buffer_; }
99
100 private:
101 virtual emboss::H4PacketType DoGetH4Type() const = 0;
102 virtual void DoSetH4Type(emboss::H4PacketType) = 0;
103
104 void Reset() {
105 buffer_ = span<uint8_t>();
106 hci_offset_ = 0;
107 release_fn_ = ReleaseFn{};
108 }
109
110 span<uint8_t> buffer_;
111 size_t hci_offset_ = 0;
112 ReleaseFn release_fn_{};
113};
114
115namespace internal {
116
118template <typename T, typename... Args>
121 Args&&... args) {
122 uint8_t* owned_buf = static_cast<uint8_t*>(
123 allocator.Allocate(allocator::Layout::Of<uint8_t[]>(src.size())));
124 if (owned_buf == nullptr) {
126 }
127 std::memcpy(owned_buf, src.data(), src.size());
128 return T(std::forward<Args>(args)...,
129 span<uint8_t>(owned_buf, src.size()),
130 [&allocator](const uint8_t* data) {
131 allocator.Deallocate(const_cast<uint8_t*>(data));
132 });
133}
134
135} // namespace internal
136
138class H4PacketWithHci final : public H4PacketInterface {
139 public:
140 constexpr H4PacketWithHci() = default;
141
142 H4PacketWithHci(emboss::H4PacketType h4_type,
143 span<uint8_t> hci_span,
144 ReleaseFn&& release_fn = nullptr)
145 : H4PacketInterface(hci_span, 0, std::move(release_fn)),
146 h4_type_(h4_type) {}
147
148 H4PacketWithHci(span<uint8_t> h4_span, ReleaseFn&& release_fn = nullptr)
150 h4_span, kH4PacketIndicatorSize, std::move(release_fn)),
151 h4_type_(emboss::H4PacketType{h4_span[0]}) {}
152
153 H4PacketWithHci(H4PacketWithHci&& other) = default;
154 H4PacketWithHci& operator=(H4PacketWithHci&& other) = default;
155
158 const H4PacketWithHci& packet) {
159 return internal::CopyPacketFrom<H4PacketWithHci>(
160 allocator, packet.GetHciSpan(), packet.GetH4Type());
161 }
162
163 private:
164 emboss::H4PacketType DoGetH4Type() const override { return h4_type_; }
165 void DoSetH4Type(emboss::H4PacketType h4_type) override {
166 h4_type_ = h4_type;
167 }
168
169 emboss::H4PacketType h4_type_ = emboss::H4PacketType::UNKNOWN;
170};
171
173class H4PacketWithH4 final : public H4PacketInterface {
174 public:
175 constexpr H4PacketWithH4() = default;
176
177 H4PacketWithH4(span<uint8_t> h4_span, ReleaseFn&& release_fn = nullptr)
179 h4_span, kH4PacketIndicatorSize, std::move(release_fn)) {}
180
181 H4PacketWithH4(emboss::H4PacketType h4_type,
182 span<uint8_t> h4_span,
183 ReleaseFn&& release_fn = nullptr)
184 : H4PacketWithH4(h4_span, std::move(release_fn)) {
185 SetH4Type(h4_type);
186 }
187
188 constexpr span<uint8_t> GetH4Span() { return buffer(); }
189 constexpr span<const uint8_t> GetH4Span() const { return buffer(); }
190
193 const H4PacketWithH4& packet) {
194 return internal::CopyPacketFrom<H4PacketWithH4>(allocator,
195 packet.GetH4Span());
196 }
197
198 private:
199 emboss::H4PacketType DoGetH4Type() const override {
200 span<const uint8_t> h4_span = GetH4Span();
201 return !h4_span.empty() ? emboss::H4PacketType(h4_span[0])
202 : emboss::H4PacketType::UNKNOWN;
203 }
204
205 void DoSetH4Type(emboss::H4PacketType h4_type) override {
206 span<uint8_t> h4_span = GetH4Span();
207 if (!h4_span.empty()) {
208 h4_span.data()[0] = cpp23::to_underlying(h4_type);
209 }
210 }
211};
212
213} // namespace pw::bluetooth::proxy
Definition: allocator.h:42
void * Allocate(Layout layout)
Definition: allocator.h:50
Definition: result.h:145
static constexpr Status ResourceExhausted()
Definition: status.h:230
Definition: h4_packet.h:36
H4PacketWithH4 is an H4Packet backed by an H4 buffer.
Definition: h4_packet.h:173
H4PacketWithHci is an H4Packet backed by an HCI buffer.
Definition: h4_packet.h:138
Definition: span_impl.h:235
constexpr span< uint8_t > GetHciSpan()
Definition: h4_packet.h:77
static Result< H4PacketWithH4 > CopyFrom(Allocator &allocator, const H4PacketWithH4 &packet)
Create an owned copy of the packet using the provided allocator.
Definition: h4_packet.h:192
Result< T > CopyPacketFrom(Allocator &allocator, span< const uint8_t > src, Args &&... args)
Create an owned copy of a packet using the provided allocator.
Definition: h4_packet.h:119
emboss::H4PacketType GetH4Type() const
Definition: h4_packet.h:70
void SetH4Type(emboss::H4PacketType type)
Sets HCI packet type indicator.
Definition: h4_packet.h:73
static Result< H4PacketWithHci > CopyFrom(Allocator &allocator, const H4PacketWithHci &packet)
Create an owned copy of the packet using the provided allocator.
Definition: h4_packet.h:157
fit::function_impl< function_internal::config::kInlineCallableSize, !function_internal::config::kEnableDynamicAllocation, FunctionType, PW_FUNCTION_DEFAULT_ALLOCATOR_TYPE > Function
Definition: function.h:73
Lightweight proxy for augmenting Bluetooth functionality.
Definition: h4_packet.h:27