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 BT_ASSERT(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 BT_ASSERT(!command_channel_);
38
39 bt_log(DEBUG, "hci", "initializing Transport");
40 auto self = GetWeakPtr();
41 auto complete_cb_wrapper =
42 [self, cb = std::move(complete_callback)](pw::Status status) mutable {
43 if (!self.is_alive()) {
44 return;
45 }
46
47 if (!status.ok()) {
48 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(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 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
GetFeatures()114 FeaturesBits Transport::GetFeatures() {
115 BT_ASSERT(features_);
116 return features_.value();
117 }
118
SetTransportErrorCallback(fit::closure callback)119 void Transport::SetTransportErrorCallback(fit::closure callback) {
120 BT_ASSERT(callback);
121 BT_ASSERT(!error_cb_);
122 error_cb_ = std::move(callback);
123 }
124
OnChannelError()125 void Transport::OnChannelError() {
126 bt_log(ERROR, "hci", "channel error, calling Transport error callback");
127 // The channels should not be shut down yet. That should be left to higher
128 // layers so dependent objects can be destroyed first.
129 if (error_cb_) {
130 error_cb_();
131 }
132 }
133
AttachInspect(inspect::Node & parent,const std::string & name)134 void Transport::AttachInspect(inspect::Node& parent, const std::string& name) {
135 BT_ASSERT(acl_data_channel_);
136 hci_node_ = parent.CreateChild(name);
137
138 if (command_channel_) {
139 command_channel_->AttachInspect(hci_node_);
140 }
141
142 if (acl_data_channel_) {
143 acl_data_channel_->AttachInspect(hci_node_,
144 AclDataChannel::kInspectNodeName);
145 }
146 }
147
148 } // namespace bt::hci
149