Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jvollmer new pr #2

Closed
wants to merge 12 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 123 additions & 0 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
name: run-tests

on:
pull_request:
branches:
- 'main'

# The cancel-in-progress concurrency option can only be specified at the workflow or job level, and job-level concurrency is ineffective when dealing with queued workflows.
# Given that we don't want to cancel the workflow while fetching mbed-os libraries or flashing, the cancel-in-progress option is set to false to prevent canceling the
# workflow at these times. However, this still prevents multiple identical queued workflows from piling up.
concurrency:
group: ${{ github.event_name }}.${{ github.head_ref }}.${{ github.workflow }}
cancel-in-progress: false

jobs:
setup:
runs-on:
- self-hosted

outputs:
target: ${{ steps.get-dev-info.outputs.device }}
ser_port: ${{ steps.get-dev-info.outputs.serial }}
flash_mntpt: ${{ steps.get-dev-info.outputs.mountpoint }}

steps:
- name: Set Environment Variables
run: |
echo "MBED_OS_REF_LOCATION=$HOME/${{ github.repository }}/mbed-os-ref" >> "$GITHUB_ENV"

- name: Get Repo
uses: actions/checkout@v3
with:
# Don't run `git clean -ffdx` and `git reset --hard HEAD` in this step to avoid removing `mbed-os/`.
# These will be run post checkout in the following step
clean: false

# Clean up any changes in the working index, including untracked files aside from mbed-os/
- name: Post Checkout Cleanup
run: |
git clean -ffdxe mbed-os
git reset --hard HEAD

# Checks if the current reference in mbed-os.lib is the same as what is stored on the runner from the
# previous workflow. If not, update the stored reference and fetch the new libraries
# TODO This only handles mbed-os.lib. To be able to handle other .lib files, it would be worth creating
# a script or custom action to check/update all library references
- name: Check if mbed-os Libraries Need to be Fetched
id: check-mbed-os-libs
run: |
echo ${{ github.event.before }} ${{ github.event.after }}
git reflog
# Get the commit hashes of the two most recent states of the repo on the runner
# If mbed-os.lib changed between the two states, fetch the mbed libraries in the next step
hashes=$(git reflog | head -n 1 | grep -Po "(?<=moving from )\S+|(?<= to )\S+$")
echo "$hashes"
git diff --name-only $hashes
echo "SEPARATOR"
git diff $hashes
if [[ -f "$MBED_OS_REF_LOCATION/mbed-os.lib" ]]; then
if [[ -n $(diff "$MBED_OS_REF_LOCATION/mbed-os.lib" mbed-os.lib) ]]; then
cp mbed-os.lib "$MBED_OS_REF_LOCATION"
echo "fetch_libs=y" >> "$GITHUB_OUTPUT"
echo "Needed to fetch mbed-os libraries because they were not up-to-date on the runner" >> $GITHUB_STEP_SUMMARY
else
echo "fetch_libs=$([[ -d mbed-os ]] && echo n || echo y)" >> "$GITHUB_OUTPUT"
[[ -d mbed-os ]] && \
echo "mbed-os libraries are up-to-date :relieved:" >> $GITHUB_STEP_SUMMARY || \
echo "Needed to fetch mbed-os libraries because mbed-os did not exist on the runner, but the stored library reference was up-to-date :finnadie:" >> $GITHUB_STEP_SUMMARY
fi
else
mkdir -p "$MBED_OS_REF_LOCATION"
cp mbed-os.lib "$MBED_OS_REF_LOCATION"
echo "fetch_libs=$([[ -d mbed-os ]] && echo n || echo y)" >> "$GITHUB_OUTPUT"
echo "Needed to fetch mbed-os libraries because neither mbed-os nor the stored reference was present on the runner :point_right::point_left:" >> $GITHUB_STEP_SUMMARY
fi

- name: Fetch Mbed Libraries
if: steps.check-mbed-os-libs.outputs.fetch_libs == 'y'
run: |
if [[ -d mbed-os ]]; then
echo "Removing mbed-os before fetching libraries"
rm -rf mbed-os
fi
mbed-tools deploy

