Skip to content

Commit

Permalink
gpio: init + mpu_walk_region test
Browse files Browse the repository at this point in the history
  • Loading branch information
charles37 committed Oct 29, 2024
1 parent 12af853 commit b42a32f
Show file tree
Hide file tree
Showing 36 changed files with 337 additions and 310 deletions.
44 changes: 24 additions & 20 deletions .github/workflows/treadmill-ci-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
26 changes: 26 additions & 0 deletions hwci/boards/nrf52dk.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -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")
Expand All @@ -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")
Expand Down Expand Up @@ -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()
28 changes: 28 additions & 0 deletions hwci/boards/specs/nrf52dk.yml
Original file line number Diff line number Diff line change
@@ -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
3 changes: 3 additions & 0 deletions hwci/core/board_harness.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ def get_serial_port(self):
def get_gpio_interface(self):
pass

def cleanup(self):
pass

def erase_board(self):
pass

Expand Down
2 changes: 1 addition & 1 deletion hwci/core/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__":
Expand Down
7 changes: 1 addition & 6 deletions hwci/tests/__init__.py → hwci/gpio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
42 changes: 42 additions & 0 deletions hwci/gpio/gpio.py
Original file line number Diff line number Diff line change
@@ -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)
6 changes: 6 additions & 0 deletions hwci/gpio/interfaces/__init__.py
Original file line number Diff line number Diff line change
@@ -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
40 changes: 40 additions & 0 deletions hwci/gpio/interfaces/mock_gpio.py
Original file line number Diff line number Diff line change
@@ -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}")
64 changes: 64 additions & 0 deletions hwci/gpio/interfaces/raspberry_pi5_gpio.py
Original file line number Diff line number Diff line change
@@ -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
5 changes: 4 additions & 1 deletion hwci/requirements-frozen.txt
Original file line number Diff line number Diff line change
@@ -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
2 changes: 2 additions & 0 deletions hwci/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@
pexpect
pyserial
tockloader
gpiozero
pyyaml
28 changes: 28 additions & 0 deletions hwci/target-spec.yml
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit b42a32f

Please sign in to comment.