Skip to content
Merged
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
5 changes: 5 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
BasedOnStyle: Google
IndentWidth: 4
ColumnLimit: 100
# HLS headers are order-dependent (spatial_hash.h defines types encoder_systolic.h uses)
SortIncludes: Never
10 changes: 10 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.git
node_modules
assets
figures
demo
models/models/*.pth
**/__pycache__
*.egg-info
build
dist
5 changes: 5 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Single source of truth for flake8 — used by make lint, pre-commit, and CI.
# Error-only gate: syntax errors and undefined names, not style.
[flake8]
select = E9,F63,F7,F82
exclude = node_modules,build,dist,.git,__pycache__,*.egg-info
120 changes: 30 additions & 90 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,106 +1,46 @@
# CI/CD Pipeline — FPGA Event-Based Drone Collision Avoidance
# CI — FPGA Event-Based Drone Collision Avoidance
#
# The `test` job is the required status check for branch protection
# (ENO-11): it builds the Docker toolchain image and runs `make test`
# (Python pipeline + golden model + ARM C++ + FPGA testbench) inside it.
# Keep the job name stable.
name: CI

on:
push:
branches: [main, master, develop]
branches: [main, master]
pull_request:
branches: [main, master]

jobs:
# ---------------------------------------------------------------------------
# Python Pipeline Tests
# ---------------------------------------------------------------------------
python-tests:
name: Python Pipeline Tests
test:
name: test
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", "3.11"]
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
- uses: docker/setup-buildx-action@v3
- name: Build toolchain image
uses: docker/build-push-action@v6
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
pip install --upgrade pip setuptools wheel
pip install -r requirements.txt
pip install pytest pytest-cov pyyaml
- name: Run Python pipeline simulator tests
run: |
python test/test_fpga_simulator.py
- name: Run FPGA equivalence check
run: |
python test/golden_model_test.py
- name: Run FPGA weight conversion test
run: |
python train/convert_weights_to_fpga.py --validate-only
- name: Lint with flake8
run: |
pip install flake8
flake8 drone/ models/ train/ --count --select=E9,F63,F7,F82 --show-source --statistics

# ---------------------------------------------------------------------------
# ARM C++ Unit Tests
# ---------------------------------------------------------------------------
arm-cpp-tests:
name: ARM C++ Unit Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install build tools
run: |
sudo apt-get update -qq && sudo apt-get install -y -qq build-essential
- name: Build ARM simulation with g++
run: |
cd arm
g++ -std=c++17 -O2 -DSIMULATION -DFPGA_SIM -I. drone_main.cpp -o drone_control_sim -lpthread 2>&1 || true
echo "ARM simulation compile attempt complete"
- name: Run ARM collision predictor tests
run: |
cd arm && g++ -std=c++17 -O2 -DSIMULATION -DFPGA_SIM -I. drone_main.cpp -o drone_control_sim -lpthread 2>&1 || true
echo "ARM C++ tests require arm-linux-gnueabihf-g++ cross-compiler."
echo "Skipping execution on standard x86 runner."
context: .
load: true
tags: fpga-event-encode:ci
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Run test suite
run: docker run --rm -v "$PWD:/repo" -w /repo fpga-event-encode:ci make test

# ---------------------------------------------------------------------------
# FPGA Testbench
# ---------------------------------------------------------------------------
fpga-testbench:
name: FPGA C++ Testbench
lint:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install build tools
run: |
sudo apt-get update -qq && sudo apt-get install -y -qq build-essential
- name: FPGA C++ build check (Vitis HLS not available)
run: |
echo "FPGA C++ testbench requires Vitis HLS (Xilinx toolchain)."
echo "Install Vitis HLS 2023.1+ and run: vitis_hls -f fpga/build.tcl csim"
echo "Standard g++ cannot compile Vitis-specific fixed-point type conversions."
echo "Skipping compilation on GitHub Actions runner."
- name: Verify config.yaml syntax
run: |
pip install pyyaml -q
python -c "import yaml; c=yaml.safe_load(open('fpga/config.yaml')); print('config.yaml: OK (',len(c),'sections)')"

# ---------------------------------------------------------------------------
# Build Check
# ---------------------------------------------------------------------------
build-check:
name: Build Verification
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install build tools
run: |
sudo apt-get update -qq && sudo apt-get install -y -qq build-essential
- name: Check setup.py builds
run: |
pip install --upgrade pip setuptools wheel
python setup.py sdist
- name: Check root Makefile targets
run: |
make help 2>&1 || echo "Root Makefile help displayed"
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install linters
# clang-format pinned to match .pre-commit-config.yaml — formatting
# differs across major versions
run: pip install flake8 clang-format==18.1.8
- name: Lint
run: make lint
10 changes: 9 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ __pycache__/
# C extensions
*.so

node_modules/
# Distribution / packaging
.Python
build/
Expand Down Expand Up @@ -161,4 +162,11 @@ cython_debug/
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

egomotion/data/
egomotion/data/

