blob: 8e68657974093fce060b0349f6e4318989b2a7e3 [file] [log] [blame]
# Copyright 2024 The Pigweed Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
"""KiCad Bazel Rules."""
load("@bazel_skylib//rules:native_binary.bzl", "native_test")
load("@rules_pkg//pkg:mappings.bzl", "pkg_files")
load("@rules_pkg//pkg:zip.bzl", "pkg_zip")
def kicad_project(name, project, sym_lib_table, fp_lib_table, schematic_root, schematic_srcs, data, pcb, pcb_design_rules, pcb_layers):
"""Top level kicad project macro.
Runs the following macros:
- kicad_schematic_pdf: Exports the schematic PDF using
https://docs.kicad.org/8.0/en/cli/cli.html#schematic_pdf_export
- kicad_schematic_test: Runs the schematic electrical rules check using
https://docs.kicad.org/8.0/en/cli/cli.html#schematic_erc
- kicad_pcb_drc_test: Runs the pcb design rules check using
https://docs.kicad.org/8.0/en/cli/cli.html#pcb_drc
- kicad_pcb_export: Generates gerber layer files using:
https://docs.kicad.org/8.0/en/cli/cli.html#pcb_gerber_export_multiple_layers_per_file
Args:
name: Name for this build rule.
project: The .kicad_pro file for this project.
sym_lib_table: The kicad symbol library table file.
fp_lib_table: The kicad footprint library table file.
schematic_root: Top level schematic .kicad_sch file.
schematic_srcs: List of additional .kicad_sch files.
data: List of symbols, footprints, and step files.
pcb: The .kicad_pcb file.
pcb_layers: A list of layers to be exported.
pcb_design_rules: A .kicad_dru file.
"""
kicad_schematic_pdf(
name = name + "_sch",
root = schematic_root,
srcs = schematic_srcs,
data = data + [project, sym_lib_table],
)
kicad_schematic_test(
name = name + "_erc_test",
root = schematic_root,
srcs = schematic_srcs,
data = data + [project, sym_lib_table],
)
kicad_pcb_drc_test(
name = name + "_drc_test",
pcb = pcb,
data = data + [project, pcb_design_rules, fp_lib_table],
)
kicad_pcb_export(
name = name + "_pcb_export",
pcb = pcb,
data = data + [project],
layer_list = pcb_layers,
)
pkg_files(
name = name + "_fabrication_output_files",
srcs = [
":" + name + "_pcb_export",
],
prefix = "fabrication_outputs",
)
pkg_zip(
name = name + "_fabrication_output_zip",
out = "fabrication_outputs.zip",
srcs = [
":" + name + "_fabrication_output_files",
],
)
def kicad_schematic_test(name, root, srcs, data):
args = ["sch", "erc", "--exit-code-violations", "$(rootpath " + root + " )"]
native_test(
name = name,
src = str(Label("//build:kicad_cli_test")),
args = args,
data = srcs + data + [root],
# Note: out is mandatory in older bazel-skylib versions.
out = name + ".exe",
)
def kicad_pcb_drc_test(name, pcb, data):
args = ["pcb", "drc", "--exit-code-violations", "$(rootpath " + pcb + " )"]
native_test(
name = name,
src = str(Label("//build:kicad_cli_test")),
args = args,
data = data + [pcb],
# Note: out is mandatory in older bazel-skylib versions.
out = name + ".exe",
)
def _kicad_schematic_pdf_impl(ctx):
pdf_file = ctx.actions.declare_file(ctx.label.name + ".pdf")
args = ["sch", "export", "pdf", "--output", pdf_file.path, ctx.file.root.path]
ctx.actions.run(
inputs = ctx.files.srcs + [ctx.file.root],
outputs = [pdf_file],
arguments = args,
use_default_shell_env = True,
progress_message = "running ERC on %s" % ctx.attr.name,
executable = ctx.executable._kicad_cli,
)
return [
DefaultInfo(files = depset([pdf_file])),
]
kicad_schematic_pdf = rule(
implementation = _kicad_schematic_pdf_impl,
attrs = {
"srcs": attr.label_list(allow_files = [".kicad_sch"]),
"root": attr.label(
allow_single_file = [".kicad_sch"],
mandatory = True,
),
"data": attr.label_list(allow_files = True),
"_kicad_cli": attr.label(
executable = True,
cfg = "exec",
allow_files = True,
default = Label("//build:kicad_cli"),
),
},
)
FOUR_LAYER_LIST = [
"F.Cu",
"In1.Cu",
"In2.Cu",
"B.Cu",
"F.Paste",
"B.Paste",
"F.Silkscreen",
"B.Silkscreen",
"F.Mask",
"B.Mask",
"Edge.Cuts",
]
def _kicad_gerber_layer_extension(layer):
layer_extensions = {
"F.Cu": "gtl",
"In1.Cu": "g2",
"In2.Cu": "g3",
"B.Cu": "gbl",
"F.Adhesive": "gta",
"B.Adhesive": "gba",
"F.Paste": "gtp",
"B.Paste": "gbp",
"F.Silkscreen": "gto",
"B.Silkscreen": "gbo",
"F.Mask": "gts",
"B.Mask": "gbs",
"User.Drawings": "gbr",
"User.Comments": "gbr",
"User.Eco1": "gbr",
"User.Eco2": "gbr",
"Edge.Cuts": "gm1",
"Margin": "gbr",
"F.Courtyard": "gbr",
"B.Courtyard": "gbr",
"F.Fab": "gbr",
"B.Fab": "gbr",
"User.1": "gbr",
"User.2": "gbr",
"User.3": "gbr",
"User.4": "gbr",
"User.5": "gbr",
"User.6": "gbr",
"User.7": "gbr",
"User.8": "gbr",
"User.9": "gbr",
}
return layer_extensions.get(layer, "gbr")
def _kicad_pcb_export_impl(ctx):
pcb_file_basename = ctx.file.pcb.basename.replace(".kicad_pcb", "")
gerber_outputs = [
ctx.actions.declare_file(pcb_file_basename + "-job.gbrjob"),
]
gerber_output_dir = gerber_outputs[0].dirname
for layer in ctx.attr.layer_list:
gerber_outputs += [
ctx.actions.declare_file(
"{}-{}.{}".format(
pcb_file_basename,
layer.replace(".", "_"),
_kicad_gerber_layer_extension(layer),
),
),
]
gerber_args = [
"pcb",
"export",
"gerbers",
"--output",
gerber_output_dir,
"--board-plot-params",
]
gerber_args += [
"--layers",
",".join(ctx.attr.layer_list),
]
gerber_args += [
ctx.file.pcb.path,
]
ctx.actions.run(
inputs = ctx.files.data + [ctx.file.pcb],
outputs = gerber_outputs,
arguments = gerber_args,
use_default_shell_env = True,
progress_message = "running PCB EXPORT GERBERS on %s" % ctx.attr.name,
executable = ctx.executable._kicad_cli,
)
drill_outputs = [
ctx.actions.declare_file(pcb_file_basename + "-NPTH-drl_map.gbr"),
ctx.actions.declare_file(pcb_file_basename + "-NPTH.drl"),
ctx.actions.declare_file(pcb_file_basename + "-PTH-drl_map.gbr"),
ctx.actions.declare_file(pcb_file_basename + "-PTH.drl"),
]
drill_output_dir = drill_outputs[0].dirname + "/"
drill_args = [
"pcb",
"export",
"drill",
"--output",
drill_output_dir,
"--drill-origin",
"absolute",
"--excellon-separate-th",
"--excellon-units",
"mm",
"--excellon-oval-format",
"alternate",
"--excellon-zeros-format",
"decimal",
"--generate-map",
"--map-format",
"gerberx2",
ctx.file.pcb.path,
]
ctx.actions.run(
inputs = ctx.files.data + [ctx.file.pcb],
outputs = drill_outputs,
arguments = drill_args,
use_default_shell_env = True,
progress_message = "running PCB EXPORT DRILL on %s" % ctx.attr.name,
executable = ctx.executable._kicad_cli,
)
return [
DefaultInfo(files = depset(gerber_outputs + drill_outputs)),
]
kicad_pcb_export = rule(
implementation = _kicad_pcb_export_impl,
attrs = {
"pcb": attr.label(
allow_single_file = [".kicad_pcb"],
mandatory = True,
),
"layer_list": attr.string_list(mandatory = True),
"data": attr.label_list(allow_files = True),
"_kicad_cli": attr.label(
executable = True,
cfg = "exec",
allow_files = True,
default = Label("//build:kicad_cli"),
),
},
)