From b42a32ff7447e83dbd727bc8bf21633227428dc7 Mon Sep 17 00:00:00 2001 From: charles37 Date: Tue, 29 Oct 2024 19:31:51 -0400 Subject: [PATCH] gpio: init + mpu_walk_region test --- .github/workflows/treadmill-ci-test.yml | 44 ++++++------ hwci/boards/nrf52dk.py | 26 ++++++++ hwci/boards/specs/nrf52dk.yml | 28 ++++++++ hwci/core/board_harness.py | 3 + hwci/core/main.py | 2 +- hwci/{tests => gpio}/__init__.py | 7 +- hwci/gpio/gpio.py | 42 ++++++++++++ hwci/gpio/interfaces/__init__.py | 6 ++ hwci/gpio/interfaces/mock_gpio.py | 40 +++++++++++ hwci/gpio/interfaces/raspberry_pi5_gpio.py | 64 ++++++++++++++++++ hwci/requirements-frozen.txt | 5 +- hwci/requirements.txt | 2 + hwci/target-spec.yml | 28 ++++++++ hwci/tests/adc.py | 30 --------- hwci/tests/adc_continuous.py | 3 - hwci/tests/ble_advertising.py | 5 -- hwci/tests/ble_env_sense.py | 6 -- hwci/tests/ble_passive_scanning.py | 26 -------- hwci/tests/c_hello_and_printf_long.py | 28 -------- hwci/tests/console_recv_long.py | 5 -- hwci/tests/console_recv_short.py | 5 -- hwci/tests/gpio_test.py | 21 ------ hwci/tests/ipc_logic.py | 24 ------- hwci/tests/lua_hello.py | 3 - hwci/tests/malloc_test01.py | 3 - hwci/tests/malloc_test02.py | 3 - hwci/tests/mpu_stack_growth.py | 16 ----- hwci/tests/mpu_walk_region.py | 78 +++++++++++++++++++--- hwci/tests/multi_alarm_simple_test.py | 41 ------------ hwci/tests/multi_alarm_test.py | 0 hwci/tests/printf_long.py | 6 -- hwci/tests/sensors.py | 23 ------- hwci/tests/stack_size_test01.py | 3 - hwci/tests/stack_size_test02.py | 3 - hwci/tests/whileone.py | 17 ----- hwci/utils/test_helpers/oneshot.py | 1 + 36 files changed, 337 insertions(+), 310 deletions(-) create mode 100644 hwci/boards/specs/nrf52dk.yml rename hwci/{tests => gpio}/__init__.py (50%) create mode 100644 hwci/gpio/gpio.py create mode 100644 hwci/gpio/interfaces/__init__.py create mode 100644 hwci/gpio/interfaces/mock_gpio.py create mode 100644 hwci/gpio/interfaces/raspberry_pi5_gpio.py create mode 100644 hwci/target-spec.yml delete mode 100644 hwci/tests/adc.py delete mode 100644 hwci/tests/adc_continuous.py delete mode 100644 hwci/tests/ble_advertising.py delete mode 100644 hwci/tests/ble_env_sense.py delete mode 100644 hwci/tests/ble_passive_scanning.py delete mode 100644 hwci/tests/c_hello_and_printf_long.py delete mode 100644 hwci/tests/console_recv_long.py delete mode 100644 hwci/tests/console_recv_short.py delete mode 100644 hwci/tests/gpio_test.py delete mode 100644 hwci/tests/ipc_logic.py delete mode 100644 hwci/tests/lua_hello.py delete mode 100644 hwci/tests/malloc_test01.py delete mode 100644 hwci/tests/malloc_test02.py delete mode 100644 hwci/tests/mpu_stack_growth.py delete mode 100644 hwci/tests/multi_alarm_simple_test.py delete mode 100644 hwci/tests/multi_alarm_test.py delete mode 100644 hwci/tests/printf_long.py delete mode 100644 hwci/tests/sensors.py delete mode 100644 hwci/tests/stack_size_test01.py delete mode 100644 hwci/tests/stack_size_test02.py delete mode 100644 hwci/tests/whileone.py diff --git a/.github/workflows/treadmill-ci-test.yml b/.github/workflows/treadmill-ci-test.yml index c31b044..bf1d547 100644 --- a/.github/workflows/treadmill-ci-test.yml +++ b/.github/workflows/treadmill-ci-test.yml @@ -48,27 +48,31 @@ jobs: tock-kernel-ref: 'master' libtock-c-ref: 'master' tests: | - tests/ble_env_sense.py - tests/ble_advertising.py - tests/ble_passive_scanning.py tests/c_hello.py - tests/printf_long.py - tests/c_hello_and_printf_long.py - tests/sensors.py - tests/console_recv_short.py - tests/console_recv_long.py - tests/lua_hello.py - tests/malloc_test01.py - tests/malloc_test02.py - tests/stack_size_test01.py - tests/stack_size_test02.py - tests/mpu_stack_growth.py tests/mpu_walk_region.py - tests/adc.py - tests/adc_continuous.py - tests/ipc_logic.py - tests/gpio_interrupt.py - tests/whileone.py - tests/multi_alarm_simple_test.py + + # tests: | + # tests/ble_env_sense.py + # tests/ble_advertising.py + # tests/ble_passive_scanning.py + # tests/c_hello.py + # tests/printf_long.py + # tests/c_hello_and_printf_long.py + # tests/sensors.py + # tests/console_recv_short.py + # tests/console_recv_long.py + # tests/lua_hello.py + # tests/malloc_test01.py + # tests/malloc_test02.py + # tests/stack_size_test01.py + # tests/stack_size_test02.py + # tests/mpu_stack_growth.py + # tests/mpu_walk_region.py + # tests/adc.py + # tests/adc_continuous.py + # tests/ipc_logic.py + # tests/gpio_interrupt.py + # tests/whileone.py + # tests/multi_alarm_simple_test.py secrets: inherit diff --git a/hwci/boards/nrf52dk.py b/hwci/boards/nrf52dk.py index e0c9220..f080cf2 100644 --- a/hwci/boards/nrf52dk.py +++ b/hwci/boards/nrf52dk.py @@ -9,6 +9,9 @@ import serial.tools.list_ports from boards.tockloader_board import TockloaderBoard from utils.serial_port import SerialPort +from gpio.gpio import GPIO +import yaml +import os class Nrf52dk(TockloaderBoard): @@ -23,6 +26,7 @@ def __init__(self): self.openocd_board = "nrf52dk" self.board = "nrf52dk" self.serial = self.get_serial_port() + self.gpio = self.get_gpio_interface() def get_uart_port(self): logging.info("Getting list of serial ports") @@ -47,6 +51,20 @@ def get_serial_port(self): ) return SerialPort(self.uart_port, self.uart_baudrate) + def get_gpio_interface(self): + # Load the target spec from a YAML file + target_spec = load_target_spec() + # Initialize GPIO with the target spec + gpio = GPIO(target_spec) + return gpio + + def cleanup(self): + if self.gpio: + for interface in self.gpio.gpio_interfaces.values(): + interface.cleanup() + if self.serial: + self.serial.close() + def flash_kernel(self): logging.info("Flashing the Tock OS kernel") tock_dir = os.path.join(self.base_dir, "tock") @@ -82,4 +100,12 @@ def change_directory(self, new_dir): logging.info(f"Reverted to directory: {os.getcwd()}") +def load_target_spec(): + # Assume the target spec file is in a fixed location + target_spec_path = os.path.join(os.getcwd(), "target_spec.yaml") + with open(target_spec_path, "r") as f: + target_spec = yaml.safe_load(f) + return target_spec + + board = Nrf52dk() diff --git a/hwci/boards/specs/nrf52dk.yml b/hwci/boards/specs/nrf52dk.yml new file mode 100644 index 0000000..6a42cdd --- /dev/null +++ b/hwci/boards/specs/nrf52dk.yml @@ -0,0 +1,28 @@ +model: nrf52840dk +hw_rev: '3.2' +serial_number: 0xfoobar +pin_mappings: + P0.13: + io_interface: raspberrypi5gpio + io_pin_spec: 20 + target_pin_function: LED1 + target_pin_mode: output + target_pin_active: low + P0.14: + io_interface: raspberrypi5gpio + io_pin_spec: 19 + target_pin_function: LED2 + target_pin_mode: output + target_pin_active: low + P0.11: + io_interface: raspberrypi5gpio + io_pin_spec: 21 + target_pin_function: BUTTON1 + target_pin_mode: input + target_pin_active: low + P0.12: + io_interface: raspberrypi5gpio + io_pin_spec: 26 + target_pin_function: BUTTON2 + target_pin_mode: input + target_pin_active: low diff --git a/hwci/core/board_harness.py b/hwci/core/board_harness.py index 446ede5..854e37b 100644 --- a/hwci/core/board_harness.py +++ b/hwci/core/board_harness.py @@ -23,6 +23,9 @@ def get_serial_port(self): def get_gpio_interface(self): pass + def cleanup(self): + pass + def erase_board(self): pass diff --git a/hwci/core/main.py b/hwci/core/main.py index 28bc028..cd5d504 100644 --- a/hwci/core/main.py +++ b/hwci/core/main.py @@ -48,7 +48,7 @@ def main(): logging.exception("An error occurred during test execution") sys.exit(1) finally: - board.serial.close() + board.cleaup() if __name__ == "__main__": diff --git a/hwci/tests/__init__.py b/hwci/gpio/__init__.py similarity index 50% rename from hwci/tests/__init__.py rename to hwci/gpio/__init__.py index b64be6c..b121810 100644 --- a/hwci/tests/__init__.py +++ b/hwci/gpio/__init__.py @@ -2,9 +2,4 @@ # SPDX-License-Identifier: Apache-2.0 OR MIT # Copyright Tock Contributors 2024. -from .console_hello_test import ( - OneshotTest, - AnalyzeConsoleTest, - WaitForConsoleMessageTest, -) -from .c_hello import test as c_hello_test +from .gpio import GPIO diff --git a/hwci/gpio/gpio.py b/hwci/gpio/gpio.py new file mode 100644 index 0000000..24835aa --- /dev/null +++ b/hwci/gpio/gpio.py @@ -0,0 +1,42 @@ +# Licensed under the Apache License, Version 2.0 or the MIT License. +# SPDX-License-Identifier: Apache-2.0 OR MIT +# Copyright Tock Contributors 2024. + +import logging + +from gpio.interfaces.raspberry_pi5_gpio import RaspberryPi5GPIO +from gpio.interfaces.mock_gpio import MockGPIO + + +class GPIO: + def __init__(self, target_spec): + self.target_spec = target_spec + self.gpio_interfaces = {} + # Initialize GPIO interfaces based on the target spec + for pin_label, pin_mapping in self.target_spec.get("pin_mappings", {}).items(): + interface_name = pin_mapping["io_interface"] + if interface_name not in self.gpio_interfaces: + interface_class = self.load_interface_class(interface_name) + self.gpio_interfaces[interface_name] = interface_class() + + def load_interface_class(self, interface_name): + # Map interface names to classes + interface_classes = { + "raspberrypi5gpio": RaspberryPi5GPIO, + "mock_gpio": MockGPIO, + } + if interface_name in interface_classes: + return interface_classes[interface_name] + else: + raise ValueError(f"Unknown GPIO interface: {interface_name}") + + def pin(self, pin_label): + # Get the pin mapping from the target spec + pin_mapping = self.target_spec["pin_mappings"].get(pin_label) + if not pin_mapping: + raise ValueError(f"Unknown pin label: {pin_label}") + interface_name = pin_mapping["io_interface"] + interface = self.gpio_interfaces.get(interface_name) + if not interface: + raise ValueError(f"No GPIO interface for {interface_name}") + return interface.pin(pin_label, pin_mapping) diff --git a/hwci/gpio/interfaces/__init__.py b/hwci/gpio/interfaces/__init__.py new file mode 100644 index 0000000..a6bec93 --- /dev/null +++ b/hwci/gpio/interfaces/__init__.py @@ -0,0 +1,6 @@ +# Licensed under the Apache License, Version 2.0 or the MIT License. +# SPDX-License-Identifier: Apache-2.0 OR MIT +# Copyright Tock Contributors 2024. + +from .raspberry_pi5_gpio import RaspberryPi5GPIO +from .mock_gpio import MockGPIO diff --git a/hwci/gpio/interfaces/mock_gpio.py b/hwci/gpio/interfaces/mock_gpio.py new file mode 100644 index 0000000..0819c46 --- /dev/null +++ b/hwci/gpio/interfaces/mock_gpio.py @@ -0,0 +1,40 @@ +# Licensed under the Apache License, Version 2.0 or the MIT License. +# SPDX-License-Identifier: Apache-2.0 OR MIT +# Copyright Tock Contributors 2024. + +import logging + + +class MockGPIO: + def __init__(self): + self.pins = {} + + def pin(self, target_pin_label, target_pin_mapping): + if target_pin_label not in self.pins: + pin = MockGPIOPin(target_pin_label) + self.pins[target_pin_label] = pin + else: + pin = self.pins[target_pin_label] + return pin + + def cleanup(self): + pass # Nothing to clean up in mock + + +class MockGPIOPin: + def __init__(self, pin_label): + self.pin_label = pin_label + self.mode = None + self.value = None + + def set_mode(self, mode): + self.mode = mode + logging.info(f"Pin {self.pin_label} set to mode {mode}") + + def read(self): + logging.info(f"Pin {self.pin_label} read value {self.value}") + return self.value + + def write(self, value): + self.value = value + logging.info(f"Pin {self.pin_label} write value {value}") diff --git a/hwci/gpio/interfaces/raspberry_pi5_gpio.py b/hwci/gpio/interfaces/raspberry_pi5_gpio.py new file mode 100644 index 0000000..cfb14b0 --- /dev/null +++ b/hwci/gpio/interfaces/raspberry_pi5_gpio.py @@ -0,0 +1,64 @@ +# Licensed under the Apache License, Version 2.0 or the MIT License. +# SPDX-License-Identifier: Apache-2.0 OR MIT +# Copyright Tock Contributors 2024. + +import logging +from gpiozero import LED, Button, DigitalOutputDevice, DigitalInputDevice + + +class RaspberryPi5GPIO: + def __init__(self): + self.pins = {} + + def pin(self, _target_pin_label, target_pin_mapping): + gpio_pin_number = int(target_pin_mapping["io_pin_spec"]) + if gpio_pin_number not in self.pins: + pin = RaspberryPiGPIOPin(gpio_pin_number) + self.pins[gpio_pin_number] = pin + else: + pin = self.pins[gpio_pin_number] + return pin + + def cleanup(self): + for pin in self.pins.values(): + pin.close() + self.pins.clear() + + +class RaspberryPiGPIOPin: + def __init__(self, gpio_pin_number): + self.gpio_pin_number = gpio_pin_number + self.device = None # Will be initialized based on mode + self.mode = None + + def set_mode(self, mode): + if mode == "input": + if self.device: + self.device.close() + self.device = DigitalInputDevice(self.gpio_pin_number) + self.mode = mode + elif mode == "output": + if self.device: + self.device.close() + self.device = DigitalOutputDevice(self.gpio_pin_number) + self.mode = mode + else: + raise ValueError(f"Unknown mode: {mode}") + + def read(self): + if self.mode != "input": + raise RuntimeError("Pin is not set to input mode") + value = self.device.value + logging.debug(f"Read value {value} from pin {self.gpio_pin_number}") + return value + + def write(self, value): + if self.mode != "output": + raise RuntimeError("Pin is not set to output mode") + self.device.value = value + logging.debug(f"Wrote value {value} to pin {self.gpio_pin_number}") + + def close(self): + if self.device: + self.device.close() + self.device = None diff --git a/hwci/requirements-frozen.txt b/hwci/requirements-frozen.txt index 5b197a1..7c15043 100644 --- a/hwci/requirements-frozen.txt +++ b/hwci/requirements-frozen.txt @@ -1,14 +1,17 @@ argcomplete==3.5.1 colorama==0.4.6 +colorzero==2.0 crcmod==1.7 +gpiozero==2.0.1 pexpect==4.9.0 prompt-toolkit==3.0.36 ptyprocess==0.7.0 pycryptodome==3.21.0 pyserial==3.5 +PyYAML==6.0.2 questionary==2.0.1 siphash==0.0.1 tockloader==1.13.0 toml==0.10.2 -tqdm==4.66.5 +tqdm==4.66.6 wcwidth==0.2.13 diff --git a/hwci/requirements.txt b/hwci/requirements.txt index 16398e5..837a8aa 100644 --- a/hwci/requirements.txt +++ b/hwci/requirements.txt @@ -5,3 +5,5 @@ pexpect pyserial tockloader +gpiozero +pyyaml diff --git a/hwci/target-spec.yml b/hwci/target-spec.yml new file mode 100644 index 0000000..6a42cdd --- /dev/null +++ b/hwci/target-spec.yml @@ -0,0 +1,28 @@ +model: nrf52840dk +hw_rev: '3.2' +serial_number: 0xfoobar +pin_mappings: + P0.13: + io_interface: raspberrypi5gpio + io_pin_spec: 20 + target_pin_function: LED1 + target_pin_mode: output + target_pin_active: low + P0.14: + io_interface: raspberrypi5gpio + io_pin_spec: 19 + target_pin_function: LED2 + target_pin_mode: output + target_pin_active: low + P0.11: + io_interface: raspberrypi5gpio + io_pin_spec: 21 + target_pin_function: BUTTON1 + target_pin_mode: input + target_pin_active: low + P0.12: + io_interface: raspberrypi5gpio + io_pin_spec: 26 + target_pin_function: BUTTON2 + target_pin_mode: input + target_pin_active: low diff --git a/hwci/tests/adc.py b/hwci/tests/adc.py deleted file mode 100644 index db4ecc7..0000000 --- a/hwci/tests/adc.py +++ /dev/null @@ -1,30 +0,0 @@ -from utils.test_helpers import AnalyzeConsoleTest -import logging - - -class AdcTest(AnalyzeConsoleTest): - def __init__(self): - super().__init__(apps=["tests/adc/adc"]) - - def analyze(self, lines): - adc_driver_found = False - adc_readings_found = False - for line in lines: - if "ADC driver exists" in line: - adc_driver_found = True - if "ADC Reading:" in line: - adc_readings_found = True - break - if "No ADC driver!" in line: - logging.warning("No ADC driver available.") - return # Test passes if ADC is not available - if adc_driver_found and adc_readings_found: - logging.info("ADC Test passed with readings.") - elif adc_driver_found: - raise Exception("ADC Test failed: Driver found but no readings.") - else: - logging.warning("ADC Test skipped: No ADC driver.") - return # Test passes if ADC is not available - - -test = AdcTest() diff --git a/hwci/tests/adc_continuous.py b/hwci/tests/adc_continuous.py deleted file mode 100644 index d7f1603..0000000 --- a/hwci/tests/adc_continuous.py +++ /dev/null @@ -1,3 +0,0 @@ -from utils.test_helpers import WaitForConsoleMessageTest - -test = WaitForConsoleMessageTest(["tests/adc/adc_continuous"], "No ADC driver!") diff --git a/hwci/tests/ble_advertising.py b/hwci/tests/ble_advertising.py deleted file mode 100644 index 44a669a..0000000 --- a/hwci/tests/ble_advertising.py +++ /dev/null @@ -1,5 +0,0 @@ -from utils.test_helpers import WaitForConsoleMessageTest - -test = WaitForConsoleMessageTest( - ["ble_advertising"], "Now advertising every 300 ms as 'TockOS'" -) diff --git a/hwci/tests/ble_env_sense.py b/hwci/tests/ble_env_sense.py deleted file mode 100644 index 60a2673..0000000 --- a/hwci/tests/ble_env_sense.py +++ /dev/null @@ -1,6 +0,0 @@ -from utils.test_helpers import WaitForConsoleMessageTest - -test = WaitForConsoleMessageTest( - ["services/ble-env-sense", "services/ble-env-sense/test-with-sensors"], - "BLE ERROR: Code = 16385", -) diff --git a/hwci/tests/ble_passive_scanning.py b/hwci/tests/ble_passive_scanning.py deleted file mode 100644 index f8bbed7..0000000 --- a/hwci/tests/ble_passive_scanning.py +++ /dev/null @@ -1,26 +0,0 @@ -from utils.test_helpers import AnalyzeConsoleTest -import logging - - -class BlePassiveScanningTest(AnalyzeConsoleTest): - def __init__(self): - super().__init__(apps=["ble_passive_scanning"]) - - def analyze(self, lines): - found_advertisements = False - for line in lines: - if "PDU Type:" in line: - found_advertisements = True - break - if found_advertisements: - logging.info("BLE Passive Scanning Test passed.") - else: - logging.warning( - "BLE Passive Scanning Test could not detect advertisements. Ensure BLE devices are nearby." - ) - raise Exception( - "BLE Passive Scanning Test failed: No advertisements detected." - ) - - -test = BlePassiveScanningTest() diff --git a/hwci/tests/c_hello_and_printf_long.py b/hwci/tests/c_hello_and_printf_long.py deleted file mode 100644 index c80ef93..0000000 --- a/hwci/tests/c_hello_and_printf_long.py +++ /dev/null @@ -1,28 +0,0 @@ -from utils.test_helpers import AnalyzeConsoleTest -import logging - - -class CHelloAndPrintfLongTest(AnalyzeConsoleTest): - def __init__(self): - super().__init__(apps=["c_hello", "tests/printf_long"]) - - def analyze(self, lines): - expected_messages = [ - "Hello World!", - "Hi welcome to Tock. This test makes sure that a greater than 64 byte message can be printed.", - "And a short message.", - ] - messages_found = {msg: False for msg in expected_messages} - - for line in lines: - for msg in expected_messages: - if msg in line: - messages_found[msg] = True - - for msg, found in messages_found.items(): - if not found: - raise Exception(f"Did not find expected message: '{msg}'") - logging.info("C Hello and Printf Long Test passed.") - - -test = CHelloAndPrintfLongTest() diff --git a/hwci/tests/console_recv_long.py b/hwci/tests/console_recv_long.py deleted file mode 100644 index 4372533..0000000 --- a/hwci/tests/console_recv_long.py +++ /dev/null @@ -1,5 +0,0 @@ -from utils.test_helpers import WaitForConsoleMessageTest - -test = WaitForConsoleMessageTest( - ["tests/console/console_recv_long"], "[SHORT] Error doing UART receive: -2" -) diff --git a/hwci/tests/console_recv_short.py b/hwci/tests/console_recv_short.py deleted file mode 100644 index 85cc668..0000000 --- a/hwci/tests/console_recv_short.py +++ /dev/null @@ -1,5 +0,0 @@ -from utils.test_helpers import WaitForConsoleMessageTest - -test = WaitForConsoleMessageTest( - ["tests/console/console_recv_short"], "[SHORT] Error doing UART receive: -2" -) diff --git a/hwci/tests/gpio_test.py b/hwci/tests/gpio_test.py deleted file mode 100644 index 3b08391..0000000 --- a/hwci/tests/gpio_test.py +++ /dev/null @@ -1,21 +0,0 @@ -from utils.test_helpers import AnalyzeConsoleTest -import logging - - -class GpioInterruptTest(AnalyzeConsoleTest): - def __init__(self): - super().__init__(apps=["tests/gpio/gpio_interrupt"]) - - def analyze(self, lines): - interrupt_detected = False - for line in lines: - if "GPIO Interrupt!" in line: - interrupt_detected = True - break - if interrupt_detected: - logging.info("GPIO Interrupt Test passed.") - else: - raise Exception("GPIO Interrupt Test failed: No interrupt detected.") - - -test = GpioInterruptTest() diff --git a/hwci/tests/ipc_logic.py b/hwci/tests/ipc_logic.py deleted file mode 100644 index 13e9a7f..0000000 --- a/hwci/tests/ipc_logic.py +++ /dev/null @@ -1,24 +0,0 @@ -from utils.test_helpers import AnalyzeConsoleTest -import logging - - -class IpcLogicTest(AnalyzeConsoleTest): - def __init__(self): - super().__init__( - apps=[ - "tutorials/05_ipc/led", - "tutorials/05_ipc/rng", - "tutorials/05_ipc/logic", - ] - ) - - def analyze(self, lines): - expected_output = "Number of LEDs:" - for line in lines: - if expected_output in line: - logging.info("IPC Logic Test passed.") - return - raise Exception("IPC Logic Test failed: Expected output not found.") - - -test = IpcLogicTest() diff --git a/hwci/tests/lua_hello.py b/hwci/tests/lua_hello.py deleted file mode 100644 index 02f3442..0000000 --- a/hwci/tests/lua_hello.py +++ /dev/null @@ -1,3 +0,0 @@ -from utils.test_helpers import WaitForConsoleMessageTest - -test = WaitForConsoleMessageTest(["lua-hello"], "Hello from Lua!") diff --git a/hwci/tests/malloc_test01.py b/hwci/tests/malloc_test01.py deleted file mode 100644 index 9a34da5..0000000 --- a/hwci/tests/malloc_test01.py +++ /dev/null @@ -1,3 +0,0 @@ -from utils.test_helpers import WaitForConsoleMessageTest - -test = WaitForConsoleMessageTest(["tests/malloc_test01"], "malloc01: success") diff --git a/hwci/tests/malloc_test02.py b/hwci/tests/malloc_test02.py deleted file mode 100644 index 8e921a6..0000000 --- a/hwci/tests/malloc_test02.py +++ /dev/null @@ -1,3 +0,0 @@ -from utils.test_helpers import WaitForConsoleMessageTest - -test = WaitForConsoleMessageTest(["tests/malloc_test02"], "malloc02: success") diff --git a/hwci/tests/mpu_stack_growth.py b/hwci/tests/mpu_stack_growth.py deleted file mode 100644 index 399afde..0000000 --- a/hwci/tests/mpu_stack_growth.py +++ /dev/null @@ -1,16 +0,0 @@ -from utils.test_helpers import AnalyzeConsoleTest - - -class MpuStackGrowthTest(AnalyzeConsoleTest): - def __init__(self): - super().__init__(apps=["tests/mpu/mpu_stack_growth"]) - - def analyze(self, lines): - for line in lines: - if "[TEST] MPU Stack Growth" in line: - # Test started successfully - return - raise Exception("MPU Stack Growth test did not start") - - -test = MpuStackGrowthTest() diff --git a/hwci/tests/mpu_walk_region.py b/hwci/tests/mpu_walk_region.py index 0e03be6..621128c 100644 --- a/hwci/tests/mpu_walk_region.py +++ b/hwci/tests/mpu_walk_region.py @@ -1,16 +1,72 @@ -from utils.test_helpers import AnalyzeConsoleTest +# Licensed under the Apache License, Version 2.0 or the MIT License. +# SPDX-License-Identifier: Apache-2.0 OR MIT +import logging +from utils.test_helpers import OneshotTest +import time -class MpuWalkRegionTest(AnalyzeConsoleTest): - def __init__(self): - super().__init__(apps=["tests/mpu/mpu_walk_region"]) - def analyze(self, lines): - for line in lines: - if "[TEST] MPU Walk Regions" in line: - # Test started successfully - return - raise Exception("MPU Walk Region test did not start") +class MpuWalkRegionTest(OneshotTest): + def oneshot_test(self, board): + gpio = board.gpio + serial = board.serial + # Map 'BTN0' to the appropriate pin label in your target spec + # Assuming 'BTN0' is 'P0.11' as per your target_spec.yaml + btn0 = gpio.pin("P0.11") -test = MpuWalkRegionTest() + # Configure the pin as output to simulate button press (active low) + btn0.set_mode("output") + btn0.write(1) # Ensure button is not pressed initially (inactive state) + + # Start the test + logging.info("Starting MPU Walk Region Test") + # Wait for "[TEST] MPU Walk Regions" + output = serial.expect(r"\[TEST\] MPU Walk Regions", timeout=10) + if not output: + raise Exception("Did not receive expected test start message") + + # First test: overrun flash region + logging.info("First overrun test: Overrun flash region") + # Wait for "Walking flash" + serial.expect("Walking flash", timeout=5) + # Wait for "Walking memory" + serial.expect("Walking memory", timeout=5) + # Wait for " incr " + serial.expect(" incr ", timeout=5) + # Simulate button press (active low) + btn0.write(0) + logging.info("Button pressed (simulated)") + # Wait for "Walking flash...Will overrun" + serial.expect(r"Walking flash.*Will overrun", timeout=10) + # Wait for "mpu_walk_region had a fault" + serial.expect("mpu_walk_region had a fault", timeout=10) + # Wait for "mcause: 0x00000005 (Load access fault)" + serial.expect("mcause: 0x00000005 \(Load access fault\)", timeout=5) + logging.info("First overrun test passed") + + # Release the button + btn0.write(1) + logging.info("Button released (simulated)") + + # Second test: overrun RAM region + logging.info("Second overrun test: Overrun RAM region") + # Wait for "Walking flash" + serial.expect("Walking flash", timeout=10) + # Wait for " incr " + serial.expect(" incr ", timeout=5) + # Simulate button press (active low) + btn0.write(0) + logging.info("Button pressed (simulated)") + # Wait for "Walking memory...Will overrun" + serial.expect(r"Walking memory.*Will overrun", timeout=10) + # Wait for "mpu_walk_region had a fault" + serial.expect("mpu_walk_region had a fault", timeout=10) + # Wait for "mcause: 0x00000005 (Load access fault)" + serial.expect("mcause: 0x00000005 \(Load access fault\)", timeout=5) + logging.info("Second overrun test passed") + + logging.info("MPU Walk Region Test completed successfully") + + +test = MpuWalkRegionTest(["tests/mpu/mpu_walk_region"]) diff --git a/hwci/tests/multi_alarm_simple_test.py b/hwci/tests/multi_alarm_simple_test.py deleted file mode 100644 index 0af582a..0000000 --- a/hwci/tests/multi_alarm_simple_test.py +++ /dev/null @@ -1,41 +0,0 @@ -from utils.test_helpers import AnalyzeConsoleTest -import logging - - -class MultiAlarmSimpleTest(AnalyzeConsoleTest): - def __init__(self): - super().__init__(apps=["tests/multi_alarm_simple_test"]) - - def analyze(self, lines): - # Initialize counts for each alarm - alarm_counts = {1: 0, 2: 0} - - for line in lines: - tokens = line.strip().split() - if len(tokens) >= 3: - try: - alarm_index = int(tokens[0]) - # Optional: parse timestamps if needed - # now = int(tokens[1]) - # expiration = int(tokens[2]) - - # Record counts - if alarm_index in [1, 2]: - alarm_counts[alarm_index] += 1 - except ValueError: - continue # Skip lines that don't parse correctly - - logging.info(f"Alarm counts: {alarm_counts}") - count1 = alarm_counts.get(1, 0) - count2 = alarm_counts.get(2, 0) - if count1 < 2 or count2 < 1: - raise Exception("MultiAlarmSimpleTest failed: Not enough alarms fired") - if count1 < 2 * count2: - raise Exception( - "MultiAlarmSimpleTest failed: Alarm 1 did not fire at least twice as often as Alarm 2" - ) - - logging.info("MultiAlarmSimpleTest passed") - - -test = MultiAlarmSimpleTest() diff --git a/hwci/tests/multi_alarm_test.py b/hwci/tests/multi_alarm_test.py deleted file mode 100644 index e69de29..0000000 diff --git a/hwci/tests/printf_long.py b/hwci/tests/printf_long.py deleted file mode 100644 index 7926f09..0000000 --- a/hwci/tests/printf_long.py +++ /dev/null @@ -1,6 +0,0 @@ -from utils.test_helpers import WaitForConsoleMessageTest - -test = WaitForConsoleMessageTest( - ["tests/printf_long"], - "Hi welcome to Tock. This test makes sure that a greater than 64 byte message can be printed.", -) diff --git a/hwci/tests/sensors.py b/hwci/tests/sensors.py deleted file mode 100644 index 243d686..0000000 --- a/hwci/tests/sensors.py +++ /dev/null @@ -1,23 +0,0 @@ -from utils.test_helpers import AnalyzeConsoleTest -import logging - - -class SensorsTest(AnalyzeConsoleTest): - def __init__(self): - super().__init__(apps=["sensors"]) - - def analyze(self, lines): - sensors_detected = False - for line in lines: - if "Sampling" in line: - sensors_detected = True - if "deg C" in line or "Light Intensity" in line or "Humidity" in line: - logging.info(f"Sensor reading: {line.strip()}") - return - if sensors_detected: - raise Exception("Sensors Test failed: No sensor readings found.") - else: - logging.warning("Sensors Test skipped: No sensors detected.") - - -test = SensorsTest() diff --git a/hwci/tests/stack_size_test01.py b/hwci/tests/stack_size_test01.py deleted file mode 100644 index c5cec35..0000000 --- a/hwci/tests/stack_size_test01.py +++ /dev/null @@ -1,3 +0,0 @@ -from utils.test_helpers import WaitForConsoleMessageTest - -test = WaitForConsoleMessageTest(["tests/stack_size_test01"], "Stack Test App") diff --git a/hwci/tests/stack_size_test02.py b/hwci/tests/stack_size_test02.py deleted file mode 100644 index b344355..0000000 --- a/hwci/tests/stack_size_test02.py +++ /dev/null @@ -1,3 +0,0 @@ -from utils.test_helpers import WaitForConsoleMessageTest - -test = WaitForConsoleMessageTest(["tests/stack_size_test02"], "Stack Test App") diff --git a/hwci/tests/whileone.py b/hwci/tests/whileone.py deleted file mode 100644 index 68b3ce6..0000000 --- a/hwci/tests/whileone.py +++ /dev/null @@ -1,17 +0,0 @@ -from utils.test_helpers import AnalyzeConsoleTest - - -class WhileOneTest(AnalyzeConsoleTest): - def __init__(self): - super().__init__(apps=["tests/whileone"]) - - def analyze(self, lines): - # This app does not produce output, but we can check for the absence of crashes - for line in lines: - if "Kernel panic" in line or "Fault" in line: - raise Exception("App crashed with a fault") - # If no faults, the test passes - return - - -test = WhileOneTest() diff --git a/hwci/utils/test_helpers/oneshot.py b/hwci/utils/test_helpers/oneshot.py index df6d799..ff7ba47 100644 --- a/hwci/utils/test_helpers/oneshot.py +++ b/hwci/utils/test_helpers/oneshot.py @@ -1,6 +1,7 @@ import logging from core.test_harness import TestHarness + class OneshotTest(TestHarness): def __init__(self, apps=[]): self.apps = apps