# Gets device info using `mbed-tools detect` and sets output needed for compiling and flashing
# NOTE: Expecting '/mnt/$USER/' to be the base path for the mount point, as specified in the runner's ldm (https://github.com/LemonBoy/ldm) configuration,
# despite /media/[$USER/] typically being the base path for removable media
- name: Get Device Info
id: get-dev-info
run: |
device=$(python3 parseConfigs.py)
detect_out=$(mbed-tools detect | grep "$device")
#device=$(echo "$detect_out" | grep -oE "NUCLEO_\\S*")
serial=$(echo "$detect_out" | grep -oE "/dev/tty\\S*")
mountpoint=$(echo "$detect_out" | grep -oE "/mnt/$USER/\\S*")
if [[ -z "$serial" || -z "$mountpoint" ]]; then
echo "Failed to detect serial port and/or mount point matching '/dev/tty*' and '/mnt/$USER/*', respectively, for target '$device' :hurtrealbad:" >> $GITHUB_STEP_SUMMARY
exit 1
fi
echo "device=$device" >> "$GITHUB_OUTPUT"
echo "serial=$serial" >> "$GITHUB_OUTPUT"
echo "mountpoint=$mountpoint" >> "$GITHUB_OUTPUT"
echo "Found target '$device' connected to serial port '$serial' with storage mounted to '$mountpoint' :relieved:" >> $GITHUB_STEP_SUMMARY

compile-and-flash:
needs: setup
env:
BUILD_PROFILE: develop
TOOLCHAIN: GCC_ARM
runs-on:
- self-hosted

steps:
- name: Compile and Flash
if: false # TODO Remove
run: |
mbed-tools configure -t ${{ env.TOOLCHAIN }} -m ${{ needs.setup.outputs.target }}
cmake -S . -B cmake_build/${{ needs.setup.outputs.target }}/${{ env.BUILD_PROFILE }}/${{ env.TOOLCHAIN }} -GNinja
cmake --build cmake_build/${{ needs.setup.outputs.target }}/${{ env.BUILD_PROFILE }}/${{ env.TOOLCHAIN }}
cp cmake_build/${{ needs.setup.outputs.target }}/${{ env.BUILD_PROFILE }}/${{ env.TOOLCHAIN }}/embedded-mbed.bin ${{ needs.setup.outputs.flash_mntpt }}
echo "Successfully flashed to ${{ needs.setup.outputs.target }} :v:" >> $GITHUB_STEP_SUMMARY

5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.build
.mbed
BUILD
cmake_build
mbed-os
33 changes: 33 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
cmake_minimum_required(VERSION 3.19.0 FATAL_ERROR)

set(MBED_PATH ${CMAKE_CURRENT_SOURCE_DIR}/mbed-os CACHE INTERNAL "")
set(MBED_CONFIG_PATH ${CMAKE_CURRENT_BINARY_DIR} CACHE INTERNAL "")
set(APP_TARGET embedded-mbed)

# --- START MACROS ---
# ---- END MACROS ----

include(${MBED_PATH}/tools/cmake/app.cmake)

project(${APP_TARGET})

add_subdirectory(${MBED_PATH})

add_executable(${APP_TARGET} testRunner.cpp)

target_sources(${APP_TARGET}
PRIVATE
testRunner.cpp
)

target_link_libraries(${APP_TARGET}
PRIVATE
mbed-os
)

mbed_set_post_build(${APP_TARGET})

option(VERBOSE_BUILD "Have a verbose build process")
if(VERBOSE_BUILD)
set(CMAKE_VERBOSE_MAKEFILE ON)
endif()
58 changes: 58 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Allow the user to specify different values for 'PROFILE' and 'TOOLCHAIN'
PROFILE?=develop
TOOLCHAIN?=GCC_ARM

# Useless change

