• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/hci/command_handler.h"
16 
17 #include <pw_bluetooth/hci_common.emb.h>
18 #include <pw_bluetooth/hci_test.emb.h>
19 
20 #include "pw_bluetooth_sapphire/internal/host/common/error.h"
21 #include "pw_bluetooth_sapphire/internal/host/testing/controller_test.h"
22 #include "pw_bluetooth_sapphire/internal/host/testing/mock_controller.h"
23 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
24 #include "pw_bluetooth_sapphire/internal/host/testing/test_packets.h"
25 
26 namespace bt::hci {
27 
28 namespace {
29 
30 constexpr hci_spec::OpCode kOpCode(hci_spec::kInquiry);
31 constexpr uint8_t kTestEventParam = 3u;
32 
33 template <bool DecodeSucceeds>
34 struct TestEvent {
35   uint8_t test_param;
Decodebt::hci::__anon28f14fde0111::TestEvent36   static fit::result<bt::Error<>, TestEvent> Decode(const EventPacket& packet) {
37     if (!DecodeSucceeds) {
38       return fit::error(bt::Error(HostError::kPacketMalformed));
39     }
40 
41     return fit::ok(TestEvent{.test_param = kTestEventParam});
42   }
43 
44   static constexpr hci_spec::EventCode kEventCode =
45       hci_spec::kInquiryCompleteEventCode;
46 };
47 using DecodableEvent = TestEvent<true>;
48 using UndecodableEvent = TestEvent<false>;
49 
MakeTestEventPacket(pw::bluetooth::emboss::StatusCode status=pw::bluetooth::emboss::StatusCode::SUCCESS)50 DynamicByteBuffer MakeTestEventPacket(
51     pw::bluetooth::emboss::StatusCode status =
52         pw::bluetooth::emboss::StatusCode::SUCCESS) {
53   return DynamicByteBuffer(StaticByteBuffer(DecodableEvent::kEventCode,
54                                             0x01,  // parameters_total_size
55                                             status));
56 }
57 
58 template <bool DecodeSucceeds>
59 struct TestCommandCompleteEvent {
60   uint8_t test_param;
61 
Decodebt::hci::__anon28f14fde0111::TestCommandCompleteEvent62   static fit::result<bt::Error<>, TestCommandCompleteEvent> Decode(
63       const EventPacket& packet) {
64     if (!DecodeSucceeds) {
65       return fit::error(bt::Error(HostError::kPacketMalformed));
66     }
67 
68     return fit::ok(TestCommandCompleteEvent{.test_param = kTestEventParam});
69   }
70 
71   static constexpr hci_spec::EventCode kEventCode =
72       hci_spec::kCommandCompleteEventCode;
73 };
74 using DecodableCommandCompleteEvent = TestCommandCompleteEvent<true>;
75 using UndecodableCommandCompleteEvent = TestCommandCompleteEvent<false>;
76 
77 constexpr uint8_t kEncodedTestCommandParam = 2u;
78 
79 template <typename CompleteEventT>
80 struct TestCommand {
81   uint8_t test_param;
82 
Encodebt::hci::__anon28f14fde0111::TestCommand83   EmbossCommandPacket Encode() {
84     auto packet = EmbossCommandPacket::New<
85         pw::bluetooth::emboss::TestCommandPacketWriter>(kOpCode);
86     packet.view_t().payload().Write(kEncodedTestCommandParam);
87     return packet;
88   }
89 
opcodebt::hci::__anon28f14fde0111::TestCommand90   static hci_spec::OpCode opcode() { return kOpCode; }
91 
92   using EventT = CompleteEventT;
93 };
94 
95 const TestCommand<DecodableEvent> kTestCommandWithAsyncEvent{.test_param = 1u};
96 const TestCommand<DecodableCommandCompleteEvent>
97     kTestCommandWithCommandCompleteEvent{.test_param = 1u};
98 const TestCommand<UndecodableCommandCompleteEvent>
99     kTestCommandWithUndecodableCommandCompleteEvent{.test_param = 1u};
100 
101 const StaticByteBuffer kTestCommandPacket(LowerBits(kOpCode),
102                                           UpperBits(kOpCode),
103                                           0x01,  // param length
104                                           kEncodedTestCommandParam);
105 
106 using TestingBase =
107     bt::testing::FakeDispatcherControllerTest<bt::testing::MockController>;
108 class CommandHandlerTest : public TestingBase {
109  public:
SetUp()110   void SetUp() override {
111     TestingBase::SetUp();
112 
113     handler_.emplace(cmd_channel()->AsWeakPtr());
114   }
115 
handler()116   CommandHandler& handler() { return handler_.value(); }
117 
118  private:
119   std::optional<CommandHandler> handler_;
120 };
121 
TEST_F(CommandHandlerTest,SuccessfulSendCommandWithSyncEvent)122 TEST_F(CommandHandlerTest, SuccessfulSendCommandWithSyncEvent) {
123   const auto kEventPacket = bt::testing::CommandCompletePacket(
124       kOpCode, pw::bluetooth::emboss::StatusCode::SUCCESS);
125   EXPECT_CMD_PACKET_OUT(test_device(), kTestCommandPacket, &kEventPacket);
126 
127   std::optional<DecodableCommandCompleteEvent> event;
128   handler().SendCommand(kTestCommandWithCommandCompleteEvent,
129                         [&event](auto result) {
130                           ASSERT_EQ(fit::ok(), result);
131                           event = result.value();
132                         });
133 
134   RunUntilIdle();
135   ASSERT_TRUE(event.has_value());
136   EXPECT_EQ(event->test_param, kTestEventParam);
137 }
138 
TEST_F(CommandHandlerTest,SendCommandReceiveFailEvent)139 TEST_F(CommandHandlerTest, SendCommandReceiveFailEvent) {
140   const auto kEventPacket = bt::testing::CommandCompletePacket(
141       kOpCode, pw::bluetooth::emboss::StatusCode::COMMAND_DISALLOWED);
142   EXPECT_CMD_PACKET_OUT(test_device(), kTestCommandPacket, &kEventPacket);
143 
144   std::optional<hci::Error> error;
145   handler().SendCommand(kTestCommandWithCommandCompleteEvent,
146                         [&error](auto result) {
147                           ASSERT_TRUE(result.is_error());
148                           error = std::move(result).error_value();
149                         });
150 
151   RunUntilIdle();
152   ASSERT_TRUE(error.has_value());
153   EXPECT_TRUE(error->is(pw::bluetooth::emboss::StatusCode::COMMAND_DISALLOWED));
154 }
155 
TEST_F(CommandHandlerTest,SendCommandWithSyncEventFailsToDecode)156 TEST_F(CommandHandlerTest, SendCommandWithSyncEventFailsToDecode) {
157   const auto kEventPacket = bt::testing::CommandCompletePacket(
158       kOpCode, pw::bluetooth::emboss::StatusCode::SUCCESS);
159   EXPECT_CMD_PACKET_OUT(test_device(), kTestCommandPacket, &kEventPacket);
160 
161   std::optional<hci::Error> error;
162   handler().SendCommand(kTestCommandWithUndecodableCommandCompleteEvent,
163                         [&error](auto result) {
164                           ASSERT_TRUE(result.is_error());
165                           error = std::move(result).error_value();
166                         });
167 
168   RunUntilIdle();
169   ASSERT_TRUE(error.has_value());
170   EXPECT_TRUE(error->is(HostError::kPacketMalformed));
171 }
172 
TEST_F(CommandHandlerTest,SuccessfulSendCommandWithAsyncEvent)173 TEST_F(CommandHandlerTest, SuccessfulSendCommandWithAsyncEvent) {
174   const auto kTestEventPacket = MakeTestEventPacket();
175   const auto kStatusEventPacket = bt::testing::CommandStatusPacket(
176       kOpCode, pw::bluetooth::emboss::StatusCode::SUCCESS);
177   EXPECT_CMD_PACKET_OUT(test_device(),
178                         kTestCommandPacket,
179                         &kStatusEventPacket,
180                         &kTestEventPacket);
181 
182   std::optional<DecodableEvent> event;
183   size_t cb_count = 0;
184   handler().SendCommand(kTestCommandWithAsyncEvent,
185                         [&event, &cb_count](auto result) {
186                           ASSERT_EQ(fit::ok(), result);
187                           event = result.value();
188                           cb_count++;
189                         });
190 
191   RunUntilIdle();
192   ASSERT_EQ(cb_count, 1u);
193   ASSERT_TRUE(event.has_value());
194   EXPECT_EQ(event->test_param, kTestEventParam);
195 }
196 
TEST_F(CommandHandlerTest,AddEventHandlerSuccess)197 TEST_F(CommandHandlerTest, AddEventHandlerSuccess) {
198   std::optional<DecodableEvent> event;
199   size_t cb_count = 0;
200   handler().AddEventHandler<DecodableEvent>([&event, &cb_count](auto cb_event) {
201     cb_count++;
202     event = cb_event;
203     return CommandChannel::EventCallbackResult::kContinue;
204   });
205   test_device()->SendCommandChannelPacket(MakeTestEventPacket());
206   test_device()->SendCommandChannelPacket(MakeTestEventPacket());
207   RunUntilIdle();
208   EXPECT_EQ(cb_count, 2u);
209   ASSERT_TRUE(event.has_value());
210   EXPECT_EQ(event->test_param, kTestEventParam);
211 }
212 
TEST_F(CommandHandlerTest,AddEventHandlerDecodeError)213 TEST_F(CommandHandlerTest, AddEventHandlerDecodeError) {
214   size_t cb_count = 0;
215   handler().AddEventHandler<UndecodableEvent>([&cb_count](auto cb_event) {
216     cb_count++;
217     return CommandChannel::EventCallbackResult::kContinue;
218   });
219   test_device()->SendCommandChannelPacket(MakeTestEventPacket());
220   test_device()->SendCommandChannelPacket(MakeTestEventPacket());
221   RunUntilIdle();
222   EXPECT_EQ(cb_count, 0u);
223 }
224 
TEST_F(CommandHandlerTest,SendCommandFinishOnStatus)225 TEST_F(CommandHandlerTest, SendCommandFinishOnStatus) {
226   const auto kStatusEventPacket = bt::testing::CommandStatusPacket(
227       kOpCode, pw::bluetooth::emboss::StatusCode::SUCCESS);
228   EXPECT_CMD_PACKET_OUT(test_device(), kTestCommandPacket, &kStatusEventPacket);
229 
230   size_t cb_count = 0;
231   handler().SendCommandFinishOnStatus(kTestCommandWithAsyncEvent,
232                                       [&cb_count](auto result) {
233                                         ASSERT_EQ(fit::ok(), result);
234                                         cb_count++;
235                                       });
236 
237   RunUntilIdle();
238   ASSERT_EQ(cb_count, 1u);
239 }
240 
241 }  // namespace
242 }  // namespace bt::hci
243