1 // Copyright 2021 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 #include "pw_bluetooth_hci/packet.h"
15
16 #include "pw_bytes/byte_builder.h"
17 #include "pw_bytes/endian.h"
18 #include "pw_status/try.h"
19
20 namespace pw::bluetooth_hci {
21 namespace {
22
23 using pw::bytes::ReadInOrder;
24
25 } // namespace
26
Encode(ByteSpan buffer,endian order) const27 Result<ConstByteSpan> CommandPacket::Encode(ByteSpan buffer,
28 endian order) const {
29 ByteBuilder builder(buffer);
30 builder.PutUint16(opcode_, order);
31 builder.PutUint8(parameters_.size_bytes());
32 builder.append(parameters_);
33 PW_TRY(builder.status());
34 return ConstByteSpan(builder.data(), builder.size());
35 }
36
Decode(ConstByteSpan data,endian order)37 std::optional<CommandPacket> CommandPacket::Decode(ConstByteSpan data,
38 endian order) {
39 if (data.size_bytes() < kHeaderSizeBytes) {
40 return std::nullopt; // Not enough data to parse the packet header.
41 }
42
43 const uint8_t parameter_total_length =
44 static_cast<uint8_t>(data[kParameterTotalLengthByteOffset]);
45 if (data.size_bytes() < (kHeaderSizeBytes + parameter_total_length)) {
46 return std::nullopt; // Not enough data to cover the parameter bytes.
47 }
48
49 const uint16_t opcode =
50 ReadInOrder<uint16_t>(order, &data[kOpcodeByteOffset]);
51 return CommandPacket(opcode,
52 data.subspan(kHeaderSizeBytes, parameter_total_length));
53 }
54
Encode(ByteSpan buffer,endian order) const55 Result<ConstByteSpan> AsyncDataPacket::Encode(ByteSpan buffer,
56 endian order) const {
57 ByteBuilder builder(buffer);
58 builder.PutUint16(handle_and_fragmentation_bits_, order);
59 builder.PutUint16(data_.size_bytes(), order);
60 builder.append(data_);
61 PW_TRY(builder.status());
62 return ConstByteSpan(builder.data(), builder.size());
63 }
64
Decode(ConstByteSpan data,endian order)65 std::optional<AsyncDataPacket> AsyncDataPacket::Decode(ConstByteSpan data,
66 endian order) {
67 if (data.size_bytes() < kHeaderSizeBytes) {
68 return std::nullopt; // Not enough data to parse the packet header.
69 }
70
71 const uint16_t data_total_length =
72 ReadInOrder<uint16_t>(order, &data[kDataTotalLengthByteOffset]);
73 if (data.size_bytes() < (kHeaderSizeBytes + data_total_length)) {
74 return std::nullopt; // Not enough data to cover the data bytes.
75 }
76
77 const uint16_t handle_and_flag_bits = ReadInOrder<uint16_t>(
78 order, &data[kHandleAndFragmentationBitsByteOffset]);
79 return AsyncDataPacket(handle_and_flag_bits,
80 data.subspan(kHeaderSizeBytes, data_total_length));
81 }
82
Encode(ByteSpan buffer,endian order) const83 Result<ConstByteSpan> SyncDataPacket::Encode(ByteSpan buffer,
84 endian order) const {
85 ByteBuilder builder(buffer);
86 builder.PutUint16(handle_and_status_bits_, order);
87 builder.PutUint8(data_.size_bytes());
88 builder.append(data_);
89 PW_TRY(builder.status());
90 return ConstByteSpan(builder.data(), builder.size());
91 }
92
Decode(ConstByteSpan data,endian order)93 std::optional<SyncDataPacket> SyncDataPacket::Decode(ConstByteSpan data,
94 endian order) {
95 if (data.size_bytes() < kHeaderSizeBytes) {
96 return std::nullopt; // Not enough data to parse the packet header.
97 }
98
99 const uint8_t data_total_length =
100 static_cast<uint8_t>(data[kDataTotalLengthByteOffset]);
101 if (data.size_bytes() < (kHeaderSizeBytes + data_total_length)) {
102 return std::nullopt; // Not enough data to cover the data bytes.
103 }
104
105 const uint16_t handle_and_status_bits =
106 ReadInOrder<uint16_t>(order, &data[kHandleAndStatusBitsByteOffset]);
107 return SyncDataPacket(handle_and_status_bits,
108 data.subspan(kHeaderSizeBytes, data_total_length));
109 }
110
Encode(ByteSpan buffer) const111 Result<ConstByteSpan> EventPacket::Encode(ByteSpan buffer) const {
112 ByteBuilder builder(buffer);
113 builder.PutUint8(event_code_);
114 builder.PutUint8(parameters_.size_bytes());
115 builder.append(parameters_);
116 PW_TRY(builder.status());
117 return ConstByteSpan(builder.data(), builder.size());
118 }
119
Decode(ConstByteSpan data)120 std::optional<EventPacket> EventPacket::Decode(ConstByteSpan data) {
121 if (data.size_bytes() < kHeaderSizeBytes) {
122 return std::nullopt; // Not enough data to parse the packet header.
123 }
124
125 const uint8_t parameter_total_length =
126 static_cast<uint8_t>(data[kParameterTotalLengthByteOffset]);
127 if (data.size_bytes() < (kHeaderSizeBytes + parameter_total_length)) {
128 return std::nullopt; // Not enough data to cover the parameter bytes.
129 }
130
131 const uint8_t event_code = static_cast<uint8_t>(data[kEventCodeByteOffset]);
132 return EventPacket(event_code,
133 data.subspan(kHeaderSizeBytes, parameter_total_length));
134 }
135
136 } // namespace pw::bluetooth_hci
137