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 <pw_async/dispatcher.h>
17 #include <pw_async/heap_dispatcher.h>
18 
19 #include "pw_bluetooth/controller.h"
20 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
21 #include "pw_bluetooth_sapphire/internal/host/common/macros.h"
22 #include "pw_bluetooth_sapphire/internal/host/common/weak_self.h"
23 
24 namespace bt::testing {
25 
26 // Abstract base for implementing a fake HCI controller endpoint. This can
27 // directly send ACL data and event packets on request and forward outgoing ACL
28 // data packets to subclass implementations.
29 class ControllerTestDoubleBase : public pw::bluetooth::Controller {
30  public:
31   using PwStatusCallback = pw::Callback<void(pw::Status)>;
32 
33   using EncodeVendorCommandFunction = fit::function<void(
34       pw::bluetooth::VendorCommandParameters,
35       pw::Callback<void(pw::Result<pw::span<const std::byte>>)>)>;
36 
37   using ConfigureScoFunction =
38       fit::function<void(ScoCodingFormat,
39                          ScoEncoding,
40                          ScoSampleRate,
41                          fit::callback<void(pw::Status)>)>;
42 
43   using ResetScoFunction = fit::function<void(fit::callback<void(pw::Status)>)>;
44 
45   explicit ControllerTestDoubleBase(pw::async::Dispatcher& pw_dispatcher);
46   ~ControllerTestDoubleBase() override;
47 
pw_dispatcher()48   pw::async::Dispatcher& pw_dispatcher() { return pw_dispatcher_; }
heap_dispatcher()49   pw::async::HeapDispatcher& heap_dispatcher() { return heap_dispatcher_; }
50 
51   // Sends the given packet over this FakeController's command channel endpoint.
52   // Returns the result of the write operation on the command channel.
53   bool SendCommandChannelPacket(const ByteBuffer& packet);
54 
55   // Sends the given packet over this FakeController's ACL data channel
56   // endpoint.
57   // Returns the result of the write operation on the channel.
58   bool SendACLDataChannelPacket(const ByteBuffer& packet);
59 
60   // Sends the given packet over this ControllerTestDouble's SCO data channel
61   // endpoint.
62   // Returns the result of the write operation on the channel.
63   bool SendScoDataChannelPacket(const ByteBuffer& packet);
64 
65   // Sends the given packet over this ControllerTestDouble's ISO data channel
66   // endpoint.
67   // Returns the result of the write operation on the channel.
68   bool SendIsoDataChannelPacket(const pw::span<const std::byte>& packet);
69 
70   // Wrapper around SignalError() to support old test code.
Stop()71   void Stop() { SignalError(pw::Status::Aborted()); }
72 
SignalError(pw::Status status)73   void SignalError(pw::Status status) {
74     if (error_cb_) {
75       error_cb_(status);
76     }
77   }
78 
79   // This only has an effect *before* Transport has been initialized.
set_features(FeaturesBits features)80   void set_features(FeaturesBits features) { features_ = features; }
81 
set_encode_vendor_command_cb(EncodeVendorCommandFunction cb)82   void set_encode_vendor_command_cb(EncodeVendorCommandFunction cb) {
83     encode_vendor_command_cb_ = std::move(cb);
84   }
85 
set_configure_sco_cb(ConfigureScoFunction cb)86   void set_configure_sco_cb(ConfigureScoFunction cb) {
87     configure_sco_cb_ = std::move(cb);
88   }
89 
set_reset_sco_cb(ResetScoFunction cb)90   void set_reset_sco_cb(ResetScoFunction cb) { reset_sco_cb_ = std::move(cb); }
91 
92   // Controller overrides:
SetEventFunction(DataFunction func)93   void SetEventFunction(DataFunction func) override {
94     event_cb_ = std::move(func);
95   }
96 
SetReceiveAclFunction(DataFunction func)97   void SetReceiveAclFunction(DataFunction func) override {
98     acl_cb_ = std::move(func);
99   }
100 
SetReceiveScoFunction(DataFunction func)101   void SetReceiveScoFunction(DataFunction func) override {
102     sco_cb_ = std::move(func);
103   }
104 
SetReceiveIsoFunction(DataFunction func)105   void SetReceiveIsoFunction(DataFunction func) override {
106     iso_cb_ = std::move(func);
107   }
108 
109   void Initialize(PwStatusCallback complete_callback,
110                   PwStatusCallback error_callback) override;
111 
112   void Close(PwStatusCallback callback) override;
113 
114   void ConfigureSco(ScoCodingFormat coding_format,
115                     ScoEncoding encoding,
116                     ScoSampleRate sample_rate,
117                     pw::Callback<void(pw::Status)> callback) override;
118 
119   void ResetSco(pw::Callback<void(pw::Status)> callback) override;
120 
GetFeatures(pw::Callback<void (FeaturesBits)> callback)121   void GetFeatures(pw::Callback<void(FeaturesBits)> callback) override {
122     callback(features_);
123   }
124 
EncodeVendorCommand(pw::bluetooth::VendorCommandParameters parameters,pw::Callback<void (pw::Result<pw::span<const std::byte>>)> callback)125   void EncodeVendorCommand(
126       pw::bluetooth::VendorCommandParameters parameters,
127       pw::Callback<void(pw::Result<pw::span<const std::byte>>)> callback)
128       override {
129     if (encode_vendor_command_cb_) {
130       encode_vendor_command_cb_(parameters, std::move(callback));
131     }
132   }
133 
134  private:
135   FeaturesBits features_{0};
136   EncodeVendorCommandFunction encode_vendor_command_cb_;
137   ConfigureScoFunction configure_sco_cb_;
138   ResetScoFunction reset_sco_cb_;
139 
140   // Send inbound packets to the host stack:
141   fit::function<void(pw::span<const std::byte>)> event_cb_;
142   DataFunction acl_cb_;
143   DataFunction sco_cb_;
144   DataFunction iso_cb_;
145 
146   PwStatusCallback error_cb_;
147 
148   pw::async::Dispatcher& pw_dispatcher_;
149   pw::async::HeapDispatcher heap_dispatcher_;
150   WeakSelf<ControllerTestDoubleBase> weak_self_{this};
151   BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(ControllerTestDoubleBase);
152 };
153 
154 }  // namespace bt::testing
155