Skip to content

Commit

Permalink
Merge pull request #87 from SteelPh0enix/scb-uart-tests
Browse files Browse the repository at this point in the history
ROS#177: Added UART logging to SCB tests
  • Loading branch information
SteelPh0enix authored Dec 5, 2023
2 parents abeec90 + 1ab2626 commit 1ec4eaf
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 19 deletions.
93 changes: 81 additions & 12 deletions testbins/test-hal-scb/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
//! In this test, D-Cache and I-Cache management is tested.
//!
//! Because of lack of reasonable way to access RTT data buffer, and lack of MPU driver, it's not
//! possible to use RTT to reliably communicate with test host. Therefore, this test writes out
//! it's D-cache test results via UART after performing a simple handshake with test platform to
//! mitigate that issue.
//!
//! It's also worth noting that neither D-Cache nor I-Cache effects can't be "observed", they serve
//! as a "black box", so the validation is performed by analysis of output assembly code that
//! confirms the proper instructions were placed to manage the caches.
#![no_std]
#![no_main]

Expand All @@ -6,7 +16,19 @@ extern crate calldwell;
extern crate cortex_m;
extern crate cortex_m_rt as rt;

use aerugo::hal::user_peripherals::{CPUID, SCB};
use core::fmt::Arguments;

use aerugo::hal::{
drivers::{
pio::{pin::Peripheral, Port},
pmc::config::PeripheralId,
uart::{
writer::Writer, Bidirectional, Config as UartConfig, Read, ReceiverConfig, Uart, Write,
},
},
user_peripherals::{CPUID, PIOD, PMC, SCB, UART4},
};
use aerugo::time::RateExtU32;
use aerugo::{Aerugo, InitApi, SystemHardwareConfig};
use calldwell::write_str;
use rt::entry;
Expand All @@ -28,6 +50,9 @@ impl Default for DummyData {

fn perform_dcache_tests(scb: &mut SCB, cpuid: &mut CPUID) {
// Check cache enabling/disabling
// From now on, all test data will be sent via UART, because with RTT the cache must be disabled
// as currently it's not possible to disable RTT region caching due to lack of support from
// `rtt_target` library for that.
scb.enable_dcache(cpuid);
assert!(
SCB::dcache_enabled(),
Expand All @@ -48,16 +73,13 @@ fn perform_dcache_tests(scb: &mut SCB, cpuid: &mut CPUID) {

scb.clean_invalidate_dcache(cpuid);

// TODO: Migrate from RTT to UART, because with RTT the cache must be
// disabled as currently it's not possible to disable RTT region
// caching due to lack of support from `rtt_target` library for that.
// scb.disable_dcache(cpuid);
// assert!(
// !SCB::dcache_enabled(),
// "D-Cache was disabled, yet it's reported as enabled"
// );
scb.disable_dcache(cpuid);
assert!(
!SCB::dcache_enabled(),
"D-Cache was disabled, yet it's reported as enabled"
);

write_str("dcache tests successful");
write_via_uart(format_args!("D-Cache management test successful\n"));
}

fn perform_icache_tests(scb: &mut SCB) {
Expand All @@ -77,13 +99,44 @@ fn perform_icache_tests(scb: &mut SCB) {
!SCB::icache_enabled(),
"I-Cache was disabled, yet it's reported as enabled"
);
write_str("icache tests successful");
write_str("I-Cache management test successful");
}

fn perform_scb_tests(mut scb: SCB, mut cpuid: CPUID) {
perform_icache_tests(&mut scb);
perform_dcache_tests(&mut scb, &mut cpuid);
write_str("all tests finished successfully");
write_via_uart(format_args!("All SCB tests finished successfully!\n"));
}

fn configure_uart_io(port: Port<PIOD>) {
let mut pins = port.into_pins();
pins[18].take().unwrap().into_peripheral_pin(Peripheral::C);
pins[19].take().unwrap().into_peripheral_pin(Peripheral::C);
}

fn configure_uart_pmc(pmc: &mut PMC) {
pmc.enable_peripheral_clock(PeripheralId::PIOD);
pmc.enable_peripheral_clock(PeripheralId::UART4);
}

fn perform_uart_handshake(uart: &mut Uart<UART4, Bidirectional>) {
let mut reader = uart.take_reader().unwrap();
let mut writer = uart.take_writer().unwrap();
let mut handshake_buffer = [0u8; 6];

reader.read_exact(&mut handshake_buffer).unwrap();
assert_eq!(handshake_buffer, "Hello!".as_bytes());
writer.write_fmt(format_args!("World!")).unwrap();

uart.put_reader(reader);
unsafe { UART_WRITER.replace(writer) };
}

static mut UART_WRITER: Option<Writer<UART4>> = None;

/// This function will panic if called before `perform_uart_handshake`.
fn write_via_uart(fmt: Arguments) {
unsafe { UART_WRITER.as_mut().unwrap().write_fmt(fmt).unwrap() };
}

#[entry]
Expand All @@ -93,6 +146,22 @@ fn main() -> ! {

let mut scb = peripherals.scb.take().unwrap();
let mut cpu_id = peripherals.cpu_id.take().unwrap();

let mut pmc = peripherals.pmc.take().unwrap();
configure_uart_pmc(&mut pmc);

let uart_port = Port::new(peripherals.pio_d.take().unwrap());
configure_uart_io(uart_port);

let mut uart = Uart::new(peripherals.uart_4.take().unwrap()).into_bidirectional(
UartConfig::new(57600, 12.MHz()).unwrap(),
ReceiverConfig {
rx_filter_enabled: true,
},
);

perform_uart_handshake(&mut uart);

scb.disable_dcache(&mut cpu_id);
scb.disable_icache();

Expand Down
77 changes: 73 additions & 4 deletions tests/requirements/test/test_hal_scb.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,17 @@

from __future__ import annotations

from test_utils import finish_test, init_test, wait_for_messages
import logging
import sys

from test_utils import finish_test, init_test, wait_for_messages, wait_for_uart_messages

from calldwell import init_default_logger
from calldwell.uart import RemoteUARTConfig, RemoteUARTConnection
from scripts.env import (
BOARD_UART_DEVICE,
BOARD_UART_PORT,
)

TEST_NAME = "test-hal-scb"

Expand All @@ -13,19 +21,80 @@ def main() -> None:
"""Main function of integration test."""
_, rtt, ssh = init_test(TEST_NAME)

# Open UART connection and perform a handshake with test app
uart_config = RemoteUARTConfig(
device_path=BOARD_UART_DEVICE,
port=BOARD_UART_PORT,
baudrate=57600,
)
uart = RemoteUARTConnection(ssh, uart_config)
if not uart.open_uart():
logging.critical("TEST FAILED, could not establish UART connection!")
sys.exit(1000)

perform_uart_handshake(uart)

wait_for_messages(
rtt,
ssh,
[
"icache tests successful",
"dcache tests successful",
"all tests finished successfully",
"I-Cache management test successful",
],
)

wait_for_uart_messages(
uart,
ssh,
[
"D-Cache management test successful",
"All SCB tests finished successfully!",
],
)

uart.close_uart()
finish_test(ssh)


def perform_uart_handshake(uart: RemoteUARTConnection) -> None:
"""Performs simple UART handshake with test app"""
handshake_message = b"Hello!"
expected_response = "World!"

logging.info("Performing UART handshake...")
written_bytes, tx_error = uart.write_bytes(handshake_message)

if tx_error is not None:
logging.critical(
f"TEST FAILED, an error occurred while sending handshake message: {tx_error}",
)
sys.exit(10)

if written_bytes != len(handshake_message):
logging.critical(
f"TEST FAILED, handshake message is not fully transmitted (sent {written_bytes} out of "
f"{len(handshake_message)} bytes)",
)
sys.exit(20)

response = uart.read_string(b"!")

if response.is_err:
logging.critical(
f"TEST FAILED, an error occurred while receiving handshake response: "
f"{response.unwrap_err()}",
)
sys.exit(30)

if (response_message := response.unwrap()) != expected_response:
logging.critical(
f"TEST FAILED, invalid handshake response\nexpected '{expected_response}'\ngot "
f"'{response_message}'",
)
sys.exit(40)

logging.info("UART handshake successful!")


if __name__ == "__main__":
init_default_logger()
main()
6 changes: 3 additions & 3 deletions tests/requirements/test/test_hal_scb.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// Test scenario:
// - Verify that icache can be disabled/enabled/cleared
// - Verify that dcache can be disabled/enabled/cleared
// TODO: SCB-030 requirement coverage
// - Verify that I-Cache can be disabled/enabled/invalidated
// - Verify that D-Cache can be disabled/enabled/cleared/invalidated

/// @SRS{ROS-FUN-BSP-SCB-020}
/// @SRS{ROS-FUN-BSP-SCB-030}
/// @SRS{ROS-FUN-BSP-SCB-040}
/// @SRS{ROS-FUN-BSP-SCB-050}
/// @SRS{ROS-FUN-BSP-SCB-060}
Expand Down
25 changes: 25 additions & 0 deletions tests/requirements/test/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from calldwell.gdb_client import GDBClient
from calldwell.rtt_client import CalldwellRTTClient
from calldwell.ssh_client import SSHClient
from calldwell.uart import RemoteUARTConnection


def init_test(
Expand Down Expand Up @@ -93,3 +94,27 @@ def wait_for_messages(
)
finish_test(ssh)
sys.exit(2)


def wait_for_uart_messages(
uart: RemoteUARTConnection,
ssh: SSHClient,
expected_messages: list[str],
) -> None:
"""Same as `wait_for_messages`, but via UART.
Assumes that every message ends with single newline (`\\n`) character."""
for message in expected_messages:
logging.info(f"Expecting '{message}' via UART")
received_message = uart.read_string(b"\n")
logging.info(f"Received '{received_message}'")
if (
received_message.is_ok
and (received_message_content := received_message.unwrap().strip()) != message
):
logging.critical(
"TEST FAILED: UNEXPECTED MESSAGE RECEIVED VIA UART "
f"(expected '{message}', got '{received_message_content}')",
)
uart.close_uart()
finish_test(ssh)
sys.exit(2)

0 comments on commit 1ec4eaf

Please sign in to comment.