blob: d62e3005eaca124c25616c9ec4573d99a368d05e [file] [log] [blame]
Ewout van Bekkum1c7c83f2021-08-05 11:13:44 -07001// 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/uart_transport.h"
15
16namespace pw::bluetooth_hci {
17
18StatusWithSize DecodeHciUartData(ConstByteSpan data,
19 const DecodedPacketCallback& packet_callback) {
20 size_t bytes_consumed = 0;
21 while (data.size_bytes() > 0) {
22 const std::byte packet_indicator = data[0];
23 data = data.subspan(1); // Pop off the packet indicator byte.
24 // Note that we do not yet claim the byte consumed until we know what it is,
25 // as it may be a partial HCI packet which cannot be consumed until later.
26
27 size_t packet_size_bytes = 0;
28 switch (packet_indicator) {
29 case kUartCommandPacketIndicator: {
30 const std::optional<CommandPacket> maybe_packet =
31 CommandPacket::Decode(data, std::endian::little);
32 if (!maybe_packet.has_value()) {
33 return StatusWithSize(
34 bytes_consumed); // Not enough data to complete this packet.
35 }
36
37 const CommandPacket& packet = maybe_packet.value();
38 packet_callback(packet);
39 packet_size_bytes = packet.size_bytes();
40 break;
41 }
42
43 case kUartAsyncDataPacketIndicator: {
44 const std::optional<AsyncDataPacket> maybe_packet =
45 AsyncDataPacket::Decode(data, std::endian::little);
46 if (!maybe_packet.has_value()) {
47 return StatusWithSize(
48 bytes_consumed); // Not enough data to complete this packet.
49 }
50
51 const AsyncDataPacket& packet = maybe_packet.value();
52 packet_callback(packet);
53 packet_size_bytes = packet.size_bytes();
54 break;
55 }
56
57 case kUartSyncDataPacketIndicator: {
58 const std::optional<SyncDataPacket> maybe_packet =
59 SyncDataPacket::Decode(data, std::endian::little);
60 if (!maybe_packet.has_value()) {
61 return StatusWithSize(
62 bytes_consumed); // Not enough data to complete this packet.
63 }
64
65 const SyncDataPacket& packet = maybe_packet.value();
66 packet_callback(packet);
67 packet_size_bytes = packet.size_bytes();
68 break;
69 }
70
71 case kUartEventPacketIndicator: {
72 const std::optional<EventPacket> maybe_packet =
73 EventPacket::Decode(data);
74 if (!maybe_packet.has_value()) {
75 return StatusWithSize(
76 bytes_consumed); // Not enough data to complete this packet.
77 }
78
79 const EventPacket& packet = maybe_packet.value();
80 packet_callback(packet);
81 packet_size_bytes = packet.size_bytes();
82 break;
83 }
84
85 default:
86 // Unrecognized PacketIndicator type, we've lost synchronization!
87 ++bytes_consumed; // Consume the invalid packet indicator.
88 return StatusWithSize::DataLoss(bytes_consumed);
89 }
90
91 data = data.subspan(packet_size_bytes); // Pop off the HCI packet.
92 // Consume the packet indicator and the packet.
93 bytes_consumed += 1 + packet_size_bytes;
94 }
95 return StatusWithSize(bytes_consumed);
96}
97
98} // namespace pw::bluetooth_hci