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
18 changes: 0 additions & 18 deletions .github/workflows/build-and-deploy.yml

This file was deleted.

36 changes: 36 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
# The portal, https://hardfoc.github.io/: an unversioned site on the shared HardFOC theme. Pull requests build,
# check (strict build, offline link check, Lighthouse, screenshots) and never publish; a push to main publishes
# the built site as the whole gh-pages branch. The repository catalogue is generated from the GitHub API at build
# time (tools/portal/catalogue.py), so every publish shows the current repositories and releases.
name: 📚 Portal

on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: '17 5 * * *' # daily: new repositories, releases and Pages sites appear without a commit
workflow_dispatch:

permissions:
contents: read

concurrency:
group: portal-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
site:
# The branch of hardfoc/hf-general-ci-tools#42 (the versioning input) until it is released; then @v1.
uses: hardfoc/hf-general-ci-tools/.github/workflows/ru-mkdocs-publish.yml@v1
permissions:
contents: write # the publish job pushes gh-pages; pull requests never publish
with:
versioning: false
check_commands: |
python3 -m unittest discover -s tests -v
python3 tools/portal/catalogue.py
hardfoc-docs check
deploy: true
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
build/
site/
__pycache__/
79 changes: 51 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,60 @@
# hardfoc.github.io

This repository hosts the documentation site for the hardfoc project. It uses
[MkDocs](https://www.mkdocs.org/) to build the static site and GitHub Pages to
publish it.
The HardFOC portal: what HardFOC is, how its repositories fit together, every public repository with its
documentation, and where to start with each board.

The site uses the [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/)
theme, which provides a sidebar and top navigation tabs configured in
`mkdocs.yml`.
[![Portal](https://github.com/hardfoc/hardfoc.github.io/actions/workflows/docs.yml/badge.svg?branch=main)](https://hardfoc.github.io/)
[![License](https://img.shields.io/github/license/hardfoc/hardfoc.github.io)](LICENSE)

## Folder structure
**Site: <https://hardfoc.github.io/>**

```
.
├── docs/ # Markdown sources
│ ├── getting-started/
│ ├── api/
│ ├── porting/
│ ├── hardware/
│ ├── index.md # Home page
│ └── about.md # About page
├── mkdocs.yml # MkDocs configuration
└── .github/workflows/ # CI workflow
<!-- figure: hardfoc-layers -->
<picture>
<source media="(prefers-color-scheme: dark)" srcset="docs/diagrams/hardfoc-layers.dark.svg">
<img src="docs/diagrams/hardfoc-layers.svg"
alt="Layer diagram, top to bottom: products (hardfoc-vortex-v1, hardfoc-flux-v1) build on board HALs (hf-
hal-vortex-v1, hf-hal-flux-v1), which build on hf-core (hf-core-drivers and hf-core-utils), which
gathers the hardware-agnostic chip drivers (hf-*-driver) and the peripheral interface wrap.">
</picture>
<!-- /figure -->

## What it does

- Introduces HardFOC and its two boards, Vortex V1 and Flux V1.
- Shows the four layers (chip drivers, core, board HALs, products) and how they are pinned together.
- Lists every public repository as a card with its description, topics, documentation and latest release,
generated from the GitHub API and [`org/org-metadata.json`](https://github.com/hardfoc/.github/blob/main/org/org-metadata.json)
at every publish, and filterable by text or topic.
- Gives a getting-started path per board, and for a chip driver on any MCU.
- Links the contribution rules and the private vulnerability report.

## Build locally

```bash
pip install "git+https://github.com/hardfoc/hf-general-ci-tools@v1#subdirectory=packages/hardfoc-mkdocs-theme"
GH_TOKEN=$(gh auth token) python3 tools/portal/catalogue.py # writes build/portal/catalogue.md
mkdocs serve # http://127.0.0.1:8000
```

Pushes to `main` trigger the workflow in `.github/workflows/build-and-deploy.yml`
which builds the site and updates the `gh-pages` branch.
The site is unversioned: `.github/workflows/docs.yml` calls `ru-mkdocs-publish.yml` from
[hf-general-ci-tools](https://hardfoc.github.io/hf-general-ci-tools/latest/) with `versioning: false`, and a push
to `main` (or the daily run) publishes the built site as the whole `gh-pages` branch.

## Documentation

| Page | What it covers |
| --- | --- |
| [Get started](https://hardfoc.github.io/get-started/) | A path per board, and for a chip driver on your MCU |
| [Repositories](https://hardfoc.github.io/repositories/) | Every public repository, searchable |
| [Architecture](https://hardfoc.github.io/architecture/) | The layers and how they are pinned |
| [Contribute](https://hardfoc.github.io/contribute/) | Issues, pull requests, vulnerability reports |

## Tests

```bash
python3 -m unittest discover -s tests && mkdocs build --strict
```

### How the workflow works
## License

1. **Checkout** – pulls the repo so the runner has the docs and config.
2. **Setup Python** – installs a recent Python release for MkDocs.
3. **Install MkDocs** – installs `mkdocs-material` to render the pages.
4. **Build** – `mkdocs build --strict` generates the static site in `./site`.
5. **Publish** – `peaceiris/actions-gh-pages` pushes that folder to the
`gh-pages` branch and writes the `CNAME` file so GitHub Pages serves
`https://docs.hardfoc.dev`.
See [LICENSE](LICENSE).
13 changes: 13 additions & 0 deletions docs/.nav.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Site navigation (mkdocs-awesome-nav): the tabs and their pages, in reading order.
nav:
- Home: index.md
- Get started:
- get-started/index.md
- Vortex V1 motor controller: get-started/vortex.md
- Flux V1 valve controller: get-started/flux.md
- A chip driver on your MCU: get-started/drivers.md
- Repositories: repositories.md
- Architecture:
- Layers: architecture.md
- Figures: diagrams/index.md
- Contribute: contribute.md
14 changes: 0 additions & 14 deletions docs/about.md

This file was deleted.

3 changes: 0 additions & 3 deletions docs/api/README.md

This file was deleted.

54 changes: 54 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Architecture

How HardFOC firmware is split into repositories, and how the layers are pinned together.

<!-- figure: hardfoc-layers -->
<picture>
<source media="(prefers-color-scheme: dark)" srcset="diagrams/hardfoc-layers.dark.svg">
<img src="diagrams/hardfoc-layers.svg"
alt="Layer diagram, top to bottom: products (hardfoc-vortex-v1, hardfoc-flux-v1) build on board HALs (hf-
hal-vortex-v1, hf-hal-flux-v1), which build on hf-core (hf-core-drivers and hf-core-utils), which
gathers the hardware-agnostic chip drivers (hf-*-driver) and the peripheral interface wrap.">
</picture>
<!-- /figure -->

## Layers

| Layer | Repositories | Depends on | Platform code |
| --- | --- | --- | --- |
| Products | `hardfoc-vortex-v1`, `hardfoc-flux-v1` | One board HAL | ESP-IDF application, tasks, CANopen (Vortex) |
| Board HALs | `hf-hal-vortex-v1`, `hf-hal-flux-v1` | `hf-core` | One object per board, one manager per board function |
| Core | `hf-core`, gathering `hf-core-drivers` and `hf-core-utils` | Drivers, interface wrap, utilities | Device handlers, RTOS wrappers, CANopen helpers |
| Interface wrap | `hf-internal-interface-wrap`, `hf-pincfg` | ESP-IDF | Peripheral base classes (GPIO, ADC, I2C, SPI, UART, CAN, PWM) and their ESP-IDF implementations; per-board pin maps |
| Utilities | `hf-utils-general`, `hf-utils-rtos-wrap`, `hf-utils-canopen` | None, or FreeRTOS | Header-only helpers, FreeRTOS wrappers, CANopen frame builders |
| Chip drivers | `hf-*-driver` | Nothing | None: each driver is a template over a small communication interface |

The [repository catalogue](repositories.md) lists every repository in each layer, with its documentation.

## Submodules, not packages

Each arrow in the figure is a Git submodule pinned to a commit or tag:

```mermaid
flowchart LR
drv["Chip drivers<br/>hf-*-driver"] --> cd["hf-core-drivers"]
iw["hf-internal-interface-wrap<br/>hf-pincfg"] --> cd
ut["hf-utils-general<br/>hf-utils-rtos-wrap<br/>hf-utils-canopen"] --> cu["hf-core-utils"]
cd --> core["hf-core"]
cu --> core
core --> hal["Board HALs"]
hal --> prod["Products"]
```

A product therefore builds exactly the commits it pins, all the way down. Moving a layer forward is a pull request
that updates one submodule pointer and passes that repository's CI.

## Shared tooling

| Repository | Provides |
| --- | --- |
| [`hf-general-ci-tools`](https://hardfoc.github.io/hf-general-ci-tools/latest/) | Reusable workflows (lint, analysis, host builds, the CI gate, releases) and the documentation platform this site is built with |
| [`hf-espidf-ci-tools`](https://github.com/hardfoc/hf-espidf-ci-tools) | ESP-IDF builds of examples and firmware, releases with artifacts |
| [`hf-espidf-project-tools`](https://github.com/hardfoc/hf-espidf-project-tools) | Build and flash scripts for ESP-IDF example projects |

Next: [Get started](get-started/index.md).
49 changes: 49 additions & 0 deletions docs/assets/catalogue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Repository catalogue filter: the search field and the topic chips hide the cards (and empty groups) that do not
// match. Works with Material's instant navigation (document$), and leaves every card visible without JavaScript.
(function () {
function setup() {
var input = document.getElementById("hf-repo-filter");
if (!input || input.dataset.ready) return;
input.dataset.ready = "1";
var cards = Array.prototype.slice.call(document.querySelectorAll(".hf-repo"));
var groups = Array.prototype.slice.call(document.querySelectorAll(".hf-catalogue__group"));
var count = document.querySelector(".hf-catalogue__count");
var total = count ? count.getAttribute("data-total") : String(cards.length);
var topic = "";

function apply() {
var words = input.value.toLowerCase().split(/\s+/).filter(Boolean);
var shown = 0;
cards.forEach(function (c) {
var hay = c.getAttribute("data-search");
var topics = " " + c.getAttribute("data-topics") + " ";
var ok = words.every(function (w) { return hay.indexOf(w) !== -1; }) &&
(!topic || topics.indexOf(" " + topic + " ") !== -1);
c.hidden = !ok;
if (ok) shown++;
});
groups.forEach(function (g) { g.hidden = !g.querySelector(".hf-repo:not([hidden])"); });
document.querySelectorAll(".hf-chipbtn").forEach(function (b) {
b.setAttribute("aria-pressed", b.getAttribute("data-topic") === topic ? "true" : "false");
});
if (count) {
count.textContent = shown === Number(total) ? total + " public repositories." :
shown + " of " + total + " repositories" + (topic ? " with topic " + topic : "") + ".";
}
}

input.addEventListener("input", apply);
document.addEventListener("click", function (e) {
var b = e.target.closest && e.target.closest(".hf-chipbtn");
if (!b) return;
var t = b.getAttribute("data-topic");
topic = topic === t ? "" : t;
apply();
});
var q = new URLSearchParams(location.search);
if (q.get("q")) input.value = q.get("q");
if (q.get("topic")) topic = q.get("topic");
apply();
}
if (window.document$) window.document$.subscribe(setup); else document.addEventListener("DOMContentLoaded", setup);
})();
35 changes: 35 additions & 0 deletions docs/contribute.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Contribute

How to report a problem, propose a change and report a vulnerability, for every HardFOC repository.

## Report a problem or ask a question

Open an issue in the repository closest to the problem: the driver for a chip, the HAL for a board, the product
for the application. If you cannot tell, open it in the product and say what you saw.

## Propose a change

| Step | Where |
| --- | --- |
| Read the rules for branches, commits, pull requests and the CI gate | [CONTRIBUTING.md](https://github.com/hardfoc/.github/blob/main/CONTRIBUTING.md) |
| Follow the code of conduct | [CODE_OF_CONDUCT.md](https://github.com/hardfoc/.github/blob/main/CODE_OF_CONDUCT.md) |
| Write documentation to the shared standard | [Documentation style guide](https://hardfoc.github.io/hf-general-ci-tools/latest/DOCS-STYLE-GUIDE/) |
| Add CI to a repository | [CI quickstart](https://hardfoc.github.io/hf-general-ci-tools/latest/quickstart/) |

A repository with its own `CONTRIBUTING.md` follows that file instead.

## Report a vulnerability

!!! danger "Never in public"
Do not open a public issue, pull request or discussion for a suspected vulnerability.

Report it privately with a GitHub security advisory: in the affected repository, **Security** > **Advisories** >
**Report a vulnerability**. The [security policy](https://github.com/hardfoc/.github/blob/main/SECURITY.md) says
what to include and what is in scope.

## This site

The portal is [`hardfoc/hardfoc.github.io`](https://github.com/hardfoc/hardfoc.github.io). The repository list is
built from the GitHub API and the organisation's repository record each time the site is published; to change a
description or topics, change
[`org/org-metadata.json`](https://github.com/hardfoc/.github/blob/main/org/org-metadata.json) in `hardfoc/.github`.
13 changes: 13 additions & 0 deletions docs/diagrams/figures.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"hardfoc-layers": {
"title": "Four layers, each a set of repositories",
"alt": "Layer diagram, top to bottom: products (hardfoc-vortex-v1, hardfoc-flux-v1) build on board HALs (hf-hal-vortex-v1, hf-hal-flux-v1), which build on hf-core (hf-core-drivers and hf-core-utils), which gathers the hardware-agnostic chip drivers (hf-*-driver) and the peripheral interface wrap.",
"description": "From bottom to top, each layer builds on the one below it as a Git submodule pinned to a commit or tag. Chip drivers are hardware-agnostic C++ libraries with no platform code; each one needs only a small bus adapter. hf-core gathers them with the peripheral interface wrap, the pin configuration and the utility libraries (RTOS wrappers, general helpers, CANopen). A board HAL builds one object per board from hf-core, with one manager per board function. A product is the application firmware for one board, on top of its HAL.",
"profile": "overview",
"width": 1200,
"source": "docs/diagrams/figures/hardfoc-layers.py",
"sources": [
"mkdocs.yml"
]
}
}
52 changes: 52 additions & 0 deletions docs/diagrams/figures/hardfoc-layers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""The four layers of HardFOC firmware: chip drivers, core, board HALs, products.

Reads: From bottom to top, each layer builds on the one below it as a Git submodule pinned to a commit or tag.
Chip drivers are hardware-agnostic C++ libraries with no platform code; each one needs only a small bus adapter.
hf-core gathers them with the peripheral interface wrap, the pin configuration and the utility libraries
(RTOS wrappers, general helpers, CANopen). A board HAL builds one object per board from hf-core, with one manager
per board function. A product is the application firmware for one board, on top of its HAL.
"""

from hardfoc_mkdocs_theme.figkit import Fig

SOURCES = ["mkdocs.yml"]


def build(_data):
f = Fig(
"hardfoc-layers",
"Four layers, each a set of repositories",
alt="Layer diagram, top to bottom: products (hardfoc-vortex-v1, hardfoc-flux-v1) build on board HALs "
"(hf-hal-vortex-v1, hf-hal-flux-v1), which build on hf-core (hf-core-drivers and hf-core-utils), which "
"gathers the hardware-agnostic chip drivers (hf-*-driver) and the peripheral interface wrap.",
width=1200,
kicker="Architecture",
subtitle="Each layer is a Git submodule of the one above it, pinned to a commit or tag.",
profile="overview",
legend=[("teal", "application firmware"), ("brand", "board and platform"), ("slate", "portable libraries")],
)
W = f.body_w
gap = 24
half = (W - gap) / 2
third = (W - 2 * gap) / 3
vortex = f.card(0, 0, half, "hardfoc-vortex-v1", ["Vortex V1 motor controller firmware"], tone="teal", accent=True)
flux = f.card(half + gap, 0, half, "hardfoc-flux-v1", ["Flux V1 valve controller firmware"], tone="teal",
accent=True, h=vortex.h)
y = vortex.b + 48
hv = f.card(0, y, half, "hf-hal-vortex-v1", ["ESP32-C6, TMC9660, AS5047U"], tone="brand")
hfx = f.card(half + gap, y, half, "hf-hal-flux-v1", ["ESP32-S3, MAX22200, TLE92466ED"], tone="brand", h=hv.h)
y = hv.b + 48
core = f.card(0, y, W, "hf-core", ["hf-core-drivers + hf-core-utils: device handlers, RTOS, CANopen"],
tone="brand", accent=True)
y = core.b + 48
drv = f.card(0, y, third, "Chip drivers", ["hf-*-driver, no platform code"], tone="slate")
wrap = f.card(third + gap, y, third, "Interface wrap", ["hf-internal-interface-wrap, hf-pincfg"], tone="slate")
utils = f.card(2 * (third + gap), y, third, "Utilities", ["hf-utils-general, hf-utils-rtos-wrap, hf-utils-canopen"], tone="slate")
for a, b in ((vortex, hv), (flux, hfx)):
f.connect(a, b, "bottom", "top", tone="rail")
# Straight arrows: each one leaves and enters at the same x.
for hal in (hv, hfx):
f.connect(hal, core, "bottom", "top", bt=(hal.cx - core.x) / core.w, tone="rail")
for b in (drv, wrap, utils):
f.connect(core, b, "bottom", "top", at=(b.cx - core.x) / core.w, tone="rail")
return f
Loading
Loading