main
noah amfm-receiver-molecule: KiCad project, fab files, 3D and README (6/7) 53707c4 1d ago
"""Export the netlist with kicad-cli and compare every pin against design.DESIGN."""
import os, subprocess, sys, tempfile
from sexp import parse, find, findall
from design import DESIGN

HERE = os.path.dirname(os.path.abspath(__file__))
PROJ = os.path.abspath(os.path.join(HERE, '..'))


def export_netlist(path):
    out = os.path.join(tempfile.gettempdir(), 'amfm_check.net')
    subprocess.run(['kicad-cli', 'sch', 'export', 'netlist', '--format', 'kicadsexpr', '-o', out, path],
                   check=True, capture_output=True)
    return parse(open(out).read())


def main():
    n = export_netlist(os.path.join(PROJ, 'amfm_receiver.kicad_sch'))
    kic = {}          # (ref, pin) -> net
    kic_nets = {}
    for net in findall(find(n, 'nets'), 'net'):
        name = find(net, 'name')[1]
        short = name.split('/')[-1]
        if short.startswith('unconnected-') or short.startswith('Net-('):
            short = None
        for nd in findall(net, 'node'):
            key = (find(nd, 'ref')[1], find(nd, 'pin')[1])
            kic[key] = short
            kic_nets.setdefault(name, []).append(key)
    comps = {find(c, 'ref')[1]: c for c in findall(find(n, 'components'), 'comp')}
    errors = 0
    for p in DESIGN.parts:
        if p.ref not in comps:
            if p.pins:
                print('MISSING component', p.ref)
                errors += 1
            continue
        c = comps[p.ref]
        fp = find(c, 'footprint')
        if fp is None or fp[1] != p.footprint:
            print('FOOTPRINT mismatch', p.ref, fp and fp[1], p.footprint)
            errors += 1
        for pin, net in p.pins.items():
            got = kic.get((p.ref, pin), None)
            if got != net:
                print('NET mismatch %s.%s: design=%s kicad=%s' % (p.ref, pin, net, got))
                errors += 1
    # local nets must not be split: a design net must map to one KiCad net
    dn = DESIGN.nets()
    for net, nodes in dn.items():
        names = set()
        for nm, keys in kic_nets.items():
            if any(k in keys for k in nodes):
                names.add(nm)
        if len(names) != 1:
            print('NET split/merged', net, names)
            errors += 1
    print('checked %d parts, %d design nets, %d KiCad nets: %d errors' % (
        len(DESIGN.parts), len(dn), len(kic_nets), errors))
    return errors


if __name__ == '__main__':
    sys.exit(1 if main() else 0)