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 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/fake_hci_transport_server.h"
16
17 #include "gtest/gtest.h"
18 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
19
20 namespace fhbt = ::fuchsia_hardware_bluetooth;
21
22 namespace bt::fidl::testing {
23
FakeHciTransportServer(::fidl::ServerEnd<fhbt::HciTransport> server_end,async_dispatcher_t * dispatcher)24 FakeHciTransportServer::FakeHciTransportServer(
25 ::fidl::ServerEnd<fhbt::HciTransport> server_end,
26 async_dispatcher_t* dispatcher)
27 : dispatcher_(dispatcher),
28 binding_(::fidl::BindServer(
29 dispatcher_,
30 std::move(server_end),
31 this,
32 std::mem_fn(&FakeHciTransportServer::OnUnbound))) {}
33
SendEvent(const BufferView & event)34 zx_status_t FakeHciTransportServer::SendEvent(const BufferView& event) {
35 ::fit::result<::fidl::OneWayError> result =
36 ::fidl::SendEvent(binding_)->OnReceive(
37 ::fuchsia_hardware_bluetooth::ReceivedPacket::WithEvent(
38 event.ToVector()));
39 return result.is_ok() ? ZX_OK : result.error_value().status();
40 }
41
SendAcl(const BufferView & buffer)42 zx_status_t FakeHciTransportServer::SendAcl(const BufferView& buffer) {
43 ::fit::result<::fidl::OneWayError> result =
44 ::fidl::SendEvent(binding_)->OnReceive(
45 ::fuchsia_hardware_bluetooth::ReceivedPacket::WithAcl(
46 buffer.ToVector()));
47 return result.is_ok() ? ZX_OK : result.error_value().status();
48 }
49
SendSco(const BufferView & buffer)50 zx_status_t FakeHciTransportServer::SendSco(const BufferView& buffer) {
51 if (!sco_server_) {
52 return ZX_ERR_UNAVAILABLE;
53 }
54 return sco_server_->Send(buffer);
55 }
56
SendIso(const BufferView & buffer)57 zx_status_t FakeHciTransportServer::SendIso(const BufferView& buffer) {
58 ::fit::result<::fidl::OneWayError> result =
59 ::fidl::SendEvent(binding_)->OnReceive(
60 ::fuchsia_hardware_bluetooth::ReceivedPacket::WithIso(
61 buffer.ToVector()));
62 return result.is_ok() ? ZX_OK : result.error_value().status();
63 }
64
UnbindSco()65 bool FakeHciTransportServer::UnbindSco() {
66 if (!sco_server_) {
67 return false;
68 }
69 sco_server_->Unbind();
70 sco_server_.reset();
71 return true;
72 }
73
ScoConnectionServer(::fidl::ServerEnd<fuchsia_hardware_bluetooth::ScoConnection> server_end,async_dispatcher_t * dispatcher,FakeHciTransportServer * hci_server)74 FakeHciTransportServer::ScoConnectionServer::ScoConnectionServer(
75 ::fidl::ServerEnd<fuchsia_hardware_bluetooth::ScoConnection> server_end,
76 async_dispatcher_t* dispatcher,
77 FakeHciTransportServer* hci_server)
78 : hci_server_(hci_server),
79 binding_(::fidl::BindServer(dispatcher, std::move(server_end), this)) {}
80
Send(const BufferView & buffer)81 zx_status_t FakeHciTransportServer::ScoConnectionServer::Send(
82 const BufferView& buffer) {
83 ::fuchsia_hardware_bluetooth::ScoPacket packet(buffer.ToVector());
84 fit::result<::fidl::OneWayError> result =
85 ::fidl::SendEvent(binding_)->OnReceive(packet);
86 return result.is_ok() ? ZX_OK : result.error_value().status();
87 }
88
Unbind()89 void FakeHciTransportServer::ScoConnectionServer::Unbind() {
90 binding_.Unbind();
91 }
92
Send(SendRequest & request,SendCompleter::Sync & completer)93 void FakeHciTransportServer::ScoConnectionServer::Send(
94 SendRequest& request, SendCompleter::Sync& completer) {
95 hci_server_->sco_packets_received_.emplace_back(BufferView(request.packet()));
96 completer.Reply();
97 }
98
AckReceive(AckReceiveCompleter::Sync & completer)99 void FakeHciTransportServer::ScoConnectionServer::AckReceive(
100 AckReceiveCompleter::Sync& completer) {
101 hci_server_->sco_ack_receive_count_++;
102 }
103
Stop(StopCompleter::Sync & completer)104 void FakeHciTransportServer::ScoConnectionServer::Stop(
105 StopCompleter::Sync& completer) {
106 binding_.Close(ZX_ERR_CANCELED);
107 if (hci_server_->reset_sco_cb_) {
108 hci_server_->reset_sco_cb_();
109 }
110 hci_server_->sco_server_.reset();
111 }
112
handle_unknown_method(::fidl::UnknownMethodMetadata<fuchsia_hardware_bluetooth::ScoConnection> metadata,::fidl::UnknownMethodCompleter::Sync & completer)113 void FakeHciTransportServer::ScoConnectionServer::handle_unknown_method(
114 ::fidl::UnknownMethodMetadata<fuchsia_hardware_bluetooth::ScoConnection>
115 metadata,
116 ::fidl::UnknownMethodCompleter::Sync& completer) {
117 FAIL();
118 }
119
OnUnbound(::fidl::UnbindInfo info,::fidl::ServerEnd<fuchsia_hardware_bluetooth::ScoConnection> server_end)120 void FakeHciTransportServer::ScoConnectionServer::OnUnbound(
121 ::fidl::UnbindInfo info,
122 ::fidl::ServerEnd<fuchsia_hardware_bluetooth::ScoConnection> server_end) {
123 if (info.is_user_initiated()) {
124 return;
125 }
126 if (info.is_peer_closed()) {
127 FAIL() << "OnUnbound() called before Stop()";
128 }
129
130 hci_server_->sco_server_.reset();
131 }
132
Send(SendRequest & request,SendCompleter::Sync & completer)133 void FakeHciTransportServer::Send(SendRequest& request,
134 SendCompleter::Sync& completer) {
135 switch (request.Which()) {
136 case SendRequest::Tag::kIso:
137 iso_packets_received_.emplace_back(BufferView(request.iso().value()));
138 break;
139 case SendRequest::Tag::kAcl:
140 acl_packets_received_.emplace_back(BufferView(request.acl().value()));
141 break;
142 case SendRequest::Tag::kCommand:
143 commands_received_.emplace_back(BufferView(request.command().value()));
144 break;
145 default:
146 FAIL() << "Send(): unknown packet type";
147 }
148 completer.Reply();
149 }
150
AckReceive(AckReceiveCompleter::Sync & completer)151 void FakeHciTransportServer::AckReceive(AckReceiveCompleter::Sync& completer) {
152 ack_receive_count_++;
153 }
154
ConfigureSco(ConfigureScoRequest & request,ConfigureScoCompleter::Sync & completer)155 void FakeHciTransportServer::ConfigureSco(
156 ConfigureScoRequest& request, ConfigureScoCompleter::Sync& completer) {
157 if (!request.connection() || !request.coding_format() ||
158 !request.sample_rate() || !request.encoding()) {
159 return;
160 }
161
162 ASSERT_FALSE(sco_server_);
163 sco_server_.emplace(
164 std::move(request.connection().value()), dispatcher_, this);
165
166 if (check_configure_sco_) {
167 check_configure_sco_(
168 *request.coding_format(), *request.encoding(), *request.sample_rate());
169 }
170 }
171
handle_unknown_method(::fidl::UnknownMethodMetadata<fuchsia_hardware_bluetooth::HciTransport> metadata,::fidl::UnknownMethodCompleter::Sync & completer)172 void FakeHciTransportServer::handle_unknown_method(
173 ::fidl::UnknownMethodMetadata<fuchsia_hardware_bluetooth::HciTransport>
174 metadata,
175 ::fidl::UnknownMethodCompleter::Sync& completer) {
176 FAIL();
177 }
178
OnUnbound(::fidl::UnbindInfo info,::fidl::ServerEnd<fuchsia_hardware_bluetooth::HciTransport> server_end)179 void FakeHciTransportServer::OnUnbound(
180 ::fidl::UnbindInfo info,
181 ::fidl::ServerEnd<fuchsia_hardware_bluetooth::HciTransport> server_end) {
182 bound_ = false;
183 }
184
185 } // namespace bt::fidl::testing
186