blob: 69e6f28ac87ca0fc58baff4fa6be2e006ea08832 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "nhlt.h"
#include <zircon/assert.h>
#include <zircon/errors.h>
#include <cstdint>
#include <vector>
#include <intel-hda/utils/nhlt.h>
#include <zxtest/zxtest.h>
namespace audio::intel_hda {
namespace {
// Push the raw bytes of the given object into the given std::vector<uint8_t>.
template <typename T>
void PushBytes(std::vector<uint8_t>* buffer, const T* object) {
const auto* object_bytes = reinterpret_cast<const uint8_t*>(object);
std::copy(object_bytes, object_bytes + sizeof(T), std::back_inserter(*buffer));
}
std::vector<uint8_t> SampleEndpoint() {
std::vector<uint8_t> data;
const specific_config_t no_capabilities = {
/*capabilities_size=*/0,
};
// Write out an endpoint.
uint32_t length =
(sizeof(nhlt_descriptor_t) + sizeof(specific_config_t) + sizeof(formats_config_t) +
sizeof(format_config_t) + sizeof(specific_config_t));
nhlt_descriptor_t endpoint = {
/*length=*/length,
/*link_type=*/NHLT_LINK_TYPE_SSP,
/*instance_id=*/1,
/*vendor_id=*/2,
/*device_id=*/3,
/*revision_id=*/4,
/*subsystem_id=*/5,
/*device_type=*/6,
/*direction=*/NHLT_DIRECTION_RENDER,
/*virtual_bus_id=*/7,
};
PushBytes(&data, &endpoint);
PushBytes(&data, &no_capabilities);
formats_config_t formats = {
/*format_config_count=*/1,
};
PushBytes(&data, &formats);
format_config_t format = {
/*format_tag=*/1,
/*n_channels=*/2,
/*n_samples_per_sec=*/3,
/*n_avg_bytes_per_sec=*/4,
/*n_block_align=*/5,
/*bits_per_sample=*/6,
/*cb_size=*/7,
/*valid_bits_per_sample=*/8,
/*channel_mask=*/9,
/*subformat_guid=*/{},
};
PushBytes(&data, &format);
PushBytes(&data, &no_capabilities);
// Ensure we got our length calculations correct.
ZX_ASSERT(data.size() == length);
return data;
}
std::vector<uint8_t> SampleNHLT() {
std::vector<uint8_t> data;
// Create endpoint.
std::vector<uint8_t> endpoint = SampleEndpoint();
// Write out header.
nhlt_table_t nhlt = {
/*header=*/{
/*signature=*/{'N', 'H', 'L', 'T'},
/*length=*/static_cast<uint32_t>(sizeof(nhlt_table_t) + endpoint.size()),
/*revision=*/5,
/*checksum=*/0, // Invalid, but we don't check.
/*oem_id=*/{'O', 'E', 'M'},
/*oem_table_id=*/{'T', 'A', 'B', 'L', 'E'},
/*oem_revision=*/0,
/*asl_compiler_id=*/{'C', 'O', 'M', 'P'},
/*asl_compiler_revision=*/0,
},
/*endpoint_desc_count=*/1,
};
PushBytes(&data, &nhlt);
// Append endpoint.
std::copy(endpoint.begin(), endpoint.end(), std::back_inserter(data));
return data;
}
TEST(Nhlt, DefaultInitializer) {
Nhlt x{};
EXPECT_TRUE(x.i2s_configs().is_empty());
}
TEST(Nhlt, ParseEmpty) {
fbl::Span<uint8_t> empty{};
EXPECT_FALSE(Nhlt::FromBuffer(empty).ok());
}
TEST(Nhlt, ParseSimple) {
std::vector<uint8_t> data = SampleNHLT();
StatusOr<std::unique_ptr<Nhlt>> nhlt = Nhlt::FromBuffer(data);
ASSERT_OK(nhlt.status().code());
// Ensure the data looks reasonable.
ASSERT_EQ(nhlt.ValueOrDie()->i2s_configs().size(), 1);
ASSERT_EQ(nhlt.ValueOrDie()->i2s_configs()[0].formats.size(), 1);
ASSERT_EQ(nhlt.ValueOrDie()->i2s_configs()[0].formats[0].config.format_tag, 1);
}
TEST(Nhlt, ParseTruncated) {
std::vector<uint8_t> data = SampleNHLT();
// Remove a byte, and ensure we still successfully notice that the data size is all wrong.
do {
data.resize(data.size() - 1);
StatusOr<std::unique_ptr<Nhlt>> nhlt = Nhlt::FromBuffer(data);
ASSERT_FALSE(nhlt.ok());
} while (!data.empty());
}
} // namespace
} // namespace audio::intel_hda