# Parse setup.yml to determine the build target
TARGET := $(shell grep -Po '(^\s+target:\s+)\K.+' setup.yml)
# Check that a value for 'target' was found in setup.yml
ifndef TARGET
$(error Did not find a value for 'target' in setup.yml)
endif
BUILD_DIR := cmake_build/$(TARGET)/$(PROFILE)/$(TOOLCHAIN)
BINARY := embedded-mbed.bin
START_MACROS := ^\# --- START MACROS ---$$
END_MACROS := ^\# ---- END MACROS ----$$
# Search for files matching *.{cpp,h}, but don't search mbed-os/ or cmake_build/
SOURCES := $(shell find . -type d \( -path ./mbed-os -o -path ./cmake_build \) -prune -o -type f -regex '.*\.\(cpp\|h\)' -print)


.PHONY: flash
flash: mountpoint compile
cp $(BUILD_DIR)/$(BINARY) $(MOUNTPOINT)

.PHONY: compile
compile: $(BUILD_DIR)/$(BINARY)

$(BUILD_DIR)/$(BINARY): $(BUILD_DIR)/mbed_config.cmake setup.yml tests.yml CMakeLists.txt parseConfigs.py $(SOURCES)
./parseConfigs.py
cmake -S . -B $(BUILD_DIR) -GNinja
cmake --build $(BUILD_DIR)

.PHONY: configure
configure: $(BUILD_DIR)/mbed_config.cmake

$(BUILD_DIR)/mbed_config.cmake: mbed-os mbed_app.json
mbed-tools configure -t $(TOOLCHAIN) -m $(TARGET)

.PHONY: deploy
deploy: mbed-os

mbed-os: mbed-os.lib
mbed-tools deploy

# Check that MOUNTPOINT was defined as a CLA
.PHONY: mountpoint
mountpoint:
ifndef MOUNTPOINT
$(error variable 'MOUNTPOINT' not set)
endif

.PHONY: clean
clean: clean-cmakelists
rm -rf cmake_build/ mbed-os/

.PHONY: clean-cmakelists
clean-cmakelists:
sed -i '/$(START_MACROS)/,/$(END_MACROS)/{/$(START_MACROS)/!{/$(END_MACROS)/!d}}' CMakeLists.txt
8 changes: 8 additions & 0 deletions install-pre-commit.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash

dir=$(dirname "${BASH_SOURCE[0]}")

chmod +x $dir/pre-commit
cp $dir/pre-commit $dir/.git/hooks/

echo "Copied $dir/pre-commit to $dir/.git/hooks/"
1 change: 1 addition & 0 deletions mbed-os.lib
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
https://github.com/ARMmbed/mbed-os/#17dc3dc2e6e2817a8bd3df62f38583319f0e4fed
8 changes: 8 additions & 0 deletions mbed_app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"target_overrides": {
"*": {
"target.printf_lib": "std",
"target.c_lib": "small"
}
}
}
68 changes: 68 additions & 0 deletions parseConfigs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/bin/python3

import yaml


# Get necessary information from configuration files and CMakeLists.txt
# Additionally, clear existing macros between start and end markers in CMakeLists.txt
with open('tests.yml', 'r') as testFile, open('setup.yml', 'r') as setupFile, open('CMakeLists.txt', 'r') as cmakeFile:
testCfg = yaml.safe_load(testFile)
setupCfg = yaml.safe_load(setupFile)
initCmake = cmakeFile.readlines()

# Iterate through CMakeLists.txt lines and
# - Add all lines to cmake, except for those between the start and end macros markers
# - Store the line number of the start macros marker
cmake = []
keep = True
for lnum, line in enumerate(initCmake):
if keep:
cmake.append(line)
if line == '# --- START MACROS ---\n':
lineNum = lnum + 1
keep = False
elif line == '# ---- END MACROS ----\n':
cmake.append(line)
keep = True


# Get target and ensure that it is consistent across the configuration files
target = setupCfg['setup']['target']
assert target == list(testCfg.keys())[0], "Target in setup.yml ({}) does not match the root key in tests.yml ({})".format(target, list(testCfg.keys())[0])


