410 lines
15 KiB
C++
410 lines
15 KiB
C++
// Copyright 2021 The Pigweed Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
// use this file except in compliance with the License. You may obtain a copy of
|
|
// the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
// License for the specific language governing permissions and limitations under
|
|
// the License.
|
|
|
|
#include "pw_bluetooth_hci/uart_transport.h"
|
|
|
|
#include "gtest/gtest.h"
|
|
#include "pw_bluetooth_hci/packet.h"
|
|
#include "pw_bytes/byte_builder.h"
|
|
#include "pw_status/status.h"
|
|
|
|
namespace pw::bluetooth_hci {
|
|
namespace {
|
|
|
|
class UartTransportTest : public ::testing::Test {
|
|
protected:
|
|
constexpr static std::byte kInvalidPacketIndicator = std::byte{0x0};
|
|
static_assert(kInvalidPacketIndicator != kUartCommandPacketIndicator);
|
|
static_assert(kInvalidPacketIndicator != kUartAsyncDataPacketIndicator);
|
|
static_assert(kInvalidPacketIndicator != kUartSyncDataPacketIndicator);
|
|
static_assert(kInvalidPacketIndicator != kUartEventPacketIndicator);
|
|
|
|
constexpr static size_t kUartBufferSizeBytes = 256;
|
|
ByteBuffer<kUartBufferSizeBytes> uart_buffer_;
|
|
};
|
|
|
|
TEST_F(UartTransportTest, EmptyBuffer) {
|
|
const StatusWithSize status_with_size =
|
|
DecodeHciUartData(ConstByteSpan(), [](const Packet&) { FAIL(); });
|
|
EXPECT_EQ(status_with_size.status(), OkStatus());
|
|
EXPECT_EQ(status_with_size.size(), 0u);
|
|
}
|
|
|
|
TEST_F(UartTransportTest, InvalidPacketIndicator) {
|
|
uart_buffer_.push_back(kInvalidPacketIndicator);
|
|
ASSERT_EQ(uart_buffer_.status(), OkStatus());
|
|
|
|
const StatusWithSize status_with_size =
|
|
DecodeHciUartData(uart_buffer_, [](const Packet&) { FAIL(); });
|
|
EXPECT_EQ(status_with_size.status(), Status::DataLoss());
|
|
EXPECT_EQ(status_with_size.size(), 1u);
|
|
}
|
|
|
|
TEST_F(UartTransportTest, CommandPacketIndicatorOnly) {
|
|
uart_buffer_.push_back(kUartCommandPacketIndicator);
|
|
ASSERT_EQ(uart_buffer_.status(), OkStatus());
|
|
|
|
const StatusWithSize status_with_size =
|
|
DecodeHciUartData(uart_buffer_, [](const Packet&) { FAIL(); });
|
|
EXPECT_EQ(status_with_size.status(), OkStatus());
|
|
EXPECT_EQ(status_with_size.size(), 0u);
|
|
}
|
|
|
|
TEST_F(UartTransportTest, CommandPacketPartialPacket) {
|
|
uart_buffer_.push_back(kUartCommandPacketIndicator);
|
|
|
|
std::array<std::byte, CommandPacket::kHeaderSizeBytes> packet_buffer;
|
|
CommandPacket packet(0u, ConstByteSpan());
|
|
const Result<ConstByteSpan> result = packet.Encode(packet_buffer);
|
|
ASSERT_EQ(result.status(), OkStatus());
|
|
|
|
uart_buffer_.append(result.value().first(result.value().size_bytes() - 1));
|
|
ASSERT_EQ(uart_buffer_.status(), OkStatus());
|
|
|
|
const StatusWithSize status_with_size =
|
|
DecodeHciUartData(uart_buffer_, [](const Packet&) { FAIL(); });
|
|
EXPECT_EQ(status_with_size.status(), OkStatus());
|
|
EXPECT_EQ(status_with_size.size(), 0u);
|
|
}
|
|
|
|
TEST_F(UartTransportTest, CommandPacket) {
|
|
uart_buffer_.push_back(kUartCommandPacketIndicator);
|
|
|
|
std::array<std::byte, CommandPacket::kHeaderSizeBytes> packet_buffer;
|
|
CommandPacket packet(0u, ConstByteSpan());
|
|
const Result<ConstByteSpan> result = packet.Encode(packet_buffer);
|
|
ASSERT_EQ(result.status(), OkStatus());
|
|
|
|
uart_buffer_.append(result.value());
|
|
ASSERT_EQ(uart_buffer_.status(), OkStatus());
|
|
|
|
size_t command_packet_count = 0;
|
|
const StatusWithSize status_with_size =
|
|
DecodeHciUartData(uart_buffer_, [&](const Packet& decoded_packet) {
|
|
ASSERT_EQ(decoded_packet.type(), Packet::Type::kCommandPacket);
|
|
++command_packet_count;
|
|
});
|
|
EXPECT_EQ(status_with_size.status(), OkStatus());
|
|
EXPECT_EQ(status_with_size.size(), uart_buffer_.size());
|
|
EXPECT_EQ(command_packet_count, 1u);
|
|
}
|
|
|
|
TEST_F(UartTransportTest, AsyncDataPacketIndicatorOnly) {
|
|
uart_buffer_.push_back(kUartAsyncDataPacketIndicator);
|
|
ASSERT_EQ(uart_buffer_.status(), OkStatus());
|
|
|
|
const StatusWithSize status_with_size =
|
|
DecodeHciUartData(uart_buffer_, [](const Packet&) { FAIL(); });
|
|
EXPECT_EQ(status_with_size.status(), OkStatus());
|
|
EXPECT_EQ(status_with_size.size(), 0u);
|
|
}
|
|
|
|
TEST_F(UartTransportTest, AsyncDataPacketPartialPacket) {
|
|
uart_buffer_.push_back(kUartAsyncDataPacketIndicator);
|
|
|
|
std::array<std::byte, AsyncDataPacket::kHeaderSizeBytes> packet_buffer;
|
|
AsyncDataPacket packet(0u, ConstByteSpan());
|
|
const Result<ConstByteSpan> result = packet.Encode(packet_buffer);
|
|
ASSERT_EQ(result.status(), OkStatus());
|
|
|
|
uart_buffer_.append(result.value().first(result.value().size_bytes() - 1));
|
|
ASSERT_EQ(uart_buffer_.status(), OkStatus());
|
|
|
|
const StatusWithSize status_with_size =
|
|
DecodeHciUartData(uart_buffer_, [](const Packet&) { FAIL(); });
|
|
EXPECT_EQ(status_with_size.status(), OkStatus());
|
|
EXPECT_EQ(status_with_size.size(), 0u);
|
|
}
|
|
|
|
TEST_F(UartTransportTest, AsyncDataPacket) {
|
|
uart_buffer_.push_back(kUartAsyncDataPacketIndicator);
|
|
|
|
std::array<std::byte, AsyncDataPacket::kHeaderSizeBytes> packet_buffer;
|
|
AsyncDataPacket packet(0u, ConstByteSpan());
|
|
const Result<ConstByteSpan> result = packet.Encode(packet_buffer);
|
|
ASSERT_EQ(result.status(), OkStatus());
|
|
|
|
uart_buffer_.append(result.value());
|
|
ASSERT_EQ(uart_buffer_.status(), OkStatus());
|
|
|
|
size_t async_data_packet_count = 0;
|
|
const StatusWithSize status_with_size =
|
|
DecodeHciUartData(uart_buffer_, [&](const Packet& decoded_packet) {
|
|
ASSERT_EQ(decoded_packet.type(), Packet::Type::kAsyncDataPacket);
|
|
++async_data_packet_count;
|
|
});
|
|
EXPECT_EQ(status_with_size.status(), OkStatus());
|
|
EXPECT_EQ(status_with_size.size(), uart_buffer_.size());
|
|
EXPECT_EQ(async_data_packet_count, 1u);
|
|
}
|
|
|
|
TEST_F(UartTransportTest, SyncDataPacketIndicatorOnly) {
|
|
uart_buffer_.push_back(kUartSyncDataPacketIndicator);
|
|
ASSERT_EQ(uart_buffer_.status(), OkStatus());
|
|
|
|
const StatusWithSize status_with_size =
|
|
DecodeHciUartData(uart_buffer_, [](const Packet&) { FAIL(); });
|
|
EXPECT_EQ(status_with_size.status(), OkStatus());
|
|
EXPECT_EQ(status_with_size.size(), 0u);
|
|
}
|
|
|
|
TEST_F(UartTransportTest, SyncDataPacketPartialPacket) {
|
|
uart_buffer_.push_back(kUartSyncDataPacketIndicator);
|
|
|
|
std::array<std::byte, SyncDataPacket::kHeaderSizeBytes> packet_buffer;
|
|
SyncDataPacket packet(0u, ConstByteSpan());
|
|
const Result<ConstByteSpan> result = packet.Encode(packet_buffer);
|
|
ASSERT_EQ(result.status(), OkStatus());
|
|
|
|
uart_buffer_.append(result.value().first(result.value().size_bytes() - 1));
|
|
ASSERT_EQ(uart_buffer_.status(), OkStatus());
|
|
|
|
const StatusWithSize status_with_size =
|
|
DecodeHciUartData(uart_buffer_, [](const Packet&) { FAIL(); });
|
|
EXPECT_EQ(status_with_size.status(), OkStatus());
|
|
EXPECT_EQ(status_with_size.size(), 0u);
|
|
}
|
|
|
|
TEST_F(UartTransportTest, SyncDataPacket) {
|
|
uart_buffer_.push_back(kUartSyncDataPacketIndicator);
|
|
|
|
std::array<std::byte, SyncDataPacket::kHeaderSizeBytes> packet_buffer;
|
|
SyncDataPacket packet(0u, ConstByteSpan());
|
|
const Result<ConstByteSpan> result = packet.Encode(packet_buffer);
|
|
ASSERT_EQ(result.status(), OkStatus());
|
|
|
|
uart_buffer_.append(result.value());
|
|
ASSERT_EQ(uart_buffer_.status(), OkStatus());
|
|
|
|
size_t sync_data_packet_count = 0;
|
|
const StatusWithSize status_with_size =
|
|
DecodeHciUartData(uart_buffer_, [&](const Packet& decoded_packet) {
|
|
ASSERT_EQ(decoded_packet.type(), Packet::Type::kSyncDataPacket);
|
|
++sync_data_packet_count;
|
|
});
|
|
EXPECT_EQ(status_with_size.status(), OkStatus());
|
|
EXPECT_EQ(status_with_size.size(), uart_buffer_.size());
|
|
EXPECT_EQ(sync_data_packet_count, 1u);
|
|
}
|
|
|
|
TEST_F(UartTransportTest, EventPacketIndicatorOnly) {
|
|
uart_buffer_.push_back(kUartEventPacketIndicator);
|
|
ASSERT_EQ(uart_buffer_.status(), OkStatus());
|
|
|
|
const StatusWithSize status_with_size =
|
|
DecodeHciUartData(uart_buffer_, [](const Packet&) { FAIL(); });
|
|
EXPECT_EQ(status_with_size.status(), OkStatus());
|
|
EXPECT_EQ(status_with_size.size(), 0u);
|
|
}
|
|
|
|
TEST_F(UartTransportTest, EventPacketPartialPacket) {
|
|
uart_buffer_.push_back(kUartEventPacketIndicator);
|
|
|
|
std::array<std::byte, EventPacket::kHeaderSizeBytes> packet_buffer;
|
|
EventPacket packet(0u, ConstByteSpan());
|
|
const Result<ConstByteSpan> result = packet.Encode(packet_buffer);
|
|
ASSERT_EQ(result.status(), OkStatus());
|
|
|
|
uart_buffer_.append(result.value().first(result.value().size_bytes() - 1));
|
|
ASSERT_EQ(uart_buffer_.status(), OkStatus());
|
|
|
|
const StatusWithSize status_with_size =
|
|
DecodeHciUartData(uart_buffer_, [](const Packet&) { FAIL(); });
|
|
EXPECT_EQ(status_with_size.status(), OkStatus());
|
|
EXPECT_EQ(status_with_size.size(), 0u);
|
|
}
|
|
|
|
TEST_F(UartTransportTest, EventPacket) {
|
|
uart_buffer_.push_back(kUartEventPacketIndicator);
|
|
|
|
std::array<std::byte, EventPacket::kHeaderSizeBytes> packet_buffer;
|
|
EventPacket packet(0u, ConstByteSpan());
|
|
const Result<ConstByteSpan> result = packet.Encode(packet_buffer);
|
|
ASSERT_EQ(result.status(), OkStatus());
|
|
|
|
uart_buffer_.append(result.value());
|
|
ASSERT_EQ(uart_buffer_.status(), OkStatus());
|
|
|
|
size_t event_packet_count = 0;
|
|
const StatusWithSize status_with_size =
|
|
DecodeHciUartData(uart_buffer_, [&](const Packet& decoded_packet) {
|
|
ASSERT_EQ(decoded_packet.type(), Packet::Type::kEventPacket);
|
|
++event_packet_count;
|
|
});
|
|
EXPECT_EQ(status_with_size.status(), OkStatus());
|
|
EXPECT_EQ(status_with_size.size(), uart_buffer_.size());
|
|
EXPECT_EQ(event_packet_count, 1u);
|
|
}
|
|
|
|
TEST_F(UartTransportTest, BadIndicatorThenPacketSequence) {
|
|
// Invalid packet indicator.
|
|
uart_buffer_.push_back(kInvalidPacketIndicator);
|
|
|
|
// Valid EventPacket w/ packet indicator.
|
|
uart_buffer_.push_back(kUartEventPacketIndicator);
|
|
std::array<std::byte, EventPacket::kHeaderSizeBytes> packet_buffer;
|
|
EventPacket packet(0u, ConstByteSpan());
|
|
const Result<ConstByteSpan> result = packet.Encode(packet_buffer);
|
|
ASSERT_EQ(result.status(), OkStatus());
|
|
uart_buffer_.append(result.value());
|
|
ASSERT_EQ(uart_buffer_.status(), OkStatus());
|
|
|
|
// First decode should fail after consuming the invalid packet indicator.
|
|
StatusWithSize status_with_size =
|
|
DecodeHciUartData(uart_buffer_, [&](const Packet&) { FAIL(); });
|
|
EXPECT_EQ(status_with_size.status(), Status::DataLoss());
|
|
EXPECT_EQ(status_with_size.size(), 1u);
|
|
|
|
const ConstByteSpan remaining_data =
|
|
ConstByteSpan(uart_buffer_).subspan(status_with_size.size());
|
|
|
|
// Second decode should work now that the invalid byte is gone.
|
|
size_t event_packet_count = 0;
|
|
status_with_size =
|
|
DecodeHciUartData(remaining_data, [&](const Packet& decoded_packet) {
|
|
ASSERT_EQ(decoded_packet.type(), Packet::Type::kEventPacket);
|
|
++event_packet_count;
|
|
});
|
|
EXPECT_EQ(status_with_size.status(), OkStatus());
|
|
EXPECT_EQ(status_with_size.size(), remaining_data.size_bytes());
|
|
EXPECT_EQ(event_packet_count, 1u);
|
|
}
|
|
|
|
TEST_F(UartTransportTest, PacketThenBadIndicatorSequence) {
|
|
// Valid EventPacket w/ packet indicator.
|
|
uart_buffer_.push_back(kUartEventPacketIndicator);
|
|
std::array<std::byte, EventPacket::kHeaderSizeBytes> packet_buffer;
|
|
EventPacket packet(0u, ConstByteSpan());
|
|
const Result<ConstByteSpan> result = packet.Encode(packet_buffer);
|
|
ASSERT_EQ(result.status(), OkStatus());
|
|
uart_buffer_.append(result.value());
|
|
ASSERT_EQ(uart_buffer_.status(), OkStatus());
|
|
|
|
// Invalid packet indicator.
|
|
uart_buffer_.push_back(kInvalidPacketIndicator);
|
|
|
|
// First decode should fail, consuming all data.
|
|
size_t event_packet_count = 0;
|
|
const StatusWithSize status_with_size =
|
|
DecodeHciUartData(uart_buffer_, [&](const Packet& decoded_packet) {
|
|
ASSERT_EQ(decoded_packet.type(), Packet::Type::kEventPacket);
|
|
++event_packet_count;
|
|
});
|
|
EXPECT_EQ(status_with_size.status(), Status::DataLoss());
|
|
EXPECT_EQ(status_with_size.size(), uart_buffer_.size());
|
|
EXPECT_EQ(event_packet_count, 1u);
|
|
}
|
|
|
|
TEST_F(UartTransportTest, AllPacketTypes) {
|
|
// Valid CommandPacket w/ packet indicator.
|
|
{
|
|
uart_buffer_.push_back(kUartCommandPacketIndicator);
|
|
std::array<std::byte, CommandPacket::kHeaderSizeBytes> packet_buffer;
|
|
CommandPacket packet(0u, ConstByteSpan());
|
|
const Result<ConstByteSpan> result = packet.Encode(packet_buffer);
|
|
ASSERT_EQ(result.status(), OkStatus());
|
|
uart_buffer_.append(result.value());
|
|
ASSERT_EQ(uart_buffer_.status(), OkStatus());
|
|
}
|
|
|
|
// Valid AsyncDataPacket w/ packet indicator.
|
|
{
|
|
uart_buffer_.push_back(kUartAsyncDataPacketIndicator);
|
|
std::array<std::byte, AsyncDataPacket::kHeaderSizeBytes> packet_buffer;
|
|
AsyncDataPacket packet(0u, ConstByteSpan());
|
|
const Result<ConstByteSpan> result = packet.Encode(packet_buffer);
|
|
ASSERT_EQ(result.status(), OkStatus());
|
|
uart_buffer_.append(result.value());
|
|
ASSERT_EQ(uart_buffer_.status(), OkStatus());
|
|
}
|
|
|
|
// Valid SyncDataPacket w/ packet indicator.
|
|
{
|
|
uart_buffer_.push_back(kUartSyncDataPacketIndicator);
|
|
std::array<std::byte, SyncDataPacket::kHeaderSizeBytes> packet_buffer;
|
|
SyncDataPacket packet(0u, ConstByteSpan());
|
|
const Result<ConstByteSpan> result = packet.Encode(packet_buffer);
|
|
ASSERT_EQ(result.status(), OkStatus());
|
|
uart_buffer_.append(result.value());
|
|
ASSERT_EQ(uart_buffer_.status(), OkStatus());
|
|
}
|
|
|
|
// Valid EventPacket w/ packet indicator.
|
|
{
|
|
uart_buffer_.push_back(kUartEventPacketIndicator);
|
|
std::array<std::byte, EventPacket::kHeaderSizeBytes> packet_buffer;
|
|
EventPacket packet(0u, ConstByteSpan());
|
|
const Result<ConstByteSpan> result = packet.Encode(packet_buffer);
|
|
ASSERT_EQ(result.status(), OkStatus());
|
|
uart_buffer_.append(result.value());
|
|
ASSERT_EQ(uart_buffer_.status(), OkStatus());
|
|
}
|
|
|
|
// First decode should succeed, consuming all data.
|
|
size_t packet_count = 0u;
|
|
const StatusWithSize status_with_size =
|
|
DecodeHciUartData(uart_buffer_, [&](const Packet& decoded_packet) {
|
|
++packet_count;
|
|
switch (packet_count) {
|
|
case 1u:
|
|
EXPECT_EQ(decoded_packet.type(), Packet::Type::kCommandPacket);
|
|
break;
|
|
|
|
case 2u:
|
|
EXPECT_EQ(decoded_packet.type(), Packet::Type::kAsyncDataPacket);
|
|
break;
|
|
|
|
case 3u:
|
|
EXPECT_EQ(decoded_packet.type(), Packet::Type::kSyncDataPacket);
|
|
break;
|
|
|
|
case 4u:
|
|
EXPECT_EQ(decoded_packet.type(), Packet::Type::kEventPacket);
|
|
break;
|
|
}
|
|
});
|
|
EXPECT_EQ(status_with_size.status(), OkStatus());
|
|
EXPECT_EQ(status_with_size.size(), uart_buffer_.size());
|
|
EXPECT_EQ(packet_count, 4u);
|
|
}
|
|
|
|
TEST_F(UartTransportTest, LotsOfEventPackets) {
|
|
std::array<std::byte, EventPacket::kHeaderSizeBytes> packet_buffer;
|
|
EventPacket packet(0u, ConstByteSpan());
|
|
const Result<ConstByteSpan> result = packet.Encode(packet_buffer);
|
|
ASSERT_EQ(result.status(), OkStatus());
|
|
|
|
size_t expected_packet_count = 0;
|
|
while ((uart_buffer_.max_size() - uart_buffer_.size()) >
|
|
packet.size_bytes()) {
|
|
++expected_packet_count;
|
|
uart_buffer_.push_back(kUartEventPacketIndicator);
|
|
uart_buffer_.append(result.value());
|
|
ASSERT_EQ(uart_buffer_.status(), OkStatus());
|
|
}
|
|
|
|
size_t event_packet_count = 0;
|
|
const StatusWithSize status_with_size =
|
|
DecodeHciUartData(uart_buffer_, [&](const Packet& decoded_packet) {
|
|
ASSERT_EQ(decoded_packet.type(), Packet::Type::kEventPacket);
|
|
++event_packet_count;
|
|
});
|
|
EXPECT_EQ(status_with_size.status(), OkStatus());
|
|
EXPECT_EQ(status_with_size.size(), uart_buffer_.size());
|
|
EXPECT_EQ(event_packet_count, expected_packet_count);
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace pw::bluetooth_hci
|