From a330a1fad3c1ccdd926297747c03fe95bcaa6587 Mon Sep 17 00:00:00 2001 From: Nathan Perry Date: Wed, 14 Aug 2024 01:34:16 -0400 Subject: nix: migrate functionality to clef --- .gitignore | 2 +- clef/.gitignore | 1 + clef/README.md | 196 +++++++++++++++++++++++++++++++++++++++++++ clef/flake.lock | 209 ++++++++++++++++++++++++++++++++++++++++++++++ clef/flake.nix | 81 ++++++++++++++++++ clef/nix/board.nix | 37 ++++++++ clef/nix/default.nix | 58 +++++++++++++ clef/nix/fabrication.nix | 82 ++++++++++++++++++ clef/nix/model.nix | 52 ++++++++++++ clef/nix/panel.nix | 46 ++++++++++ clef/nix/schematic.nix | 51 +++++++++++ clef/nix/svg.nix | 82 ++++++++++++++++++ clef/overlays.nix | 49 +++++++++++ flake.lock | 26 ++++-- flake.nix | 60 ++----------- kikit/jlc_edge_rails.json | 52 ------------ nix/board.nix | 34 -------- nix/default.nix | 52 ------------ nix/fabrication.nix | 82 ------------------ nix/model.nix | 52 ------------ nix/panel.nix | 46 ---------- nix/schematic.nix | 51 ----------- nix/svg.nix | 82 ------------------ 23 files changed, 968 insertions(+), 515 deletions(-) create mode 100644 clef/flake.lock create mode 100644 clef/flake.nix create mode 100644 clef/nix/board.nix create mode 100644 clef/nix/default.nix create mode 100644 clef/nix/fabrication.nix create mode 100644 clef/nix/model.nix create mode 100644 clef/nix/panel.nix create mode 100644 clef/nix/schematic.nix create mode 100644 clef/nix/svg.nix create mode 100644 clef/overlays.nix delete mode 100644 kikit/jlc_edge_rails.json delete mode 100644 nix/board.nix delete mode 100644 nix/default.nix delete mode 100644 nix/fabrication.nix delete mode 100644 nix/model.nix delete mode 100644 nix/panel.nix delete mode 100644 nix/schematic.nix delete mode 100644 nix/svg.nix diff --git a/.gitignore b/.gitignore index 2973796..95929f0 100644 --- a/.gitignore +++ b/.gitignore @@ -31,5 +31,5 @@ __pycache__/ /production/ /panel/ panel.* -!nix/panel.nix +!panel.nix /bom/ diff --git a/clef/.gitignore b/clef/.gitignore index 4d36fb6..3159192 100644 --- a/clef/.gitignore +++ b/clef/.gitignore @@ -33,3 +33,4 @@ __pycache__/ /panel/ panel.* /bom/ +!panel.nix diff --git a/clef/README.md b/clef/README.md index 780fa8e..19520b9 100644 --- a/clef/README.md +++ b/clef/README.md @@ -1,3 +1,199 @@ # clef My kicad templates, libraries, and sheets. + +Comes with a Nix function to process a KiCad project into: + +- Board SVGs +- Board 3d model (.glb, .step) +- Schematic PDF, SVGs +- Fabrication files (using kikit) + - Currently untested — I had to use Fabrication Toolkit on my last + project +- Panelized board (using kikit) + - Also minimal testing + +Example output for [ocularium](https://pub.npry.dev/ocularium), which provides +the content for [this blog post](https://blog.npry.dev/resenv/ocularium): + +```bash +$ nix build .# && nix run nixpkgs#tree result +result +└── share + └── npry + └── ocularium + ├── fab + │   ├── bom.csv + │   ├── gerbers.zip + │   └── pos.csv + ├── model + │   ├── okm.glb + │   └── okm.step + ├── schematic + │   ├── schematic.pdf + │   └── svg + │   ├── IO.svg + │   ├── MCU.svg + │   ├── Power.svg + │   ├── root.svg + │   └── Sensors.svg + └── svg + ├── back.mirror.svg + ├── back.svg + ├── front.mirror.svg + ├── front.svg + ├── in1.mirror.svg + ├── in1.svg + ├── in2.mirror.svg + └── in2.svg + +8 directories, 19 files +``` + +## usage: subtree + +I currently include this repo as a [git +_subtree_](https://manpages.debian.org/testing/git-man/git-subtree.1.en.html) +in kicad projects that use it: + +```bash +# to init: +$ git subtree add --squash --prefix clef https://pub.npry.dev/clef master + +# then to update: +$ git subtree pull --squash --prefix clef https://pub.npry.dev/clef master +``` + +Submodules are closer to what I want semantically, but I consider them too +fragile to use. + +## nix + +The flake provides `pkgs.clef`, a function building a derivation that contains +the processed content. + +Please be aware that complete functionality will involve rebuilding a couple +of large derivations from source (KiCad, occt and dependents) until I get +around to upstreaming my overlays. + +### example + +```nix +# flake.nix +{ + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/release-24.05"; + flake-utils.url = "github:numtide/flake-utils/main"; + + clef = { + url = "git+https://pub.npry.dev/clef"; + + # or if using subtree/submodules: + # url = "path:clef"; + + inputs.nixpkgs.follows = "nixpkgs"; + flake-utils.follows = "flake-utils"; + }; + }; + + outputs = { nixpkgs, clef }: (flake-utils.lib.eachDefaultSystem (system: let + pkgs = import nixpkgs { + overlays = [ + # NB: This causes another independent nixpkgs eval -- it's just: + # + # final: prev: { inherit (clef.packages.${prev.system}) clef; } + # + # This is the easiest way to get started, and if you don't know or + # care why you don't want to eval nixpkgs multiple times, this is + # probably what you want. + # + # If you are looking for a more efficient nixpkgs config, see the + # flake source for notes -- currently you need to include + # clef.overlays.kicad and clef.overlays.nix-filter. + clef.default + ]; + }; + + clefDrv = pkgs.clef { + name = "my_board"; + + # Kicad project directory. Automatically filtered by clef to + # kicad-relevant files. + src = ./.; + + main_pcb = "my_pcb.kicad_pcb"; + main_sch = "my_sch.kicad_sch"; + + outPath = "share/npry/example"; + + layers = 4; + + # Parameters to `kikit panelize -p`. Only required if you want + # to panelize or tile your board. + panelizeConfigs = [ + ":jlcTooling" + ./kikit/jlc_frame.json + ]; + }; + + in { + packages = { + # The main derivation has all of the processed output in it -- + # gerbers, 3d files, SVGs, schematic PDFs, and a panelized + # board (if configured). They are found in the `outPath` you + # configure in the argument attrs. + default = clefDrv; + + # You can use `passthru` attributes to access individual components + # of the build. Outputs are all found as subdirs of + # `share/npry/clef`. + inherit (clefDrv) models; + + # `panelSrc` has the panelized kicad project (new .kicad_pcb with + # the original .kicad_sch and .kicad_pro). + panelizedProject = clefDrv.panelSrc; + + # `panel` is the result of calling `clef` with `src = panelSrc;`, + # i.e. 3d models, fabrication outputs, and so on for the + # panelized board. + inherit (clefDrv) panel; + + # If for you need a recursive panelization, you can in + # principle do that: + panelPanel = (clefDrv.panel.override { + panelizeConfigs = [ ":jlcTooling" ./my_nested_panel_config.json ]; + }).panel; + }; + })); +} +``` + +### direct `callPackage` + +The individual component derivations are intentionally written to be usable +directly: + +```nix +pkgs.callPackage "${clef}/nix/model.nix" { + src = ./.; + pcb_path = "my_pcb.kicad_pcb"; +} +``` + +Bear in mind that you will need the relevant overlays in the calling `nixpkgs` +for this usage mode: + +- `models` needs `clef.overlays.kicad` (adds RapidJSON support to occt, + enabling glb export) +- `fab` wants `clef.overlays.kicad` for a newer version of kikit +- Everything needs `nix-filter`. + +Output for the individual derivations will be found in subdirectories of +`share/npry/clef`, with filenames normalized. + +## etymology + +French: "key", pronounced like "clay". (Cognate with the "clef" of "treble +clef", "bass clef" ~> "treble key", "bass key"). + +Train of thought: KiCad's "Ki" -> "key" -> "clef". diff --git a/clef/flake.lock b/clef/flake.lock new file mode 100644 index 0000000..79b9ab4 --- /dev/null +++ b/clef/flake.lock @@ -0,0 +1,209 @@ +{ + "nodes": { + "cadquery-src": { + "flake": false, + "locked": { + "lastModified": 1705326221, + "narHash": "sha256-f/qnq5g4FOiit9WQ7zs0axCJBITcAtqF18txMV97Gb8=", + "owner": "CadQuery", + "repo": "cadquery", + "rev": "c44978d60cee2d61bdadf4cb4498286b7034b4c6", + "type": "github" + }, + "original": { + "owner": "CadQuery", + "ref": "2.4.0", + "repo": "cadquery", + "type": "github" + } + }, + "cq": { + "inputs": { + "cadquery-src": "cadquery-src", + "cq-editor-src": "cq-editor-src", + "flake-utils": [ + "flake-utils" + ], + "nixpkgs": [ + "nixpkgs" + ], + "ocp-src": "ocp-src", + "ocp-stubs-src": "ocp-stubs-src", + "pybind11-stubgen-src": "pybind11-stubgen-src", + "pywrap-src": "pywrap-src" + }, + "locked": { + "lastModified": 1723029696, + "narHash": "sha256-awv2fEsTkc749YcedWK1Y5P1xg5NfAosttlFnBsVVdg=", + "owner": "vinszent", + "repo": "cq-flake", + "rev": "27d9ac5b7f1fb5f271070ca0eed6a40c3fcfec17", + "type": "github" + }, + "original": { + "owner": "vinszent", + "ref": "main", + "repo": "cq-flake", + "type": "github" + } + }, + "cq-editor-src": { + "flake": false, + "locked": { + "lastModified": 1701895648, + "narHash": "sha256-mHXEaA6vphps6F0WemdB6fGRY4lzpcxLU7WuYEp8c20=", + "owner": "CadQuery", + "repo": "CQ-editor", + "rev": "4ef178af06d24a53fee87d576f8cada14c0111a3", + "type": "github" + }, + "original": { + "owner": "CadQuery", + "repo": "CQ-editor", + "rev": "4ef178af06d24a53fee87d576f8cada14c0111a3", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "ref": "main", + "repo": "flake-utils", + "type": "github" + } + }, + "nix-filter": { + "locked": { + "lastModified": 1710156097, + "narHash": "sha256-1Wvk8UP7PXdf8bCCaEoMnOT1qe5/Duqgj+rL8sRQsSM=", + "owner": "numtide", + "repo": "nix-filter", + "rev": "3342559a24e85fc164b295c3444e8a139924675b", + "type": "github" + }, + "original": { + "owner": "numtide", + "ref": "main", + "repo": "nix-filter", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1723556749, + "narHash": "sha256-+CHVZnTnIYRLYsARInHYoWkujzcRkLY/gXm3s5bE52o=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "4a92571f9207810b559c9eac203d1f4d79830073", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-24.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "ocp-src": { + "flake": false, + "locked": { + "lastModified": 1701196143, + "narHash": "sha256-PMkMYEVBHt0i7ahgqF8jLhHHp7IRS7hd+JyydovNJ4A=", + "owner": "cadquery", + "repo": "ocp", + "rev": "4b98a5dc79fa900f7429975708f6a8c2e41cecd1", + "type": "github" + }, + "original": { + "owner": "cadquery", + "repo": "ocp", + "rev": "4b98a5dc79fa900f7429975708f6a8c2e41cecd1", + "type": "github" + } + }, + "ocp-stubs-src": { + "flake": false, + "locked": { + "lastModified": 1672527176, + "narHash": "sha256-m9Rg36GYlYfwEfF0PQJWEXf8TyM5HmjeuhJCODiurvY=", + "owner": "cadquery", + "repo": "ocp-stubs", + "rev": "e838ff400d5ee2f4a0579d2a713b19311855288f", + "type": "github" + }, + "original": { + "owner": "cadquery", + "repo": "ocp-stubs", + "type": "github" + } + }, + "pybind11-stubgen-src": { + "flake": false, + "locked": { + "lastModified": 1700678104, + "narHash": "sha256-76u1GcHPPh8oYQeQZDJ4K/so0U7F6rznZ1xa6syqI9s=", + "owner": "CadQuery", + "repo": "pybind11-stubgen", + "rev": "6dc681d838d3ec9a8a9aa4260c8392d3fb700ff0", + "type": "github" + }, + "original": { + "owner": "CadQuery", + "repo": "pybind11-stubgen", + "type": "github" + } + }, + "pywrap-src": { + "flake": false, + "locked": { + "lastModified": 1676015766, + "narHash": "sha256-QhAvJHV5tFq9bjKOzEpcudZNnmUmNVrJ+BLCZJhO31g=", + "owner": "CadQuery", + "repo": "pywrap", + "rev": "f3bcde70fd66a2d884fa60a7a9d9f6aa7c3b6e16", + "type": "github" + }, + "original": { + "owner": "CadQuery", + "repo": "pywrap", + "type": "github" + } + }, + "root": { + "inputs": { + "cq": "cq", + "flake-utils": "flake-utils", + "nix-filter": "nix-filter", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/clef/flake.nix b/clef/flake.nix new file mode 100644 index 0000000..66e350f --- /dev/null +++ b/clef/flake.nix @@ -0,0 +1,81 @@ +# vim: ft=nix : +{ + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-24.05"; + flake-utils.url = "github:numtide/flake-utils/main"; + nix-filter.url = "github:numtide/nix-filter/main"; + + cq = { + url = "github:vinszent/cq-flake/main"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.flake-utils.follows = "flake-utils"; + }; + }; + + description = "clef: kicad shared data and utils"; + + outputs = { self, nixpkgs, flake-utils, ... } @ inputs: (flake-utils.lib.eachDefaultSystem (system: { + packages = let + pkgs = import nixpkgs { + inherit system; + + overlays = with self.overlays; [ + kicad + nix-filter + ]; + }; + + clef = pkgs.callPackage ./nix; + in { + inherit clef; + default = clef; + }; + + devShells.default = let + pkgs = import nixpkgs { + inherit system; + + overlays = with self.overlays; [ + kicad + ]; + }; + + in pkgs.mkShell { + name = "devshell"; + version = self.rev or "dirty"; + + packages = with pkgs; [ + kicad + kikit + ]; + }; + } + )) // { + overlays = let + base = (import ./overlays.nix { inherit inputs; }); + + in base // { + # clef built against its own nixpkgs import with its required overlay + # deps (cadquery, kicad, occt). + # + # _This will cause another evaluation of nixpkgs_, which is generally + # undesirable. However, this provides for the most hassle-free way to + # use clef, as you don't need to include all of the overlay dependencies + # in your nixpkgs. + default = final: prev: { + clef = self.packages.${prev.system}.default; + }; + + # No overlay dependencies included -- clef will not work by default. + # You can replicate overlays.default with: + # + # import nixpkgs { overlays = with clef.overlays; [ freestanding kicad nix-filter ]; } + # + # Assuming you've pinned clef's nixpkgs to the same version as yours. + # This functionality is provided to give you an option + freestanding = final: prev: { + clef = prev.callPackage ./nix; + }; + }; + }; +} diff --git a/clef/nix/board.nix b/clef/nix/board.nix new file mode 100644 index 0000000..d67417b --- /dev/null +++ b/clef/nix/board.nix @@ -0,0 +1,37 @@ +{ + runCommand, + + svg, + model, + fabrication, + schematic, + panel, + panelSrc, + + name, + outPath, +}: let + pkg = runCommand name {} '' + set -e + + mkdir -p "$out/${outPath}" + cd "$out/${outPath}" + + echo "populating $(pwd)" + + cp --reflink=auto -vr "${schematic}/share/npry/clef/schematic" ./ + cp --reflink=auto -vr "${svg}/share/npry/clef/svg" ./ + cp --reflink=auto -vr "${fabrication}/share/npry/clef/fab" ./ + cp --reflink=auto -vr "${model}/share/npry/clef/model" ./ + + ${if panelSrc != null then '' + cp --reflink=auto -vr "${panelSrc}/share/npry/clef/panel" ./ + '' else ""} + ''; + +in pkg.overrideAttrs (prevAttrs: { + passthru = (prevAttrs.passthru or {}) // { + inherit schematic fabrication svg model panel panelSrc; + fab = fabrication; + }; +}) diff --git a/clef/nix/default.nix b/clef/nix/default.nix new file mode 100644 index 0000000..4438bbe --- /dev/null +++ b/clef/nix/default.nix @@ -0,0 +1,58 @@ +{ + pkgs, + + src, + main_pcb, + main_sch, + + name, + outPath ? "share/npry/clef", + layers ? 2, + + # set to a list of arguments to be passed to `kikit panelize -p` + panelizeConfigs ? null, +}: let + pcb_path = main_pcb; + sch_path = main_sch; + + pcb_args = { + inherit pcb_path src; + }; + + panelSrc = if panelizeConfigs != null then pkgs.callPackage ./panel.nix (pcb_args // { inherit panelizeConfigs; }) else null; + + panel = if panelizeConfigs != null then + pkgs.callPackage ./. { + src = "${panelSrc}/share/npry/clef/panel"; + main_pcb = "panel.kicad_pcb"; + + name = "${name}.sub.panel"; + outPath = "${outPath}/panel"; + + inherit main_sch layers; + } + else null; + + svg = pkgs.callPackage ./svg.nix (pcb_args // { nLayer = layers; }); + model = pkgs.callPackage ./model.nix pcb_args; + + fabrication = pkgs.callPackage ./fabrication.nix (pcb_args // { + inherit sch_path; + }); + + schematic = pkgs.callPackage ./schematic.nix { + inherit sch_path src; + }; + +in pkgs.callPackage ./board.nix { + inherit + svg + model + fabrication + schematic + name + outPath + panel + panelSrc + ; +} diff --git a/clef/nix/fabrication.nix b/clef/nix/fabrication.nix new file mode 100644 index 0000000..18bc6f6 --- /dev/null +++ b/clef/nix/fabrication.nix @@ -0,0 +1,82 @@ +{ + kicad, + kikit, + zip, + + runCommand, + + nix-filter, + lib, + + src, + pcb_path, + sch_path, + + boardName ? (lib.removeSuffix ".kicad_pcb" (builtins.baseNameOf pcb_path)), + + fabHouse ? "jlcpcb", + withAssembly ? true, +}: let + sharePath = "share/npry/clef/fab"; + + fabSrc = nix-filter { + root = src; + + include = [ + (nix-filter.matchExt "kicad_sch") + (nix-filter.matchExt "kicad_wks") + (nix-filter.matchExt "kicad_pcb") + (nix-filter.matchExt "kicad_pro") + + (_args: path: type: type == "directory") + ]; + }; + +in runCommand "${boardName}.fab" { + nativeBuildInputs = [ + kicad + kikit + zip + ]; + + src = fabSrc; + + allowedRequisites = []; +} '' + set -e + + export HOME=$(mktemp -d) + + echo "board: '${boardName}'" >&2 + + mkdir -p "$out/${sharePath}" + cd "$src" + + kikit fab ${fabHouse} \ + ${if withAssembly then "--assembly" else ""} \ + --no-drc \ + --schematic "${sch_path}" \ + --field 'LCSC Part #,LCSC Part No' \ + --missingError \ + "${pcb_path}" \ + "$out/${sharePath}" + + cd "$out/${sharePath}" + rm -vf "gerbers.zip" + + pushd gerber + + # normalize + for f in ${boardName}-*; do + mv -nv "$f" "''${f#${boardName}-}" + done + + for f in ${boardName}.*; do + mv -nv "$f" "board''${f#${boardName}}" + done + + popd + + zip -vj "gerbers.zip" gerber/* + rm -vrf gerber +'' diff --git a/clef/nix/model.nix b/clef/nix/model.nix new file mode 100644 index 0000000..04bf1b1 --- /dev/null +++ b/clef/nix/model.nix @@ -0,0 +1,52 @@ +{ + kicad, + runCommand, + + nix-filter, + lib, + + withTracks ? false, + withZones ? false, + + src, + pcb_path, + + boardName ? (lib.removeSuffix ".kicad_pcb" (builtins.baseNameOf pcb_path)), +}: let + zonesArg = if withZones then "--include-zones" else ""; + tracksArg = if withTracks then "--include-tracks" else ""; + sharePath = "share/npry/clef/model"; + +in runCommand "${boardName}.model" { + nativeBuildInputs = [ + kicad + ]; + + src = nix-filter { + root = src; + + include = [ + (nix-filter.matchExt "kicad_pcb") + + (nix-filter.matchExt "stp") + (nix-filter.matchExt "step") + (nix-filter.matchExt "wrl") + ]; + }; + + allowedRequisites = []; + + KICAD8_3DMODEL_DIR = "${kicad.libraries.packages3d}/share/kicad/3dmodels"; +} '' + set -e + + export HOME=$(mktemp -d) + + echo "board: '${boardName}'" >&2 + + mkdir -p $out/${sharePath} + cd "$out/${sharePath}" + + kicad-cli pcb export step --subst-models --no-dnp ${tracksArg} ${zonesArg} "$src/${pcb_path}" -o "${boardName}.step" + kicad-cli pcb export glb --subst-models --no-dnp ${tracksArg} ${zonesArg} "$src/${pcb_path}" -o "${boardName}.glb" +'' diff --git a/clef/nix/panel.nix b/clef/nix/panel.nix new file mode 100644 index 0000000..1d88d46 --- /dev/null +++ b/clef/nix/panel.nix @@ -0,0 +1,46 @@ +{ + kikit, + runCommand, + + nix-filter, + lib, + + panelizeConfigs, + src, + pcb_path, + + boardName ? (lib.removeSuffix ".kicad_pcb" (builtins.baseNameOf pcb_path)), +}: let + sharePath = "share/npry/clef/panel"; + + panelSrc = nix-filter { + root = src; + + include = [ + (nix-filter.matchExt "kicad_pcb") + ]; + }; + +in runCommand "${boardName}.panel" { + nativeBuildInputs = [ + kikit + ]; + + allowedRequisites = []; +} '' + set -e + export HOME=$(mktemp -d) + + mkdir -p "$out/${sharePath}" + + # do the panelize here rather than in $out because it creates junk we don't want + cd $HOME + + kikit panelize \ + ${lib.concatMapStrings (conf: "-p ${conf} \\\n") panelizeConfigs} \ + "${panelSrc}/${pcb_path}" \ + "panel.kicad_pcb" + + cp -v panel.kicad_{pcb,pro} "$out/${sharePath}" + cp -v "${src}/"*.kicad_{sch,pro} "$out/${sharePath}" +'' diff --git a/clef/nix/schematic.nix b/clef/nix/schematic.nix new file mode 100644 index 0000000..acc136f --- /dev/null +++ b/clef/nix/schematic.nix @@ -0,0 +1,51 @@ +{ + kicad, + runCommand, + + nix-filter, + lib, + + src, + sch_path, + + schName ? (lib.removeSuffix ".kicad_sch" (builtins.baseNameOf sch_path)), +}: let + sharePath = "share/npry/clef/schematic"; + +in runCommand "${schName}.schematic" { + nativeBuildInputs = [ + kicad + ]; + + src = nix-filter { + root = src; + + include = [ + (nix-filter.matchExt "kicad_sch") + (nix-filter.matchExt "kicad_pro") + ]; + }; +} '' + set -e + export HOME=$(mktemp -d) + + echo "schematic: '${schName}'" >&2 + + mkdir -p "$out/${sharePath}/svg" + cd "$out/${sharePath}" + + kicad-cli sch export pdf -o schematic.pdf $src/${sch_path} + kicad-cli sch export svg -n -o svg $src/${sch_path} + + cd svg + + # normalize + for f in *.svg; do + if [ "$f" = "${schName}.svg" ]; then + mv -nv "$f" "root.svg" + continue + fi + + mv -nv "$f" "''${f#${schName}-}" + done +'' diff --git a/clef/nix/svg.nix b/clef/nix/svg.nix new file mode 100644 index 0000000..fc1a404 --- /dev/null +++ b/clef/nix/svg.nix @@ -0,0 +1,82 @@ +{ + runCommand, + kicad, + + nix-filter, + lib, + + pcb_path, + src, + + withSilk ? true, + withEdgeCuts ? true, + withMirrors ? true, + nLayer ? 2, + + boardName ? (lib.removeSuffix ".kicad_pcb" (builtins.baseNameOf pcb_path)), +}: let + sharePath = "share/npry/clef/svg"; + +in runCommand "${boardName}.svg" { + nativeBuildInputs = [ + kicad + ]; + + src = nix-filter { + root = src; + + include = [ + (nix-filter.matchExt "kicad_pcb") + ]; + }; + + nInnerLayer = if nLayer < 2 then 0 else nLayer - 2; + + allowedRequisites = []; +} '' + set -e + + export HOME=$(mktemp -d) + + echo "board: '${boardName}'" >&2 + + mkdir -p $out/${sharePath} + cd "$out/${sharePath}" + + mksvg() { + local infile=$1 + local layers=$2 + local outfile=$3 + + kicad-cli pcb export svg \ + "$infile" \ + -l "$layers" \ + -o "$outfile.svg" \ + --page-size-mode 2 \ + --exclude-drawing-sheet + + ${if withMirrors then '' + kicad-cli pcb export svg \ + "$infile" \ + -m \ + -l "$layers" \ + -o "$outfile.mirror.svg" \ + --page-size-mode 2 \ + --exclude-drawing-sheet + '' else ""} + } + + mksvg "$src/${pcb_path}" \ + "F.Cu,${if withSilk then "F.Silkscreen," else ""}${if withEdgeCuts then "Edge.Cuts," else ""}" \ + front + + mksvg "$src/${pcb_path}" \ + "B.Cu,${if withSilk then "B.Silkscreen," else ""}${if withEdgeCuts then "Edge.Cuts," else ""}" \ + back + + for i in $(seq 1 $nInnerLayer); do + mksvg "$src/${pcb_path}" \ + "In$i.Cu,${if withEdgeCuts then "Edge.Cuts," else ""}" \ + "in$i" + done +'' diff --git a/clef/overlays.nix b/clef/overlays.nix new file mode 100644 index 0000000..7e3a00e --- /dev/null +++ b/clef/overlays.nix @@ -0,0 +1,49 @@ +{ + inputs, +}: { + kicad = final: prev: { + opencascade-occt_7_6 = prev.opencascade-occt_7_6.overrideAttrs (finalAttrs: prevAttrs: { + buildInputs = (prevAttrs.buildInputs or []) ++ [ + prev.rapidjson + ]; + + cmakeFlags = (prevAttrs.cmakeFlags or []) ++ [ + "-DUSE_RAPIDJSON=1" + ]; + }); + + kicad = prev.kicad.override { + with3d = true; + withI18n = false; + + addons = with prev.kicadAddons; [ + kikit + kikit-library + ]; + }; + + kikit = let + version = "1.6.0"; + + in prev.kikit.overridePythonAttrs { + inherit version; + + src = final.fetchFromGitHub { + owner = "yaqwsx"; + repo = "KiKit"; + rev = "refs/tags/v${version}"; + hash = "sha256-r8LQcy3I6hmcrU/6HfPAYJd+cEZdhad6DUldC9HvXZU="; + }; + + doCheck = false; + }; + }; + + cq = (final: prev: { + inherit (inputs.cq.packages.${prev.system}) cadquery; + }); + + nix-filter = (final: prev: { + nix-filter = inputs.nix-filter.lib; + }); +} diff --git a/flake.lock b/flake.lock index 5f3d9ad..62abf7c 100644 --- a/flake.lock +++ b/flake.lock @@ -18,15 +18,25 @@ } }, "clef": { - "flake": false, + "inputs": { + "cq": "cq", + "flake-utils": [ + "flake-utils" + ], + "nix-filter": "nix-filter", + "nixpkgs": [ + "nixpkgs" + ] + }, "locked": { - "narHash": "sha256-VsarKxUotDEPzjyw+fa6gK3snk0XXObTlplS86PvhpM=", - "type": "file", - "url": "https://pub.npry.dev/clef" + "lastModified": 1, + "narHash": "sha256-keX8wAIShSwyQpzHeMpzYf4Edqn4XddHu6QvVFrG/3g=", + "path": "./clef", + "type": "path" }, "original": { - "type": "file", - "url": "https://pub.npry.dev/clef" + "path": "./clef", + "type": "path" } }, "cq": { @@ -34,9 +44,11 @@ "cadquery-src": "cadquery-src", "cq-editor-src": "cq-editor-src", "flake-utils": [ + "clef", "flake-utils" ], "nixpkgs": [ + "clef", "nixpkgs" ], "ocp-src": "ocp-src", @@ -195,9 +207,7 @@ "root": { "inputs": { "clef": "clef", - "cq": "cq", "flake-utils": "flake-utils", - "nix-filter": "nix-filter", "nixpkgs": "nixpkgs" } }, diff --git a/flake.nix b/flake.nix index 8cc182a..3e7839c 100644 --- a/flake.nix +++ b/flake.nix @@ -3,75 +3,26 @@ inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixos-24.05"; flake-utils.url = "github:numtide/flake-utils/main"; - nix-filter.url = "github:numtide/nix-filter/main"; - cq = { - url = "github:vinszent/cq-flake/main"; + clef = { + url = "path:./clef"; inputs.nixpkgs.follows = "nixpkgs"; inputs.flake-utils.follows = "flake-utils"; }; - - clef = { - url = "https://pub.npry.dev/clef"; - flake = false; - }; }; description = "tiny kite-borne sensor node"; - outputs = { self, nixpkgs, flake-utils, ... } @ inputs: let - kicadOverlay = final: prev: { - opencascade-occt_7_6 = prev.opencascade-occt_7_6.overrideAttrs (finalAttrs: prevAttrs: { - buildInputs = (prevAttrs.buildInputs or []) ++ [ - prev.rapidjson - ]; - - cmakeFlags = (prevAttrs.cmakeFlags or []) ++ [ - "-DUSE_RAPIDJSON=1" - ]; - }); - - kicad = prev.kicad.override { - with3d = true; - withI18n = false; - - addons = with prev.kicadAddons; [ - kikit - kikit-library - ]; - }; - - kikit = let - version = "1.6.0"; - - in prev.kikit.overridePythonAttrs { - inherit version; - - src = final.fetchFromGitHub { - owner = "yaqwsx"; - repo = "KiKit"; - rev = "refs/tags/v${version}"; - hash = "sha256-r8LQcy3I6hmcrU/6HfPAYJd+cEZdhad6DUldC9HvXZU="; - }; - - doCheck = false; - }; - }; - + outputs = { self, nixpkgs, flake-utils, clef, ... } @ inputs: let mkPkgs = system: import nixpkgs { inherit system; overlays = [ - kicadOverlay - (final: prev: { nix-filter = inputs.nix-filter.lib; }) - - (final: prev: { - inherit (inputs.cq.packages.${system}) cadquery; - }) + clef.overlays.default ]; }; - mkPkg = pkgs: pkgs.callPackage ./nix { + mkPkg = pkgs: pkgs.clef { name = "ocularium"; src = ./.; @@ -110,7 +61,6 @@ ) // { overlays = { default = final: prev: self.packages.${prev.system}; - kicad = kicadOverlay; }; }; } diff --git a/kikit/jlc_edge_rails.json b/kikit/jlc_edge_rails.json deleted file mode 100644 index 27a1bb1..0000000 --- a/kikit/jlc_edge_rails.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "layout": { - "type": "grid", - "rows": 1, - "cols": 1, - "space": "2mm" - }, - "framing": { - "type": "frame", - "width": "5mm", - "space": "3mm", - "cuts": "both", - "mintotalwidth": "70mm", - "mintotalheight": "70mm" - }, - "tabs": { - "type": "annotation" - }, - "cuts": { - "type": "mousebites", - "drill": "0.5mm", - "spacing": "1mm", - "offset": "0.2mm", - "prolong": "0.5mm" - }, - "fiducials": { - "type": "3fid", - "hoffset": "5mm", - "voffset": "5mm", - "coppersize": "1mm", - "opening": "2mm" - }, - "post": { - "millradius": "1mm" - }, - "text": { - "type": "simple", - "text": "ocularium v0.1.0", - "anchor": "mt", - "voffset": "5mm", - "hjustify": "center", - "vjustify": "center" - }, - "text2": { - "type": "simple", - "text": "npry 2024", - "anchor": "mb", - "voffset": "-5mm", - "hjustify": "center", - "vjustify": "center" - } -} \ No newline at end of file diff --git a/nix/board.nix b/nix/board.nix deleted file mode 100644 index 49418f0..0000000 --- a/nix/board.nix +++ /dev/null @@ -1,34 +0,0 @@ -{ - runCommand, - - svg, - model, - fabrication, - schematic, - panel, - panelSrc, - - name, - outPath, -}: let - pkg = runCommand name {} '' - set -e - - mkdir -p "$out/${outPath}" - cd "$out/${outPath}" - - echo "populating $(pwd)" - - cp --reflink=auto -vr "${schematic}/share/npry/clef/schematic" ./ - cp --reflink=auto -vr "${svg}/share/npry/clef/svg" ./ - cp --reflink=auto -vr "${fabrication}/share/npry/clef/fab" ./ - cp --reflink=auto -vr "${model}/share/npry/clef/model" ./ - cp --reflink=auto -vr "${panelSrc}/share/npry/clef/panel" ./ - ''; - -in pkg.overrideAttrs (prevAttrs: { - passthru = (prevAttrs.passthru or {}) // { - inherit schematic fabrication svg model panel panelSrc; - fab = fabrication; - }; -}) diff --git a/nix/default.nix b/nix/default.nix deleted file mode 100644 index eee258c..0000000 --- a/nix/default.nix +++ /dev/null @@ -1,52 +0,0 @@ -{ - pkgs, - - src, - main_pcb, - main_sch, - - name, - outPath ? "share/npry/clef", - layers ? 2, -}: let - pcb_path = main_pcb; - sch_path = main_sch; - - pcb_args = { - inherit pcb_path src; - }; - - panelSrc = pkgs.callPackage ./panel.nix pcb_args; - panel = pkgs.callPackage ./. { - src = "${panelSrc}/share/npry/clef/panel"; - main_pcb = "panel.kicad_pcb"; - - name = "${name}.sub.panel"; - outPath = "${outPath}/panel"; - - inherit main_sch layers; - }; - - svg = pkgs.callPackage ./svg.nix (pcb_args // { nLayer = layers; }); - model = pkgs.callPackage ./model.nix pcb_args; - - fabrication = pkgs.callPackage ./fabrication.nix (pcb_args // { - inherit sch_path; - }); - - schematic = pkgs.callPackage ./schematic.nix { - inherit sch_path src; - }; - -in pkgs.callPackage ./board.nix { - inherit - svg - model - fabrication - schematic - name - outPath - panel - panelSrc - ; -} diff --git a/nix/fabrication.nix b/nix/fabrication.nix deleted file mode 100644 index 18bc6f6..0000000 --- a/nix/fabrication.nix +++ /dev/null @@ -1,82 +0,0 @@ -{ - kicad, - kikit, - zip, - - runCommand, - - nix-filter, - lib, - - src, - pcb_path, - sch_path, - - boardName ? (lib.removeSuffix ".kicad_pcb" (builtins.baseNameOf pcb_path)), - - fabHouse ? "jlcpcb", - withAssembly ? true, -}: let - sharePath = "share/npry/clef/fab"; - - fabSrc = nix-filter { - root = src; - - include = [ - (nix-filter.matchExt "kicad_sch") - (nix-filter.matchExt "kicad_wks") - (nix-filter.matchExt "kicad_pcb") - (nix-filter.matchExt "kicad_pro") - - (_args: path: type: type == "directory") - ]; - }; - -in runCommand "${boardName}.fab" { - nativeBuildInputs = [ - kicad - kikit - zip - ]; - - src = fabSrc; - - allowedRequisites = []; -} '' - set -e - - export HOME=$(mktemp -d) - - echo "board: '${boardName}'" >&2 - - mkdir -p "$out/${sharePath}" - cd "$src" - - kikit fab ${fabHouse} \ - ${if withAssembly then "--assembly" else ""} \ - --no-drc \ - --schematic "${sch_path}" \ - --field 'LCSC Part #,LCSC Part No' \ - --missingError \ - "${pcb_path}" \ - "$out/${sharePath}" - - cd "$out/${sharePath}" - rm -vf "gerbers.zip" - - pushd gerber - - # normalize - for f in ${boardName}-*; do - mv -nv "$f" "''${f#${boardName}-}" - done - - for f in ${boardName}.*; do - mv -nv "$f" "board''${f#${boardName}}" - done - - popd - - zip -vj "gerbers.zip" gerber/* - rm -vrf gerber -'' diff --git a/nix/model.nix b/nix/model.nix deleted file mode 100644 index 04bf1b1..0000000 --- a/nix/model.nix +++ /dev/null @@ -1,52 +0,0 @@ -{ - kicad, - runCommand, - - nix-filter, - lib, - - withTracks ? false, - withZones ? false, - - src, - pcb_path, - - boardName ? (lib.removeSuffix ".kicad_pcb" (builtins.baseNameOf pcb_path)), -}: let - zonesArg = if withZones then "--include-zones" else ""; - tracksArg = if withTracks then "--include-tracks" else ""; - sharePath = "share/npry/clef/model"; - -in runCommand "${boardName}.model" { - nativeBuildInputs = [ - kicad - ]; - - src = nix-filter { - root = src; - - include = [ - (nix-filter.matchExt "kicad_pcb") - - (nix-filter.matchExt "stp") - (nix-filter.matchExt "step") - (nix-filter.matchExt "wrl") - ]; - }; - - allowedRequisites = []; - - KICAD8_3DMODEL_DIR = "${kicad.libraries.packages3d}/share/kicad/3dmodels"; -} '' - set -e - - export HOME=$(mktemp -d) - - echo "board: '${boardName}'" >&2 - - mkdir -p $out/${sharePath} - cd "$out/${sharePath}" - - kicad-cli pcb export step --subst-models --no-dnp ${tracksArg} ${zonesArg} "$src/${pcb_path}" -o "${boardName}.step" - kicad-cli pcb export glb --subst-models --no-dnp ${tracksArg} ${zonesArg} "$src/${pcb_path}" -o "${boardName}.glb" -'' diff --git a/nix/panel.nix b/nix/panel.nix deleted file mode 100644 index a56539a..0000000 --- a/nix/panel.nix +++ /dev/null @@ -1,46 +0,0 @@ -{ - kikit, - runCommand, - - nix-filter, - lib, - - panelizeConfigs ? [":jlcTooling"], - src, - pcb_path, - - boardName ? (lib.removeSuffix ".kicad_pcb" (builtins.baseNameOf pcb_path)), -}: let - sharePath = "share/npry/clef/panel"; - - panelSrc = nix-filter { - root = src; - - include = [ - (nix-filter.matchExt "kicad_pcb") - ]; - }; - -in runCommand "${boardName}.panel" { - nativeBuildInputs = [ - kikit - ]; - - allowedRequisites = []; -} '' - set -e - export HOME=$(mktemp -d) - - mkdir -p "$out/${sharePath}" - - # do the panelize here rather than in $out because it creates junk we don't want - cd $HOME - - kikit panelize \ - ${lib.concatMapStrings (conf: "-p ${conf} \\\n") panelizeConfigs} \ - "${panelSrc}/${pcb_path}" \ - "panel.kicad_pcb" - - cp -v panel.kicad_{pcb,pro} "$out/${sharePath}" - cp -v "${src}/"*.kicad_{sch,pro} "$out/${sharePath}" -'' diff --git a/nix/schematic.nix b/nix/schematic.nix deleted file mode 100644 index acc136f..0000000 --- a/nix/schematic.nix +++ /dev/null @@ -1,51 +0,0 @@ -{ - kicad, - runCommand, - - nix-filter, - lib, - - src, - sch_path, - - schName ? (lib.removeSuffix ".kicad_sch" (builtins.baseNameOf sch_path)), -}: let - sharePath = "share/npry/clef/schematic"; - -in runCommand "${schName}.schematic" { - nativeBuildInputs = [ - kicad - ]; - - src = nix-filter { - root = src; - - include = [ - (nix-filter.matchExt "kicad_sch") - (nix-filter.matchExt "kicad_pro") - ]; - }; -} '' - set -e - export HOME=$(mktemp -d) - - echo "schematic: '${schName}'" >&2 - - mkdir -p "$out/${sharePath}/svg" - cd "$out/${sharePath}" - - kicad-cli sch export pdf -o schematic.pdf $src/${sch_path} - kicad-cli sch export svg -n -o svg $src/${sch_path} - - cd svg - - # normalize - for f in *.svg; do - if [ "$f" = "${schName}.svg" ]; then - mv -nv "$f" "root.svg" - continue - fi - - mv -nv "$f" "''${f#${schName}-}" - done -'' diff --git a/nix/svg.nix b/nix/svg.nix deleted file mode 100644 index fc1a404..0000000 --- a/nix/svg.nix +++ /dev/null @@ -1,82 +0,0 @@ -{ - runCommand, - kicad, - - nix-filter, - lib, - - pcb_path, - src, - - withSilk ? true, - withEdgeCuts ? true, - withMirrors ? true, - nLayer ? 2, - - boardName ? (lib.removeSuffix ".kicad_pcb" (builtins.baseNameOf pcb_path)), -}: let - sharePath = "share/npry/clef/svg"; - -in runCommand "${boardName}.svg" { - nativeBuildInputs = [ - kicad - ]; - - src = nix-filter { - root = src; - - include = [ - (nix-filter.matchExt "kicad_pcb") - ]; - }; - - nInnerLayer = if nLayer < 2 then 0 else nLayer - 2; - - allowedRequisites = []; -} '' - set -e - - export HOME=$(mktemp -d) - - echo "board: '${boardName}'" >&2 - - mkdir -p $out/${sharePath} - cd "$out/${sharePath}" - - mksvg() { - local infile=$1 - local layers=$2 - local outfile=$3 - - kicad-cli pcb export svg \ - "$infile" \ - -l "$layers" \ - -o "$outfile.svg" \ - --page-size-mode 2 \ - --exclude-drawing-sheet - - ${if withMirrors then '' - kicad-cli pcb export svg \ - "$infile" \ - -m \ - -l "$layers" \ - -o "$outfile.mirror.svg" \ - --page-size-mode 2 \ - --exclude-drawing-sheet - '' else ""} - } - - mksvg "$src/${pcb_path}" \ - "F.Cu,${if withSilk then "F.Silkscreen," else ""}${if withEdgeCuts then "Edge.Cuts," else ""}" \ - front - - mksvg "$src/${pcb_path}" \ - "B.Cu,${if withSilk then "B.Silkscreen," else ""}${if withEdgeCuts then "Edge.Cuts," else ""}" \ - back - - for i in $(seq 1 $nInnerLayer); do - mksvg "$src/${pcb_path}" \ - "In$i.Cu,${if withEdgeCuts then "Edge.Cuts," else ""}" \ - "in$i" - done -'' -- cgit v1.3.1