Coverage Report

Created: 2025-06-13 06:31

/proc/self/cwd/pw_bluetooth_hci/packet.cc
Line
Count
Source (jump to first uncovered line)
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
27
Result<ConstByteSpan> CommandPacket::Encode(ByteSpan buffer,
28
0
                                            endian order) const {
29
0
  ByteBuilder builder(buffer);
30
0
  builder.PutUint16(opcode_, order);
31
0
  builder.PutUint8(parameters_.size_bytes());
32
0
  builder.append(parameters_);
33
0
  PW_TRY(builder.status());
34
0
  return ConstByteSpan(builder.data(), builder.size());
35
0
}
36
37
std::optional<CommandPacket> CommandPacket::Decode(ConstByteSpan data,
38
1.93k
                                                   endian order) {
39
1.93k
  if (data.size_bytes() < kHeaderSizeBytes) {
40
11
    return std::nullopt;  // Not enough data to parse the packet header.
41
11
  }
42
43
1.92k
  const uint8_t parameter_total_length =
44
1.92k
      static_cast<uint8_t>(data[kParameterTotalLengthByteOffset]);
45
1.92k
  if (data.size_bytes() < (kHeaderSizeBytes + parameter_total_length)) {
46
15
    return std::nullopt;  // Not enough data to cover the parameter bytes.
47
15
  }
48
49
1.91k
  const uint16_t opcode =
50
1.91k
      ReadInOrder<uint16_t>(order, &data[kOpcodeByteOffset]);
51
1.91k
  return CommandPacket(opcode,
52
1.91k
                       data.subspan(kHeaderSizeBytes, parameter_total_length));
53
1.92k
}
54
55
Result<ConstByteSpan> AsyncDataPacket::Encode(ByteSpan buffer,
56
0
                                              endian order) const {
57
0
  ByteBuilder builder(buffer);
58
0
  builder.PutUint16(handle_and_fragmentation_bits_, order);
59
0
  builder.PutUint16(data_.size_bytes(), order);
60
0
  builder.append(data_);
61
0
  PW_TRY(builder.status());
62
0
  return ConstByteSpan(builder.data(), builder.size());
63
0
}
64
65
std::optional<AsyncDataPacket> AsyncDataPacket::Decode(ConstByteSpan data,
66
1.13k
                                                       endian order) {
67
1.13k
  if (data.size_bytes() < kHeaderSizeBytes) {
68
10
    return std::nullopt;  // Not enough data to parse the packet header.
69
10
  }
70
71
1.12k
  const uint16_t data_total_length =
72
1.12k
      ReadInOrder<uint16_t>(order, &data[kDataTotalLengthByteOffset]);
73
1.12k
  if (data.size_bytes() < (kHeaderSizeBytes + data_total_length)) {
74
45
    return std::nullopt;  // Not enough data to cover the data bytes.
75
45
  }
76
77
1.08k
  const uint16_t handle_and_flag_bits = ReadInOrder<uint16_t>(
78
1.08k
      order, &data[kHandleAndFragmentationBitsByteOffset]);
79
1.08k
  return AsyncDataPacket(handle_and_flag_bits,
80
1.08k
                         data.subspan(kHeaderSizeBytes, data_total_length));
81
1.12k
}
82
83
Result<ConstByteSpan> SyncDataPacket::Encode(ByteSpan buffer,
84
0
                                             endian order) const {
85
0
  ByteBuilder builder(buffer);
86
0
  builder.PutUint16(handle_and_status_bits_, order);
87
0
  builder.PutUint8(data_.size_bytes());
88
0
  builder.append(data_);
89
0
  PW_TRY(builder.status());
90
0
  return ConstByteSpan(builder.data(), builder.size());
91
0
}
92
93
std::optional<SyncDataPacket> SyncDataPacket::Decode(ConstByteSpan data,
94
1.55k
                                                     endian order) {
95
1.55k
  if (data.size_bytes() < kHeaderSizeBytes) {
96
10
    return std::nullopt;  // Not enough data to parse the packet header.
97
10
  }
98
99
1.54k
  const uint8_t data_total_length =
100
1.54k
      static_cast<uint8_t>(data[kDataTotalLengthByteOffset]);
101
1.54k
  if (data.size_bytes() < (kHeaderSizeBytes + data_total_length)) {
102
15
    return std::nullopt;  // Not enough data to cover the data bytes.
103
15
  }
104
105
1.52k
  const uint16_t handle_and_status_bits =
106
1.52k
      ReadInOrder<uint16_t>(order, &data[kHandleAndStatusBitsByteOffset]);
107
1.52k
  return SyncDataPacket(handle_and_status_bits,
108
1.52k
                        data.subspan(kHeaderSizeBytes, data_total_length));
109
1.54k
}
110
111
0
Result<ConstByteSpan> EventPacket::Encode(ByteSpan buffer) const {
112
0
  ByteBuilder builder(buffer);
113
0
  builder.PutUint8(event_code_);
114
0
  builder.PutUint8(parameters_.size_bytes());
115
0
  builder.append(parameters_);
116
0
  PW_TRY(builder.status());
117
0
  return ConstByteSpan(builder.data(), builder.size());
118
0
}
119
120
1.22k
std::optional<EventPacket> EventPacket::Decode(ConstByteSpan data) {
121
1.22k
  if (data.size_bytes() < kHeaderSizeBytes) {
122
9
    return std::nullopt;  // Not enough data to parse the packet header.
123
9
  }
124
125
1.21k
  const uint8_t parameter_total_length =
126
1.21k
      static_cast<uint8_t>(data[kParameterTotalLengthByteOffset]);
127
1.21k
  if (data.size_bytes() < (kHeaderSizeBytes + parameter_total_length)) {
128
12
    return std::nullopt;  // Not enough data to cover the parameter bytes.
129
12
  }
130
131
1.20k
  const uint8_t event_code = static_cast<uint8_t>(data[kEventCodeByteOffset]);
132
1.20k
  return EventPacket(event_code,
133
1.20k
                     data.subspan(kHeaderSizeBytes, parameter_total_length));
134
1.21k
}
135
136
}  // namespace pw::bluetooth_hci