xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/host/transport/transport.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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