• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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