# Insert definitions for devices and drivers macros
# These macros will be used throughout the project whenever test setup-related info is needed
for setupCat in ['devices', 'drivers']:
if isinstance(setupCfg['setup'][setupCat], dict):
cmake.insert(lineNum, '\n# Define macros for {}\n'.format(setupCat))
lineNum += 1
for setup, setupInfo in setupCfg['setup'][setupCat].items():
for attr, val in setupInfo.items():
# If val is a list, make it a string and reformat it as a C array (i.e. {...} instead of [...])
if isinstance(val, list):
val = '{' + str(val)[1:-1] + '}'
cmake.insert(lineNum, 'ADD_DEFINITIONS(-D{}_{}={})\n'.format(setup.upper(), attr.upper(), val))
lineNum += 1

# Insert definitions for test macros
# These macros will be used in testRunner.cpp to determine what tests should be run
if isinstance(testCfg[target], dict):
cmake.insert(lineNum, '\n# Define macros for tests\n')
lineNum += 1
for testCat, tests in testCfg[target].items():
for test, testType in tests.items():
if testType != 'disabled':
cmake.insert(lineNum, 'ADD_DEFINITIONS(-D{}_{})\n'.format(testCat.upper(), test.upper()))
lineNum += 1

# Add empty line before end macros marker for styling purposes
cmake.insert(lineNum, '\n')

# Replace the contents of CMakeLists.txt with the modified lines
with open('CMakeLists.txt', 'w') as cmakeFile:
cmakeFile.writelines(cmake)


# Output the target so that it can be used to check target availability in the workflow
print(target)
20 changes: 20 additions & 0 deletions pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/bin/bash

# If there are no changes to CMakeLists.txt being committed, then there's no need to check this commit's diff
if [[ -z $(git diff --cached --name-only CMakeLists.txt) ]]; then
exit 0
fi

# Store a diff with every line of CMakeLists.txt in the context to determine if there were any changes between the markers
diff=$(git diff --cached -U$(wc -l CMakeLists.txt) CMakeLists.txt)
grep -Pzo " # --- START MACROS ---\n # ---- END MACROS ----\n" <<< "$diff" 2>/dev/null

# Strict check to ensure that each marker is still in the proper location and only appears once
if [ $(grep -E "^.# --- START MACROS ---$" <<< "$diff" 2>/dev/null | wc -l) != 1 ] || \
[ $(grep -E "^.# ---- END MACROS ----$" <<< "$diff" 2>/dev/null | wc -l) != 1 ] || \
[ $(grep -Pzo " # --- START MACROS ---\n # ---- END MACROS ----\n" <<< "$diff" 2>/dev/null | wc -l) != 2 ]
then
echo -e "\033[1;31mIllegal Modification:\n \033[0;31mAttempted to change lines related to start and end macro definition markers in CMakeLists.txt\033[0m\n\n"
git diff --cached CMakeLists.txt
exit 1
fi
32 changes: 32 additions & 0 deletions setup.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# --- Structure ---
# setup:
# target: <target>
# devices:
# <device>:
# <attribute>: <value>
# drivers:
# <driver>:
# <attribute>: <value>
#
# NOTE: If <value> is an array, format it as a Python list (i.e. [...])

setup:
target: NUCLEO_F767ZI
devices:
i2c_generic:
address: '0x10'
ina219:
address: '0x24'
tcp_server:
address: '"192.168.1.16"'
port: 4001
tcp_client:
address: '"192.168.1.15"'
port: 4001
drivers:
i2c:
data: PF_0
clock: PF_1
ethernet:
netmask: '"255.255.255.0"'
gateway: '"0.0.0.0"'
8 changes: 8 additions & 0 deletions testRunner.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include "mbed.h"

int main()
{
printf("Hello World!\n");

while(1) {}
}
17 changes: 17 additions & 0 deletions tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# --- Structure ---
# <target>:
# <driver>:
# <test_name>: <mock|hardware|disabled>
#
# --- Test Options ---
# mock: Raspberry Pi emulates the device through software
# hardware: Hardware setup connected to the UUT. The Raspberry Pi does not mock the device
# disabled: Test will not be run

NUCLEO_F767ZI:
i2c:
generic: mock
ina219: mock
ethernet:
ping_tcp_server: mock
ping_tcp_client: mock