# Native test/build artifacts (rebuilt by make test)
arm/drone_control_sim
arm/*.o
fpga/testbench
test/test_arm_cp
test/test_arm_evasion
13 changes: 13 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Setup: pip install pre-commit && pre-commit install
repos:
- repo: https://github.com/pycqa/flake8
rev: 7.1.1
hooks:
- id: flake8
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v18.1.8
hooks:
- id: clang-format
types_or: [c++]
files: ^(arm|fpga|test)/
exclude: ^fpga/weights/ # auto-generated by convert_weights_to_fpga.py
4 changes: 4 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ git clone https://github.com/Enotrium/FPGA-Event-Based-encode
cd FPGA-Event-Based-encode
pip install -e .
make install
pip install pre-commit && pre-commit install # flake8 + clang-format on commit
```

No local toolchain? `make docker-test` builds the pinned environment
(Python 3.11, g++-13, CPU torch) and runs the full suite inside it.

## Running Tests

```bash
Expand Down
23 changes: 23 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Toolchain image for FPGA Event-Based Drone Collision Avoidance.
# The repo is bind-mounted at /repo (see `make docker-test`), so this image
# only carries dependencies and rebuilds only when this file or
# requirements.txt change.
FROM python:3.11-slim-trixie

# g++-13 pinned: trixie's default g++ is 14, which rejects the template
# bodies in fpga/hls_compat.h. The Makefiles invoke plain `g++`.
RUN apt-get update && apt-get install -y --no-install-recommends \
g++-13 gcc-13 make libgl1 libglib2.0-0 \
&& rm -rf /var/lib/apt/lists/* \
&& ln -s /usr/bin/g++-13 /usr/local/bin/g++ \
&& ln -s /usr/bin/gcc-13 /usr/local/bin/gcc \
&& ln -s /usr/bin/g++-13 /usr/local/bin/c++ \
&& ln -s /usr/bin/gcc-13 /usr/local/bin/cc

# CPU-only torch (no CUDA wheels) keeps the image ~1.5 GB smaller.
COPY requirements.txt /tmp/requirements.txt
RUN pip install --no-cache-dir torch --index-url https://download.pytorch.org/whl/cpu \
&& pip install --no-cache-dir -r /tmp/requirements.txt flake8 clang-format==18.1.8

WORKDIR /repo
CMD ["make", "test"]
24 changes: 19 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@
# make install : Install Python package
# make ci : Run full CI pipeline locally
#
.PHONY: help test test-py test-arm test-fpga lint build build-arm convert clean install ci
.PHONY: help test test-py test-arm test-fpga lint build build-arm convert clean install ci docker-build docker-test

# Default Python
PYTHON := python3

# Docker toolchain image (Python 3.11 + g++-13 + CPU torch)
IMAGE ?= fpga-event-encode:dev

help:
@echo "FPGA Event-Based Drone Collision Avoidance"
@echo ""
Expand All @@ -35,6 +38,8 @@ help:
@echo " make clean Remove build artifacts"
@echo " make install Install Python package (pip install -e .)"
@echo " make ci Run full CI pipeline locally"
@echo " make docker-build Build the Docker toolchain image"
@echo " make docker-test Run make test inside the Docker image"
@echo ""

# ── Test Targets ────────────────────────────────────────────────────────────
Expand All @@ -54,11 +59,11 @@ test-py:
test-arm:
@echo "=== ARM C++ Unit Tests ==="
cd arm && $(MAKE) sim
cd test && g++ -std=c++17 -I.. -I../arm -o test_arm_cp test_arm_collision_predictor.cpp -lpthread && ./test_arm_cp
cd test && g++ -std=c++17 -O2 -I.. -I../arm -o test_arm_cp test_arm_collision_predictor.cpp -lpthread && ./test_arm_cp

test-fpga:
@echo "=== FPGA C++ Testbench ==="
cd fpga && g++ -std=c++11 -I. -D__SIMULATION__ -o testbench testbench.cpp -lm && ./testbench
cd fpga && g++ -std=c++11 -O2 -I. -D__SIMULATION__ -o testbench testbench.cpp -lm && ./testbench

test-hil:
@echo "=== Hardware-in-the-Loop Simulation ==="
Expand All @@ -68,11 +73,12 @@ test-hil:

lint:
@echo "=== flake8 ==="
pip install -q flake8 2>/dev/null
flake8 drone/ models/ train/ test/ --count --select=E9,F63,F7,F82 --show-source --statistics
flake8 drone/ models/ train/ test/ --count --show-source --statistics
@echo "=== Python syntax check ==="
$(PYTHON) -m py_compile setup.py
$(PYTHON) -m compileall -q drone/ models/ train/ test/
@echo "=== clang-format ==="
clang-format --dry-run --Werror arm/*.h arm/*.cpp fpga/*.h fpga/*.cpp test/*.cpp

# ── Build Targets ────────────────────────────────────────────────────────────

Expand All @@ -88,6 +94,14 @@ convert:
--input models/models/UNION.pth \
--output models/models/FPGA.pth

# ── Docker ───────────────────────────────────────────────────────────────────

docker-build:
docker build -t $(IMAGE) .

docker-test: docker-build
docker run --rm -u $(shell id -u):$(shell id -g) -v $(CURDIR):/repo -w /repo $(IMAGE) make test

# ── Install ──────────────────────────────────────────────────────────────────

install:
Expand Down
3 changes: 3 additions & 0 deletions arm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ $(TARGET): $(OBJECTS)
@echo "Built $@ for Zynq ARM (hardware mode)"

# Simulation target (no FPGA hardware needed)
# Override CXX too: objects must be compiled with the same native g++ the
# sim link rule uses, not the ARM cross-compiler default.
sim: CXX = g++
sim: CXXFLAGS = $(CXXFLAGS_COMMON) $(RELEASE_FLAGS) $(SIM_FLAGS)
sim: $(TARGET_SIM)

Expand Down
Loading
Loading