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