1 // Copyright 2023 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 #include "pw_bluetooth_sapphire/internal/host/transport/transport.h"
16
17 #include <pw_assert/check.h>
18
19 #include "pw_bluetooth_sapphire/internal/host/common/log.h"
20 #include "pw_bluetooth_sapphire/internal/host/transport/acl_data_channel.h"
21
22 namespace bt::hci {
23
24 using FeaturesBits = pw::bluetooth::Controller::FeaturesBits;
25
Transport(std::unique_ptr<pw::bluetooth::Controller> controller,pw::async::Dispatcher & dispatcher)26 Transport::Transport(std::unique_ptr<pw::bluetooth::Controller> controller,
27 pw::async::Dispatcher& dispatcher)
28 : WeakSelf(this),
29 dispatcher_(dispatcher),
30 controller_(std::move(controller)) {
31 PW_CHECK(controller_);
32 }
33
~Transport()34 Transport::~Transport() { bt_log(INFO, "hci", "Transport shutting down"); }
35
Initialize(fit::callback<void (bool)> complete_callback)36 void Transport::Initialize(
37 fit::callback<void(bool /*success*/)> complete_callback) {
38 PW_CHECK(!command_channel_);
39
40 bt_log(DEBUG, "hci", "initializing Transport");
41 auto self = GetWeakPtr();
42 auto complete_cb_wrapper = [self, complete_cb = std::move(complete_callback)](
43 pw::Status status) mutable {
44 if (!self.is_alive()) {
45 return;
46 }
47
48 if (!status.ok()) {
49 complete_cb(/*success=*/false);
50 return;
51 }
52
53 self->command_channel_ = std::make_unique<CommandChannel>(
54 self->controller_.get(), self->dispatcher_);
55 self->command_channel_->set_channel_timeout_cb([self] {
56 if (self.is_alive()) {
57 self->OnChannelError();
58 }
59 });
60
61 self->controller_->GetFeatures(
62 [self, cb = std::move(complete_cb)](FeaturesBits features) mutable {
63 if (!self.is_alive()) {
64 return;
65 }
66 self->features_ = features;
67
68 bt_log(INFO, "hci", "Transport initialized");
69 cb(/*success=*/true);
70 });
71 };
72
73 auto error_cb = [self](pw::Status) {
74 if (self.is_alive()) {
75 self->OnChannelError();
76 }
77 };
78
79 controller_->Initialize(std::move(complete_cb_wrapper), std::move(error_cb));
80 }
81
InitializeACLDataChannel(const DataBufferInfo & bredr_buffer_info,const DataBufferInfo & le_buffer_info)82 bool Transport::InitializeACLDataChannel(
83 const DataBufferInfo& bredr_buffer_info,
84 const DataBufferInfo& le_buffer_info) {
85 acl_data_channel_ = AclDataChannel::Create(
86 this, controller_.get(), bredr_buffer_info, le_buffer_info);
87
88 if (hci_node_) {
89 acl_data_channel_->AttachInspect(hci_node_,
90 AclDataChannel::kInspectNodeName);
91 }
92
93 return true;
94 }
95
InitializeScoDataChannel(const DataBufferInfo & buffer_info)96 bool Transport::InitializeScoDataChannel(const DataBufferInfo& buffer_info) {
97 if (!buffer_info.IsAvailable()) {
98 bt_log(
99 WARN,
100 "hci",
101 "failed to initialize SCO data channel: buffer info is not available");
102 return false;
103 }
104
105 if (static_cast<uint32_t>(*features_ & FeaturesBits::kHciSco) == 0) {
106 bt_log(WARN, "hci", "HCI SCO not supported");
107 return false;
108 }
109
110 sco_data_channel_ = ScoDataChannel::Create(
111 buffer_info, command_channel_.get(), controller_.get());
112 return true;
113 }
114
InitializeIsoDataChannel(const DataBufferInfo & buffer_info)115 bool Transport::InitializeIsoDataChannel(const DataBufferInfo& buffer_info) {
116 PW_CHECK(buffer_info.IsAvailable());
117
118 if (static_cast<uint32_t>(*features_ & FeaturesBits::kHciIso) == 0) {
119 bt_log(WARN, "hci", "HCI ISO not supported");
120 return false;
121 }
122
123 iso_data_channel_ = IsoDataChannel::Create(
124 buffer_info, command_channel_.get(), controller_.get());
125 return true;
126 }
127
GetFeatures()128 FeaturesBits Transport::GetFeatures() {
129 PW_CHECK(features_);
130 return features_.value();
131 }
132
SetTransportErrorCallback(fit::closure callback)133 void Transport::SetTransportErrorCallback(fit::closure callback) {
134 PW_CHECK(callback);
135 PW_CHECK(!error_cb_);
136 error_cb_ = std::move(callback);
137 }
138
OnChannelError()139 void Transport::OnChannelError() {
140 bt_log(ERROR, "hci", "channel error, calling Transport error callback");
141 // The channels should not be shut down yet. That should be left to higher
142 // layers so dependent objects can be destroyed first.
143 if (error_cb_) {
144 error_cb_();
145 }
146 }
147
AttachInspect(inspect::Node & parent,const std::string & name)148 void Transport::AttachInspect(inspect::Node& parent, const std::string& name) {
149 PW_CHECK(acl_data_channel_);
150 hci_node_ = parent.CreateChild(name);
151
152 if (command_channel_) {
153 command_channel_->AttachInspect(hci_node_);
154 }
155
156 if (acl_data_channel_) {
157 acl_data_channel_->AttachInspect(hci_node_,
158 AclDataChannel::kInspectNodeName);
159 }
160 }
161
162 } // namespace bt::hci
163