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