aboutsummaryrefslogtreecommitdiff
path: root/hw/clef/nix
diff options
context:
space:
mode:
Diffstat (limited to 'hw/clef/nix')
-rw-r--r--hw/clef/nix/board.nix39
-rw-r--r--hw/clef/nix/bom.nix48
-rw-r--r--hw/clef/nix/default.nix61
-rw-r--r--hw/clef/nix/fabrication.nix82
-rw-r--r--hw/clef/nix/model.nix58
-rw-r--r--hw/clef/nix/panel.nix46
-rw-r--r--hw/clef/nix/pkgs/default.nix5
-rw-r--r--hw/clef/nix/pkgs/interactive_html_bom.nix69
-rw-r--r--hw/clef/nix/schematic.nix54
-rw-r--r--hw/clef/nix/svg.nix92
10 files changed, 554 insertions, 0 deletions
diff --git a/hw/clef/nix/board.nix b/hw/clef/nix/board.nix
new file mode 100644
index 0000000..5de46e0
--- /dev/null
+++ b/hw/clef/nix/board.nix
@@ -0,0 +1,39 @@
+{
+ runCommand,
+
+ svg,
+ model,
+ fabrication,
+ schematic,
+ panel,
+ panelSrc,
+ bom,
+
+ 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 "${bom}/share/npry/clef/bom" ./
+
+ ${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 bom;
+ fab = fabrication;
+ };
+})
diff --git a/hw/clef/nix/bom.nix b/hw/clef/nix/bom.nix
new file mode 100644
index 0000000..fbff8ff
--- /dev/null
+++ b/hw/clef/nix/bom.nix
@@ -0,0 +1,48 @@
+{
+ runCommand,
+ interactiveHtmlBom,
+
+ nix-filter,
+ lib,
+
+ pcb_path,
+ src,
+
+ boardName ? (lib.removeSuffix ".kicad_pcb" (builtins.baseNameOf pcb_path)),
+ extraArgs ? [
+ "--dark-mode"
+ "--include-tracks"
+ "--include-nets"
+ ],
+}: let
+ sharePath = "share/npry/clef/bom";
+
+in runCommand "${boardName}.bom" {
+ nativeBuildInputs = [
+ interactiveHtmlBom
+ ];
+
+ INTERACTIVE_HTML_BOM_NO_DISPLAY = 1;
+
+ src = nix-filter {
+ root = src;
+
+ include = [
+ (nix-filter.matchExt "kicad_pcb")
+ (nix-filter.matchExt "kicad_pro")
+ (nix-filter.matchExt "kicad_wks")
+
+ (_args: path: type: type == "directory")
+ ];
+ };
+} ''
+ mkdir -p "$out/${sharePath}"
+
+ cd $src
+
+ generate_interactive_bom \
+ --dest-dir "$out/${sharePath}" \
+ --no-browser \
+ ${lib.concatMapStrings (arg: "${arg} \\\n") extraArgs} \
+ "$src/${pcb_path}"
+''
diff --git a/hw/clef/nix/default.nix b/hw/clef/nix/default.nix
new file mode 100644
index 0000000..419c8fd
--- /dev/null
+++ b/hw/clef/nix/default.nix
@@ -0,0 +1,61 @@
+{
+ 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;
+
+ bom = pkgs.callPackage ./bom.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
+ bom
+ fabrication
+ schematic
+ name
+ outPath
+ panel
+ panelSrc
+ ;
+}
diff --git a/hw/clef/nix/fabrication.nix b/hw/clef/nix/fabrication.nix
new file mode 100644
index 0000000..18bc6f6
--- /dev/null
+++ b/hw/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/hw/clef/nix/model.nix b/hw/clef/nix/model.nix
new file mode 100644
index 0000000..da8be82
--- /dev/null
+++ b/hw/clef/nix/model.nix
@@ -0,0 +1,58 @@
+{
+ 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 "kicad_pro")
+
+ (nix-filter.matchExt "stp")
+ (nix-filter.matchExt "STP")
+ (nix-filter.matchExt "step")
+ (nix-filter.matchExt "STEP")
+ (nix-filter.matchExt "wrl")
+
+ (_args: path: type: type == "directory")
+ ];
+ };
+
+ allowedRequisites = [];
+
+ KICAD8_3DMODEL_DIR = "${kicad.libraries.packages3d}/share/kicad/3dmodels";
+} ''
+ set -e
+
+ export HOME=$(mktemp -d)
+
+ echo "board: '${boardName}'" >&2
+ echo "KICAD8_3DMODEL_DIR: $KICAD8_3DMODEL_DIR" >&2
+
+ mkdir -p $out/${sharePath}
+ cd "$src"
+
+ kicad-cli pcb export step --subst-models --no-dnp ${tracksArg} ${zonesArg} "${pcb_path}" -o "$out/${sharePath}/${boardName}.step"
+ kicad-cli pcb export glb --subst-models --no-dnp ${tracksArg} ${zonesArg} "${pcb_path}" -o "$out/${sharePath}/${boardName}.glb"
+''
diff --git a/hw/clef/nix/panel.nix b/hw/clef/nix/panel.nix
new file mode 100644
index 0000000..1d88d46
--- /dev/null
+++ b/hw/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/hw/clef/nix/pkgs/default.nix b/hw/clef/nix/pkgs/default.nix
new file mode 100644
index 0000000..a0a9f92
--- /dev/null
+++ b/hw/clef/nix/pkgs/default.nix
@@ -0,0 +1,5 @@
+{
+ pkgs,
+}: {
+ interactiveHtmlBom = pkgs.callPackage ./interactive_html_bom.nix {};
+}
diff --git a/hw/clef/nix/pkgs/interactive_html_bom.nix b/hw/clef/nix/pkgs/interactive_html_bom.nix
new file mode 100644
index 0000000..8adf7a7
--- /dev/null
+++ b/hw/clef/nix/pkgs/interactive_html_bom.nix
@@ -0,0 +1,69 @@
+{
+ python3Packages,
+ writeText,
+ kicad-small,
+
+ fetchFromGitHub,
+
+ version ? "v2.9.0",
+ thisSrc ? fetchFromGitHub {
+ owner = "openscopeproject";
+ repo = "interactivehtmlbom";
+ rev = version;
+ hash = "sha256-jUHEI0dWMFPQlXei3+0m1ruHzpG1hcRnxptNOXzXDqQ=";
+ },
+}:
+
+let
+ src = thisSrc;
+ dummySetupPy = writeText "setup.py" ''
+ #!/usr/bin/env python3
+ # vim: set ft=python :
+
+ from setuptools import setup, find_packages
+ import sys
+
+ packages = find_packages(include=['InteractiveHtmlBom', 'InteractiveHtmlBom.*'])
+
+ setup(
+ name="InteractiveHtmlBom",
+ version='${version}',
+ packages=packages,
+ install_requires=['wxpython>=4.0', 'jsonschema>=4.1'],
+ entry_points={
+ 'console_scripts': [
+ 'generate_interactive_bom=InteractiveHtmlBom.generate_interactive_bom:main'
+ ]
+ },
+ include_package_data=True
+ )
+ '';
+
+ dummyManifest = writeText "MANIFEST.in" ''
+ recursive-include InteractiveHtmlBom/schema *
+ recursive-include InteractiveHtmlBom/web *
+ recursive-include InteractiveHtmlBom/dialog/bitmaps *
+ '';
+
+in python3Packages.buildPythonApplication {
+ pname = "interactive_html_bom";
+
+ inherit
+ version
+ src
+ ;
+
+ preBuild = ''
+ cp -nv ${dummySetupPy} setup.py
+ cp -nv ${dummyManifest} MANIFEST.in
+ rm pyproject.toml
+ '';
+
+ dependencies = with python3Packages; [
+ wxpython
+ jsonschema
+ kicad-small.base
+ ];
+
+ doCheck = false;
+}
diff --git a/hw/clef/nix/schematic.nix b/hw/clef/nix/schematic.nix
new file mode 100644
index 0000000..e931dd4
--- /dev/null
+++ b/hw/clef/nix/schematic.nix
@@ -0,0 +1,54 @@
+{
+ 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")
+ (nix-filter.matchExt "kicad_wks")
+
+ (_args: path: type: type == "directory")
+ ];
+ };
+} ''
+ set -e
+ export HOME=$(mktemp -d)
+
+ echo "schematic: '${schName}'" >&2
+
+ mkdir -p "$out/${sharePath}/svg"
+ cd "$src"
+
+ kicad-cli sch export pdf -o "$out/${sharePath}/schematic.pdf" $src/${sch_path}
+ kicad-cli sch export svg -n -o "$out/${sharePath}/svg" $src/${sch_path}
+
+ cd "$out/${sharePath}/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/hw/clef/nix/svg.nix b/hw/clef/nix/svg.nix
new file mode 100644
index 0000000..c93ba87
--- /dev/null
+++ b/hw/clef/nix/svg.nix
@@ -0,0 +1,92 @@
+{
+ runCommand,
+ kicad,
+ inkscape,
+
+ 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
+ inkscape
+ ];
+
+ 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
+
+ inkscape --actions 'select-all;fit-canvas-to-selection' \
+ -o "$outfile.trim.svg" \
+ "$outfile.svg"
+
+ ${if withMirrors then ''
+ kicad-cli pcb export svg \
+ "$infile" \
+ -m \
+ -l "$layers" \
+ -o "$outfile.mirror.svg" \
+ --page-size-mode 2 \
+ --exclude-drawing-sheet
+
+ inkscape --actions 'select-all;fit-canvas-to-selection' \
+ -o "$outfile.mirror.trim.svg" \
+ "$outfile.mirror.svg"
+ '' 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
+''