"""Trace reviewed supply paths from fresh KiCad netlists; not an electrical rating check.""" import json from check_hardware import Board from schematic_maintenance import ROOT, children, parse, properties OUT = ROOT / 'out/power-path-review' def main(): OUT.mkdir(parents=True, exist_ok=True) boards = {n: Board(n) for n in (1, 2)} for b in boards.values(): b.compile('D:/KiCad/bin/kicad-cli.exe', OUT) a, b = boards[1], boards[2] checks = [] def same(number, *endpoints, net=None): board = boards[number] names = {board.net(*p) for p in endpoints} assert len(names) == 1 and (net is None or names == {net}), (number, endpoints, names) checks.append({'board': number, 'endpoints': endpoints, 'net': names.pop()}) same(1, ('J1', 1), net='GND') same(1, ('J1', 2), ('F1', 1)) same(1, ('F1', 2), ('Q1', 1), ('Q1', 2), ('Q1', 3)) same(1, ('Q1', 5), ('Q1', 6), ('Q1', 7), ('Q1', 8), ('Rs6', 1)) same(1, ('Rs6', 2), ('U19', 3), ('U30', 3), net='+12V') same(1, ('U19', 2), ('L2', 1)) same(1, ('L2', 2), ('U20', 2), net='+3V3') same(1, ('U30', 2), ('L3', 1)) same(1, ('L3', 2), ('J24', 8), net='+5V') for ch in range(1, 6): same(1, (f'U{ch}', 4), (f'U{ch}', 5), (f'U{ch}', 6), net='+12V') same(1, (f'U{ch}', 11), (f'U{ch}', 12), (f'L{ch}01', 1)) same(1, (f'L{ch}01', 2), *[(f'U{13+ch}', p) for p in range(9, 14)], net=f'VO{ch}') same(2, (f'U{23+ch}', 1), ('U31', 3), net='+5V') # The mechanical contract swaps odd/even physical pin numbers across the mating pair. for lower, upper in [('J24', 'J31'), ('J25', 'J32')]: for pin in range(1, 41): mate = pin + 1 if pin % 2 else pin - 1 net = a.net(lower, pin) assert net == b.net(upper, mate), (lower, pin, upper, mate) if net in ('GND', '+5V'): checks.append({'mating': [[1, lower, pin], [2, upper, mate]], 'net': net}) expected = {1: {'GND', '+3V3', '+12V', *[f'VO{ch}' for ch in range(1, 6)]}, 2: {'GND', '+5V'}} reported = {} for number, board in boards.items(): report = json.loads((OUT / f'Board{number}-erc.json').read_text()) names = [] for sheet in report['sheets']: for v in sheet['violations']: if v['type'] != 'power_pin_not_driven': continue description = v['items'][0]['description'].split() ref = description[1] if ref.startswith('#PWR'): path = board.path.parent / (sheet['path'].strip('/') + '.kicad_sch') symbol = next(s for s in children(parse(path.read_text(encoding='utf-8')), 'symbol') if properties(s)['Reference'][2] == ref) net = properties(symbol)['Value'][2] else: net = board.net(ref, description[3]) names.append(net) assert set(names) == expected[number] and len(names) == len(expected[number]) reported[number] = names result = {'status': 'PASS', 'scope': 'Netlist topology and coverage of all 10 power ERC reports', 'power_erc_nets': reported, 'checks': checks, 'limits': ['No PWR_FLAG added; ERC remains visible', 'MOS gate operation, component ratings, startup and physical copper are not validated']} (OUT / 'verification.json').write_text(json.dumps(result, indent=2) + '\n') print(json.dumps({'status': 'PASS', 'checks': len(checks), 'power_erc_nets': reported})) if __name__ == '__main__': main()