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/hci_commands.emb.h" // IWYU pragma: keep
24 #include "pw_bluetooth/hci_common.emb.h"
25 #include "pw_bluetooth/hci_data.emb.h"
26 #include "pw_bluetooth/hci_events.emb.h" // IWYU pragma: keep
27 #include "pw_bluetooth/hci_h4.emb.h" // IWYU pragma: keep
28 #include "pw_bluetooth/hci_test.emb.h"
29 #include "pw_bluetooth/hci_android.emb.h" // IWYU pragma: keep
30 #include "pw_bluetooth/l2cap_frames.emb.h" // IWYU pragma: keep
31 // clang-format on
32
33 namespace pw::bluetooth {
34 namespace {
35
36 // Examples are used in docs.rst.
TEST(EmbossExamples,MakeView)37 TEST(EmbossExamples, MakeView) {
38 // DOCSTAG: [pw_bluetooth-examples-make_view]
39 std::array<uint8_t, 4> buffer = {0x00, 0x01, 0x02, 0x03};
40 auto view = emboss::MakeTestCommandPacketView(&buffer);
41 EXPECT_TRUE(view.IsComplete());
42 EXPECT_EQ(view.payload().Read(), 0x03);
43 // DOCSTAG: [pw_bluetooth-examples-make_view]
44 }
45
TEST(EmbossTest,MakeView)46 TEST(EmbossTest, MakeView) {
47 std::array<uint8_t, 4> buffer = {0x00, 0x01, 0x02, 0x03};
48 auto view = emboss::MakeTestCommandPacketView(&buffer);
49 EXPECT_TRUE(view.IsComplete());
50 EXPECT_EQ(view.payload().Read(), 0x03);
51 }
52
53 // This definition has a mix of full-width values and bitfields and includes
54 // conditional bitfields. Let's add this to verify that the structure itself
55 // doesn't get changed incorrectly and that emboss' size calculation matches
56 // ours.
TEST(EmbossTest,CheckIsoHeaderSize)57 TEST(EmbossTest, CheckIsoHeaderSize) {
58 EXPECT_EQ(emboss::IsoDataFrameHeader::MaxSizeInBytes(), 12);
59 }
60
61 // Test and demonstrate various ways of reading opcodes.
TEST(EmbossTest,ReadOpcodesFromCommandHeader)62 TEST(EmbossTest, ReadOpcodesFromCommandHeader) {
63 // First two bytes will be used as opcode.
64 std::array<uint8_t, 4> buffer = {0x00, 0x00, 0x02, 0x03};
65 auto view = emboss::MakeTestCommandPacketView(&buffer);
66 EXPECT_TRUE(view.IsComplete());
67 auto header = view.header();
68
69 EXPECT_EQ(header.opcode_enum().Read(), emboss::OpCode::UNSPECIFIED);
70 EXPECT_EQ(header.opcode().BackingStorage().ReadUInt(), 0x0000);
71 EXPECT_EQ(header.opcode_bits().ogf().Read(), 0x00);
72 EXPECT_EQ(header.opcode_bits().ocf().Read(), 0x00);
73 // TODO: https://pwbug.dev/338068316 - Delete these opcode type
74 // OpCodeBits cases once opcode has type OpCode.
75 EXPECT_EQ(header.opcode().ogf().Read(), 0x00);
76 EXPECT_EQ(header.opcode().ocf().Read(), 0x00);
77
78 // LINK_KEY_REQUEST_REPLY is OGF 0x01 and OCF 0x0B.
79 header.opcode_enum().Write(emboss::OpCode::LINK_KEY_REQUEST_REPLY);
80 EXPECT_EQ(header.opcode_enum().Read(),
81 emboss::OpCode::LINK_KEY_REQUEST_REPLY);
82 EXPECT_EQ(header.opcode().BackingStorage().ReadUInt(), 0x040B);
83 EXPECT_EQ(header.opcode_bits().ogf().Read(), 0x01);
84 EXPECT_EQ(header.opcode_bits().ocf().Read(), 0x0B);
85 // TODO: https://pwbug.dev/338068316 - Delete these opcode type
86 // OpCodeBits cases once opcode has type OpCode.
87 EXPECT_EQ(header.opcode().ogf().Read(), 0x01);
88 EXPECT_EQ(header.opcode().ocf().Read(), 0x0B);
89 }
90
91 // Test and demonstrate various ways of writing opcodes.
TEST(EmbossTest,WriteOpcodesFromCommandHeader)92 TEST(EmbossTest, WriteOpcodesFromCommandHeader) {
93 std::array<uint8_t, 4> buffer = {};
94 buffer.fill(0xFF);
95 auto view = emboss::MakeTestCommandPacketView(&buffer);
96 EXPECT_TRUE(view.IsComplete());
97 auto header = view.header();
98
99 header.opcode_enum().Write(emboss::OpCode::UNSPECIFIED);
100 EXPECT_EQ(header.opcode().BackingStorage().ReadUInt(), 0x0000);
101
102 header.opcode().ocf().Write(0x0B);
103 EXPECT_EQ(header.opcode().BackingStorage().ReadUInt(), 0x000B);
104
105 header.opcode().ogf().Write(0x01);
106 EXPECT_EQ(header.opcode().BackingStorage().ReadUInt(), 0x040B);
107 // LINK_KEY_REQUEST_REPLY is OGF 0x01 and OCF 0x0B.
108 EXPECT_EQ(header.opcode_enum().Read(),
109 emboss::OpCode::LINK_KEY_REQUEST_REPLY);
110 }
111
112 // Test and demonstrate using to_underlying with OpCodes enums
TEST(EmbossTest,OPCodeEnumsWithToUnderlying)113 TEST(EmbossTest, OPCodeEnumsWithToUnderlying) {
114 EXPECT_EQ(0x0000, cpp23::to_underlying(emboss::OpCode::UNSPECIFIED));
115 }
116
TEST(EmbossTest,ReadAndWriteOpcodesInCommandResponseHeader)117 TEST(EmbossTest, ReadAndWriteOpcodesInCommandResponseHeader) {
118 // First two bytes will be used as opcode.
119 std::array<uint8_t,
120 emboss::ReadBufferSizeCommandCompleteEventView::SizeInBytes()>
121 buffer;
122 std::iota(buffer.begin(), buffer.end(), 100);
123 auto view = emboss::MakeReadBufferSizeCommandCompleteEventView(&buffer);
124 EXPECT_TRUE(view.IsComplete());
125 auto header = view.command_complete();
126
127 header.command_opcode().BackingStorage().WriteUInt(0x0000);
128 EXPECT_EQ(header.command_opcode_enum().Read(), emboss::OpCode::UNSPECIFIED);
129 EXPECT_EQ(header.command_opcode().BackingStorage().ReadUInt(), 0x0000);
130 EXPECT_EQ(header.command_opcode_bits().ogf().Read(), 0x00);
131 EXPECT_EQ(header.command_opcode_bits().ocf().Read(), 0x00);
132 // TODO: https://pwbug.dev/338068316 - Delete these command_opcode type
133 // OpCodeBits cases once command_opcode has type OpCode.
134 EXPECT_EQ(header.command_opcode().ogf().Read(), 0x00);
135 EXPECT_EQ(header.command_opcode().ocf().Read(), 0x00);
136
137 // LINK_KEY_REQUEST_REPLY is OGF 0x01 and OCF 0x0B.
138 header.command_opcode_enum().Write(emboss::OpCode::LINK_KEY_REQUEST_REPLY);
139 EXPECT_EQ(header.command_opcode_enum().Read(),
140 emboss::OpCode::LINK_KEY_REQUEST_REPLY);
141 EXPECT_EQ(header.command_opcode().BackingStorage().ReadUInt(), 0x040B);
142 EXPECT_EQ(header.command_opcode_bits().ogf().Read(), 0x01);
143 EXPECT_EQ(header.command_opcode_bits().ocf().Read(), 0x0B);
144 // TODO: https://pwbug.dev/338068316 - Delete these command_opcode type
145 // OpCodeBits cases once command_opcode has type OpCode.
146 EXPECT_EQ(header.command_opcode().ogf().Read(), 0x01);
147 EXPECT_EQ(header.command_opcode().ocf().Read(), 0x0B);
148 }
149
TEST(EmbossTest,ReadAndWriteEventCodesInEventHeader)150 TEST(EmbossTest, ReadAndWriteEventCodesInEventHeader) {
151 std::array<uint8_t, emboss::EventHeaderWriter::SizeInBytes()> buffer;
152 std::iota(buffer.begin(), buffer.end(), 100);
153 auto header = emboss::MakeEventHeaderView(&buffer);
154 EXPECT_TRUE(header.IsComplete());
155
156 header.event_code_uint().Write(
157 cpp23::to_underlying(emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS));
158 EXPECT_EQ(header.event_code_enum().Read(),
159 emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS);
160 EXPECT_EQ(
161 header.event_code_uint().Read(),
162 cpp23::to_underlying(emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS));
163
164 // TODO: https://pwbug.dev/338068316 - Delete these event_code type
165 // UInt cases once event_code has type EventCode.
166 EXPECT_EQ(
167 header.event_code().Read(),
168 cpp23::to_underlying(emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS));
169
170 header.event_code().Write(
171 cpp23::to_underlying(emboss::EventCode::CONNECTION_REQUEST));
172 EXPECT_EQ(header.event_code_uint().Read(),
173 cpp23::to_underlying(emboss::EventCode::CONNECTION_REQUEST));
174 }
175
176 } // namespace
177 } // namespace pw::bluetooth
178