xref: /aosp_15_r20/external/pigweed/pw_bluetooth/emboss_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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"  // IWYU pragma: keep
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_enum().Read(), emboss::OpCode::UNSPECIFIED);
160   EXPECT_EQ(header.opcode().BackingStorage().ReadUInt(), 0x0000);
161   EXPECT_EQ(header.opcode_bits().ogf().Read(), 0x00);
162   EXPECT_EQ(header.opcode_bits().ocf().Read(), 0x00);
163   // TODO: https://pwbug.dev/338068316 - Delete these opcode type
164   // OpCodeBits cases once opcode has type OpCode.
165   EXPECT_EQ(header.opcode().ogf().Read(), 0x00);
166   EXPECT_EQ(header.opcode().ocf().Read(), 0x00);
167 
168   // LINK_KEY_REQUEST_REPLY is OGF 0x01 and OCF 0x0B.
169   header.opcode_enum().Write(emboss::OpCode::LINK_KEY_REQUEST_REPLY);
170   EXPECT_EQ(header.opcode_enum().Read(),
171             emboss::OpCode::LINK_KEY_REQUEST_REPLY);
172   EXPECT_EQ(header.opcode().BackingStorage().ReadUInt(), 0x040B);
173   EXPECT_EQ(header.opcode_bits().ogf().Read(), 0x01);
174   EXPECT_EQ(header.opcode_bits().ocf().Read(), 0x0B);
175   // TODO: https://pwbug.dev/338068316 - Delete these opcode type
176   // OpCodeBits cases once opcode has type OpCode.
177   EXPECT_EQ(header.opcode().ogf().Read(), 0x01);
178   EXPECT_EQ(header.opcode().ocf().Read(), 0x0B);
179 }
180 
181 // Test and demonstrate various ways of writing opcodes.
TEST(EmbossTest,WriteOpcodesFromCommandHeader)182 TEST(EmbossTest, WriteOpcodesFromCommandHeader) {
183   std::array<uint8_t, 4> buffer = {};
184   buffer.fill(0xFF);
185   auto view = emboss::MakeTestCommandPacketView(&buffer);
186   EXPECT_TRUE(view.IsComplete());
187   auto header = view.header();
188 
189   header.opcode_enum().Write(emboss::OpCode::UNSPECIFIED);
190   EXPECT_EQ(header.opcode().BackingStorage().ReadUInt(), 0x0000);
191 
192   header.opcode().ocf().Write(0x0B);
193   EXPECT_EQ(header.opcode().BackingStorage().ReadUInt(), 0x000B);
194 
195   header.opcode().ogf().Write(0x01);
196   EXPECT_EQ(header.opcode().BackingStorage().ReadUInt(), 0x040B);
197   // LINK_KEY_REQUEST_REPLY is OGF 0x01 and OCF 0x0B.
198   EXPECT_EQ(header.opcode_enum().Read(),
199             emboss::OpCode::LINK_KEY_REQUEST_REPLY);
200 }
201 
202 // Test and demonstrate using to_underlying with OpCodes enums
TEST(EmbossTest,OPCodeEnumsWithToUnderlying)203 TEST(EmbossTest, OPCodeEnumsWithToUnderlying) {
204   EXPECT_EQ(0x0000, cpp23::to_underlying(emboss::OpCode::UNSPECIFIED));
205 }
206 
TEST(EmbossTest,ReadAndWriteOpcodesInCommandResponseHeader)207 TEST(EmbossTest, ReadAndWriteOpcodesInCommandResponseHeader) {
208   // First two bytes will be used as opcode.
209   std::array<uint8_t,
210              emboss::ReadBufferSizeCommandCompleteEventView::SizeInBytes()>
211       buffer;
212   std::iota(buffer.begin(), buffer.end(), 100);
213   auto view = emboss::MakeReadBufferSizeCommandCompleteEventView(&buffer);
214   EXPECT_TRUE(view.IsComplete());
215   auto header = view.command_complete();
216 
217   header.command_opcode().BackingStorage().WriteUInt(0x0000);
218   EXPECT_EQ(header.command_opcode_enum().Read(), emboss::OpCode::UNSPECIFIED);
219   EXPECT_EQ(header.command_opcode().BackingStorage().ReadUInt(), 0x0000);
220   EXPECT_EQ(header.command_opcode_bits().ogf().Read(), 0x00);
221   EXPECT_EQ(header.command_opcode_bits().ocf().Read(), 0x00);
222   // TODO: https://pwbug.dev/338068316 - Delete these command_opcode type
223   // OpCodeBits cases once command_opcode has type OpCode.
224   EXPECT_EQ(header.command_opcode().ogf().Read(), 0x00);
225   EXPECT_EQ(header.command_opcode().ocf().Read(), 0x00);
226 
227   // LINK_KEY_REQUEST_REPLY is OGF 0x01 and OCF 0x0B.
228   header.command_opcode_enum().Write(emboss::OpCode::LINK_KEY_REQUEST_REPLY);
229   EXPECT_EQ(header.command_opcode_enum().Read(),
230             emboss::OpCode::LINK_KEY_REQUEST_REPLY);
231   EXPECT_EQ(header.command_opcode().BackingStorage().ReadUInt(), 0x040B);
232   EXPECT_EQ(header.command_opcode_bits().ogf().Read(), 0x01);
233   EXPECT_EQ(header.command_opcode_bits().ocf().Read(), 0x0B);
234   // TODO: https://pwbug.dev/338068316 - Delete these command_opcode type
235   // OpCodeBits cases once command_opcode has type OpCode.
236   EXPECT_EQ(header.command_opcode().ogf().Read(), 0x01);
237   EXPECT_EQ(header.command_opcode().ocf().Read(), 0x0B);
238 }
239 
TEST(EmbossTest,ReadAndWriteEventCodesInEventHeader)240 TEST(EmbossTest, ReadAndWriteEventCodesInEventHeader) {
241   std::array<uint8_t, emboss::EventHeaderWriter::SizeInBytes()> buffer;
242   std::iota(buffer.begin(), buffer.end(), 100);
243   auto header = emboss::MakeEventHeaderView(&buffer);
244   EXPECT_TRUE(header.IsComplete());
245 
246   header.event_code_uint().Write(
247       cpp23::to_underlying(emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS));
248   EXPECT_EQ(header.event_code_enum().Read(),
249             emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS);
250   EXPECT_EQ(
251       header.event_code_uint().Read(),
252       cpp23::to_underlying(emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS));
253 
254   // TODO: https://pwbug.dev/338068316 - Delete these event_code type
255   // UInt cases once event_code has type EventCode.
256   EXPECT_EQ(
257       header.event_code().Read(),
258       cpp23::to_underlying(emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS));
259 
260   header.event_code().Write(
261       cpp23::to_underlying(emboss::EventCode::CONNECTION_REQUEST));
262   EXPECT_EQ(header.event_code_uint().Read(),
263             cpp23::to_underlying(emboss::EventCode::CONNECTION_REQUEST));
264 }
265 
TEST(EmbossTest,ReadCommandPayloadLength)266 TEST(EmbossTest, ReadCommandPayloadLength) {
267   std::array<uint8_t, 8> hci_buffer = {
268       0x4c, 0xfc, 0x05, 0x73, 0x86, 0x30, 0x00, 0x00};
269   emboss::CommandHeaderView command = emboss::MakeCommandHeaderView(
270       hci_buffer.data(), emboss::CommandHeaderView::SizeInBytes());
271   EXPECT_TRUE(command.IsComplete());
272   EXPECT_EQ(command.parameter_total_size().Read(), 5);
273 }
274 
TEST(EmbossTest,ReadEventPayloadLength)275 TEST(EmbossTest, ReadEventPayloadLength) {
276   std::array<uint8_t, 8> hci_buffer = {0x0e, 0x04, 0x01, 0x2e, 0xfc, 0x00};
277   emboss::EventHeaderView event = emboss::MakeEventHeaderView(
278       hci_buffer.data(), emboss::EventHeaderView::SizeInBytes());
279   EXPECT_TRUE(event.IsComplete());
280   EXPECT_EQ(event.parameter_total_size().Read(), 4);
281 }
282 
TEST(EmbossTest,ReadAclPayloadLength)283 TEST(EmbossTest, ReadAclPayloadLength) {
284   std::array<uint8_t, 16> hci_buffer = {0x0c,
285                                         0x00,
286                                         0x0c,
287                                         0x00,
288                                         0x08,
289                                         0x00,
290                                         0x01,
291                                         0x00,
292                                         0x06,
293                                         0x06,
294                                         0x04,
295                                         0x00,
296                                         0x5b,
297                                         0x00,
298                                         0x41,
299                                         0x00};
300   emboss::AclDataFrameHeaderView acl = emboss::MakeAclDataFrameHeaderView(
301       hci_buffer.data(), emboss::AclDataFrameHeaderView::SizeInBytes());
302   EXPECT_TRUE(acl.IsComplete());
303   EXPECT_EQ(acl.data_total_length().Read(), 12);
304 }
305 
TEST(EmbossTest,ReadScoPayloadLength)306 TEST(EmbossTest, ReadScoPayloadLength) {
307   std::array<uint8_t, 9> hci_buffer = {
308       0x02, 0x00, 0x06, 0xFF, 0xD3, 0x4A, 0x1B, 0x2C, 0x3D};
309   emboss::ScoDataHeaderView sco = emboss::ScoDataHeaderView(
310       hci_buffer.data(), emboss::ScoDataHeaderView::SizeInBytes());
311   EXPECT_TRUE(sco.IsComplete());
312   EXPECT_EQ(sco.data_total_length().Read(), 6);
313 }
314 
TEST(EmbossTest,WriteSniffMode)315 TEST(EmbossTest, WriteSniffMode) {
316   std::array<uint8_t, emboss::SniffModeCommandWriter::SizeInBytes()> buffer{};
317   emboss::SniffModeCommandWriter writer =
318       emboss::MakeSniffModeCommandView(&buffer);
319   writer.header().opcode_enum().Write(emboss::OpCode::SNIFF_MODE);
320   writer.header().parameter_total_size().Write(
321       emboss::SniffModeCommandWriter::SizeInBytes() -
322       emboss::CommandHeaderWriter::SizeInBytes());
323   writer.connection_handle().Write(0x0004);
324   writer.sniff_max_interval().Write(0x0330);
325   writer.sniff_min_interval().Write(0x0190);
326   writer.sniff_attempt().Write(0x0004);
327   writer.sniff_timeout().Write(0x0001);
328   std::array<uint8_t, emboss::SniffModeCommandView::SizeInBytes()> expected{
329       // Opcode (LSB, MSB)
330       0x03,
331       0x08,
332       // Parameter Total Size
333       0x0A,
334       // Connection Handle (LSB, MSB)
335       0x04,
336       0x00,
337       // Sniff Max Interval (LSB, MSB)
338       0x30,
339       0x03,
340       // Sniff Min Interval (LSB, MSB)
341       0x90,
342       0x01,
343       // Sniff Attempt (LSB, MSB)
344       0x04,
345       0x00,
346       // Sniff Timeout (LSB, MSB)
347       0x01,
348       0x00};
349   EXPECT_EQ(buffer, expected);
350 }
351 
TEST(EmbossTest,ReadSniffMode)352 TEST(EmbossTest, ReadSniffMode) {
353   std::array<uint8_t, emboss::SniffModeCommandView::SizeInBytes()> buffer{
354       // Opcode (LSB, MSB)
355       0x03,
356       0x08,
357       // Parameter Total Size
358       0x0A,
359       // Connection Handle (LSB, MSB)
360       0x04,
361       0x00,
362       // Sniff Max Interval (LSB, MSB)
363       0x30,
364       0x03,
365       // Sniff Min Interval (LSB, MSB)
366       0x90,
367       0x01,
368       // Sniff Attempt (LSB, MSB)
369       0x04,
370       0x00,
371       // Sniff Timeout (LSB, MSB)
372       0x01,
373       0x00};
374   emboss::SniffModeCommandView view = emboss::MakeSniffModeCommandView(&buffer);
375   EXPECT_EQ(view.header().opcode_enum().Read(), emboss::OpCode::SNIFF_MODE);
376   EXPECT_TRUE(view.header().IsComplete());
377   EXPECT_EQ(view.connection_handle().Read(), 0x0004);
378   EXPECT_EQ(view.sniff_max_interval().Read(), 0x0330);
379   EXPECT_EQ(view.sniff_min_interval().Read(), 0x0190);
380   EXPECT_EQ(view.sniff_attempt().Read(), 0x0004);
381   EXPECT_EQ(view.sniff_timeout().Read(), 0x0001);
382 }
383 
TEST(EmbossTest,ReadRfcomm)384 TEST(EmbossTest, ReadRfcomm) {
385   std::array<uint8_t,
386              emboss::RfcommFrame::MinSizeInBytes() + /*credits*/ 1 +
387                  /*payload*/ 3>
388       buffer_with_credits = {// Address
389                              0x19,
390                              // UIH Poll/Final
391                              0xFF,
392                              // Information Length
393                              0x07,
394                              // Credits
395                              0x0A,
396                              // Payload/Information
397                              0xAB,
398                              0xCD,
399                              0xEF,
400                              // FCS
401                              0x49};
402 
403   emboss::RfcommFrameView rfcomm =
404       emboss::MakeRfcommFrameView(&buffer_with_credits);
405   EXPECT_TRUE(rfcomm.Ok());
406   EXPECT_EQ(rfcomm.credits().Read(), 10);
407 
408   EXPECT_EQ(rfcomm.information()[0].Read(), 0xAB);
409   EXPECT_EQ(rfcomm.information()[1].Read(), 0xCD);
410   EXPECT_EQ(rfcomm.information()[2].Read(), 0xEF);
411 
412   EXPECT_EQ(rfcomm.fcs().Read(), 0x49);
413 
414   std::array<uint8_t,
415              emboss::RfcommFrame::MinSizeInBytes() +
416                  /*payload*/ 3>
417       buffer_without_credits = {// Address
418                                 0x19,
419                                 // UIH
420                                 0xEF,
421                                 // Information Length
422                                 0x07,
423                                 // Payload/Information
424                                 0xAB,
425                                 0xCD,
426                                 0xEF,
427                                 // FCS
428                                 0x55};
429 
430   rfcomm = emboss::MakeRfcommFrameView(&buffer_without_credits);
431   EXPECT_TRUE(rfcomm.Ok());
432   EXPECT_FALSE(rfcomm.has_credits().ValueOrDefault());
433   EXPECT_EQ(rfcomm.information()[0].Read(), 0xAB);
434   EXPECT_EQ(rfcomm.information()[1].Read(), 0xCD);
435   EXPECT_EQ(rfcomm.information()[2].Read(), 0xEF);
436   EXPECT_EQ(rfcomm.fcs().Read(), 0x55);
437 }
438 
TEST(EmbossTest,ReadRfcommExtended)439 TEST(EmbossTest, ReadRfcommExtended) {
440   constexpr size_t kMaxShortLength = 0x7f;
441   std::array<uint8_t,
442              emboss::RfcommFrame::MinSizeInBytes() + /*length_extended*/ 1 +
443                  /*credits*/ 1 +
444                  /*payload*/ (kMaxShortLength + 1)>
445       buffer_extended_length_with_credits = {
446           // Address
447           0x19,
448           // UIH Poll/Final
449           0xFF,
450           // Information Length
451           0x00,
452           0x01,
453           // Credits
454           0x0A,
455           // Payload/Information
456           0xAB,
457           0xCD,
458           0xEF,
459       };
460 
461   // FCS
462   buffer_extended_length_with_credits
463       [buffer_extended_length_with_credits.size() - 1] = 0x49;
464 
465   emboss::RfcommFrameView rfcomm =
466       emboss::MakeRfcommFrameView(&buffer_extended_length_with_credits);
467   EXPECT_TRUE(rfcomm.Ok());
468   EXPECT_TRUE(rfcomm.has_credits().ValueOrDefault());
469   EXPECT_TRUE(rfcomm.has_length_extended().ValueOrDefault());
470   EXPECT_EQ(rfcomm.information_length().Read(), 128);
471   EXPECT_EQ(rfcomm.information()[0].Read(), 0xAB);
472   EXPECT_EQ(rfcomm.information()[1].Read(), 0xCD);
473   EXPECT_EQ(rfcomm.information()[2].Read(), 0xEF);
474   EXPECT_EQ(rfcomm.fcs().Read(), 0x49);
475 }
476 
TEST(EmbossTest,WriteRfcomm)477 TEST(EmbossTest, WriteRfcomm) {
478   const std::array<uint8_t, 3> expected_payload = {0xAB, 0xCD, 0xEF};
479   constexpr size_t kFrameSize = emboss::RfcommFrame::MinSizeInBytes() +
480                                 /*credits*/ 1 + expected_payload.size();
481   std::array<uint8_t, kFrameSize> buffer{};
482 
483   emboss::RfcommFrameWriter rfcomm = emboss::MakeRfcommFrameView(&buffer);
484   rfcomm.extended_address().Write(true);
485   rfcomm.command_response_direction().Write(
486       emboss::RfcommCommandResponseAndDirection::COMMAND_FROM_RESPONDER);
487   rfcomm.channel().Write(3);
488   rfcomm.control().Write(
489       emboss::RfcommFrameType::
490           UNNUMBERED_INFORMATION_WITH_HEADER_CHECK_AND_POLL_FINAL);
491 
492   rfcomm.length_extended_flag().Write(emboss::RfcommLengthExtended::NORMAL);
493   rfcomm.length().Write(expected_payload.size());
494 
495   EXPECT_TRUE(rfcomm.has_credits().ValueOrDefault());
496   rfcomm.credits().Write(10);
497 
498   std::memcpy(rfcomm.information().BackingStorage().data(),
499               expected_payload.data(),
500               expected_payload.size());
501   rfcomm.fcs().Write(0x49);
502 
503   std::array<uint8_t, kFrameSize> expected{// Address
504                                            0x19,
505                                            // UIH Poll/Final
506                                            0xFF,
507                                            // Information Length
508                                            0x07,
509                                            // Credits
510                                            0x0A,
511                                            // Payload/Information
512                                            0xAB,
513                                            0xCD,
514                                            0xEF,
515                                            // FCS
516                                            0x49};
517   EXPECT_EQ(buffer, expected);
518 }
519 
TEST(EmbossTest,WriteRfcommExtended)520 TEST(EmbossTest, WriteRfcommExtended) {
521   const std::array<uint8_t, 128> expected_payload = {0xAB, 0xCD, 0xEF};
522   constexpr size_t kFrameSize = emboss::RfcommFrame::MinSizeInBytes() +
523                                 /* length_extended */ 1 +
524                                 /*credits*/ 1 + expected_payload.size();
525   std::array<uint8_t, kFrameSize> buffer{};
526 
527   emboss::RfcommFrameWriter rfcomm = emboss::MakeRfcommFrameView(&buffer);
528   rfcomm.extended_address().Write(true);
529   rfcomm.command_response_direction().Write(
530       emboss::RfcommCommandResponseAndDirection::COMMAND_FROM_RESPONDER);
531   rfcomm.channel().Write(3);
532   rfcomm.control().Write(
533       emboss::RfcommFrameType::
534           UNNUMBERED_INFORMATION_WITH_HEADER_CHECK_AND_POLL_FINAL);
535 
536   rfcomm.length_extended_flag().Write(emboss::RfcommLengthExtended::EXTENDED);
537   rfcomm.length_extended().Write(expected_payload.size());
538 
539   EXPECT_TRUE(rfcomm.has_credits().ValueOrDefault());
540   rfcomm.credits().Write(10);
541 
542   std::memcpy(rfcomm.information().BackingStorage().data(),
543               expected_payload.data(),
544               expected_payload.size());
545   rfcomm.fcs().Write(0x49);
546 
547   std::array<uint8_t, kFrameSize> expected{
548       // Address
549       0x19,
550       // UIH Poll/Final
551       0xFF,
552       // Information Length
553       0x00,
554       0x01,
555       // Credits
556       0x0A,
557       // Payload/Information
558       0xAB,
559       0xCD,
560       0xEF,
561   };
562   // FCS
563   expected[expected.size() - 1] = 0x49;
564 
565   EXPECT_EQ(expected[2], buffer[2]);
566   EXPECT_EQ(expected[3], buffer[3]);
567 
568   EXPECT_EQ(buffer, expected);
569 }
570 
571 }  // namespace
572 }  // namespace pw::bluetooth
573