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