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 #pragma once
16 #include <atomic>
17 #include <memory>
18 #include <thread>
19 
20 #include "pw_bluetooth/controller.h"
21 #include "pw_bluetooth_sapphire/internal/host/common/inspect.h"
22 #include "pw_bluetooth_sapphire/internal/host/common/macros.h"
23 #include "pw_bluetooth_sapphire/internal/host/common/weak_self.h"
24 #include "pw_bluetooth_sapphire/internal/host/transport/acl_data_channel.h"
25 #include "pw_bluetooth_sapphire/internal/host/transport/command_channel.h"
26 #include "pw_bluetooth_sapphire/internal/host/transport/iso_data_channel.h"
27 #include "pw_bluetooth_sapphire/internal/host/transport/sco_data_channel.h"
28 
29 namespace bt::hci {
30 
31 // Represents the HCI transport layer. This object owns the HCI command, ACL,
32 // SCO, and ISO data channels and provides the necessary control-flow mechanisms
33 // to send and receive HCI packets from the underlying Bluetooth controller.
34 class Transport final : public WeakSelf<Transport> {
35  public:
36   explicit Transport(std::unique_ptr<pw::bluetooth::Controller> hci,
37                      pw::async::Dispatcher& dispatcher);
38 
39   // Initializes the command channel and features. The result will be reported
40   // via |complete_callback|.
41   //
42   // NOTE: AclDataChannel and ScoDataChannel will be left uninitialized. They
43   // must be initialized after available data buffer information has been
44   // obtained from the controller (via HCI_Read_Buffer_Size and
45   // HCI_LE_Read_Buffer_Size).
46   void Initialize(fit::callback<void(bool /*success*/)> complete_callback);
47 
48   // TODO(armansito): hci::Transport::~Transport() should send a shutdown
49   // message to the bt-hci device, which would be responsible for sending
50   // HCI_Reset upon exit.
51   ~Transport();
52 
53   // Initializes the ACL data channel with the given parameters. Returns false
54   // if an error occurs during initialization. Initialize() must have been
55   // called successfully prior to calling this method.
56   bool InitializeACLDataChannel(const DataBufferInfo& bredr_buffer_info,
57                                 const DataBufferInfo& le_buffer_info);
58 
59   // Initializes the SCO data channel with the given parameters. Returns false
60   // if an error occurs during initialization.
61   bool InitializeScoDataChannel(const DataBufferInfo& buffer_info);
62 
63   // Initializes the ISO data channel with the given parameters. Returns false
64   // if an error occurs during initialization.
65   bool InitializeIsoDataChannel(const DataBufferInfo& buffer_info);
66 
67   pw::bluetooth::Controller::FeaturesBits GetFeatures();
68 
69   // Returns a pointer to the HCI command and event flow control handler.
70   // CommandChannel is guaranteed to live as long as Transport, but may stop
71   // processing packets after the Transport error callback has been called.
command_channel()72   CommandChannel* command_channel() const { return command_channel_.get(); }
73 
74   // Returns a pointer to the HCI ACL data flow control handler. Nullptr until
75   // InitializeACLDataChannel() has succeeded.
76   // AclDataChannel is guaranteed to live as long as Transport.
acl_data_channel()77   AclDataChannel* acl_data_channel() const { return acl_data_channel_.get(); }
78 
79   // Returns a pointer to the HCI SCO data flow control handler. Nullptr until
80   // InitializeScoDataChannel succeeds.
81   // ScoDataChannel is guaranteed to live as long as Transport.
sco_data_channel()82   ScoDataChannel* sco_data_channel() const { return sco_data_channel_.get(); }
83 
84   // Returns a pointer to the HCI ISO data flow control handler. Nullptr until
85   // InitializeIsoDataChannel succeeds. IsoDataChannel is guaranteed to live as
86   // long as Transport.
iso_data_channel()87   IsoDataChannel* iso_data_channel() const { return iso_data_channel_.get(); }
88 
89   // Set a callback that should be invoked when any one of the underlying
90   // channels experiences a fatal error (e.g. the HCI device has disappeared).
91   //
92   // When this callback is called the channels will be in an invalid state and
93   // packet processing is no longer guaranteed to work. However, the channel
94   // pointers are guaranteed to still be valid. It is the responsibility of the
95   // callback implementation to clean up this Transport instance.
96   void SetTransportErrorCallback(fit::closure callback);
97 
98   // Attach hci transport inspect node as a child node of |parent|.
99   static constexpr const char* kInspectNodeName = "hci";
100   void AttachInspect(inspect::Node& parent,
101                      const std::string& name = kInspectNodeName);
102 
103  private:
104   // Callback called by CommandChannel or ACLDataChannel on errors.
105   void OnChannelError();
106 
107   pw::async::Dispatcher& dispatcher_;
108 
109   // HCI inspect node.
110   inspect::Node hci_node_;
111 
112   // Callback invoked when the transport is closed (due to a channel error).
113   fit::closure error_cb_;
114 
115   std::unique_ptr<pw::bluetooth::Controller> controller_;
116 
117   std::optional<pw::bluetooth::Controller::FeaturesBits> features_;
118 
119   // The HCI command and event flow control handler.
120   // CommandChannel must be constructed first & shut down last because
121   // AclDataChannel and ScoDataChannel depend on it. CommandChannel must live as
122   // long as Transport to meet the expectations of upper layers, which may try
123   // to send commands on destruction.
124   std::unique_ptr<CommandChannel> command_channel_;
125 
126   // The ACL data flow control handler.
127   std::unique_ptr<AclDataChannel> acl_data_channel_;
128 
129   // The SCO data flow control handler.
130   std::unique_ptr<ScoDataChannel> sco_data_channel_;
131 
132   // The ISO data flow control handler.
133   std::unique_ptr<IsoDataChannel> iso_data_channel_;
134 
135   BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(Transport);
136 };
137 
138 }  // namespace bt::hci
139