• 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 <numeric>
16 
17 #include "lib/stdcompat/utility.h"
18 #include "pw_unit_test/framework.h"
19 
20 // clang-format off
21 // All emboss headers are listed (even if they don't have explicit tests) to
22 // ensure they are compiled.
23 #include "pw_bluetooth/att.emb.h"  // IWYU pragma: keep
24 #include "pw_bluetooth/hci_commands.emb.h"  // IWYU pragma: keep
25 #include "pw_bluetooth/hci_common.emb.h"
26 #include "pw_bluetooth/hci_data.emb.h"
27 #include "pw_bluetooth/hci_events.emb.h"  // IWYU pragma: keep
28 #include "pw_bluetooth/hci_h4.emb.h"      // IWYU pragma: keep
29 #include "pw_bluetooth/hci_test.emb.h"
30 #include "pw_bluetooth/hci_android.emb.h"    // IWYU pragma: keep
31 #include "pw_bluetooth/l2cap_frames.emb.h"  // IWYU pragma: keep
32 #include "pw_bluetooth/rfcomm_frames.emb.h"  // IWYU pragma: keep
33 // clang-format on
34 
35 namespace pw::bluetooth {
36 namespace {
37 
38 // Examples are used in docs.rst.
TEST(EmbossExamples,MakeView)39 TEST(EmbossExamples, MakeView) {
40   // DOCSTAG: [pw_bluetooth-examples-make_view]
41   std::array<uint8_t, 4> buffer = {0x00, 0x01, 0x02, 0x03};
42   auto view = emboss::MakeTestCommandPacketView(&buffer);
43   EXPECT_TRUE(view.IsComplete());
44   EXPECT_EQ(view.payload().Read(), 0x03);
45   // DOCSTAG: [pw_bluetooth-examples-make_view]
46 }
47 
TEST(EmbossTest,MakeView)48 TEST(EmbossTest, MakeView) {
49   std::array<uint8_t, 4> buffer = {0x00, 0x01, 0x02, 0x03};
50   auto view = emboss::MakeTestCommandPacketView(&buffer);
51   EXPECT_TRUE(view.IsComplete());
52   EXPECT_EQ(view.payload().Read(), 0x03);
53 }
54 
InitializeIsoPacket(const emboss::IsoDataFramePacketWriter & view,emboss::TsFlag ts_flag,emboss::IsoDataPbFlag pb_flag,size_t sdu_fragment_size)55 static void InitializeIsoPacket(const emboss::IsoDataFramePacketWriter& view,
56                                 emboss::TsFlag ts_flag,
57                                 emboss::IsoDataPbFlag pb_flag,
58                                 size_t sdu_fragment_size) {
59   view.header().connection_handle().Write(0x123);
60   view.header().ts_flag().Write(ts_flag);
61   view.header().pb_flag().Write(pb_flag);
62 
63   size_t optional_fields_total_size = 0;
64   if (ts_flag == emboss::TsFlag::TIMESTAMP_PRESENT) {
65     optional_fields_total_size += 4;
66   }
67 
68   if ((pb_flag == emboss::IsoDataPbFlag::FIRST_FRAGMENT) ||
69       (pb_flag == emboss::IsoDataPbFlag::COMPLETE_SDU)) {
70     optional_fields_total_size += 4;
71   }
72 
73   view.header().data_total_length().Write(sdu_fragment_size +
74                                           optional_fields_total_size);
75 }
76 
77 // This definition has a mix of full-width values and bitfields and includes
78 // conditional bitfields. Let's add this to verify that the structure itself
79 // doesn't get changed incorrectly and that emboss' size calculation matches
80 // ours.
TEST(EmbossTest,CheckIsoPacketSize)81 TEST(EmbossTest, CheckIsoPacketSize) {
82   std::array<uint8_t, 2048> buffer;
83   const size_t kSduFragmentSize = 100;
84   auto view = emboss::MakeIsoDataFramePacketView(&buffer);
85 
86   InitializeIsoPacket(view,
87                       emboss::TsFlag::TIMESTAMP_NOT_PRESENT,
88                       emboss::IsoDataPbFlag::FIRST_FRAGMENT,
89                       kSduFragmentSize);
90   ASSERT_TRUE(view.IntrinsicSizeInBytes().Ok());
91   EXPECT_EQ(static_cast<size_t>(view.IntrinsicSizeInBytes().Read()),
92             view.hdr_size().Read() + kSduFragmentSize + 4);
93 
94   InitializeIsoPacket(view,
95                       emboss::TsFlag::TIMESTAMP_NOT_PRESENT,
96                       emboss::IsoDataPbFlag::INTERMEDIATE_FRAGMENT,
97                       kSduFragmentSize);
98   ASSERT_TRUE(view.IntrinsicSizeInBytes().Ok());
99   EXPECT_EQ(static_cast<size_t>(view.IntrinsicSizeInBytes().Read()),
100             view.hdr_size().Read() + kSduFragmentSize);
101 
102   InitializeIsoPacket(view,
103                       emboss::TsFlag::TIMESTAMP_NOT_PRESENT,
104                       emboss::IsoDataPbFlag::COMPLETE_SDU,
105                       kSduFragmentSize);
106   ASSERT_TRUE(view.IntrinsicSizeInBytes().Ok());
107   EXPECT_EQ(static_cast<size_t>(view.IntrinsicSizeInBytes().Read()),
108             view.hdr_size().Read() + kSduFragmentSize + 4);
109 
110   InitializeIsoPacket(view,
111                       emboss::TsFlag::TIMESTAMP_NOT_PRESENT,
112                       emboss::IsoDataPbFlag::LAST_FRAGMENT,
113                       kSduFragmentSize);
114   ASSERT_TRUE(view.IntrinsicSizeInBytes().Ok());
115   EXPECT_EQ(static_cast<size_t>(view.IntrinsicSizeInBytes().Read()),
116             view.hdr_size().Read() + kSduFragmentSize);
117 
118   InitializeIsoPacket(view,
119                       emboss::TsFlag::TIMESTAMP_PRESENT,
120                       emboss::IsoDataPbFlag::FIRST_FRAGMENT,
121                       kSduFragmentSize);
122   ASSERT_TRUE(view.IntrinsicSizeInBytes().Ok());
123   EXPECT_EQ(static_cast<size_t>(view.IntrinsicSizeInBytes().Read()),
124             view.hdr_size().Read() + kSduFragmentSize + 8);
125 
126   InitializeIsoPacket(view,
127                       emboss::TsFlag::TIMESTAMP_PRESENT,
128                       emboss::IsoDataPbFlag::INTERMEDIATE_FRAGMENT,
129                       kSduFragmentSize);
130   ASSERT_TRUE(view.IntrinsicSizeInBytes().Ok());
131   EXPECT_EQ(static_cast<size_t>(view.IntrinsicSizeInBytes().Read()),
132             view.hdr_size().Read() + kSduFragmentSize + 4);
133 
134   InitializeIsoPacket(view,
135                       emboss::TsFlag::TIMESTAMP_PRESENT,
136                       emboss::IsoDataPbFlag::COMPLETE_SDU,
137                       kSduFragmentSize);
138   ASSERT_TRUE(view.IntrinsicSizeInBytes().Ok());
139   EXPECT_EQ(static_cast<size_t>(view.IntrinsicSizeInBytes().Read()),
140             view.hdr_size().Read() + kSduFragmentSize + 8);
141 
142   InitializeIsoPacket(view,
143                       emboss::TsFlag::TIMESTAMP_PRESENT,
144                       emboss::IsoDataPbFlag::LAST_FRAGMENT,
145                       kSduFragmentSize);
146   ASSERT_TRUE(view.IntrinsicSizeInBytes().Ok());
147   EXPECT_EQ(static_cast<size_t>(view.IntrinsicSizeInBytes().Read()),
148             view.hdr_size().Read() + kSduFragmentSize + 4);
149 }
150 
151 // Test and demonstrate various ways of reading opcodes.
TEST(EmbossTest,ReadOpcodesFromCommandHeader)152 TEST(EmbossTest, ReadOpcodesFromCommandHeader) {
153   // First two bytes will be used as opcode.
154   std::array<uint8_t, 4> buffer = {0x00, 0x00, 0x02, 0x03};
155   auto view = emboss::MakeTestCommandPacketView(&buffer);
156   EXPECT_TRUE(view.IsComplete());
157   auto header = view.header();
158 
159   EXPECT_EQ(header.opcode().Read(), emboss::OpCode::UNSPECIFIED);
160   EXPECT_EQ(header.opcode_bits().BackingStorage().ReadUInt(), 0x0000);
161   EXPECT_EQ(header.opcode_bits().ogf().Read(), 0x00);
162   EXPECT_EQ(header.opcode_bits().ocf().Read(), 0x00);
163 
164   // LINK_KEY_REQUEST_REPLY is OGF 0x01 and OCF 0x0B.
165   header.opcode().Write(emboss::OpCode::LINK_KEY_REQUEST_REPLY);
166   EXPECT_EQ(header.opcode().Read(), emboss::OpCode::LINK_KEY_REQUEST_REPLY);
167   EXPECT_EQ(header.opcode_bits().BackingStorage().ReadUInt(), 0x040B);
168   EXPECT_EQ(header.opcode_bits().ogf().Read(), 0x01);
169   EXPECT_EQ(header.opcode_bits().ocf().Read(), 0x0B);
170 }
171 
172 // Test and demonstrate various ways of writing opcodes.
TEST(EmbossTest,WriteOpcodesFromCommandHeader)173 TEST(EmbossTest, WriteOpcodesFromCommandHeader) {
174   std::array<uint8_t, 4> buffer = {};
175   buffer.fill(0xFF);
176   auto view = emboss::MakeTestCommandPacketView(&buffer);
177   EXPECT_TRUE(view.IsComplete());
178   auto header = view.header();
179 
180   header.opcode().Write(emboss::OpCode::UNSPECIFIED);
181   EXPECT_EQ(header.opcode_bits().BackingStorage().ReadUInt(), 0x0000);
182 
183   header.opcode_bits().ocf().Write(0x0B);
184   EXPECT_EQ(header.opcode_bits().BackingStorage().ReadUInt(), 0x000B);
185 
186   header.opcode_bits().ogf().Write(0x01);
187   EXPECT_EQ(header.opcode_bits().BackingStorage().ReadUInt(), 0x040B);
188   // LINK_KEY_REQUEST_REPLY is OGF 0x01 and OCF 0x0B.
189   EXPECT_EQ(header.opcode().Read(), emboss::OpCode::LINK_KEY_REQUEST_REPLY);
190 }
191 
192 // Test and demonstrate using to_underlying with OpCodes enums
TEST(EmbossTest,OPCodeEnumsWithToUnderlying)193 TEST(EmbossTest, OPCodeEnumsWithToUnderlying) {
194   EXPECT_EQ(0x0000, cpp23::to_underlying(emboss::OpCode::UNSPECIFIED));
195 }
196 
TEST(EmbossTest,ReadAndWriteOpcodesInCommandResponseHeader)197 TEST(EmbossTest, ReadAndWriteOpcodesInCommandResponseHeader) {
198   // First two bytes will be used as opcode.
199   std::array<uint8_t,
200              emboss::ReadBufferSizeCommandCompleteEventView::SizeInBytes()>
201       buffer;
202   std::iota(buffer.begin(), buffer.end(), 100);
203   auto view = emboss::MakeReadBufferSizeCommandCompleteEventView(&buffer);
204   EXPECT_TRUE(view.IsComplete());
205   auto header = view.command_complete();
206 
207   header.command_opcode_uint().Write(0x0000);
208   EXPECT_EQ(header.command_opcode().Read(), emboss::OpCode::UNSPECIFIED);
209   EXPECT_EQ(header.command_opcode_bits().BackingStorage().ReadUInt(), 0x0000);
210   EXPECT_EQ(header.command_opcode_bits().ogf().Read(), 0x00);
211   EXPECT_EQ(header.command_opcode_bits().ocf().Read(), 0x00);
212 
213   // LINK_KEY_REQUEST_REPLY is OGF 0x01 and OCF 0x0B.
214   header.command_opcode().Write(emboss::OpCode::LINK_KEY_REQUEST_REPLY);
215   EXPECT_EQ(header.command_opcode().Read(),
216             emboss::OpCode::LINK_KEY_REQUEST_REPLY);
217   EXPECT_EQ(header.command_opcode_bits().BackingStorage().ReadUInt(), 0x040B);
218   EXPECT_EQ(header.command_opcode_bits().ogf().Read(), 0x01);
219   EXPECT_EQ(header.command_opcode_bits().ocf().Read(), 0x0B);
220 }
221 
TEST(EmbossTest,ReadAndWriteEventCodesInEventHeader)222 TEST(EmbossTest, ReadAndWriteEventCodesInEventHeader) {
223   std::array<uint8_t, emboss::EventHeaderWriter::SizeInBytes()> buffer;
224   std::iota(buffer.begin(), buffer.end(), 100);
225   auto header = emboss::MakeEventHeaderView(&buffer);
226   EXPECT_TRUE(header.IsComplete());
227 
228   header.event_code_uint().Write(
229       cpp23::to_underlying(emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS));
230   EXPECT_EQ(header.event_code().Read(),
231             emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS);
232   EXPECT_EQ(
233       header.event_code_uint().Read(),
234       cpp23::to_underlying(emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS));
235 
236   EXPECT_EQ(
237       header.event_code_uint().Read(),
238       cpp23::to_underlying(emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS));
239 
240   header.event_code().Write(emboss::EventCode::CONNECTION_REQUEST);
241   EXPECT_EQ(header.event_code_uint().Read(),
242             cpp23::to_underlying(emboss::EventCode::CONNECTION_REQUEST));
243 }
244 
TEST(EmbossTest,ReadCommandPayloadLength)245 TEST(EmbossTest, ReadCommandPayloadLength) {
246   std::array<uint8_t, 8> hci_buffer = {
247       0x4c, 0xfc, 0x05, 0x73, 0x86, 0x30, 0x00, 0x00};
248   emboss::CommandHeaderView command = emboss::MakeCommandHeaderView(
249       hci_buffer.data(), emboss::CommandHeaderView::SizeInBytes());
250   EXPECT_TRUE(command.IsComplete());
251   EXPECT_EQ(command.parameter_total_size().Read(), 5);
252 }
253 
TEST(EmbossTest,ReadEventPayloadLength)254 TEST(EmbossTest, ReadEventPayloadLength) {
255   std::array<uint8_t, 8> hci_buffer = {0x0e, 0x04, 0x01, 0x2e, 0xfc, 0x00};
256   emboss::EventHeaderView event = emboss::MakeEventHeaderView(
257       hci_buffer.data(), emboss::EventHeaderView::SizeInBytes());
258   EXPECT_TRUE(event.IsComplete());
259   EXPECT_EQ(event.parameter_total_size().Read(), 4);
260 }
261 
TEST(EmbossTest,ReadAclPayloadLength)262 TEST(EmbossTest, ReadAclPayloadLength) {
263   std::array<uint8_t, 16> hci_buffer = {0x0c,
264                                         0x00,
265                                         0x0c,
266                                         0x00,
267                                         0x08,
268                                         0x00,
269                                         0x01,
270                                         0x00,
271                                         0x06,
272                                         0x06,
273                                         0x04,
274                                         0x00,
275                                         0x5b,
276                                         0x00,
277                                         0x41,
278                                         0x00};
279   emboss::AclDataFrameHeaderView acl = emboss::MakeAclDataFrameHeaderView(
280       hci_buffer.data(), emboss::AclDataFrameHeaderView::SizeInBytes());
281   EXPECT_TRUE(acl.IsComplete());
282   EXPECT_EQ(acl.data_total_length().Read(), 12);
283 }
284 
TEST(EmbossTest,ReadScoPayloadLength)285 TEST(EmbossTest, ReadScoPayloadLength) {
286   std::array<uint8_t, 9> hci_buffer = {
287       0x02, 0x00, 0x06, 0xFF, 0xD3, 0x4A, 0x1B, 0x2C, 0x3D};
288   emboss::ScoDataHeaderView sco = emboss::ScoDataHeaderView(
289       hci_buffer.data(), emboss::ScoDataHeaderView::SizeInBytes());
290   EXPECT_TRUE(sco.IsComplete());
291   EXPECT_EQ(sco.data_total_length().Read(), 6);
292 }
293 
TEST(EmbossTest,WriteSniffMode)294 TEST(EmbossTest, WriteSniffMode) {
295   std::array<uint8_t, emboss::SniffModeCommandWriter::SizeInBytes()> buffer{};
296   emboss::SniffModeCommandWriter writer =
297       emboss::MakeSniffModeCommandView(&buffer);
298   writer.header().opcode().Write(emboss::OpCode::SNIFF_MODE);
299   writer.header().parameter_total_size().Write(
300       emboss::SniffModeCommandWriter::SizeInBytes() -
301       emboss::CommandHeaderWriter::SizeInBytes());
302   writer.connection_handle().Write(0x0004);
303   writer.sniff_max_interval().Write(0x0330);
304   writer.sniff_min_interval().Write(0x0190);
305   writer.sniff_attempt().Write(0x0004);
306   writer.sniff_timeout().Write(0x0001);
307   std::array<uint8_t, emboss::SniffModeCommandView::SizeInBytes()> expected{
308       // Opcode (LSB, MSB)
309       0x03,
310       0x08,
311       // Parameter Total Size
312       0x0A,
313       // Connection Handle (LSB, MSB)
314       0x04,
315       0x00,
316       // Sniff Max Interval (LSB, MSB)
317       0x30,
318       0x03,
319       // Sniff Min Interval (LSB, MSB)
320       0x90,
321       0x01,
322       // Sniff Attempt (LSB, MSB)
323       0x04,
324       0x00,
325       // Sniff Timeout (LSB, MSB)
326       0x01,
327       0x00};
328   EXPECT_EQ(buffer, expected);
329 }
330 
TEST(EmbossTest,ReadSniffMode)331 TEST(EmbossTest, ReadSniffMode) {
332   std::array<uint8_t, emboss::SniffModeCommandView::SizeInBytes()> buffer{
333       // Opcode (LSB, MSB)
334       0x03,
335       0x08,
336       // Parameter Total Size
337       0x0A,
338       // Connection Handle (LSB, MSB)
339       0x04,
340       0x00,
341       // Sniff Max Interval (LSB, MSB)
342       0x30,
343       0x03,
344       // Sniff Min Interval (LSB, MSB)
345       0x90,
346       0x01,
347       // Sniff Attempt (LSB, MSB)
348       0x04,
349       0x00,
350       // Sniff Timeout (LSB, MSB)
351       0x01,
352       0x00};
353   emboss::SniffModeCommandView view = emboss::MakeSniffModeCommandView(&buffer);
354   EXPECT_EQ(view.header().opcode().Read(), emboss::OpCode::SNIFF_MODE);
355   EXPECT_TRUE(view.header().IsComplete());
356   EXPECT_EQ(view.connection_handle().Read(), 0x0004);
357   EXPECT_EQ(view.sniff_max_interval().Read(), 0x0330);
358   EXPECT_EQ(view.sniff_min_interval().Read(), 0x0190);
359   EXPECT_EQ(view.sniff_attempt().Read(), 0x0004);
360   EXPECT_EQ(view.sniff_timeout().Read(), 0x0001);
361 }
362 
TEST(EmbossTest,ReadRfcomm)363 TEST(EmbossTest, ReadRfcomm) {
364   std::array<uint8_t,
365              emboss::RfcommFrame::MinSizeInBytes() + /*credits*/ 1 +
366                  /*payload*/ 3>
367       buffer_with_credits = {// Address
368                              0x19,
369                              // UIH Poll/Final
370                              0xFF,
371                              // Information Length
372                              0x07,
373                              // Credits
374                              0x0A,
375                              // Payload/Information
376                              0xAB,
377                              0xCD,
378                              0xEF,
379                              // FCS
380                              0x49};
381 
382   emboss::RfcommFrameView rfcomm =
383       emboss::MakeRfcommFrameView(&buffer_with_credits);
384   EXPECT_TRUE(rfcomm.Ok());
385   EXPECT_EQ(rfcomm.credits().Read(), 10);
386 
387   EXPECT_EQ(rfcomm.information()[0].Read(), 0xAB);
388   EXPECT_EQ(rfcomm.information()[1].Read(), 0xCD);
389   EXPECT_EQ(rfcomm.information()[2].Read(), 0xEF);
390 
391   EXPECT_EQ(rfcomm.fcs().Read(), 0x49);
392 
393   std::array<uint8_t,
394              emboss::RfcommFrame::MinSizeInBytes() +
395                  /*payload*/ 3>
396       buffer_without_credits = {// Address
397                                 0x19,
398                                 // UIH
399                                 0xEF,
400                                 // Information Length
401                                 0x07,
402                                 // Payload/Information
403                                 0xAB,
404                                 0xCD,
405                                 0xEF,
406                                 // FCS
407                                 0x55};
408 
409   rfcomm = emboss::MakeRfcommFrameView(&buffer_without_credits);
410   EXPECT_TRUE(rfcomm.Ok());
411   EXPECT_FALSE(rfcomm.has_credits().ValueOrDefault());
412   EXPECT_EQ(rfcomm.information()[0].Read(), 0xAB);
413   EXPECT_EQ(rfcomm.information()[1].Read(), 0xCD);
414   EXPECT_EQ(rfcomm.information()[2].Read(), 0xEF);
415   EXPECT_EQ(rfcomm.fcs().Read(), 0x55);
416 }
417 
TEST(EmbossTest,ReadRfcommExtended)418 TEST(EmbossTest, ReadRfcommExtended) {
419   constexpr size_t kMaxShortLength = 0x7f;
420   std::array<uint8_t,
421              emboss::RfcommFrame::MinSizeInBytes() + /*length_extended*/ 1 +
422                  /*credits*/ 1 +
423                  /*payload*/ (kMaxShortLength + 1)>
424       buffer_extended_length_with_credits = {
425           // Address
426           0x19,
427           // UIH Poll/Final
428           0xFF,
429           // Information Length
430           0x00,
431           0x01,
432           // Credits
433           0x0A,
434           // Payload/Information
435           0xAB,
436           0xCD,
437           0xEF,
438       };
439 
440   // FCS
441   buffer_extended_length_with_credits
442       [buffer_extended_length_with_credits.size() - 1] = 0x49;
443 
444   emboss::RfcommFrameView rfcomm =
445       emboss::MakeRfcommFrameView(&buffer_extended_length_with_credits);
446   EXPECT_TRUE(rfcomm.Ok());
447   EXPECT_TRUE(rfcomm.has_credits().ValueOrDefault());
448   EXPECT_TRUE(rfcomm.has_length_extended().ValueOrDefault());
449   EXPECT_EQ(rfcomm.information_length().Read(), 128);
450   EXPECT_EQ(rfcomm.information()[0].Read(), 0xAB);
451   EXPECT_EQ(rfcomm.information()[1].Read(), 0xCD);
452   EXPECT_EQ(rfcomm.information()[2].Read(), 0xEF);
453   EXPECT_EQ(rfcomm.fcs().Read(), 0x49);
454 }
455 
TEST(EmbossTest,WriteRfcomm)456 TEST(EmbossTest, WriteRfcomm) {
457   const std::array<uint8_t, 3> expected_payload = {0xAB, 0xCD, 0xEF};
458   constexpr size_t kFrameSize = emboss::RfcommFrame::MinSizeInBytes() +
459                                 /*credits*/ 1 + expected_payload.size();
460   std::array<uint8_t, kFrameSize> buffer{};
461 
462   emboss::RfcommFrameWriter rfcomm = emboss::MakeRfcommFrameView(&buffer);
463   rfcomm.extended_address().Write(true);
464   rfcomm.command_response_direction().Write(
465       emboss::RfcommCommandResponseAndDirection::COMMAND_FROM_RESPONDER);
466   rfcomm.channel().Write(3);
467   rfcomm.control().Write(
468       emboss::RfcommFrameType::
469           UNNUMBERED_INFORMATION_WITH_HEADER_CHECK_AND_POLL_FINAL);
470 
471   rfcomm.length_extended_flag().Write(emboss::RfcommLengthExtended::NORMAL);
472   rfcomm.length().Write(expected_payload.size());
473 
474   EXPECT_TRUE(rfcomm.has_credits().ValueOrDefault());
475   rfcomm.credits().Write(10);
476 
477   std::memcpy(rfcomm.information().BackingStorage().data(),
478               expected_payload.data(),
479               expected_payload.size());
480   rfcomm.fcs().Write(0x49);
481 
482   std::array<uint8_t, kFrameSize> expected{// Address
483                                            0x19,
484                                            // UIH Poll/Final
485                                            0xFF,
486                                            // Information Length
487                                            0x07,
488                                            // Credits
489                                            0x0A,
490                                            // Payload/Information
491                                            0xAB,
492                                            0xCD,
493                                            0xEF,
494                                            // FCS
495                                            0x49};
496   EXPECT_EQ(buffer, expected);
497 }
498 
TEST(EmbossTest,WriteRfcommExtended)499 TEST(EmbossTest, WriteRfcommExtended) {
500   const std::array<uint8_t, 128> expected_payload = {0xAB, 0xCD, 0xEF};
501   constexpr size_t kFrameSize = emboss::RfcommFrame::MinSizeInBytes() +
502                                 /* length_extended */ 1 +
503                                 /*credits*/ 1 + expected_payload.size();
504   std::array<uint8_t, kFrameSize> buffer{};
505 
506   emboss::RfcommFrameWriter rfcomm = emboss::MakeRfcommFrameView(&buffer);
507   rfcomm.extended_address().Write(true);
508   rfcomm.command_response_direction().Write(
509       emboss::RfcommCommandResponseAndDirection::COMMAND_FROM_RESPONDER);
510   rfcomm.channel().Write(3);
511   rfcomm.control().Write(
512       emboss::RfcommFrameType::
513           UNNUMBERED_INFORMATION_WITH_HEADER_CHECK_AND_POLL_FINAL);
514 
515   rfcomm.length_extended_flag().Write(emboss::RfcommLengthExtended::EXTENDED);
516   rfcomm.length_extended().Write(expected_payload.size());
517 
518   EXPECT_TRUE(rfcomm.has_credits().ValueOrDefault());
519   rfcomm.credits().Write(10);
520 
521   std::memcpy(rfcomm.information().BackingStorage().data(),
522               expected_payload.data(),
523               expected_payload.size());
524   rfcomm.fcs().Write(0x49);
525 
526   std::array<uint8_t, kFrameSize> expected{
527       // Address
528       0x19,
529       // UIH Poll/Final
530       0xFF,
531       // Information Length
532       0x00,
533       0x01,
534       // Credits
535       0x0A,
536       // Payload/Information
537       0xAB,
538       0xCD,
539       0xEF,
540   };
541   // FCS
542   expected[expected.size() - 1] = 0x49;
543 
544   EXPECT_EQ(expected[2], buffer[2]);
545   EXPECT_EQ(expected[3], buffer[3]);
546 
547   EXPECT_EQ(buffer, expected);
548 }
549 
550 }  // namespace
551 }  // namespace pw::bluetooth
552