1 // Copyright 2024 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 
17 #include <fidl/fuchsia.hardware.bluetooth/cpp/fidl.h>
18 #include <lib/async/cpp/wait.h>
19 #include <lib/async/dispatcher.h>
20 #include <lib/zx/channel.h>
21 
22 #include "pw_bluetooth/controller.h"
23 
24 namespace bt::controllers {
25 
26 class VendorEventHandler
27     : public fidl::AsyncEventHandler<fuchsia_hardware_bluetooth::Vendor> {
28  public:
29   explicit VendorEventHandler(std::function<void(zx_status_t)> unbind_callback);
30   void on_fidl_error(fidl::UnbindInfo error) override;
31   void handle_unknown_event(
32       fidl::UnknownEventMetadata<fuchsia_hardware_bluetooth::Vendor> metadata)
33       override;
34 
35  private:
36   std::function<void(zx_status_t)> unbind_callback_;
37 };
38 
39 class HciEventHandler
40     : public fidl::AsyncEventHandler<fuchsia_hardware_bluetooth::HciTransport> {
41  public:
42   HciEventHandler(
43       std::function<void(zx_status_t)> unbind_callback,
44       std::function<void(fuchsia_hardware_bluetooth::ReceivedPacket)>
45           on_receive_callback);
46   void OnReceive(fuchsia_hardware_bluetooth::ReceivedPacket&) override;
47   void on_fidl_error(fidl::UnbindInfo error) override;
48   void handle_unknown_event(
49       fidl::UnknownEventMetadata<fuchsia_hardware_bluetooth::HciTransport>
50           metadata) override;
51 
52  private:
53   std::function<void(fuchsia_hardware_bluetooth::ReceivedPacket)>
54       on_receive_callback_;
55   std::function<void(zx_status_t)> unbind_callback_;
56 };
57 
58 class FidlController final : public pw::bluetooth::Controller {
59  public:
60   using PwStatusCallback = pw::Callback<void(pw::Status)>;
61 
62   // |dispatcher| must outlive this object.
63   FidlController(
64       fidl::ClientEnd<fuchsia_hardware_bluetooth::Vendor> vendor_client_end,
65       async_dispatcher_t* dispatcher);
66 
67   ~FidlController() override;
68 
69   // Controller overrides:
SetEventFunction(DataFunction func)70   void SetEventFunction(DataFunction func) override {
71     event_cb_ = std::move(func);
72   }
73 
SetReceiveAclFunction(DataFunction func)74   void SetReceiveAclFunction(DataFunction func) override {
75     acl_cb_ = std::move(func);
76   }
77 
SetReceiveScoFunction(DataFunction func)78   void SetReceiveScoFunction(DataFunction func) override {
79     sco_cb_ = std::move(func);
80   }
81 
SetReceiveIsoFunction(DataFunction func)82   void SetReceiveIsoFunction(DataFunction func) override {
83     iso_cb_ = std::move(func);
84   }
85 
86   void Initialize(PwStatusCallback complete_callback,
87                   PwStatusCallback error_callback) override;
88 
89   void Close(PwStatusCallback callback) override;
90 
91   void SendCommand(pw::span<const std::byte> command) override;
92 
93   void SendAclData(pw::span<const std::byte> data) override;
94 
95   void SendScoData(pw::span<const std::byte> data) override;
96 
97   void SendIsoData(pw::span<const std::byte> data) override;
98 
99   void ConfigureSco(ScoCodingFormat coding_format,
100                     ScoEncoding encoding,
101                     ScoSampleRate sample_rate,
102                     pw::Callback<void(pw::Status)> callback) override;
103 
104   void ResetSco(pw::Callback<void(pw::Status)> callback) override;
105 
106   void GetFeatures(pw::Callback<void(FeaturesBits)> callback) override;
107   void EncodeVendorCommand(
108       pw::bluetooth::VendorCommandParameters parameters,
109       pw::Callback<void(pw::Result<pw::span<const std::byte>>)> callback)
110       override;
111 
112  private:
113   class ScoEventHandler : public fidl::AsyncEventHandler<
114                               fuchsia_hardware_bluetooth::ScoConnection> {
115    public:
116     ScoEventHandler(pw::Function<void(zx_status_t)> unbind_callback,
117                     pw::Function<void(fuchsia_hardware_bluetooth::ScoPacket)>
118                         on_receive_callback);
119 
120    private:
121     // AsyncEventHandler<ScoConnection> overrides:
122     void OnReceive(fuchsia_hardware_bluetooth::ScoPacket& packet) override;
123     void on_fidl_error(fidl::UnbindInfo error) override;
124     void handle_unknown_event(
125         fidl::UnknownEventMetadata<fuchsia_hardware_bluetooth::ScoConnection>
126             metadata) override;
127 
128     pw::Function<void(fuchsia_hardware_bluetooth::ScoPacket)>
129         on_receive_callback_;
130     pw::Function<void(zx_status_t)> unbind_callback_;
131   };
132 
133   void OnReceive(fuchsia_hardware_bluetooth::ReceivedPacket packet);
134   void OnReceiveSco(fuchsia_hardware_bluetooth::ScoPacket packet);
135 
136   void OnScoUnbind(zx_status_t status);
137 
138   // Cleanup and call |error_cb_| with |status|
139   void OnError(zx_status_t status);
140 
141   void CleanUp();
142 
143   // Initializes HCI layer by binding |hci_handle| to |hci_| and opening two-way
144   // command channel and ACL data channel
145   void InitializeHci(
146       fidl::ClientEnd<fuchsia_hardware_bluetooth::HciTransport> hci_client_end);
147 
148   // |vendor_handle_| holds the Vendor channel until Initialize() is called, at
149   // which point |vendor_| is bound to the channel. This prevents errors from
150   // being lost before initialization.
151   fidl::ClientEnd<fuchsia_hardware_bluetooth::Vendor> vendor_client_end_;
152   fidl::Client<fuchsia_hardware_bluetooth::Vendor> vendor_;
153 
154   fidl::Client<fuchsia_hardware_bluetooth::HciTransport> hci_;
155 
156   VendorEventHandler vendor_event_handler_;
157   HciEventHandler hci_event_handler_;
158 
159   // Only set after ConfigureSco() is called. Unbound on ResetSco().
160   std::optional<fidl::Client<fuchsia_hardware_bluetooth::ScoConnection>>
161       sco_connection_;
162   // Shared across all ScoConnections.
163   ScoEventHandler sco_event_handler_;
164   // Valid only when a ResetSco() call is pending.
165   PwStatusCallback reset_sco_cb_;
166 
167   async_dispatcher_t* dispatcher_;
168 
169   DataFunction event_cb_;
170   DataFunction acl_cb_;
171   DataFunction sco_cb_;
172   DataFunction iso_cb_;
173   PwStatusCallback initialize_complete_cb_;
174   PwStatusCallback error_cb_;
175 
176   bool shutting_down_ = false;
177 };
178 
179 }  // namespace bt::controllers
180