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 #include "pw_bluetooth_sapphire/internal/host/transport/command_channel.h"
16
17 #include <pw_bluetooth/hci_android.emb.h>
18 #include <pw_bluetooth/hci_commands.emb.h>
19
20 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
21 #include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h"
22 #include "pw_bluetooth_sapphire/internal/host/testing/controller_test.h"
23 #include "pw_bluetooth_sapphire/internal/host/testing/inspect.h"
24 #include "pw_bluetooth_sapphire/internal/host/testing/mock_controller.h"
25 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
26 #include "pw_bluetooth_sapphire/internal/host/testing/test_packets.h"
27 #include "pw_bluetooth_sapphire/internal/host/transport/control_packets.h"
28
29 namespace bt::hci {
30 namespace {
31
32 using namespace inspect::testing;
33
34 using bt::LowerBits;
35 using bt::UpperBits;
36 using EventCallbackResult = CommandChannel::EventCallbackResult;
37
38 constexpr pw::chrono::SystemClock::duration kCommandTimeout =
39 std::chrono::seconds(12);
40
41 using TestingBase =
42 bt::testing::FakeDispatcherControllerTest<bt::testing::MockController>;
43
44 // A reference counted object used to verify that HCI command completion and
45 // status callbacks are properly cleaned up after the end of a transaction.
46 class TestCallbackObject {
47 public:
TestCallbackObject(fit::closure deletion_callback)48 explicit TestCallbackObject(fit::closure deletion_callback)
49 : deletion_cb_(std::move(deletion_callback)) {}
50
~TestCallbackObject()51 virtual ~TestCallbackObject() { deletion_cb_(); }
52
53 private:
54 fit::closure deletion_cb_;
55 };
56
57 class CommandChannelTest : public TestingBase {
58 public:
59 CommandChannelTest() = default;
60 ~CommandChannelTest() override = default;
61
heap_dispatcher()62 pw::async::HeapDispatcher heap_dispatcher() { return heap_dispatcher_; }
63
64 inspect::Inspector inspector_;
65
66 private:
67 pw::async::HeapDispatcher heap_dispatcher_{dispatcher()};
68 };
69
MakeReadRemoteSupportedFeatures(uint16_t connection_handle)70 EmbossCommandPacket MakeReadRemoteSupportedFeatures(
71 uint16_t connection_handle) {
72 auto packet = EmbossCommandPacket::New<
73 pw::bluetooth::emboss::ReadRemoteSupportedFeaturesCommandWriter>(
74 hci_spec::kReadRemoteSupportedFeatures);
75 packet.view_t().connection_handle().Write(connection_handle);
76 return packet;
77 }
78
TEST_F(CommandChannelTest,SingleRequestResponse)79 TEST_F(CommandChannelTest, SingleRequestResponse) {
80 // Set up expectations:
81 // clang-format off
82 // HCI_Reset
83 StaticByteBuffer req(
84 LowerBits(hci_spec::kReset), UpperBits(hci_spec::kReset), // HCI_Reset opcode
85 0x00 // parameter_total_size
86 );
87 // HCI_CommandComplete
88 StaticByteBuffer rsp(
89 hci_spec::kCommandCompleteEventCode,
90 0x04, // parameter_total_size (4 byte payload)
91 0x01, // num_hci_command_packets (1 can be sent)
92 LowerBits(hci_spec::kReset), UpperBits(hci_spec::kReset), // HCI_Reset opcode
93 pw::bluetooth::emboss::StatusCode::HARDWARE_FAILURE);
94 // clang-format on
95 EXPECT_CMD_PACKET_OUT(test_device(), req, &rsp);
96
97 // Send a HCI_Reset command. We attach an instance of TestCallbackObject to
98 // the callbacks to verify that it gets cleaned up as expected.
99 bool test_obj_deleted = false;
100 auto test_obj = std::make_shared<TestCallbackObject>(
101 [&test_obj_deleted] { test_obj_deleted = true; });
102
103 auto reset =
104 hci::EmbossCommandPacket::New<pw::bluetooth::emboss::ResetCommandWriter>(
105 hci_spec::kReset);
106 CommandChannel::TransactionId id = cmd_channel()->SendCommand(
107 std::move(reset),
108 [&id, test_obj](CommandChannel::TransactionId callback_id,
109 const EventPacket& event) {
110 EXPECT_EQ(id, callback_id);
111 EXPECT_EQ(hci_spec::kCommandCompleteEventCode, event.event_code());
112 EXPECT_EQ(4, event.view().header().parameter_total_size);
113 EXPECT_EQ(1,
114 event.view()
115 .payload<hci_spec::CommandCompleteEventParams>()
116 .num_hci_command_packets);
117 EXPECT_EQ(hci_spec::kReset,
118 le16toh(event.view()
119 .payload<hci_spec::CommandCompleteEventParams>()
120 .command_opcode));
121 EXPECT_EQ(pw::bluetooth::emboss::StatusCode::HARDWARE_FAILURE,
122 event.return_params<hci_spec::SimpleReturnParams>()->status);
123 });
124
125 test_obj = nullptr;
126 EXPECT_FALSE(test_obj_deleted);
127 RunUntilIdle();
128
129 // Make sure that the I/O thread is no longer holding on to |test_obj|.
130 TearDown();
131
132 EXPECT_TRUE(test_obj_deleted);
133 }
134
TEST_F(CommandChannelTest,SingleAsynchronousRequest)135 TEST_F(CommandChannelTest, SingleAsynchronousRequest) {
136 // Set up expectations:
137 // clang-format off
138 // HCI_Inquiry (general, unlimited, 1s)
139 StaticByteBuffer req(
140 LowerBits(hci_spec::kInquiry), UpperBits(hci_spec::kInquiry), // HCI_Inquiry opcode
141 0x05, // parameter_total_size
142 0x33, 0x8B, 0x9E, // General Inquiry
143 0x01, // 1.28s
144 0x00 // Unlimited responses
145 );
146 // HCI_CommandStatus
147 auto rsp0 = StaticByteBuffer(
148 hci_spec::kCommandStatusEventCode,
149 0x04, // parameter_total_size (4 byte payload)
150 pw::bluetooth::emboss::StatusCode::SUCCESS, 0x01, // status, num_hci_command_packets (1 can be sent)
151 LowerBits(hci_spec::kInquiry), UpperBits(hci_spec::kInquiry) // HCI_Inquiry opcode
152 );
153 // HCI_InquiryComplete
154 auto rsp1 = StaticByteBuffer(
155 hci_spec::kInquiryCompleteEventCode,
156 0x01, // parameter_total_size (1 byte payload)
157 pw::bluetooth::emboss::StatusCode::SUCCESS);
158 // clang-format on
159 EXPECT_CMD_PACKET_OUT(test_device(), req, &rsp0, &rsp1);
160
161 // Send HCI_Inquiry
162 CommandChannel::TransactionId id;
163 int cb_count = 0;
164 auto cb = [&cb_count, &id](CommandChannel::TransactionId callback_id,
165 const EventPacket& event) {
166 cb_count++;
167 EXPECT_EQ(callback_id, id);
168 if (cb_count == 1) {
169 ASSERT_EQ(hci_spec::kCommandStatusEventCode, event.event_code());
170 const auto params = event.params<hci_spec::CommandStatusEventParams>();
171 EXPECT_EQ(pw::bluetooth::emboss::StatusCode::SUCCESS, params.status);
172 EXPECT_EQ(hci_spec::kInquiry, params.command_opcode);
173 } else {
174 EXPECT_EQ(hci_spec::kInquiryCompleteEventCode, event.event_code());
175 EXPECT_EQ(fit::ok(), event.ToResult());
176 }
177 };
178
179 auto packet = hci::EmbossCommandPacket::New<
180 pw::bluetooth::emboss::InquiryCommandWriter>(hci_spec::kInquiry);
181 auto view = packet.view_t();
182 view.lap().Write(pw::bluetooth::emboss::InquiryAccessCode::GIAC);
183 view.inquiry_length().Write(1);
184 view.num_responses().Write(0);
185
186 id = cmd_channel()->SendCommand(
187 std::move(packet), cb, hci_spec::kInquiryCompleteEventCode);
188 RunUntilIdle();
189 EXPECT_EQ(2, cb_count);
190 }
191
TEST_F(CommandChannelTest,SingleRequestWithStatusResponse)192 TEST_F(CommandChannelTest, SingleRequestWithStatusResponse) {
193 // Set up expectations
194 // clang-format off
195 // HCI_Reset for the sake of testing
196 auto req = StaticByteBuffer(
197 LowerBits(hci_spec::kReset), UpperBits(hci_spec::kReset), // HCI_Reset opcode
198 0x00 // parameter_total_size
199 );
200 // HCI_CommandStatus
201 auto rsp = StaticByteBuffer(
202 hci_spec::kCommandStatusEventCode,
203 0x04, // parameter_total_size (4 byte payload)
204 pw::bluetooth::emboss::StatusCode::SUCCESS, 0x01, // status, num_hci_command_packets (1 can be sent)
205 LowerBits(hci_spec::kReset), UpperBits(hci_spec::kReset) // HCI_Reset opcode
206 );
207 // clang-format on
208 EXPECT_CMD_PACKET_OUT(test_device(), req, &rsp);
209
210 // Send HCI_Reset
211 CommandChannel::TransactionId id;
212 auto complete_cb = [&id](CommandChannel::TransactionId callback_id,
213 const EventPacket& event) {
214 EXPECT_EQ(callback_id, id);
215 EXPECT_EQ(hci_spec::kCommandStatusEventCode, event.event_code());
216 EXPECT_EQ(pw::bluetooth::emboss::StatusCode::SUCCESS,
217 event.params<hci_spec::CommandStatusEventParams>().status);
218 EXPECT_EQ(1,
219 event.view()
220 .payload<hci_spec::CommandStatusEventParams>()
221 .num_hci_command_packets);
222 EXPECT_EQ(
223 hci_spec::kReset,
224 le16toh(
225 event.params<hci_spec::CommandStatusEventParams>().command_opcode));
226 };
227
228 auto reset =
229 hci::EmbossCommandPacket::New<pw::bluetooth::emboss::ResetCommandWriter>(
230 hci_spec::kReset);
231 id = cmd_channel()->SendCommand(
232 std::move(reset), complete_cb, hci_spec::kCommandStatusEventCode);
233 RunUntilIdle();
234 }
235
236 // Tests:
237 // - Only one HCI command sent until a status is received.
238 // - Receiving a status update with a new number of packets available works.
TEST_F(CommandChannelTest,OneSentUntilStatus)239 TEST_F(CommandChannelTest, OneSentUntilStatus) {
240 // Set up expectations
241 // clang-format off
242 // HCI_Reset for the sake of testing
243 auto req1 = StaticByteBuffer(
244 LowerBits(hci_spec::kReset), UpperBits(hci_spec::kReset), // HCI_Reset opcode
245 0x00 // parameter_total_size
246 );
247 auto rsp1 = StaticByteBuffer(
248 hci_spec::kCommandCompleteEventCode,
249 0x03, // parameter_total_size (4 byte payload)
250 0x00, // num_hci_command_packets (None can be sent)
251 LowerBits(hci_spec::kReset), UpperBits(hci_spec::kReset) // HCI_Reset opcode
252 );
253 auto req2 = StaticByteBuffer(
254 LowerBits(hci_spec::kInquiryCancel), UpperBits(hci_spec::kInquiryCancel), // HCI_InquiryCancel opcode
255 0x00 // parameter_total_size
256 );
257 auto rsp2 = StaticByteBuffer(
258 hci_spec::kCommandCompleteEventCode,
259 0x03, // parameter_total_size (4 byte payload)
260 0x01, // num_hci_command_packets (1 can be sent)
261 LowerBits(hci_spec::kInquiryCancel), UpperBits(hci_spec::kInquiryCancel) // HCI_InquiryCancel opcode
262 );
263 auto rsp_commandsavail = StaticByteBuffer(
264 hci_spec::kCommandStatusEventCode,
265 0x04, // parameter_total_size (3 byte payload)
266 pw::bluetooth::emboss::StatusCode::SUCCESS, 0x01, // status, num_hci_command_packets (1 can be sent)
267 0x00, 0x00 // No associated opcode.
268 );
269 // clang-format on
270 EXPECT_CMD_PACKET_OUT(test_device(), req1, &rsp1);
271 EXPECT_CMD_PACKET_OUT(test_device(), req2, &rsp2);
272
273 size_t cb_event_count = 0u;
274 size_t transaction_count = 0u;
275
276 test_device()->SetTransactionCallback(
277 [&transaction_count]() { transaction_count++; });
278
279 auto cb = [&cb_event_count](CommandChannel::TransactionId,
280 const EventPacket& event) {
281 EXPECT_EQ(hci_spec::kCommandCompleteEventCode, event.event_code());
282 hci_spec::OpCode expected_opcode;
283 if (cb_event_count == 0u) {
284 expected_opcode = hci_spec::kReset;
285 } else {
286 expected_opcode = hci_spec::kInquiryCancel;
287 }
288 EXPECT_EQ(expected_opcode,
289 le16toh(event.params<hci_spec::CommandCompleteEventParams>()
290 .command_opcode));
291 cb_event_count++;
292 };
293
294 auto reset =
295 hci::EmbossCommandPacket::New<pw::bluetooth::emboss::ResetCommandWriter>(
296 hci_spec::kReset);
297 [[maybe_unused]] auto reset_id =
298 cmd_channel()->SendCommand(std::move(reset), cb);
299 auto inquiry = CommandPacket::New(hci_spec::kInquiryCancel);
300 [[maybe_unused]] auto inquiry_id =
301 cmd_channel()->SendCommand(std::move(inquiry), cb);
302
303 RunUntilIdle();
304
305 EXPECT_EQ(1u, transaction_count);
306 EXPECT_EQ(1u, cb_event_count);
307
308 test_device()->SendCommandChannelPacket(rsp_commandsavail);
309
310 RunUntilIdle();
311
312 EXPECT_EQ(2u, transaction_count);
313 EXPECT_EQ(2u, cb_event_count);
314 }
315
316 // Tests:
317 // - Different opcodes can be sent concurrently
318 // - Same opcodes are queued until a status opcode is sent.
TEST_F(CommandChannelTest,QueuedCommands)319 TEST_F(CommandChannelTest, QueuedCommands) {
320 // Set up expectations
321 // clang-format off
322 // HCI_Reset for the sake of testing
323 auto req_reset = StaticByteBuffer(
324 LowerBits(hci_spec::kReset), UpperBits(hci_spec::kReset), // HCI_Reset opcode
325 0x00 // parameter_total_size
326 );
327 auto rsp_reset = StaticByteBuffer(
328 hci_spec::kCommandCompleteEventCode,
329 0x03, // parameter_total_size (4 byte payload)
330 0xFF, // num_hci_command_packets (255 can be sent)
331 LowerBits(hci_spec::kReset), UpperBits(hci_spec::kReset) // HCI_Reset opcode
332 );
333 auto req_inqcancel = StaticByteBuffer(
334 LowerBits(hci_spec::kInquiryCancel), UpperBits(hci_spec::kInquiryCancel), // HCI_InquiryCancel opcode
335 0x00 // parameter_total_size
336 );
337 auto rsp_inqcancel = StaticByteBuffer(
338 hci_spec::kCommandCompleteEventCode,
339 0x03, // parameter_total_size (4 byte payload)
340 0xFF, // num_hci_command_packets (255 can be sent)
341 LowerBits(hci_spec::kInquiryCancel), UpperBits(hci_spec::kInquiryCancel) // HCI_Reset opcode
342 );
343 auto rsp_commandsavail = StaticByteBuffer(
344 hci_spec::kCommandStatusEventCode,
345 0x04, // parameter_total_size (3 byte payload)
346 pw::bluetooth::emboss::StatusCode::SUCCESS, 0xFA, // status, num_hci_command_packets (250 can be sent)
347 0x00, 0x00 // No associated opcode.
348 );
349 // clang-format on
350
351 // We handle our own responses to make sure commands are queued.
352 EXPECT_CMD_PACKET_OUT(test_device(), req_reset, );
353 EXPECT_CMD_PACKET_OUT(test_device(), req_inqcancel, );
354 EXPECT_CMD_PACKET_OUT(test_device(), req_reset, &rsp_reset);
355
356 size_t transaction_count = 0u;
357 size_t reset_count = 0u;
358 size_t cancel_count = 0u;
359
360 test_device()->SetTransactionCallback(
361 [&transaction_count]() { transaction_count++; });
362
363 auto cb = [&reset_count, &cancel_count](CommandChannel::TransactionId id,
364 const EventPacket& event) {
365 EXPECT_EQ(hci_spec::kCommandCompleteEventCode, event.event_code());
366 auto opcode = le16toh(
367 event.params<hci_spec::CommandCompleteEventParams>().command_opcode);
368 if (opcode == hci_spec::kReset) {
369 reset_count++;
370 } else if (opcode == hci_spec::kInquiryCancel) {
371 cancel_count++;
372 } else {
373 EXPECT_TRUE(false) << "Unexpected opcode in command callback!";
374 }
375 };
376
377 // CommandChannel only one can be sent - update num_hci_command_packets
378 test_device()->SendCommandChannelPacket(rsp_commandsavail);
379
380 auto reset =
381 hci::EmbossCommandPacket::New<pw::bluetooth::emboss::ResetCommandWriter>(
382 hci_spec::kReset);
383 cmd_channel()->SendCommand(std::move(reset), cb);
384 auto inquiry_cancel = hci::EmbossCommandPacket::New<
385 pw::bluetooth::emboss::InquiryCancelCommandWriter>(
386 hci_spec::kInquiryCancel);
387 cmd_channel()->SendCommand(std::move(inquiry_cancel), cb);
388 reset =
389 hci::EmbossCommandPacket::New<pw::bluetooth::emboss::ResetCommandWriter>(
390 hci_spec::kReset);
391 cmd_channel()->SendCommand(std::move(reset), cb);
392
393 RunUntilIdle();
394
395 // Different opcodes can be sent without a reply
396 EXPECT_EQ(2u, transaction_count);
397
398 // Even if we get a response to one, the duplicate opcode is still queued.
399 test_device()->SendCommandChannelPacket(rsp_inqcancel);
400 RunUntilIdle();
401
402 EXPECT_EQ(2u, transaction_count);
403 EXPECT_EQ(1u, cancel_count);
404 EXPECT_EQ(0u, reset_count);
405
406 // Once we get a reset back, the second can be sent (and replied to)
407 test_device()->SendCommandChannelPacket(rsp_reset);
408 RunUntilIdle();
409
410 EXPECT_EQ(3u, transaction_count);
411 EXPECT_EQ(1u, cancel_count);
412 EXPECT_EQ(2u, reset_count);
413 }
414
415 // Tests:
416 // - Asynchronous commands are handled correctly (two callbacks, one for
417 // status, one for complete)
418 // - Asynchronous commands with the same event result are queued even if they
419 // have different opcodes.
420 // - Can't register an event handler when an asynchronous command is waiting.
TEST_F(CommandChannelTest,AsynchronousCommands)421 TEST_F(CommandChannelTest, AsynchronousCommands) {
422 constexpr hci_spec::EventCode kTestEventCode0 = 0xFE;
423 // Set up expectations
424 // clang-format off
425 // Using HCI_Reset for testing.
426 auto req_reset = StaticByteBuffer(
427 LowerBits(hci_spec::kReset), UpperBits(hci_spec::kReset), // HCI_Reset opcode
428 0x00 // parameter_total_size
429 );
430 auto rsp_resetstatus = StaticByteBuffer(
431 hci_spec::kCommandStatusEventCode,
432 0x04, // parameter_total_size (4 byte payload)
433 pw::bluetooth::emboss::StatusCode::SUCCESS, 0xFA, // status, num_hci_command_packets (250 can be sent)
434 LowerBits(hci_spec::kReset), UpperBits(hci_spec::kReset) // HCI_Reset opcode
435 );
436 auto req_inqcancel = StaticByteBuffer(
437 LowerBits(hci_spec::kInquiryCancel), UpperBits(hci_spec::kInquiryCancel), // HCI_InquiryCancel opcode
438 0x00 // parameter_total_size
439 );
440 auto rsp_inqstatus = StaticByteBuffer(
441 hci_spec::kCommandStatusEventCode,
442 0x04, // parameter_total_size (4 byte payload)
443 pw::bluetooth::emboss::StatusCode::SUCCESS, 0xFA, // status, num_hci_command_packets (250 can be sent)
444 LowerBits(hci_spec::kInquiryCancel), UpperBits(hci_spec::kInquiryCancel) // HCI_Reset opcode
445 );
446 auto rsp_bogocomplete = StaticByteBuffer(
447 kTestEventCode0,
448 0x00 // parameter_total_size (no payload)
449 );
450 // clang-format on
451
452 EXPECT_CMD_PACKET_OUT(test_device(), req_reset, &rsp_resetstatus);
453 EXPECT_CMD_PACKET_OUT(test_device(), req_inqcancel, &rsp_inqstatus);
454
455 CommandChannel::TransactionId id1, id2;
456 size_t cb_count = 0u;
457
458 auto cb = [&id1, &id2, &cb_count, kTestEventCode0](
459 CommandChannel::TransactionId callback_id,
460 const EventPacket& event) {
461 if (cb_count < 2) {
462 EXPECT_EQ(id1, callback_id);
463 } else {
464 EXPECT_EQ(id2, callback_id);
465 }
466 if ((cb_count % 2) == 0) {
467 EXPECT_EQ(hci_spec::kCommandStatusEventCode, event.event_code());
468 auto params = event.params<hci_spec::CommandStatusEventParams>();
469 EXPECT_EQ(pw::bluetooth::emboss::StatusCode::SUCCESS, params.status);
470 } else if ((cb_count % 2) == 1) {
471 EXPECT_EQ(kTestEventCode0, event.event_code());
472 }
473 cb_count++;
474 };
475
476 hci::EmbossCommandPacket packet =
477 hci::EmbossCommandPacket::New<pw::bluetooth::emboss::ResetCommandWriter>(
478 hci_spec::kReset);
479 id1 = cmd_channel()->SendCommand(std::move(packet), cb, kTestEventCode0);
480
481 RunUntilIdle();
482
483 // Should have received the Status but not the result.
484 EXPECT_EQ(1u, cb_count);
485
486 // Setting another event up with different opcode will still queue the command
487 // because we don't want to have two commands waiting on an event.
488 packet = hci::EmbossCommandPacket::New<
489 pw::bluetooth::emboss::InquiryCancelCommandWriter>(
490 hci_spec::kInquiryCancel);
491 id2 = cmd_channel()->SendCommand(std::move(packet), cb, kTestEventCode0);
492 RunUntilIdle();
493
494 EXPECT_EQ(1u, cb_count);
495
496 // Sending the complete will release the queue and send the next command.
497 test_device()->SendCommandChannelPacket(rsp_bogocomplete);
498 RunUntilIdle();
499
500 EXPECT_EQ(3u, cb_count);
501
502 // Should not be able to register an event handler now, we're still waiting on
503 // the asynchronous command.
504 auto event_id0 = cmd_channel()->AddEventHandler(
505 kTestEventCode0,
506 [](const EventPacket&) { return EventCallbackResult::kContinue; });
507 EXPECT_EQ(0u, event_id0);
508
509 // Finish out the commands.
510 test_device()->SendCommandChannelPacket(rsp_bogocomplete);
511 RunUntilIdle();
512
513 EXPECT_EQ(4u, cb_count);
514 }
515
516 // Tests:
517 // - Updating to say no commands can be sent works. (commands are queued)
518 // - Can't add an event handler once a SendCommand() succeeds watiing on
519 // the same event code. (even if they are queued)
TEST_F(CommandChannelTest,AsyncQueueWhenBlocked)520 TEST_F(CommandChannelTest, AsyncQueueWhenBlocked) {
521 constexpr hci_spec::EventCode kTestEventCode0 = 0xF0;
522 // Set up expectations
523 // clang-format off
524 // Using HCI_Reset for testing.
525 auto req_reset = StaticByteBuffer(
526 LowerBits(hci_spec::kReset), UpperBits(hci_spec::kReset), // HCI_Reset opcode
527 0x00 // parameter_total_size
528 );
529 auto rsp_resetstatus = StaticByteBuffer(
530 hci_spec::kCommandStatusEventCode,
531 0x04, // parameter_total_size (4 byte payload)
532 pw::bluetooth::emboss::StatusCode::SUCCESS, 0xFA, // status, num_hci_command_packets (250 can be sent)
533 LowerBits(hci_spec::kReset), UpperBits(hci_spec::kReset) // HCI_Reset opcode
534 );
535 auto rsp_bogocomplete = StaticByteBuffer(
536 kTestEventCode0,
537 0x00 // parameter_total_size (no payload)
538 );
539 auto rsp_nocommandsavail = StaticByteBuffer(
540 hci_spec::kCommandStatusEventCode,
541 0x04, // parameter_total_size (3 byte payload)
542 pw::bluetooth::emboss::StatusCode::SUCCESS, 0x00, // status, num_hci_command_packets (none can be sent)
543 0x00, 0x00 // No associated opcode.
544 );
545 auto rsp_commandsavail = StaticByteBuffer(
546 hci_spec::kCommandStatusEventCode,
547 0x04, // parameter_total_size (3 byte payload)
548 pw::bluetooth::emboss::StatusCode::SUCCESS, 0x01, // status, num_hci_command_packets (one can be sent)
549 0x00, 0x00 // No associated opcode.
550 );
551 // clang-format on
552
553 size_t transaction_count = 0u;
554
555 test_device()->SetTransactionCallback(
556 [&transaction_count]() { transaction_count++; });
557
558 EXPECT_CMD_PACKET_OUT(
559 test_device(), req_reset, &rsp_resetstatus, &rsp_bogocomplete);
560
561 test_device()->SendCommandChannelPacket(rsp_nocommandsavail);
562
563 RunUntilIdle();
564
565 CommandChannel::TransactionId id;
566 size_t cb_count = 0;
567 auto cb = [&cb_count, &id, kTestEventCode0](
568 CommandChannel::TransactionId callback_id,
569 const EventPacket& event) {
570 cb_count++;
571 EXPECT_EQ(callback_id, id);
572 if (cb_count == 1) {
573 ASSERT_EQ(hci_spec::kCommandStatusEventCode, event.event_code());
574 const auto params = event.params<hci_spec::CommandStatusEventParams>();
575 EXPECT_EQ(pw::bluetooth::emboss::StatusCode::SUCCESS, params.status);
576 EXPECT_EQ(hci_spec::kReset, params.command_opcode);
577 } else {
578 EXPECT_EQ(kTestEventCode0, event.event_code());
579 }
580 };
581
582 auto packet =
583 hci::EmbossCommandPacket::New<pw::bluetooth::emboss::ResetCommandWriter>(
584 hci_spec::kReset);
585 id = cmd_channel()->SendCommand(std::move(packet), cb, kTestEventCode0);
586
587 RunUntilIdle();
588
589 ASSERT_NE(0u, id);
590 ASSERT_EQ(0u, transaction_count);
591
592 // This returns invalid because an async command is registered.
593 auto invalid_id = cmd_channel()->AddEventHandler(
594 kTestEventCode0,
595 [](const EventPacket&) { return EventCallbackResult::kContinue; });
596
597 RunUntilIdle();
598
599 ASSERT_EQ(0u, invalid_id);
600
601 // Commands become available and the whole transaction finishes.
602 test_device()->SendCommandChannelPacket(rsp_commandsavail);
603
604 RunUntilIdle();
605
606 ASSERT_EQ(1u, transaction_count);
607 ASSERT_EQ(2u, cb_count);
608 }
609
610 // Tests:
611 // - Events are routed to the event handler.
612 // - Can't queue a command on the same event that is already in an event
613 // handler.
TEST_F(CommandChannelTest,EventHandlerBasic)614 TEST_F(CommandChannelTest, EventHandlerBasic) {
615 constexpr hci_spec::EventCode kTestEventCode0 = 0xFD;
616 constexpr hci_spec::EventCode kTestEventCode1 = 0xFE;
617 StaticByteBuffer cmd_status(
618 hci_spec::kCommandStatusEventCode, 0x04, 0x00, 0x01, 0x00, 0x00);
619 auto cmd_complete = StaticByteBuffer(
620 hci_spec::kCommandCompleteEventCode, 0x03, 0x01, 0x00, 0x00);
621 auto event0 = StaticByteBuffer(kTestEventCode0, 0x00);
622 auto event1 = StaticByteBuffer(kTestEventCode1, 0x00);
623
624 int event_count0 = 0;
625 auto event_cb0 = [&event_count0, kTestEventCode0](const EventPacket& event) {
626 event_count0++;
627 EXPECT_EQ(kTestEventCode0, event.event_code());
628 return EventCallbackResult::kContinue;
629 };
630
631 int event_count1 = 0;
632 auto event_cb1 = [&event_count1, kTestEventCode0](const EventPacket& event) {
633 event_count1++;
634 EXPECT_EQ(kTestEventCode0, event.event_code());
635 return EventCallbackResult::kContinue;
636 };
637
638 int event_count2 = 0;
639 auto event_cb2 = [&event_count2, kTestEventCode1](const EventPacket& event) {
640 event_count2++;
641 EXPECT_EQ(kTestEventCode1, event.event_code());
642 return EventCallbackResult::kContinue;
643 };
644 auto id0 = cmd_channel()->AddEventHandler(kTestEventCode0, event_cb0);
645 EXPECT_NE(0u, id0);
646
647 // Can register a handler for the same event code more than once.
648 auto id1 = cmd_channel()->AddEventHandler(kTestEventCode0, event_cb1);
649 EXPECT_NE(0u, id1);
650 EXPECT_NE(id0, id1);
651
652 // Add a handler for a different event code.
653 auto id2 = cmd_channel()->AddEventHandler(kTestEventCode1, event_cb2);
654 EXPECT_NE(0u, id2);
655
656 auto reset =
657 hci::EmbossCommandPacket::New<pw::bluetooth::emboss::ResetCommandWriter>(
658 hci_spec::kReset);
659 auto transaction_id = cmd_channel()->SendCommand(
660 std::move(reset), [](auto, const auto&) {}, kTestEventCode0);
661
662 EXPECT_EQ(0u, transaction_id);
663
664 test_device()->SendCommandChannelPacket(cmd_status);
665 test_device()->SendCommandChannelPacket(cmd_complete);
666 test_device()->SendCommandChannelPacket(event1);
667 test_device()->SendCommandChannelPacket(event0);
668 test_device()->SendCommandChannelPacket(cmd_complete);
669 test_device()->SendCommandChannelPacket(event0);
670 test_device()->SendCommandChannelPacket(event0);
671 test_device()->SendCommandChannelPacket(cmd_status);
672 test_device()->SendCommandChannelPacket(event1);
673
674 RunUntilIdle();
675
676 EXPECT_EQ(3, event_count0);
677 EXPECT_EQ(3, event_count1);
678 EXPECT_EQ(2, event_count2);
679
680 event_count0 = 0;
681 event_count1 = 0;
682 event_count2 = 0;
683
684 // Remove the first event handler.
685 cmd_channel()->RemoveEventHandler(id0);
686 test_device()->SendCommandChannelPacket(event0);
687 test_device()->SendCommandChannelPacket(event0);
688 test_device()->SendCommandChannelPacket(event0);
689 test_device()->SendCommandChannelPacket(event1);
690 test_device()->SendCommandChannelPacket(event0);
691 test_device()->SendCommandChannelPacket(event0);
692 test_device()->SendCommandChannelPacket(event0);
693 test_device()->SendCommandChannelPacket(event0);
694 test_device()->SendCommandChannelPacket(event1);
695
696 RunUntilIdle();
697
698 EXPECT_EQ(0, event_count0);
699 EXPECT_EQ(7, event_count1);
700 EXPECT_EQ(2, event_count2);
701
702 event_count0 = 0;
703 event_count1 = 0;
704 event_count2 = 0;
705
706 // Remove the second event handler.
707 cmd_channel()->RemoveEventHandler(id1);
708 test_device()->SendCommandChannelPacket(event0);
709 test_device()->SendCommandChannelPacket(event0);
710 test_device()->SendCommandChannelPacket(event1);
711 test_device()->SendCommandChannelPacket(event0);
712 test_device()->SendCommandChannelPacket(event1);
713 test_device()->SendCommandChannelPacket(event1);
714
715 RunUntilIdle();
716
717 EXPECT_EQ(0, event_count0);
718 EXPECT_EQ(0, event_count1);
719 EXPECT_EQ(3, event_count2);
720 }
721
722 // Tests:
723 // - can't send a command that masks an event handler.
724 // - can send a command without a callback.
TEST_F(CommandChannelTest,EventHandlerEventWhileTransactionPending)725 TEST_F(CommandChannelTest, EventHandlerEventWhileTransactionPending) {
726 // clang-format off
727 // HCI_Reset
728 auto req = StaticByteBuffer(
729 LowerBits(hci_spec::kReset), UpperBits(hci_spec::kReset), // HCI_Reset opcode
730 0x00 // parameter_total_size
731 );
732
733 auto req_complete = StaticByteBuffer(
734 hci_spec::kCommandCompleteEventCode,
735 0x03, // parameter_total_size (3 byte payload)
736 0x01, // num_hci_command_packets (1 can be sent)
737 LowerBits(hci_spec::kReset), UpperBits(hci_spec::kReset) // HCI_Reset opcode
738 );
739 // clang-format on
740
741 constexpr hci_spec::EventCode kTestEventCode = 0xFE;
742 auto event = StaticByteBuffer(kTestEventCode, 0x01, 0x00);
743
744 // We will send the HCI_Reset command with kTestEventCode as the completion
745 // event. The event handler we register below should only get invoked once and
746 // after the pending transaction completes.
747 EXPECT_CMD_PACKET_OUT(test_device(), req, &req_complete, &event, &event);
748
749 int event_count = 0;
750 auto event_cb = [&event_count, kTestEventCode](const EventPacket& event) {
751 event_count++;
752 EXPECT_EQ(kTestEventCode, event.event_code());
753 EXPECT_EQ(1u, event.view().header().parameter_total_size);
754 EXPECT_EQ(1u, event.view().payload_size());
755 return EventCallbackResult::kContinue;
756 };
757
758 cmd_channel()->AddEventHandler(kTestEventCode, event_cb);
759
760 auto reset =
761 hci::EmbossCommandPacket::New<pw::bluetooth::emboss::ResetCommandWriter>(
762 hci_spec::kReset);
763 CommandChannel::TransactionId id =
764 cmd_channel()->SendCommand(std::move(reset), nullptr, kTestEventCode);
765 EXPECT_EQ(0u, id);
766
767 reset =
768 hci::EmbossCommandPacket::New<pw::bluetooth::emboss::ResetCommandWriter>(
769 hci_spec::kReset);
770 id = cmd_channel()->SendCommand(std::move(reset), nullptr);
771 EXPECT_NE(0u, id);
772
773 RunUntilIdle();
774
775 EXPECT_EQ(2, event_count);
776 }
777
778 // Tests:
779 // - Calling RemoveQueuedCommand on a synchronous command that has already been
780 // sent to the
781 // controller returns false.
782 // - The command still completes and notifies the callback.
TEST_F(CommandChannelTest,RemoveQueuedSyncCommandPendingStatus)783 TEST_F(CommandChannelTest, RemoveQueuedSyncCommandPendingStatus) {
784 auto req_reset =
785 StaticByteBuffer(LowerBits(hci_spec::kReset),
786 UpperBits(hci_spec::kReset), // HCI_Reset opcode
787 0x00 // parameter_total_size
788 );
789 auto rsp_reset =
790 StaticByteBuffer(hci_spec::kCommandCompleteEventCode,
791 0x03, // parameter_total_size (3 byte payload)
792 0xFF, // num_hci_command_packets (255 can be sent)
793 LowerBits(hci_spec::kReset),
794 UpperBits(hci_spec::kReset) // HCI_Reset opcode
795 );
796 EXPECT_CMD_PACKET_OUT(test_device(), req_reset, );
797
798 int transaction_count = 0u;
799 test_device()->SetTransactionCallback(
800 [&transaction_count]() { transaction_count++; });
801
802 auto cmd =
803 hci::EmbossCommandPacket::New<pw::bluetooth::emboss::ResetCommandWriter>(
804 hci_spec::kReset);
805 int cmd_cb_count = 0;
806 auto cmd_cb = [&cmd_cb_count](auto, auto&) { cmd_cb_count++; };
807 auto cmd_id = cmd_channel()->SendCommand(std::move(cmd), std::move(cmd_cb));
808 EXPECT_NE(0u, cmd_id);
809
810 RunUntilIdle();
811
812 EXPECT_EQ(1, transaction_count);
813 EXPECT_FALSE(cmd_channel()->RemoveQueuedCommand(cmd_id));
814 test_device()->SendCommandChannelPacket(rsp_reset);
815
816 RunUntilIdle();
817
818 EXPECT_EQ(1, transaction_count);
819 EXPECT_EQ(1, cmd_cb_count);
820 }
821
822 // Tests:
823 // - Remove a synchronous command that is queued up behind another command with
824 // the same opcode.
825 // - The first command (after removal) does not receive the update event for
826 // the second command.
TEST_F(CommandChannelTest,RemoveQueuedQueuedSyncCommand)827 TEST_F(CommandChannelTest, RemoveQueuedQueuedSyncCommand) {
828 using namespace std::placeholders;
829 auto req_reset =
830 StaticByteBuffer(LowerBits(hci_spec::kReset),
831 UpperBits(hci_spec::kReset), // HCI_Reset opcode
832 0x00 // parameter_total_size
833 );
834 auto rsp_reset =
835 StaticByteBuffer(hci_spec::kCommandCompleteEventCode,
836 0x03, // parameter_total_size (4 byte payload)
837 0xFF, // num_hci_command_packets (255 can be sent)
838 LowerBits(hci_spec::kReset),
839 UpperBits(hci_spec::kReset) // HCI_Reset opcode
840 );
841 EXPECT_CMD_PACKET_OUT(test_device(), req_reset, );
842
843 int transaction_count = 0u;
844 test_device()->SetTransactionCallback(
845 [&transaction_count]() { transaction_count++; });
846
847 auto event_cb = [](CommandChannel::TransactionId id,
848 const EventPacket& event,
849 int* event_count) {
850 EXPECT_EQ(hci_spec::kCommandCompleteEventCode, event.event_code());
851 (*event_count)++;
852 };
853
854 // Send two reset commands so that the second one is queued up.
855 auto reset =
856 hci::EmbossCommandPacket::New<pw::bluetooth::emboss::ResetCommandWriter>(
857 hci_spec::kReset);
858 int event_count0 = 0;
859 auto id0 = cmd_channel()->SendCommand(
860 std::move(reset), std::bind(event_cb, _1, _2, &event_count0));
861 EXPECT_NE(0u, id0);
862 reset =
863 hci::EmbossCommandPacket::New<pw::bluetooth::emboss::ResetCommandWriter>(
864 hci_spec::kReset);
865 int event_count1 = 0;
866 auto id1 = cmd_channel()->SendCommand(
867 std::move(reset), std::bind(event_cb, _1, _2, &event_count1));
868 EXPECT_NE(0u, id1);
869
870 RunUntilIdle();
871
872 EXPECT_EQ(1, transaction_count);
873 EXPECT_TRUE(cmd_channel()->RemoveQueuedCommand(id1));
874
875 RunUntilIdle();
876
877 EXPECT_EQ(0, event_count0);
878 test_device()->SendCommandChannelPacket(rsp_reset);
879
880 RunUntilIdle();
881
882 // Only one command should have been sent.
883 EXPECT_EQ(1, transaction_count);
884 // The queued (then canceled) command should never have gotten an event.
885 EXPECT_EQ(0, event_count1);
886 // The sent command should have gotten one event (CommandComplete).
887 EXPECT_EQ(1, event_count0);
888 }
889
890 // Read Remote Supported Features
891 const StaticByteBuffer kReadRemoteSupportedFeaturesCmd(
892 LowerBits(hci_spec::kReadRemoteSupportedFeatures),
893 UpperBits(hci_spec::kReadRemoteSupportedFeatures),
894 0x02, // parameter_total_size
895 0x01,
896 0x00 // connection_handle
897 );
898
899 // Command Status for Read Remote Supported Features
900 const auto kReadRemoteSupportedFeaturesRsp = StaticByteBuffer(
901 hci_spec::kCommandStatusEventCode,
902 0x04, // parameter_total_size (4 byte payload)
903 pw::bluetooth::emboss::StatusCode::SUCCESS, // status
904 0xFF, // num_hci_command_packets
905 LowerBits(hci_spec::kReadRemoteSupportedFeatures),
906 UpperBits(hci_spec::kReadRemoteSupportedFeatures) // opcode
907 );
908
909 // Read Remote Supported Features Complete
910 const auto kReadRemoteSupportedFeaturesComplete = StaticByteBuffer(
911 hci_spec::kReadRemoteSupportedFeaturesCompleteEventCode,
912 0x0B, // parameter_total_size (11 bytes)
913 pw::bluetooth::emboss::StatusCode::SUCCESS, // status
914 0x01,
915 0x00, // connection_handle
916 0xFF,
917 0x00,
918 0x00,
919 0x00,
920 0x02,
921 0x00,
922 0x00,
923 0x80 // lmp_features
924 // Set: 3 slot packets, 5 slot packets, Encryption, Timing Accuracy,
925 // Role Switch, Hold Mode, Sniff Mode, LE Supported, Extended Features
926 );
927
928 // Tests:
929 // - Remove an asynchronous command that is queued up behind another command
930 // with the same opcode.
931 // - The first command (after removal) does not receive the update event for
932 // the second command.
TEST_F(CommandChannelTest,RemoveQueuedQueuedAsyncCommand)933 TEST_F(CommandChannelTest, RemoveQueuedQueuedAsyncCommand) {
934 using namespace std::placeholders;
935 EXPECT_CMD_PACKET_OUT(test_device(), kReadRemoteSupportedFeaturesCmd, );
936
937 int transaction_count = 0u;
938 test_device()->SetTransactionCallback(
939 [&transaction_count]() { transaction_count++; });
940
941 auto event_cb = [](CommandChannel::TransactionId id,
942 const EventPacket& event,
943 int* event_count) { (*event_count)++; };
944
945 // Send two read commands so that the second one is queued up.
946 auto packet = MakeReadRemoteSupportedFeatures(0x0001);
947 int event_count0 = 0;
948 auto id0 = cmd_channel()->SendCommand(
949 std::move(packet),
950 std::bind(event_cb, _1, _2, &event_count0),
951 hci_spec::kReadRemoteSupportedFeaturesCompleteEventCode);
952 EXPECT_NE(0u, id0);
953 packet = MakeReadRemoteSupportedFeatures(0x0001);
954 int event_count1 = 0;
955 auto id1 = cmd_channel()->SendCommand(
956 std::move(packet),
957 std::bind(event_cb, _1, _2, &event_count1),
958 hci_spec::kReadRemoteSupportedFeaturesCompleteEventCode);
959 EXPECT_NE(0u, id1);
960
961 RunUntilIdle();
962
963 EXPECT_EQ(1, transaction_count);
964 EXPECT_TRUE(cmd_channel()->RemoveQueuedCommand(id1));
965
966 RunUntilIdle();
967
968 EXPECT_EQ(0, event_count0);
969 test_device()->SendCommandChannelPacket(kReadRemoteSupportedFeaturesRsp);
970 test_device()->SendCommandChannelPacket(kReadRemoteSupportedFeaturesComplete);
971
972 RunUntilIdle();
973
974 // Only one command should have been sent.
975 EXPECT_EQ(1, transaction_count);
976 // The queued (then canceled) command should never have gotten an event.
977 EXPECT_EQ(0, event_count1);
978 // The sent command should have gotten two events (Command Status, Read Remote
979 // Supported Features Complete).
980 EXPECT_EQ(2, event_count0);
981 }
982
983 // Tests:
984 // - Calling RemoveQueuedCommand on an asynchronous command that has received
985 // both Command Status
986 // and command completion events returns false and has no effect.
TEST_F(CommandChannelTest,RemoveQueuedCompletedAsyncCommand)987 TEST_F(CommandChannelTest, RemoveQueuedCompletedAsyncCommand) {
988 EXPECT_CMD_PACKET_OUT(test_device(),
989 kReadRemoteSupportedFeaturesCmd,
990 &kReadRemoteSupportedFeaturesRsp,
991 &kReadRemoteSupportedFeaturesComplete);
992
993 int transaction_count = 0;
994 test_device()->SetTransactionCallback(
995 [&transaction_count] { transaction_count++; });
996
997 int event_count = 0;
998 auto event_cb = [&event_count](CommandChannel::TransactionId id,
999 const EventPacket& event) { event_count++; };
1000
1001 auto packet = MakeReadRemoteSupportedFeatures(0x0001);
1002 auto id = cmd_channel()->SendCommand(
1003 std::move(packet),
1004 std::move(event_cb),
1005 hci_spec::kReadRemoteSupportedFeaturesCompleteEventCode);
1006 EXPECT_NE(0u, id);
1007
1008 RunUntilIdle();
1009
1010 EXPECT_EQ(2, event_count);
1011 EXPECT_FALSE(cmd_channel()->RemoveQueuedCommand(id));
1012
1013 RunUntilIdle();
1014
1015 // Only one command should have been sent.
1016 EXPECT_EQ(1, transaction_count);
1017 // The sent command should have received CommandStatus and InquiryComplete.
1018 EXPECT_EQ(2, event_count);
1019 }
1020
1021 // Tests:
1022 // - Calling RemoveQueuedCommand on an asynchronous command that has already
1023 // been sent to the
1024 // controller returns false.
1025 // - The command still notifies the callback for update and completion events.
TEST_F(CommandChannelTest,RemoveQueuedAsyncCommandPendingUpdate)1026 TEST_F(CommandChannelTest, RemoveQueuedAsyncCommandPendingUpdate) {
1027 EXPECT_CMD_PACKET_OUT(test_device(), kReadRemoteSupportedFeaturesCmd, );
1028
1029 int transaction_count = 0;
1030 test_device()->SetTransactionCallback(
1031 [&transaction_count] { transaction_count++; });
1032
1033 CommandChannel::TransactionId cmd_id;
1034 int cmd_events = 0;
1035 auto cmd_cb = [&cmd_id, &cmd_events](CommandChannel::TransactionId id,
1036 const EventPacket& event) {
1037 EXPECT_EQ(cmd_id, id);
1038 if (cmd_events == 0) {
1039 EXPECT_EQ(hci_spec::kCommandStatusEventCode, event.event_code());
1040 }
1041 cmd_events++;
1042 };
1043
1044 auto cmd_packet = MakeReadRemoteSupportedFeatures(0x0001);
1045 cmd_id = cmd_channel()->SendCommand(
1046 std::move(cmd_packet),
1047 std::move(cmd_cb),
1048 hci_spec::kReadRemoteSupportedFeaturesCompleteEventCode);
1049 EXPECT_NE(0u, cmd_id);
1050
1051 RunUntilIdle();
1052
1053 EXPECT_EQ(0, cmd_events);
1054 EXPECT_FALSE(cmd_channel()->RemoveQueuedCommand(cmd_id));
1055
1056 RunUntilIdle();
1057
1058 test_device()->SendCommandChannelPacket(kReadRemoteSupportedFeaturesRsp);
1059 test_device()->SendCommandChannelPacket(kReadRemoteSupportedFeaturesComplete);
1060
1061 RunUntilIdle();
1062
1063 EXPECT_EQ(1, transaction_count);
1064 // The command should have gotten update and complete events.
1065 EXPECT_EQ(2, cmd_events);
1066 }
1067
1068 // Tests:
1069 // - Calling RemoveQueuedCommand on an asynchronous command that has already
1070 // been sent to the
1071 // controller and gotten Command Status returns false.
1072 // - The command still notifies the callback for completion event.
TEST_F(CommandChannelTest,RemoveQueuedAsyncCommandPendingCompletion)1073 TEST_F(CommandChannelTest, RemoveQueuedAsyncCommandPendingCompletion) {
1074 EXPECT_CMD_PACKET_OUT(test_device(),
1075 kReadRemoteSupportedFeaturesCmd,
1076 &kReadRemoteSupportedFeaturesRsp);
1077
1078 int transaction_count = 0;
1079 test_device()->SetTransactionCallback(
1080 [&transaction_count] { transaction_count++; });
1081
1082 CommandChannel::TransactionId cmd_id;
1083 int cmd_events = 0;
1084 auto cmd_cb = [&cmd_id, &cmd_events](CommandChannel::TransactionId id,
1085 const EventPacket& event) {
1086 EXPECT_EQ(cmd_id, id);
1087 if (cmd_events == 0) {
1088 EXPECT_EQ(hci_spec::kCommandStatusEventCode, event.event_code());
1089 }
1090 cmd_events++;
1091 };
1092
1093 auto cmd_packet = MakeReadRemoteSupportedFeatures(0x0001);
1094 cmd_id = cmd_channel()->SendCommand(
1095 std::move(cmd_packet),
1096 std::move(cmd_cb),
1097 hci_spec::kReadRemoteSupportedFeaturesCompleteEventCode);
1098 EXPECT_NE(0u, cmd_id);
1099
1100 RunUntilIdle();
1101
1102 EXPECT_EQ(1, cmd_events);
1103 EXPECT_FALSE(cmd_channel()->RemoveQueuedCommand(cmd_id));
1104
1105 RunUntilIdle();
1106
1107 test_device()->SendCommandChannelPacket(kReadRemoteSupportedFeaturesComplete);
1108
1109 RunUntilIdle();
1110
1111 EXPECT_EQ(1, transaction_count);
1112 // The command should have gotten update and complete events.
1113 EXPECT_EQ(2, cmd_events);
1114 }
1115
TEST_F(CommandChannelTest,VendorEventHandler)1116 TEST_F(CommandChannelTest, VendorEventHandler) {
1117 constexpr hci_spec::EventCode kTestSubeventCode0 = 0x10;
1118 constexpr hci_spec::EventCode kTestSubeventCode1 = 0x12;
1119 StaticByteBuffer vendor_event_bytes0(
1120 hci_spec::kVendorDebugEventCode, 0x01, kTestSubeventCode0);
1121 auto vendor_event_bytes1 = StaticByteBuffer(
1122 hci_spec::kVendorDebugEventCode, 0x01, kTestSubeventCode1);
1123
1124 int event_count0 = 0;
1125 auto event_cb0 = [&event_count0,
1126 kTestSubeventCode0](const EmbossEventPacket& event) {
1127 event_count0++;
1128 EXPECT_EQ(hci_spec::kVendorDebugEventCode, event.event_code());
1129 EXPECT_EQ(kTestSubeventCode0,
1130 event.view<pw::bluetooth::emboss::VendorDebugEventView>()
1131 .subevent_code()
1132 .Read());
1133 return EventCallbackResult::kContinue;
1134 };
1135
1136 int event_count1 = 0;
1137 auto event_cb1 = [&event_count1,
1138 kTestSubeventCode1](const EmbossEventPacket& event) {
1139 event_count1++;
1140 EXPECT_EQ(hci_spec::kVendorDebugEventCode, event.event_code());
1141 EXPECT_EQ(kTestSubeventCode1,
1142 event.view<pw::bluetooth::emboss::VendorDebugEventView>()
1143 .subevent_code()
1144 .Read());
1145 return EventCallbackResult::kContinue;
1146 };
1147
1148 auto id0 =
1149 cmd_channel()->AddVendorEventHandler(kTestSubeventCode0, event_cb0);
1150 EXPECT_NE(0u, id0);
1151
1152 // Can register a handler for the same event code more than once.
1153 auto id1 =
1154 cmd_channel()->AddVendorEventHandler(kTestSubeventCode0, event_cb0);
1155 EXPECT_NE(0u, id1);
1156 EXPECT_NE(id0, id1);
1157
1158 // Add a handler for a different event code.
1159 auto id2 =
1160 cmd_channel()->AddVendorEventHandler(kTestSubeventCode1, event_cb1);
1161 EXPECT_NE(0u, id2);
1162
1163 test_device()->SendCommandChannelPacket(vendor_event_bytes0);
1164 RunUntilIdle();
1165 EXPECT_EQ(2, event_count0);
1166 EXPECT_EQ(0, event_count1);
1167
1168 test_device()->SendCommandChannelPacket(vendor_event_bytes0);
1169 RunUntilIdle();
1170 EXPECT_EQ(4, event_count0);
1171 EXPECT_EQ(0, event_count1);
1172
1173 test_device()->SendCommandChannelPacket(vendor_event_bytes1);
1174 RunUntilIdle();
1175 EXPECT_EQ(4, event_count0);
1176 EXPECT_EQ(1, event_count1);
1177
1178 // Remove the first event handler.
1179 cmd_channel()->RemoveEventHandler(id0);
1180 test_device()->SendCommandChannelPacket(vendor_event_bytes0);
1181 test_device()->SendCommandChannelPacket(vendor_event_bytes1);
1182 RunUntilIdle();
1183 EXPECT_EQ(5, event_count0);
1184 EXPECT_EQ(2, event_count1);
1185 }
1186
TEST_F(CommandChannelTest,LEMetaEventHandler)1187 TEST_F(CommandChannelTest, LEMetaEventHandler) {
1188 constexpr hci_spec::EventCode kTestSubeventCode0 = 0xFE;
1189 constexpr hci_spec::EventCode kTestSubeventCode1 = 0xFF;
1190 auto le_meta_event_bytes0 =
1191 StaticByteBuffer(hci_spec::kLEMetaEventCode, 0x01, kTestSubeventCode0);
1192 auto le_meta_event_bytes1 =
1193 StaticByteBuffer(hci_spec::kLEMetaEventCode, 0x01, kTestSubeventCode1);
1194
1195 int event_count0 = 0;
1196 auto event_cb0 = [&event_count0,
1197 kTestSubeventCode0](const EventPacket& event) {
1198 event_count0++;
1199 EXPECT_EQ(hci_spec::kLEMetaEventCode, event.event_code());
1200 EXPECT_EQ(kTestSubeventCode0,
1201 event.params<hci_spec::LEMetaEventParams>().subevent_code);
1202 return EventCallbackResult::kContinue;
1203 };
1204
1205 int event_count1 = 0;
1206 auto event_cb1 = [&event_count1,
1207 kTestSubeventCode1](const EventPacket& event) {
1208 event_count1++;
1209 EXPECT_EQ(hci_spec::kLEMetaEventCode, event.event_code());
1210 EXPECT_EQ(kTestSubeventCode1,
1211 event.params<hci_spec::LEMetaEventParams>().subevent_code);
1212 return EventCallbackResult::kContinue;
1213 };
1214
1215 auto id0 =
1216 cmd_channel()->AddLEMetaEventHandler(kTestSubeventCode0, event_cb0);
1217 EXPECT_NE(0u, id0);
1218
1219 // Can register a handler for the same event code more than once.
1220 auto id1 =
1221 cmd_channel()->AddLEMetaEventHandler(kTestSubeventCode0, event_cb0);
1222 EXPECT_NE(0u, id1);
1223 EXPECT_NE(id0, id1);
1224
1225 // Add a handler for a different event code.
1226 auto id2 =
1227 cmd_channel()->AddLEMetaEventHandler(kTestSubeventCode1, event_cb1);
1228 EXPECT_NE(0u, id2);
1229
1230 test_device()->SendCommandChannelPacket(le_meta_event_bytes0);
1231 RunUntilIdle();
1232 EXPECT_EQ(2, event_count0);
1233 EXPECT_EQ(0, event_count1);
1234
1235 test_device()->SendCommandChannelPacket(le_meta_event_bytes0);
1236 RunUntilIdle();
1237 EXPECT_EQ(4, event_count0);
1238 EXPECT_EQ(0, event_count1);
1239
1240 test_device()->SendCommandChannelPacket(le_meta_event_bytes1);
1241 RunUntilIdle();
1242 EXPECT_EQ(4, event_count0);
1243 EXPECT_EQ(1, event_count1);
1244
1245 // Remove the first event handler.
1246 cmd_channel()->RemoveEventHandler(id0);
1247 test_device()->SendCommandChannelPacket(le_meta_event_bytes0);
1248 test_device()->SendCommandChannelPacket(le_meta_event_bytes1);
1249 RunUntilIdle();
1250 EXPECT_EQ(5, event_count0);
1251 EXPECT_EQ(2, event_count1);
1252 }
1253
TEST_F(CommandChannelTest,EventHandlerIdsDontCollide)1254 TEST_F(CommandChannelTest, EventHandlerIdsDontCollide) {
1255 // Add a LE Meta event handler and a event handler and make sure that IDs are
1256 // generated correctly across the two methods.
1257 EXPECT_EQ(1u,
1258 cmd_channel()->AddLEMetaEventHandler(
1259 hci_spec::kLEConnectionCompleteSubeventCode,
1260 [](const EmbossEventPacket&) {
1261 return EventCallbackResult::kContinue;
1262 }));
1263 EXPECT_EQ(
1264 2u,
1265 cmd_channel()->AddEventHandler(
1266 hci_spec::kDisconnectionCompleteEventCode,
1267 [](const EventPacket&) { return EventCallbackResult::kContinue; }));
1268 }
1269
1270 // Tests:
1271 // - Can't register an event handler for CommandStatus or CommandComplete
TEST_F(CommandChannelTest,EventHandlerRestrictions)1272 TEST_F(CommandChannelTest, EventHandlerRestrictions) {
1273 auto id0 = cmd_channel()->AddEventHandler(
1274 hci_spec::kCommandStatusEventCode,
1275 [](const EventPacket&) { return EventCallbackResult::kContinue; });
1276 EXPECT_EQ(0u, id0);
1277 id0 = cmd_channel()->AddEventHandler(
1278 hci_spec::kCommandCompleteEventCode,
1279 [](const EventPacket&) { return EventCallbackResult::kContinue; });
1280 EXPECT_EQ(0u, id0);
1281 }
1282
1283 // Tests that an asynchronous command with a completion event code does not
1284 // remove an existing handler for colliding LE meta subevent code.
TEST_F(CommandChannelTest,AsyncEventHandlersAndLeMetaEventHandlersDoNotInterfere)1285 TEST_F(CommandChannelTest,
1286 AsyncEventHandlersAndLeMetaEventHandlersDoNotInterfere) {
1287 // Set up expectations for the asynchronous command and its corresponding
1288 // command status event.
1289 // clang-format off
1290 auto cmd = StaticByteBuffer(
1291 LowerBits(hci_spec::kInquiry), UpperBits(hci_spec::kInquiry), // HCI_Inquiry opcode
1292 0x00 // parameter_total_size
1293 );
1294 auto cmd_status = StaticByteBuffer(
1295 hci_spec::kCommandStatusEventCode,
1296 0x04, // parameter_total_size (4 byte payload)
1297 pw::bluetooth::emboss::StatusCode::SUCCESS, 0x01, // status, num_hci_command_packets (1 can be sent)
1298 LowerBits(hci_spec::kInquiry), UpperBits(hci_spec::kInquiry) // HCI_Inquiry opcode
1299 );
1300 // clang-format on
1301
1302 EXPECT_CMD_PACKET_OUT(test_device(), cmd, &cmd_status);
1303
1304 constexpr hci_spec::EventCode kTestEventCode = 0x01;
1305
1306 // Add LE event handler for kTestEventCode
1307 int le_event_count = 0;
1308 auto le_event_cb = [&](const EventPacket& event) {
1309 EXPECT_EQ(hci_spec::kLEMetaEventCode, event.event_code());
1310 EXPECT_EQ(kTestEventCode,
1311 event.params<hci_spec::LEMetaEventParams>().subevent_code);
1312 le_event_count++;
1313 return EventCallbackResult::kContinue;
1314 };
1315 cmd_channel()->AddLEMetaEventHandler(
1316 hci_spec::kLEConnectionCompleteSubeventCode, std::move(le_event_cb));
1317
1318 // Initiate the async transaction with kTestEventCode as its completion code
1319 // (we use hci_spec::kInquiry as a test opcode).
1320 int async_cmd_cb_count = 0;
1321 auto async_cmd_cb = [&](auto id, const EventPacket& event) {
1322 if (async_cmd_cb_count == 0) {
1323 EXPECT_EQ(hci_spec::kCommandStatusEventCode, event.event_code());
1324 } else {
1325 EXPECT_EQ(kTestEventCode, event.event_code());
1326 }
1327 async_cmd_cb_count++;
1328 };
1329
1330 auto packet =
1331 EmbossCommandPacket::New<pw::bluetooth::emboss::InquiryCommandView>(
1332 hci_spec::kInquiry,
1333 pw::bluetooth::emboss::CommandHeader::IntrinsicSizeInBytes());
1334 cmd_channel()->SendCommand(
1335 std::move(packet), std::move(async_cmd_cb), kTestEventCode);
1336
1337 // clang-format off
1338 auto event_bytes = StaticByteBuffer(
1339 kTestEventCode,
1340 0x01, // parameter_total_size
1341 pw::bluetooth::emboss::StatusCode::SUCCESS);
1342 auto le_event_bytes = StaticByteBuffer(
1343 hci_spec::kLEMetaEventCode,
1344 0x01, // parameter_total_size
1345 kTestEventCode);
1346 // clang-format on
1347
1348 // Send a spurious LE event before processing the Command Status event. This
1349 // should get routed to the correct event handler.
1350 test_device()->SendCommandChannelPacket(le_event_bytes);
1351
1352 // Process the async command expectation.
1353 RunUntilIdle();
1354
1355 // End the asynchronous transaction. This should NOT unregister the LE event
1356 // handler.
1357 test_device()->SendCommandChannelPacket(event_bytes);
1358
1359 // Send more LE events. These should get routed to the LE event handler.
1360 test_device()->SendCommandChannelPacket(le_event_bytes);
1361 test_device()->SendCommandChannelPacket(le_event_bytes);
1362
1363 RunUntilIdle();
1364
1365 // Should have received 3 LE events.
1366 EXPECT_EQ(3, le_event_count);
1367
1368 // The async command handler should have been called twice: once for Command
1369 // Status and once for the completion event.
1370 EXPECT_EQ(2, async_cmd_cb_count);
1371 }
1372
TEST_F(CommandChannelTest,TransportClosedCallback)1373 TEST_F(CommandChannelTest, TransportClosedCallback) {
1374 bool error_cb_called = false;
1375 auto error_cb = [&error_cb_called] { error_cb_called = true; };
1376 transport()->SetTransportErrorCallback(error_cb);
1377
1378 (void)heap_dispatcher().Post(
1379 [this](pw::async::Context /*ctx*/, pw::Status status) {
1380 if (status.ok()) {
1381 test_device()->Stop();
1382 }
1383 });
1384 RunUntilIdle();
1385 EXPECT_TRUE(error_cb_called);
1386 }
1387
TEST_F(CommandChannelTest,CommandTimeoutCallback)1388 TEST_F(CommandChannelTest, CommandTimeoutCallback) {
1389 auto req_reset =
1390 StaticByteBuffer(LowerBits(hci_spec::kReset),
1391 UpperBits(hci_spec::kReset), // HCI_Reset opcode
1392 0x00 // parameter_total_size
1393 );
1394
1395 // Expect the HCI_Reset command but dont send a reply back to make the command
1396 // time out.
1397 EXPECT_CMD_PACKET_OUT(test_device(), req_reset, );
1398
1399 size_t timeout_cb_count = 0;
1400 auto timeout_cb = [&] { timeout_cb_count++; };
1401 cmd_channel()->set_channel_timeout_cb(timeout_cb);
1402
1403 size_t cmd_cb_count = 0;
1404 auto cb = [&](auto, auto&) { cmd_cb_count++; };
1405
1406 auto packet =
1407 hci::EmbossCommandPacket::New<pw::bluetooth::emboss::ResetCommandWriter>(
1408 hci_spec::kReset);
1409 CommandChannel::TransactionId id1 =
1410 cmd_channel()->SendCommand(std::move(packet), cb);
1411 ASSERT_NE(0u, id1);
1412
1413 packet =
1414 hci::EmbossCommandPacket::New<pw::bluetooth::emboss::ResetCommandWriter>(
1415 hci_spec::kReset);
1416 CommandChannel::TransactionId id2 =
1417 cmd_channel()->SendCommand(std::move(packet), cb);
1418 ASSERT_NE(0u, id2);
1419
1420 // Run the loop until the command timeout task gets scheduled.
1421 RunUntilIdle();
1422 EXPECT_EQ(0u, timeout_cb_count);
1423 EXPECT_EQ(0u, cmd_cb_count);
1424
1425 RunFor(kCommandTimeout);
1426
1427 EXPECT_EQ(1u, timeout_cb_count);
1428 EXPECT_EQ(0u, cmd_cb_count);
1429
1430 DeleteTransport();
1431 EXPECT_EQ(0u, cmd_cb_count);
1432 }
1433
TEST_F(CommandChannelTest,DestroyChannelInTimeoutCallback)1434 TEST_F(CommandChannelTest, DestroyChannelInTimeoutCallback) {
1435 auto req_reset =
1436 StaticByteBuffer(LowerBits(hci_spec::kReset),
1437 UpperBits(hci_spec::kReset), // HCI_Reset opcode
1438 0x00 // parameter_total_size
1439 );
1440
1441 // Expect the HCI_Reset command but dont send a reply back to make the command
1442 // time out.
1443 EXPECT_CMD_PACKET_OUT(test_device(), req_reset, );
1444
1445 size_t timeout_cb_count = 0;
1446 auto timeout_cb = [&] {
1447 timeout_cb_count++;
1448 DeleteTransport();
1449 };
1450 cmd_channel()->set_channel_timeout_cb(timeout_cb);
1451
1452 size_t cmd_cb_count = 0;
1453 auto cb = [&](auto, auto&) { cmd_cb_count++; };
1454
1455 auto packet =
1456 hci::EmbossCommandPacket::New<pw::bluetooth::emboss::ResetCommandWriter>(
1457 hci_spec::kReset);
1458 CommandChannel::TransactionId id1 =
1459 cmd_channel()->SendCommand(std::move(packet), cb);
1460 ASSERT_NE(0u, id1);
1461
1462 packet =
1463 hci::EmbossCommandPacket::New<pw::bluetooth::emboss::ResetCommandWriter>(
1464 hci_spec::kReset);
1465 CommandChannel::TransactionId id2 =
1466 cmd_channel()->SendCommand(std::move(packet), cb);
1467 ASSERT_NE(0u, id2);
1468
1469 RunFor(kCommandTimeout);
1470 EXPECT_EQ(1u, timeout_cb_count);
1471 }
1472
TEST_F(CommandChannelTest,CommandsAndEventsIgnoredAfterCommandTimeout)1473 TEST_F(CommandChannelTest, CommandsAndEventsIgnoredAfterCommandTimeout) {
1474 size_t timeout_cb_count = 0;
1475 auto timeout_cb = [&] { timeout_cb_count++; };
1476 cmd_channel()->set_channel_timeout_cb(timeout_cb);
1477
1478 size_t cmd_cb_count = 0;
1479 auto cb = [&](auto, auto&) { cmd_cb_count++; };
1480
1481 // Expect the HCI_Reset command but dont send a reply back to make the command
1482 // time out.
1483 auto req_reset =
1484 StaticByteBuffer(LowerBits(hci_spec::kReset),
1485 UpperBits(hci_spec::kReset), // HCI_Reset opcode
1486 0x00 // parameter_total_size
1487 );
1488 EXPECT_CMD_PACKET_OUT(test_device(), req_reset);
1489 auto packet =
1490 hci::EmbossCommandPacket::New<pw::bluetooth::emboss::ResetCommandWriter>(
1491 hci_spec::kReset);
1492 CommandChannel::TransactionId id1 =
1493 cmd_channel()->SendCommand(std::move(packet), cb);
1494 ASSERT_NE(0u, id1);
1495
1496 // Run the loop until the command timeout task gets scheduled.
1497 RunUntilIdle();
1498 EXPECT_EQ(0u, timeout_cb_count);
1499 RunFor(kCommandTimeout);
1500 EXPECT_EQ(1u, timeout_cb_count);
1501 EXPECT_EQ(0u, cmd_cb_count);
1502
1503 // Additional commands should be ignored.
1504 packet =
1505 hci::EmbossCommandPacket::New<pw::bluetooth::emboss::ResetCommandWriter>(
1506 hci_spec::kReset);
1507 CommandChannel::TransactionId id2 =
1508 cmd_channel()->SendCommand(std::move(packet), cb);
1509 EXPECT_EQ(0u, id2);
1510 // No command should be sent.
1511 RunUntilIdle();
1512
1513 // Events should be ignored.
1514 test_device()->SendCommandChannelPacket(bt::testing::CommandCompletePacket(
1515 hci_spec::kReset, pw::bluetooth::emboss::StatusCode::SUCCESS));
1516 RunUntilIdle();
1517 EXPECT_EQ(0u, cmd_cb_count);
1518 }
1519
1520 // Tests:
1521 // - Asynchronous commands should be able to schedule another asynchronous
1522 // command in their callback.
TEST_F(CommandChannelTest,AsynchronousCommandChaining)1523 TEST_F(CommandChannelTest, AsynchronousCommandChaining) {
1524 constexpr size_t kExpectedCallbacksPerCommand = 2;
1525 constexpr hci_spec::EventCode kTestEventCode0 = 0xFE;
1526 // Set up expectations
1527 // clang-format off
1528 // Using HCI_Reset for testing.
1529 auto req_reset = StaticByteBuffer(
1530 LowerBits(hci_spec::kReset), UpperBits(hci_spec::kReset), // HCI_Reset opcode
1531 0x00 // parameter_total_size (no payload)
1532 );
1533 auto rsp_resetstatus = StaticByteBuffer(
1534 hci_spec::kCommandStatusEventCode,
1535 0x04, // parameter_total_size (4 byte payload)
1536 pw::bluetooth::emboss::StatusCode::SUCCESS, 0xFA, // status, num_hci_command_packets (250)
1537 LowerBits(hci_spec::kReset), UpperBits(hci_spec::kReset) // HCI_Reset opcode
1538 );
1539 auto req_inqcancel = StaticByteBuffer(
1540 LowerBits(hci_spec::kInquiryCancel), UpperBits(hci_spec::kInquiryCancel), // HCI_InquiryCancel
1541 0x00 // parameter_total_size (no payload)
1542 );
1543 auto rsp_inqstatus = StaticByteBuffer(
1544 hci_spec::kCommandStatusEventCode,
1545 0x04, // parameter_total_size (4 byte payload)
1546 pw::bluetooth::emboss::StatusCode::SUCCESS, 0xFA, // status, num_hci_command_packets (250)
1547 LowerBits(hci_spec::kInquiryCancel), UpperBits(hci_spec::kInquiryCancel) // HCI_InquiryCanacel
1548 );
1549 auto rsp_bogocomplete = StaticByteBuffer(
1550 kTestEventCode0,
1551 0x00 // parameter_total_size (no payload)
1552 );
1553 // clang-format on
1554
1555 EXPECT_CMD_PACKET_OUT(test_device(), req_reset, &rsp_resetstatus);
1556 EXPECT_CMD_PACKET_OUT(test_device(), req_reset, &rsp_resetstatus);
1557
1558 CommandChannel::TransactionId id1, id2;
1559 CommandChannel::CommandCallback cb;
1560 size_t cb_count = 0u;
1561
1562 cb = [&cb,
1563 cmd_channel = cmd_channel(),
1564 &id1,
1565 &id2,
1566 &cb_count,
1567 kTestEventCode0](CommandChannel::TransactionId callback_id,
1568 const EventPacket& event) {
1569 if (cb_count < kExpectedCallbacksPerCommand) {
1570 EXPECT_EQ(id1, callback_id);
1571 } else {
1572 EXPECT_EQ(id2, callback_id);
1573 }
1574 if ((cb_count % 2) == 0) {
1575 // First event from each command - CommandStatus
1576 EXPECT_EQ(hci_spec::kCommandStatusEventCode, event.event_code());
1577 auto params = event.params<hci_spec::CommandStatusEventParams>();
1578 EXPECT_EQ(pw::bluetooth::emboss::StatusCode::SUCCESS, params.status);
1579 } else {
1580 // Second event from each command - completion event
1581 EXPECT_EQ(kTestEventCode0, event.event_code());
1582 if (cb_count < 2) {
1583 // Add the second command when the first one completes.
1584 auto packet = hci::EmbossCommandPacket::New<
1585 pw::bluetooth::emboss::ResetCommandWriter>(hci_spec::kReset);
1586 id2 = cmd_channel->SendCommand(
1587 std::move(packet), cb.share(), kTestEventCode0);
1588 }
1589 }
1590 cb_count++;
1591 };
1592
1593 auto packet =
1594 hci::EmbossCommandPacket::New<pw::bluetooth::emboss::ResetCommandWriter>(
1595 hci_spec::kReset);
1596 id1 = cmd_channel()->SendCommand(
1597 std::move(packet), cb.share(), kTestEventCode0);
1598
1599 RunUntilIdle();
1600
1601 // Should have received the Status but not the result.
1602 EXPECT_EQ(1u, cb_count);
1603
1604 // Sending the complete will finish the command and add the next command.
1605 test_device()->SendCommandChannelPacket(rsp_bogocomplete);
1606 RunUntilIdle();
1607
1608 EXPECT_EQ(3u, cb_count);
1609
1610 // Finish out the command.
1611 test_device()->SendCommandChannelPacket(rsp_bogocomplete);
1612 RunUntilIdle();
1613
1614 EXPECT_EQ(4u, cb_count);
1615 }
1616
1617 // Tests:
1618 // - Commands that are exclusive of other commands cannot run together, and
1619 // instead wait until the exclusive commands finish.
1620 // - Exclusive Commands in the queue still get started in order
1621 // - Commands that aren't exclusive run as normal even when an exclusive one is
1622 // waiting.
TEST_F(CommandChannelTest,ExclusiveCommands)1623 TEST_F(CommandChannelTest, ExclusiveCommands) {
1624 constexpr hci_spec::EventCode kExclOneCompleteEvent = 0xFE;
1625 constexpr hci_spec::EventCode kExclTwoCompleteEvent = 0xFD;
1626 constexpr hci_spec::OpCode kExclusiveOne = hci_spec::DefineOpCode(0x01, 0x01);
1627 constexpr hci_spec::OpCode kExclusiveTwo = hci_spec::DefineOpCode(0x01, 0x02);
1628 constexpr hci_spec::OpCode kNonExclusive = hci_spec::DefineOpCode(0x01, 0x03);
1629
1630 // Set up expectations
1631 // - kExclusiveOne can't run at the same time as kExclusiveTwo, and
1632 // vice-versa.
1633 // - kExclusiveOne finishes with kExclOneCompleteEvent
1634 // - kExclusiveTwo finishes with kExclTwoCompleteEvent
1635 // - kNonExclusive can run whenever it wants.
1636 // - For testing, we omit the payloads of all commands.
1637 auto excl_one_cmd = StaticByteBuffer(
1638 LowerBits(kExclusiveOne), UpperBits(kExclusiveOne), 0x00 // (no payload)
1639 );
1640 auto rsp_excl_one_status =
1641 StaticByteBuffer(hci_spec::kCommandStatusEventCode,
1642 0x04, // parameter_total_size (4 byte payload)
1643 pw::bluetooth::emboss::StatusCode::SUCCESS,
1644 0xFA, // status, num_hci_command_packets (250)
1645 LowerBits(kExclusiveOne),
1646 UpperBits(kExclusiveOne) // HCI opcode
1647 );
1648 auto rsp_one_complete = StaticByteBuffer(
1649 kExclOneCompleteEvent, 0x00 // parameter_total_size (no payload)
1650 );
1651
1652 auto excl_two_cmd = StaticByteBuffer(
1653 LowerBits(kExclusiveTwo), UpperBits(kExclusiveTwo), 0x00 // (no payload)
1654 );
1655 auto rsp_excl_two_status =
1656 StaticByteBuffer(hci_spec::kCommandStatusEventCode,
1657 0x04, // parameter_total_size (4 byte payload)
1658 pw::bluetooth::emboss::StatusCode::SUCCESS,
1659 0xFA, // status, num_hci_command_packets (250)
1660 LowerBits(kExclusiveTwo),
1661 UpperBits(kExclusiveTwo) // HCI opcode
1662 );
1663 auto rsp_two_complete = StaticByteBuffer(
1664 kExclTwoCompleteEvent, 0x00 // parameter_total_size (no payload)
1665 );
1666
1667 auto nonexclusive_cmd =
1668 StaticByteBuffer(LowerBits(kNonExclusive),
1669 UpperBits(kNonExclusive), // HCI opcode
1670 0x00 // parameter_total_size (no payload)
1671 );
1672 auto nonexclusive_complete = StaticByteBuffer(
1673 hci_spec::kCommandCompleteEventCode,
1674 0x04, // parameter_total_size (4 byte payload)
1675 0xFA, // num_hci_command_packets (250)
1676 LowerBits(kNonExclusive),
1677 UpperBits(kNonExclusive), // HCI opcode
1678 pw::bluetooth::emboss::StatusCode::SUCCESS // Command succeeded
1679 );
1680
1681 CommandChannel::TransactionId id1, id2, id3;
1682 CommandChannel::CommandCallback exclusive_cb;
1683 size_t exclusive_cb_count = 0u;
1684
1685 size_t nonexclusive_cb_count = 0;
1686 CommandChannel::CommandCallback nonexclusive_cb =
1687 [&nonexclusive_cb_count](auto callback_id, const EventPacket& event) {
1688 EXPECT_EQ(hci_spec::kCommandCompleteEventCode, event.event_code());
1689 nonexclusive_cb_count++;
1690 };
1691
1692 exclusive_cb = [&exclusive_cb,
1693 &nonexclusive_cb,
1694 cmd_channel = cmd_channel(),
1695 &id1,
1696 &id2,
1697 &id3,
1698 &exclusive_cb_count,
1699 kExclOneCompleteEvent,
1700 kExclTwoCompleteEvent](
1701 CommandChannel::TransactionId callback_id,
1702 const EventPacket& event) {
1703 // Expected event -> Action in response
1704 // 0. Status for kExclusiveOne -> Send a kExclusiveTwo
1705 // 1. Complete for kExclusiveOne -> Send Another kExclusiveOne and
1706 // kNonExclusive
1707 // 2. Status for kExclusiveTwo -> Nothing
1708 // 3. Complete for kExclusiveTwo -> Nothing
1709 // 4. Status for kExclusiveOne -> Nothing
1710 // 5. Complete for kExclusiveOne -> Nothing
1711 switch (exclusive_cb_count) {
1712 case 0: {
1713 // Status for kExclusiveOne -> Send kExclusiveTwo (queued)
1714 EXPECT_EQ(id1, callback_id);
1715 EXPECT_EQ(hci_spec::kCommandStatusEventCode, event.event_code());
1716 auto params = event.params<hci_spec::CommandStatusEventParams>();
1717 EXPECT_EQ(pw::bluetooth::emboss::StatusCode::SUCCESS, params.status);
1718 auto packet = CommandPacket::New(kExclusiveTwo);
1719 id2 = cmd_channel->SendExclusiveCommand(std::move(packet),
1720 exclusive_cb.share(),
1721 kExclTwoCompleteEvent,
1722 {kExclusiveOne});
1723 std::cout << "queued Exclusive Two: " << id2 << std::endl;
1724 break;
1725 }
1726 case 1: {
1727 // Complete for kExclusiveOne -> Resend kExclusiveOne
1728 EXPECT_EQ(id1, callback_id);
1729 EXPECT_EQ(kExclOneCompleteEvent, event.event_code());
1730 // Add the second command when the first one completes.
1731 auto packet = CommandPacket::New(kExclusiveOne);
1732 id3 = cmd_channel->SendExclusiveCommand(std::move(packet),
1733 exclusive_cb.share(),
1734 kExclOneCompleteEvent,
1735 {kExclusiveTwo});
1736 std::cout << "queued Second Exclusive One: " << id3 << std::endl;
1737 packet = CommandPacket::New(kNonExclusive);
1738 cmd_channel->SendCommand(std::move(packet), nonexclusive_cb.share());
1739
1740 break;
1741 }
1742 case 2: { // Status for kExclusiveTwo
1743 EXPECT_EQ(id2, callback_id);
1744 EXPECT_EQ(hci_spec::kCommandStatusEventCode, event.event_code());
1745 auto params = event.params<hci_spec::CommandStatusEventParams>();
1746 EXPECT_EQ(pw::bluetooth::emboss::StatusCode::SUCCESS, params.status);
1747 break;
1748 }
1749 case 3: { // Complete for kExclusiveTwo
1750 EXPECT_EQ(id2, callback_id);
1751 EXPECT_EQ(kExclTwoCompleteEvent, event.event_code());
1752 break;
1753 }
1754 case 4: { // Status for Second kExclusiveOne
1755 EXPECT_EQ(id3, callback_id);
1756 EXPECT_EQ(hci_spec::kCommandStatusEventCode, event.event_code());
1757 auto params = event.params<hci_spec::CommandStatusEventParams>();
1758 EXPECT_EQ(pw::bluetooth::emboss::StatusCode::SUCCESS, params.status);
1759 break;
1760 }
1761 case 5: { // Complete for Second kExclusiveOne
1762 EXPECT_EQ(id3, callback_id);
1763 EXPECT_EQ(kExclOneCompleteEvent, event.event_code());
1764 break;
1765 }
1766 default: {
1767 ASSERT_TRUE(false); // Should never be called more than 6 times.
1768 break;
1769 }
1770 }
1771 exclusive_cb_count++;
1772 };
1773
1774 EXPECT_CMD_PACKET_OUT(test_device(), excl_one_cmd, &rsp_excl_one_status);
1775 EXPECT_CMD_PACKET_OUT(
1776 test_device(), nonexclusive_cmd, &nonexclusive_complete);
1777 id1 = cmd_channel()->SendExclusiveCommand(CommandPacket::New(kExclusiveOne),
1778 exclusive_cb.share(),
1779 kExclOneCompleteEvent,
1780 {kExclusiveTwo});
1781 cmd_channel()->SendCommand(CommandPacket::New(kNonExclusive),
1782 nonexclusive_cb.share());
1783 RunUntilIdle();
1784 // Should have received the ExclusiveOne status but not the complete.
1785 // ExclusiveTwo should be queued.
1786 EXPECT_EQ(1u, exclusive_cb_count);
1787 // NonExclusive should be completed.
1788 EXPECT_EQ(1u, nonexclusive_cb_count);
1789
1790 // Sending the ExclusiveOne complete will send the ExclusiveTwo command, queue
1791 // another ExclusiveOne command, and send a NonExclusive command.
1792 EXPECT_CMD_PACKET_OUT(test_device(), excl_two_cmd, &rsp_excl_two_status);
1793 EXPECT_CMD_PACKET_OUT(
1794 test_device(), nonexclusive_cmd, &nonexclusive_complete);
1795 test_device()->SendCommandChannelPacket(rsp_one_complete);
1796 RunUntilIdle();
1797 EXPECT_EQ(3u,
1798 exclusive_cb_count); // +2: rsp_one_complete, rsp_excl_two_status
1799 EXPECT_EQ(2u, nonexclusive_cb_count); // +1: nonexclusive_complete
1800
1801 // Complete ExclusiveTwo and send a NonExclusive. The queued ExclusiveOne
1802 // should be sent.
1803 EXPECT_CMD_PACKET_OUT(
1804 test_device(), nonexclusive_cmd, &nonexclusive_complete);
1805 EXPECT_CMD_PACKET_OUT(test_device(), excl_one_cmd, &rsp_excl_one_status);
1806 test_device()->SendCommandChannelPacket(rsp_two_complete);
1807 cmd_channel()->SendCommand(CommandPacket::New(kNonExclusive),
1808 nonexclusive_cb.share());
1809 RunUntilIdle();
1810 EXPECT_EQ(5u,
1811 exclusive_cb_count); // +2: rsp_two_complete, rsp_excl_one_status
1812 EXPECT_EQ(3u, nonexclusive_cb_count); // +1: nonexclusive_complete
1813
1814 // Finish the second ExclusiveOne
1815 test_device()->SendCommandChannelPacket(rsp_one_complete);
1816 RunUntilIdle();
1817 EXPECT_EQ(6u, exclusive_cb_count); // +1: rsp_one_complete
1818 EXPECT_EQ(3u, nonexclusive_cb_count);
1819 }
1820
TEST_F(CommandChannelTest,SendCommandFailsIfEventHandlerInstalled)1821 TEST_F(CommandChannelTest, SendCommandFailsIfEventHandlerInstalled) {
1822 constexpr hci_spec::EventCode kTestEventCode0 = 0xFE;
1823
1824 // Register event handler for kTestEventCode0.
1825 auto id0 = cmd_channel()->AddEventHandler(
1826 kTestEventCode0,
1827 [](const EventPacket& event) { return EventCallbackResult::kContinue; });
1828 EXPECT_NE(0u, id0);
1829
1830 // Try to send a command for kTestEventCode0. SendCommand should fail for a
1831 // code already registered with "AddEventHandler".
1832 auto reset =
1833 hci::EmbossCommandPacket::New<pw::bluetooth::emboss::ResetCommandWriter>(
1834 hci_spec::kReset);
1835 auto transaction_id = cmd_channel()->SendCommand(
1836 std::move(reset), [](auto, const auto&) {}, kTestEventCode0);
1837 EXPECT_EQ(0u, transaction_id);
1838 }
1839
TEST_F(CommandChannelTest,EventHandlerResults)1840 TEST_F(CommandChannelTest, EventHandlerResults) {
1841 constexpr hci_spec::EventCode kTestEventCode0 = 0xFE;
1842
1843 int event_count = 0;
1844 auto event_cb = [&event_count, kTestEventCode0](const EventPacket& event) {
1845 event_count++;
1846 EXPECT_EQ(kTestEventCode0, event.event_code());
1847
1848 if (event_count == 1) {
1849 return EventCallbackResult::kContinue;
1850 }
1851
1852 return EventCallbackResult::kRemove;
1853 };
1854
1855 EXPECT_NE(cmd_channel()->AddEventHandler(kTestEventCode0, event_cb), 0u);
1856
1857 // Send three requests, and process the callbacks immediately. The second
1858 // callback returns "remove" before the third event callback has been called.
1859 auto event0 = StaticByteBuffer(kTestEventCode0, 0x00);
1860 test_device()->SendCommandChannelPacket(event0);
1861 test_device()->SendCommandChannelPacket(event0);
1862 test_device()->SendCommandChannelPacket(event0);
1863 RunUntilIdle();
1864 EXPECT_EQ(2, event_count);
1865 }
1866
TEST_F(CommandChannelTest,SendCommandWithLEMetaEventSubeventRsp)1867 TEST_F(CommandChannelTest, SendCommandWithLEMetaEventSubeventRsp) {
1868 constexpr hci_spec::OpCode kOpCode = hci_spec::kLEReadRemoteFeatures;
1869 constexpr hci_spec::EventCode kSubeventCode =
1870 hci_spec::kLEReadRemoteFeaturesCompleteSubeventCode;
1871
1872 auto cmd = StaticByteBuffer(LowerBits(kOpCode),
1873 UpperBits(kOpCode),
1874 // parameter total size (0 byte payload)
1875 0x00);
1876
1877 auto cmd_status_event =
1878 StaticByteBuffer(hci_spec::kCommandStatusEventCode,
1879 // parameter total size (4 byte payload)
1880 0x04,
1881 // status, num_hci_command_packets (250)
1882 pw::bluetooth::emboss::StatusCode::SUCCESS,
1883 0xFA,
1884 // HCI opcode
1885 LowerBits(kOpCode),
1886 UpperBits(kOpCode));
1887 auto cmd_complete_subevent =
1888 StaticByteBuffer(hci_spec::kLEMetaEventCode,
1889 0x01, // parameter total size (1 byte payload)
1890 kSubeventCode);
1891
1892 EXPECT_CMD_PACKET_OUT(test_device(), cmd, &cmd_status_event);
1893
1894 auto cmd_packet = CommandPacket::New(kOpCode);
1895
1896 size_t event_count = 0;
1897 auto event_cb = [&event_count](auto, const EventPacket& event) {
1898 switch (event_count) {
1899 case 0: {
1900 EXPECT_EQ(hci_spec::kCommandStatusEventCode, event.event_code());
1901 break;
1902 }
1903 case 1: {
1904 EXPECT_EQ(hci_spec::kLEMetaEventCode, event.event_code());
1905 break;
1906 }
1907 default: {
1908 FAIL();
1909 }
1910 }
1911 event_count++;
1912 };
1913 auto id = cmd_channel()->SendLeAsyncCommand(
1914 std::move(cmd_packet), std::move(event_cb), kSubeventCode);
1915 EXPECT_NE(0u, id);
1916
1917 RunUntilIdle();
1918 EXPECT_EQ(1u, event_count);
1919
1920 // Handler should be removed when subevent received.
1921 test_device()->SendCommandChannelPacket(cmd_complete_subevent);
1922 RunUntilIdle();
1923 EXPECT_EQ(2u, event_count);
1924
1925 // This seconod complete event should be ignored because the handler should
1926 // have been removed.
1927 test_device()->SendCommandChannelPacket(cmd_complete_subevent);
1928 RunUntilIdle();
1929 EXPECT_EQ(2u, event_count);
1930 }
1931
TEST_F(CommandChannelTest,SendingLECommandAfterAddingLEMetaEventHandlerFailsForSameSubeventCodeAndSucceedsForDifferentSubeventCode)1932 TEST_F(
1933 CommandChannelTest,
1934 SendingLECommandAfterAddingLEMetaEventHandlerFailsForSameSubeventCodeAndSucceedsForDifferentSubeventCode) {
1935 constexpr hci_spec::EventCode kSubeventCode =
1936 hci_spec::kLEReadRemoteFeaturesCompleteSubeventCode;
1937 constexpr hci_spec::OpCode kOpCode =
1938 hci_spec::kLEReadRemoteFeatures; // LE Read Remote Features
1939
1940 EXPECT_NE(0u,
1941 cmd_channel()->AddLEMetaEventHandler(
1942 kSubeventCode, [](const EmbossEventPacket&) {
1943 return EventCallbackResult::kContinue;
1944 }));
1945 EXPECT_EQ(0u,
1946 cmd_channel()->SendLeAsyncCommand(
1947 CommandPacket::New(kOpCode),
1948 [](auto, const auto&) {},
1949 kSubeventCode));
1950
1951 auto cmd = StaticByteBuffer(LowerBits(kOpCode),
1952 UpperBits(kOpCode),
1953 // parameter total size (0 byte payload)
1954 0x00);
1955 EXPECT_CMD_PACKET_OUT(test_device(), std::move(cmd), );
1956 EXPECT_NE(0u,
1957 cmd_channel()->SendLeAsyncCommand(
1958 CommandPacket::New(kOpCode),
1959 [](auto, const auto&) {},
1960 kSubeventCode + 1));
1961 RunUntilIdle();
1962 }
1963
TEST_F(CommandChannelTest,SendingSecondLECommandWithSameSubeventShouldWaitForFirstToComplete)1964 TEST_F(CommandChannelTest,
1965 SendingSecondLECommandWithSameSubeventShouldWaitForFirstToComplete) {
1966 // Commands have different op codes but same subevent code so that second
1967 // command is not blocked because of matching op codes (which would not test
1968 // LE command handling).
1969 constexpr hci_spec::OpCode kOpCode0 = hci_spec::kLEReadRemoteFeatures;
1970 constexpr hci_spec::OpCode kOpCode1 = hci_spec::kLEReadBufferSizeV1;
1971 constexpr hci_spec::EventCode kSubeventCode =
1972 hci_spec::kLEReadRemoteFeaturesCompleteSubeventCode;
1973
1974 auto cmd0 = StaticByteBuffer(LowerBits(kOpCode0),
1975 UpperBits(kOpCode0),
1976 // parameter total size (0 byte payload)
1977 0x00);
1978 auto cmd0_status_event =
1979 StaticByteBuffer(hci_spec::kCommandStatusEventCode,
1980 // parameter total size (4 byte payload)
1981 0x04,
1982 // status, num_hci_command_packets (250)
1983 pw::bluetooth::emboss::StatusCode::SUCCESS,
1984 0xFA,
1985 // HCI opcode
1986 LowerBits(kOpCode0),
1987 UpperBits(kOpCode0));
1988 auto cmd1 = StaticByteBuffer(LowerBits(kOpCode1),
1989 UpperBits(kOpCode1),
1990 // parameter total size (0 byte payload)
1991 0x00);
1992 auto cmd1_status_event =
1993 StaticByteBuffer(hci_spec::kCommandStatusEventCode,
1994 // parameter total size (4 byte payload)
1995 0x04,
1996 // status, num_hci_command_packets (250)
1997 pw::bluetooth::emboss::StatusCode::SUCCESS,
1998 0xFA,
1999 // HCI opcode
2000 LowerBits(kOpCode1),
2001 UpperBits(kOpCode1));
2002
2003 auto cmd_complete_subevent =
2004 StaticByteBuffer(hci_spec::kLEMetaEventCode,
2005 0x01, // parameter total size (1 byte payload)
2006 kSubeventCode);
2007
2008 EXPECT_CMD_PACKET_OUT(test_device(), cmd0, &cmd0_status_event);
2009
2010 size_t event_count_0 = 0;
2011 auto event_cb_0 = [&event_count_0](auto, const EventPacket& event) {
2012 switch (event_count_0) {
2013 case 0: {
2014 EXPECT_EQ(hci_spec::kCommandStatusEventCode, event.event_code());
2015 break;
2016 }
2017 case 1: {
2018 EXPECT_EQ(hci_spec::kLEMetaEventCode, event.event_code());
2019 break;
2020 }
2021 default: {
2022 FAIL();
2023 }
2024 }
2025 event_count_0++;
2026 };
2027 auto id_0 = cmd_channel()->SendLeAsyncCommand(
2028 CommandPacket::New(kOpCode0), std::move(event_cb_0), kSubeventCode);
2029 EXPECT_NE(0u, id_0);
2030
2031 RunUntilIdle();
2032 EXPECT_EQ(1u, event_count_0);
2033
2034 size_t event_count_1 = 0;
2035 auto event_cb_1 = [&event_count_1](auto, const EventPacket& event) {
2036 switch (event_count_1) {
2037 case 0: {
2038 EXPECT_EQ(hci_spec::kCommandStatusEventCode, event.event_code());
2039 break;
2040 }
2041 case 1: {
2042 EXPECT_EQ(hci_spec::kLEMetaEventCode, event.event_code());
2043 break;
2044 }
2045 default: {
2046 FAIL();
2047 }
2048 }
2049 event_count_1++;
2050 };
2051 // Command should be queued and not sent until after first complete event
2052 // received.
2053 auto id_1 = cmd_channel()->SendLeAsyncCommand(
2054 CommandPacket::New(kOpCode1), std::move(event_cb_1), kSubeventCode);
2055 EXPECT_NE(0u, id_1);
2056 RunUntilIdle();
2057 EXPECT_EQ(0u, event_count_1);
2058
2059 // When first command complete event is received, second command should be
2060 // sent.
2061 EXPECT_CMD_PACKET_OUT(test_device(), cmd1, &cmd1_status_event);
2062 test_device()->SendCommandChannelPacket(cmd_complete_subevent);
2063 RunUntilIdle();
2064 EXPECT_EQ(2u, event_count_0);
2065 EXPECT_EQ(1u, event_count_1);
2066
2067 // Second complete event should be received by second command event handler
2068 // only.
2069 test_device()->SendCommandChannelPacket(cmd_complete_subevent);
2070 RunUntilIdle();
2071 EXPECT_EQ(2u, event_count_0);
2072 EXPECT_EQ(2u, event_count_1);
2073 }
2074
TEST_F(CommandChannelTest,RegisteringLEMetaEventHandlerWhileLECommandPendingFailsForSameSubeventAndSucceedsForDifferentSubevent)2075 TEST_F(
2076 CommandChannelTest,
2077 RegisteringLEMetaEventHandlerWhileLECommandPendingFailsForSameSubeventAndSucceedsForDifferentSubevent) {
2078 constexpr hci_spec::OpCode kOpCode = hci_spec::kLEReadRemoteFeatures;
2079 constexpr hci_spec::EventCode kSubeventCode =
2080 hci_spec::kLEReadRemoteFeaturesCompleteSubeventCode;
2081
2082 auto cmd = StaticByteBuffer(LowerBits(kOpCode),
2083 UpperBits(kOpCode),
2084 // parameter total size (0 byte payload)
2085 0x00);
2086
2087 auto cmd_status_event =
2088 StaticByteBuffer(hci_spec::kCommandStatusEventCode,
2089 // parameter total size (4 byte payload)
2090 0x04,
2091 // status, num_hci_command_packets (250)
2092 pw::bluetooth::emboss::StatusCode::SUCCESS,
2093 0xFA,
2094 // HCI opcode
2095 LowerBits(kOpCode),
2096 UpperBits(kOpCode));
2097
2098 EXPECT_CMD_PACKET_OUT(test_device(), cmd, &cmd_status_event);
2099
2100 size_t event_count = 0;
2101 auto event_cb = [&event_count](auto, const EventPacket& event) {
2102 EXPECT_EQ(hci_spec::kCommandStatusEventCode, event.event_code());
2103 event_count++;
2104 };
2105 auto id = cmd_channel()->SendLeAsyncCommand(
2106 CommandPacket::New(kOpCode), std::move(event_cb), kSubeventCode);
2107 EXPECT_NE(0u, id);
2108 RunUntilIdle();
2109 EXPECT_EQ(1u, event_count);
2110
2111 // Async LE command for subevent is already pending, so registering event
2112 // handler should fail by returning 0.
2113 id = cmd_channel()->AddLEMetaEventHandler(
2114 kSubeventCode,
2115 [](const EmbossEventPacket&) { return EventCallbackResult::kContinue; });
2116 EXPECT_EQ(0u, id);
2117
2118 // Registering event handler for different subevent code should succeed.
2119 id = cmd_channel()->AddLEMetaEventHandler(
2120 kSubeventCode + 1,
2121 [](const EmbossEventPacket&) { return EventCallbackResult::kContinue; });
2122 EXPECT_NE(0u, id);
2123 }
2124
2125 #ifndef NINSPECT
TEST_F(CommandChannelTest,InspectHierarchy)2126 TEST_F(CommandChannelTest, InspectHierarchy) {
2127 cmd_channel()->AttachInspect(inspector_.GetRoot(), "command_channel");
2128
2129 auto command_channel_matcher = AllOf(NodeMatches(AllOf(
2130 NameMatches("command_channel"),
2131 PropertyList(UnorderedElementsAre(UintIs("allowed_command_packets", 1),
2132 UintIs("next_event_handler_id", 1),
2133 UintIs("next_transaction_id", 1))))));
2134
2135 EXPECT_THAT(inspect::ReadFromVmo(inspector_.DuplicateVmo()).value(),
2136 ChildrenMatch(ElementsAre(command_channel_matcher)));
2137 }
2138 #endif // NINSPECT
2139
2140 } // namespace
2141 } // namespace bt::hci
2142