fixed export script

This commit is contained in:
cpu
2026-06-08 12:49:42 +02:00
parent 3b423af5b5
commit eada18d3f0
4 changed files with 513 additions and 552 deletions

View File

@@ -6,25 +6,29 @@
#
# Options:
# --layers LAYER,LAYER,... KiCad layer names to export (default: F.Cu)
# --invert LAYER,LAYER,... Layers to invert (comma-separated, e.g. F.Cu,B.Mask)
# --mirror LAYER,LAYER,... Layers to mirror (comma-separated, e.g. F.Cu,F.Mask)
# --invert LAYER,LAYER,... Layers to invert (comma-separated)
# --mirror LAYER,LAYER,... Layers to mirror (comma-separated)
# --exposure SECONDS Exposure time in seconds (default: 60)
# --dummy FILE Dummy .pm4n template (default: Dummy.pm4n beside this script)
# --out DIR Output directory (default: ./output)
# --dpmm N Render resolution in dots/mm (default: native 58.824)
# --pos X,Y Board position on LCD in mm (default: centred)
# --verbose Print detailed progress
# -h, --help Show this help
#
# Example:
# ./export_for_msla.sh --invert F.Cu,B.Mask --mirror F.Cu,F.Mask panel/Flow_Controller_Panel.kicad_pcb
# Normal output: one output filepath per layer.
# Verbose output: full progress from KiCad and the converter.
#
# Layer name → Gerber filename mapping (KiCad default):
# F.Cu → <board>-F_Cu.gbr
# B.Cu → <board>-B_Cu.gbr
# F.Mask → <board>-F_Mask.gbr
# B.Mask → <board>-B_Mask.gbr
# F.SilkS → <board>-F_Silkscreen.gbr
# (etc.)
# Example:
# ./export_for_msla.sh --invert F.Cu,B.Mask --mirror F.Cu,F.Mask panel/board.kicad_pcb
#
# KiCad layer name → Gerber filename stem:
# F.Cu → F_Cu B.Cu → B_Cu
# F.Mask → F_Mask B.Mask → B_Mask
# F.SilkS → F_Silkscreen B.SilkS → B_Silkscreen
# F.Paste → F_Paste B.Paste → B_Paste
# Edge.Cuts → Edge_Cuts
# Front → Front Back → Back
set -euo pipefail
@@ -41,21 +45,28 @@ DUMMY="$SCRIPT_DIR/Dummy.pm4n"
OUT_DIR="./output"
DPMM=""
POS=""
VERBOSE=0
# ---- helpers ----
usage() {
sed -n '/^# Usage/,/^[^#]/{ /^#/{ s/^# \{0,1\}//; p } }' "$0"
grep '^#' "$0" | sed 's/^# \{0,1\}//'
exit 0
}
contains() { # contains <list> <item> — comma-separated list membership
log() { [[ $VERBOSE -eq 1 ]] && echo "$@" || true; }
contains() {
local list="$1" item="$2"
echo "$list" | tr ',' '\n' | grep -qx "$item"
}
layer_to_filename() { # KiCad layer name → Gerber filename stem
local layer="$1"
echo "$layer" | sed 's/\./_/g'
layer_to_filename() {
case "$1" in
F.SilkS) echo "F_Silkscreen" ;;
B.SilkS) echo "B_Silkscreen" ;;
Edge.Cuts) echo "Edge_Cuts" ;;
*) echo "${1//./_}" ;;
esac
}
# ---- parse arguments ----
@@ -70,54 +81,40 @@ while [[ $# -gt 0 ]]; do
--out) OUT_DIR="$2"; shift 2 ;;
--dpmm) DPMM="$2"; shift 2 ;;
--pos) POS="$2"; shift 2 ;;
--verbose) VERBOSE=1; shift ;;
-h|--help) usage ;;
-*) echo "Unknown option: $1"; exit 1 ;;
-*) echo "ERROR: unknown option: $1" >&2; exit 1 ;;
*) PCB_FILE="$1"; shift ;;
esac
done
if [[ -z "$PCB_FILE" ]]; then
echo "ERROR: no .kicad_pcb file specified"
echo "Usage: $0 [OPTIONS] <board.kicad_pcb>"
exit 1
fi
[[ -z "$PCB_FILE" ]] && { echo "ERROR: no .kicad_pcb file specified" >&2; exit 1; }
[[ ! -f "$PCB_FILE" ]] && { echo "ERROR: file not found: $PCB_FILE" >&2; exit 1; }
[[ ! -f "$DUMMY" ]] && { echo "ERROR: Dummy.pm4n not found: $DUMMY" >&2; exit 1; }
if [[ ! -f "$PCB_FILE" ]]; then
echo "ERROR: file not found: $PCB_FILE"
exit 1
fi
if [[ ! -f "$DUMMY" ]]; then
echo "ERROR: dummy .pm4n not found: $DUMMY"
echo "Place Dummy.pm4n next to export.sh, or pass --dummy <path>"
exit 1
fi
# ---- derive names ----
BOARD_NAME="$(basename "$PCB_FILE" .kicad_pcb)"
GERBERS_DIR="$OUT_DIR/gerbers"
PM4N_DIR="$OUT_DIR/pm4n"
mkdir -p "$GERBERS_DIR" "$PM4N_DIR"
# ---- Step 1: export Gerbers via kicad-cli ----
echo "=== Exporting Gerbers from KiCad ==="
echo " Board: $PCB_FILE"
echo " Layers: $LAYERS"
echo " Output: $GERBERS_DIR"
echo ""
# ---- Step 1: export Gerbers ----
log "=== Exporting Gerbers ==="
log " Board: $PCB_FILE"
log " Layers: $LAYERS"
kicad-cli pcb export gerbers \
--output "$GERBERS_DIR" \
--layers "$LAYERS" \
--no-protel-ext \
--subtract-soldermask \
"$PCB_FILE"
--no-netlist \
"$PCB_FILE" \
2>/dev/null
echo ""
log ""
# ---- Step 2: convert each layer to .pm4n ----
echo "=== Converting Gerbers to .pm4n ==="
# ---- Step 2: convert to pm4n ----
log "=== Converting to .pm4n ==="
IFS=',' read -ra LAYER_LIST <<< "$LAYERS"
for LAYER in "${LAYER_LIST[@]}"; do
@@ -125,23 +122,20 @@ for LAYER in "${LAYER_LIST[@]}"; do
GBR_FILE="$GERBERS_DIR/${BOARD_NAME}-${LAYER_STEM}.gbr"
if [[ ! -f "$GBR_FILE" ]]; then
echo " WARNING: expected Gerber not found: $GBR_FILE — skipping"
echo "WARNING: Gerber not found for layer $LAYER (expected: $GBR_FILE)" >&2
continue
fi
OUT_PM4N="$PM4N_DIR/${BOARD_NAME}-${LAYER_STEM}.pm4n"
# Build flags
FLAGS=()
if contains "$INVERT_LAYERS" "$LAYER"; then FLAGS+=(--invert); fi
if contains "$MIRROR_LAYERS" "$LAYER"; then FLAGS+=(--mirror); fi
contains "$INVERT_LAYERS" "$LAYER" && FLAGS+=(--invert)
contains "$MIRROR_LAYERS" "$LAYER" && FLAGS+=(--mirror)
[[ -n "$DPMM" ]] && FLAGS+=(--dpmm "$DPMM")
[[ -n "$POS" ]] && FLAGS+=(--pos "$POS")
[[ $VERBOSE -eq 1 ]] && FLAGS+=(--verbose)
echo " Layer: $LAYER"
echo " Gerber: $GBR_FILE"
echo " pm4n: $OUT_PM4N"
echo " Flags: ${FLAGS[*]:-<none>} exposure=${EXPOSURE}s"
log " $LAYER$OUT_PM4N [${FLAGS[*]:-} exposure=${EXPOSURE}s]"
"$PYTHON" "$CONVERTER" \
"$DUMMY" \
@@ -149,8 +143,6 @@ for LAYER in "${LAYER_LIST[@]}"; do
--output "$OUT_PM4N" \
--exposure "$EXPOSURE" \
"${FLAGS[@]}"
echo ""
done
echo "=== Done ==="
echo "pm4n files in: $PM4N_DIR"
log "=== Done ==="