• 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_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