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