blob: 6e54eb8d980eb4b356999a8d8dabc0571b28c918 [file] [log] [blame]
// Copyright 2023 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 <lib/standalone-test/standalone.h>
#include <lib/stdcompat/span.h>
#include <lib/zx/time.h>
#include <cstdint>
#include <string_view>
#include <zxtest/zxtest.h>
namespace {
// The host test attaches uart_test.message_size=XXXX where XXXXX is the expected number of bytes.
// This allows us to continue reading until we read everything. Worst case this test will time out
// if the interrupts are never fired.
class UartInterruptTest : public zxtest::Test {
public:
static void SetUpTestSuite() {
standalone::Option option = {.prefix = "uart_test.message_size="};
standalone::GetOptions({option});
// The host side will add a line break character \n.
std::string value = option.option.substr(option.prefix.length());
message_size_ = atoi(value.c_str()) + 1;
}
void SetUp() final { message_.resize(message_size_, '\0'); }
cpp20::span<char> message() { return message_; }
size_t max_message_size() const { return message_size_; }
private:
static size_t message_size_;
std::vector<char> message_;
};
size_t UartInterruptTest::message_size_ = 0;
// Read everything from the UART then write it back so it can be read by the serial listener.
TEST_F(UartInterruptTest, KernelEchoTest) {
// Magic string telling the host interaction test it should start pushing characters into the
// UART.
printf("uart-interrupt-test: Uart Ready\n");
// Let the RX Buffer fill up.
zx::nanosleep(zx::deadline_after(zx::sec(2)));
size_t total = 0;
size_t empty_count = 0;
auto system_resource = standalone::GetSystemResource();
zx::result<zx::resource> result =
standalone::GetSystemResourceWithBase(system_resource, ZX_RSRC_SYSTEM_DEBUG_BASE);
ASSERT_OK(result.status_value());
zx::resource debug_resource = std::move(result.value());
while (total < max_message_size()) {
size_t read = 0;
ASSERT_OK(zx_debug_read(debug_resource.get(), message().data() + total,
max_message_size() - total, &read));
total += read;
if (read == 0) {
empty_count++;
// If we did not find anything in the uart, go to sleep.
zx::nanosleep(zx::deadline_after(zx::sec(1)));
} else {
empty_count = 0;
}
// We retried 5 times and failed to read a single character.
if (empty_count >= 5) {
FAIL("Reached maximum retries while trying to read characters from UART.");
return;
}
}
// zx_debug_write has a maximum write chunk of 256.
constexpr size_t kChunkSize = 256;
size_t written = 0;
size_t tail = total % kChunkSize;
while (written < total - tail) {
ASSERT_OK(zx_debug_write(message().data() + written, kChunkSize));
written += kChunkSize;
}
// write trailing bytes.
if (tail != 0) {
ASSERT_OK(zx_debug_write(message().data() + total - tail, tail));
}
zx::nanosleep(zx::deadline_after(zx::sec(1)));
}
} // namespace