This repo contains experimental software for parsing KiCAD electronic design files and extracting information from them. There is also a parser for device tree files and some nushell helper scripts.
If you need a quick start to generate BOM and other fabrication files see: BUILD.md
KiCAD schematic, PCB, footprint, and symbol files are in S-expression form. The parser here was adapted from the example in the Nom project.
The structure of a device tree is similar but the syntax is different. There is a separate parser for those.
Once parsed, the KiCAD data can be transformed and then serialized. The parser/serializer are good enough to roundtrip the projects I have on hand without loss.
KiCAD file -> parse -> transform -> serialize -> output file
The transform step could be used to make a systematic change that preserves the structure, in which case the output could be a valid KiCAD file. Or it could be extracting information, such as symbol or footprint names, in which case the output would be a summary.
The output format can be an S-expression or JSON. A JSON conversion is provided that does a reasonable job of finding objects in among the nested lists of an S-expression.
A basic executable is provided to summarize footprints and symbols and to convert KiCAD files to JSON. But the software is more flexible when used as a library.
Commands:
./ki_parse footprints
./ki_parse symbols
./ki_parse sheets
./ki_parse format
./ki_merge symbol-library
./dts_parse
footprints
takes a PCB (.kicad_pcb
) file on the standard input and produces a JSON summary of the footprints found.symbols
takes a schematic (.kicad_sch
) file and summarizes its symbolssheets
summarizes schematic sheetsformat
command takes either type of file and produces a JSON translation
Appending -s
to these commands produces an S-expression instead of JSON.
This takes a symbol library on its standard input and the file name of another symbol library as its argument. Their contents are merged producing a new symbol library on the standard output.
The two libraries must have the same version and generator attributes. (Use the KiCAD CLI to upgrade libraries.) Duplicate symbols are eliminated, the first symbol with a given name is kept.
Produces a series of symbol libraries each containing a single symbol from an input symbol library.
The input symbol library is read on the standard input. The argument is the name of an existing directory
where the output symbol libraries will be created. Each output file is named for the symbol it contains,
santised to make a valid file name.
This command takes device tree source and produces a JSON rendition of it.
A nushell
module provides higher level commands.
nushell> use kiops.nu
nushell> $env.kiops_lib_location = <kicad-libs-location>
nushell> kiops upgrade footprints
nushell> kiops upgrade symlibs
nushell> kiops merge symlibs
nushell> kiops install libs <project_dir>
nushell> kiops survey symbols <project_dir>
nushell> kiops survey footprints <project_dir>
The core data structure for KiCAD S-expressions looks like this:
pub enum Atom {
Symbol(String),
Str(String),
Num(f64),
Bits(u64),
Bool(bool),
Uuid(Uuid),
}
pub enum Expr {
Constant(Atom),
List(VecDeque<Expr>),
}
The From<X>
trait is implemented for Atom
and Expr
with various types X
and extraction methods as_X
yielding Option<X>
are defined.
The Simplifier
trait makes it easy to extract information from an Expr
in many cases.
pub trait Simplifier {
fn simplify(&self, subject: &Expr) -> Option<Expr>;
}
Any function Fn(&Expr) -> Option<Expr>
is a simplifier (a blanket implementation is provided). For example, to match a Expr::Constant(Atom::Str(_))
and trim white space:
pub fn trim(x: &Expr) -> Option<Expr> {
Some(x.as_atom()?.as_string()?.trim().into())
}
Simplifiers can be combined. For example, KiCAD symbols and footprints have properties. Here is a simplifier that matches any property and trims its value:
let property = Cons("property", Cons(AnyStr, Cons(trim, Anything)))
This uses a combinator called Cons
that applies one simplifier to the head and another to the tail of an Expr::List(_)
.
Some of the information in a KiCAD property concerns how and where to display it. This comes after the property value and is matched by Anything
in the above. If we want to discard that information:
let property_kv_only = Cons("property", Cons(AnyStr, Cons(trim, Discard(Anything))))
Putting it all together, this example consumes a complete schematic diagram and reduces it to symbols and their properties.
pub fn extract_symbols(schematic: &Expr) -> Option<Expr> {
let property_kv_only = Cons("property", Cons(AnyStr, Cons(trim, Discard(Anything))));
let symbols = Cons(
"kicad_sch",
Filter(Cons("symbol", Filter(property_kv_only))),
);
symbols.simplify(schematic)
}
Simplifier | Description |
---|---|
AnyNum |
match a Constant(Num(_)) |
AntStr |
match a Constant(Str(_)) |
a: Atom |
match a Constant(a) |
s: &'static str |
match a Constant(Symbol(s)) |
Anything |
match any expression |
Nothing |
match an empty List |
Combinator | Description |
---|---|
Cons(H,T) |
match the head element of a List with H and the tail with T producing a new List |
Head(H) |
match the head element of a List with H extracting this from the list |
Filter(X) |
match each element of a List with X producing a List of the successes |
Find(X) |
match each element of a List with X extracting the first success from the list |
Or(X,Y) |
match with X or, if that fails, match with Y |
And(X,Y) |
match with X and, if that succeeds, match the simplified result with Y |
Discard(X) |
match with X and, if that succeeds, replace with an empty List |
Special case: Cons(Discard(H), T)
produces the result of T
if H
and T
succeed.