xref: /aosp_15_r20/external/pigweed/pw_bluetooth_hci/uart_transport.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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/uart_transport.h"
15 
16 namespace pw::bluetooth_hci {
17 
DecodeHciUartData(ConstByteSpan data,const DecodedPacketCallback & packet_callback)18 StatusWithSize 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, 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, 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, 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
99