diff --git a/.github/workflows/pcb.yaml b/.github/workflows/pcb.yaml new file mode 100644 index 0000000..79f3569 --- /dev/null +++ b/.github/workflows/pcb.yaml @@ -0,0 +1,118 @@ +name: PCB exports and GitHub Pages + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: pcb-pages-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +jobs: + pcb: + runs-on: ubuntu-latest + container: ghcr.io/systemscape/kicad_and_pandoc:10 + env: + PCB: hardware/ese-rust-board/ese-rust-board + outputs: + available: ${{ steps.board.outputs.available }} + steps: + - uses: actions/checkout@v4 + + - name: Check board sources + id: board + shell: bash + run: | + files=("$PCB.kicad_pro" "$PCB.kicad_sch" "$PCB.kicad_pcb") + count=0 + for file in "${files[@]}"; do + if [[ -f "$file" ]]; then + count=$((count + 1)) + fi + done + if [[ "$count" == 0 ]]; then + echo 'available=false' >> "$GITHUB_OUTPUT" + echo 'No board sources yet; publishing documentation only.' >> "$GITHUB_STEP_SUMMARY" + elif [[ "$count" != 3 ]]; then + echo '::error::The board needs matching .kicad_pro, .kicad_sch and .kicad_pcb files.' + exit 1 + else + echo 'available=true' >> "$GITHUB_OUTPUT" + fi + + - name: Run ERC/DRC and generate exports + if: steps.board.outputs.available == 'true' + run: | + kibot -c hardware/config.kibot.yaml \ + -b "$PCB.kicad_pcb" -e "$PCB.kicad_sch" -d outputs + + - name: Package manufacturing files + if: steps.board.outputs.available == 'true' + run: | + python3 - <<'PY' + import shutil + shutil.make_archive('outputs/gerbers', 'zip', 'outputs/gerber') + PY + + - name: Upload PCB exports and check reports + if: ${{ !cancelled() && steps.board.outputs.available == 'true' }} + uses: actions/upload-artifact@v4 + with: + name: pcb-outputs + path: outputs/ + if-no-files-found: error + retention-days: 90 + + site: + needs: pcb + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Download PCB exports + if: needs.pcb.outputs.available == 'true' + uses: actions/download-artifact@v4 + with: + name: pcb-outputs + path: downloads/ + + - name: Configure Pages + if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request' + uses: actions/configure-pages@v5 + + - name: Render Markdown with Jekyll + uses: actions/jekyll-build-pages@v1 + with: + source: ./ + destination: ./_site + + - name: Upload site preview + uses: actions/upload-artifact@v4 + with: + name: site-preview + path: _site/ + if-no-files-found: error + + - name: Upload Pages artifact + if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request' + uses: actions/upload-pages-artifact@v3 + + deploy: + if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request' + needs: site + runs-on: ubuntu-latest + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index 6b13d93..2a1be84 100644 --- a/.gitignore +++ b/.gitignore @@ -56,3 +56,8 @@ fp-info-cache **/node_modules/ .github/site/dist/ artifact/ +# Generated PCB exports and GitHub Pages build +/outputs/ +/downloads/ +/_site/ +/.jekyll-cache/ diff --git a/README.md b/README.md index 995c256..cbf4a6f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Embedded Rust zum Anfassen: Hackathon auf dem exklusiven ESE 2026 Rust Devboard +[Hardware](hardware/README.md) · [PCB-Downloads](downloads.md) · [CI](docs/ci.md) + ## Worum geht es? Rust ist auch in der Embedded-Entwicklung auf dem Vormarsch. Aber wie funktioniert “dieses Rust” auf echter Hardware? Wie schreibe ich einen Sensor-Treiber? Wie steuere ich ein Display an? Und wie sieht “Fearless Concurrency” in der Praxis aus? diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000..29599e2 --- /dev/null +++ b/_config.yml @@ -0,0 +1,24 @@ +title: ESE 2026 Rust Hackathon +description: Embedded Rust zum Anfassen +url: https://systemscape.github.io +baseurl: /ese-2026-rust-hackathon +theme: jekyll-theme-cayman +plugins: + - jekyll-relative-links + - jekyll-readme-index +readme_index: + remove_originals: true +relative_links: + enabled: true + collections: true +defaults: + - scope: + path: "" + values: + layout: default +exclude: + - LICENSE + - hardware/config.kibot.yaml + - hardware/ese-rust-board + - outputs + - target diff --git a/docs/ci.md b/docs/ci.md new file mode 100644 index 0000000..41d99fb --- /dev/null +++ b/docs/ci.md @@ -0,0 +1,42 @@ +--- +title: Hardware CI +--- + +# Hardware CI + +The [workflow](https://github.com/Systemscape/ese-2026-rust-hackathon/blob/main/.github/workflows/pcb.yaml) builds on pull requests, pushes to +`main`, and manual runs. It uses the same KiCad 10 / KiBot container as the OnMCU +hardware repository, with one board and one complete +[KiBot config](https://github.com/Systemscape/ese-2026-rust-hackathon/blob/main/hardware/config.kibot.yaml). + +Add the board's matching `.kicad_pro`, `.kicad_sch` and `.kicad_pcb` files at +`hardware/ese-rust-board/ese-rust-board.*`. Commit any referenced sheets, custom +libraries, library tables and 3D models too, using project-relative paths. +If the board moves, update `PCB` in the workflow and the exclusion in `_config.yml`. +When all three sources are absent, CI publishes documentation only; a partially +added board fails the build. + +KiBot runs ERC and DRC, then generates schematic and PCB PDFs, a CSV BOM, +interactive BOM, Gerbers and drills, pick-and-place files, PCB drawings, SVGs, +STEP, 3D-printable stencils and netlists. Errors fail the build and block +deployment. Available check reports and partial exports are uploaded even on +failure. The `pcb-outputs` artifact is retained for 90 days; `site-preview` +contains the rendered site for review on pull requests. + +GitHub Pages uses Jekyll to render the README files and other Markdown. The +downloads page lists the generated files automatically. Only successful runs +on `main` deploy the public site; pull requests do not deploy. + +In repository **Settings → Pages → Build and deployment**, set **Source** to +**GitHub Actions** before the first deployment. No additional secrets are needed. +The workflow follows GitHub's [Jekyll build](https://github.com/actions/jekyll-build-pages) +and [Pages deployment](https://github.com/actions/deploy-pages) actions. + +To generate the same PCB exports locally with KiCad 10 and KiBot installed: + +```sh +kibot -c hardware/config.kibot.yaml \ + -b hardware/ese-rust-board/ese-rust-board.kicad_pcb \ + -e hardware/ese-rust-board/ese-rust-board.kicad_sch -d outputs +python3 -c "import shutil; shutil.make_archive('outputs/gerbers', 'zip', 'outputs/gerber')" +``` diff --git a/downloads.md b/downloads.md new file mode 100644 index 0000000..0ecfdaf --- /dev/null +++ b/downloads.md @@ -0,0 +1,21 @@ +--- +title: PCB downloads +permalink: /downloads/ +--- + +# PCB downloads + +[Hackathon](./README.md) · [Hardware](./hardware/README.md) + +{% assign exports = site.static_files | where_exp: "file", "file.path contains '/downloads/'" | sort: 'path' %} +{% if exports.size > 0 %} +Exports from commit `{{ site.github.build_revision }}`. + +The Gerber ZIP includes copper, mask, silkscreen, paste, board outline and drill files. + +{% for file in exports %} +- [{{ file.path | remove_first: '/downloads/' }}]({{ file.path | relative_url }}) +{% endfor %} +{% else %} +PCB downloads will appear here once the KiCad board sources are added and pass ERC/DRC. +{% endif %} diff --git a/hardware/README.md b/hardware/README.md index 4198a1f..07d5677 100644 --- a/hardware/README.md +++ b/hardware/README.md @@ -1,3 +1,7 @@ +# ESE Rust Devboard + +[Hackathon](../README.md) · [PCB downloads](../downloads.md) · [Hardware CI](../docs/ci.md) + ## MCU Foundation - 2x Raspberry Pi RP2354B (SC1512-A4) https://mou.sr/4yLfwo5 ca. 0.80 € - 1x as debugger using https://github.com/raspberrypi/debugprobe or https://github.com/probe-rs/rusty-probe-firmware diff --git a/hardware/config.kibot.yaml b/hardware/config.kibot.yaml new file mode 100644 index 0000000..282ef9c --- /dev/null +++ b/hardware/config.kibot.yaml @@ -0,0 +1,127 @@ +# Single-board exports, adapted from the OnMCU hardware CI. +kibot: + version: 1 +preflight: + erc: + dir: reports + drc: + dir: reports +global: + output: '%f-%i.%x' +outputs: +- name: print_sch + comment: Print schematic (PDF) + type: pdf_sch_print + dir: pdf +- name: print_top + comment: Print Top + type: pcb_print + dir: pdf + options: + format: PDF + output: '%f-pcb-top.%x' + pages: + - layers: + - layer: F.Paste + - layer: F.SilkS + - layer: F.Mask + - layer: F.CrtYd + - layer: Edge.Cuts +- name: print_bottom + comment: Print Bottom + type: pcb_print + dir: pdf + options: + format: PDF + output: '%f-pcb-bottom.%x' + pages: + - layers: + - layer: B.Paste + - layer: B.SilkS + - layer: B.Mask + - layer: B.CrtYd + - layer: Edge.Cuts +- name: interactive_bom + comment: Generates an interactive web page useful to identify the position of the + components in the PCB. + type: ibom + options: + blacklist: DNF*,DNP* + checkboxes: Sourced,Placed,Soldered + name_format: '%f_ibom' + dark_mode: true + dir: ibom +- name: bom_csv + comment: Bill of Materials in CSV format + type: bom + options: + format: CSV + csv: + separator: ; + dir: bom +- name: gerbers + comment: Gerbers for the board house + type: gerber + dir: gerber + options: + exclude_edge_layer: true + exclude_pads_from_silkscreen: true + use_aux_axis_as_origin: false + plot_sheet_reference: false + plot_footprint_refs: true + plot_footprint_values: true + force_plot_invisible_refs_vals: false + tent_vias: true + line_width: 0.1 + subtract_mask_from_silk: false + use_protel_extensions: false + gerber_precision: 4.6 + create_gerber_job_file: true + use_gerber_x2_attributes: true + use_gerber_net_attributes: true + layers: all +- name: drills + comment: Excellon drill files, packaged with Gerbers + type: excellon + dir: gerber + options: + use_aux_axis_as_origin: false +- name: position + comment: Pick and place file + type: position + dir: pickplace + options: + format: ASCII + units: millimeters + separate_files_for_front_and_back: true + only_smd: true +- name: 3dstep + comment: 3D model (step) + type: step + dir: step +- name: stencil_3d + comment: 3d-printable stencil + type: stencil_3d + dir: stencils +- name: pcbdraw + comment: pcbdraw file + type: pcbdraw + dir: pcbdraw + options: + format: svg +- name: svg + comment: SVG files + type: svg + dir: svg +- name: netlist + comment: Schematic Netlist + type: netlist + options: + format: kicadxml + dir: netlist +- name: netlist_kicad + comment: KiCad Format Netlist + type: netlist + options: + format: classic + dir: netlist