blob: 916dd1ffaeccd6b484676a2c5db6baed09980da0 [file]
// Copyright 2025 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.
#![no_main]
#![no_std]
use pw_status::{Error, Result};
use test_uart_codegen::{handle, mapping};
use uart_16550_user::Uart;
use userspace::syscall::Signals;
use userspace::time::Instant;
use userspace::{entry, syscall};
fn read_expected_value(expected_value: u8) -> Result<()> {
// the UART listener responds on IPC with the value written to the UART.
let wait_return = syscall::object_wait(handle::IPC, Signals::READABLE, Instant::MAX)?;
if !wait_return.pending_signals.contains(Signals::READABLE) || wait_return.user_data != 0 {
return Err(Error::Internal);
}
let mut buffer = [0u8; 1];
let len = syscall::channel_read(handle::IPC, 0, &mut buffer)?;
if len != 1 {
return Err(Error::OutOfRange);
};
if buffer[0] != expected_value {
test_logger::step_failed!(
"UART read() wrong value {} (expected {})",
buffer[0] as u8,
expected_value as u8
);
return Err(Error::Internal);
}
let response_buffer = [0u8; 0];
syscall::channel_respond(handle::IPC, &response_buffer)?;
Ok(())
}
fn test_uart_interrupts() -> Result<()> {
let mut uart = Uart::new(mapping::UART0_START_ADDRESS);
// enable lo to support writing and then reading back the result.
uart.enable_loopback();
// drain UART buffer
while !uart.read().is_none() {}
uart.write(7);
read_expected_value(7)?;
if !uart.read().is_none() {
test_logger::step_failed!("Buffer not empty after read");
return Err(Error::FailedPrecondition);
}
for i in 0..3u8 {
uart.write(i);
read_expected_value(i)?;
}
if !uart.read().is_none() {
test_logger::step_failed!("Buffer not empty after multiple reads");
return Err(Error::FailedPrecondition);
}
Ok(())
}
#[entry]
fn entry() -> Result<()> {
test_logger::start("User UART Test");
let ret = test_uart_interrupts()
.inspect(|_| test_logger::passed("User UART Test"))
.inspect_err(|e| {
test_logger::failed("User UART Test");
test_logger::step_failed!("status code: {}", *e as u32);
});
// Since this is written as a test, shut down with the return status from `main()`.
let _ = syscall::debug_shutdown(ret);
ret
}
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {}
}