from itertools import chain, takewhile, dropwhile, filterfalse SOURCE_SIGNALS = {'VDD', 'VCC', 'VCCIO', 'VCORE', 'VPHY', 'VPLL'} SINK_SIGNALS = {'GND', 'AGND'} POWER_SIGNALS = SOURCE_SIGNALS | SINK_SIGNALS def split_power(lines): source = [] sink = [] other = [] for pin, signal, type in lines: if signal in SOURCE_SIGNALS: source.append((pin, signal, type)) elif signal in SINK_SIGNALS: sink.append((pin, signal, type)) else: other.append((pin, signal, type)) return source, sink, other def make_pin_left(lines, half_width): for ix, (number, name, type) in enumerate(lines): x = u(-half_width) y = u((-ix + 0) * 2) r = 0 yield pin(x, y, r, number, name, type) def make_pin_right(lines, half_width): for ix, (number, name, type) in enumerate(lines): x = u(half_width) y = u((-ix + 0) * 2) r = 180 yield pin(x, y, r, number, name, type) def make_pin_top(lines): for ix, (number, name, type) in enumerate(lines): x = u((ix - (len(lines) / 2)) * 2) y = u(6) r = 270 yield pin(x, y, r, number, name, type) def make_pin_bottom(lines, height): for ix, (number, name, type) in enumerate(lines): x = u((ix - (len(lines) / 2)) * 2) y = u(-((height + 2) * 2)) r = 90 yield pin(x, y, r, number, name, type) input_p = lambda lnt: lnt[2] in {"input", "power_in"} def make_pins(lines, half_width, split_p=input_p): pin_sort = lambda l: pin_sort_key(l[1]) lines = sorted(lines, key=pin_sort) left = list(filter(split_p, lines)) right = list(filterfalse(split_p, lines)) pins = chain( make_pin_left(left, half_width), make_pin_right(right, half_width) ) return pins, max(len(left), len(right)) def pin_sort_key(s): is_not_numeric = lambda c: not (ord(c) >= ord('0') and ord(c) <= ord('9')) h = ''.join(takewhile(is_not_numeric, s)) t = ''.join(dropwhile(is_not_numeric, s)) return h, int(t) if t else -1 def assert_valid(lines): pins = set() signals = set() types = set([ "power_in", "power_out", "bidirectional", "input", "output" ]) for line in lines: pin, signal, type = line[:3] assert type in types, type assert pin not in pins, pins pins.add(pin) if signal not in POWER_SIGNALS: assert signal not in signals, signal signals.add(signal) def read_txt(filename): with open(filename) as f: lines = [l.split() for l in f.read().split('\n') if l] assert_valid(lines) return lines _lib = """ (kicad_symbol_lib (version 20220914) (generator kicad_sym) {symbols} ) """.strip('\n') _symbol = """ (symbol "{name}" (in_bom yes) (on_board yes) (property "Reference" "U" (at 0 -7.62 0) (effects (font (size 1.27 1.27))) ) (property "Value" "{value}" (at 0 -10.16 0) (effects (font (size 1.27 1.27))) ) (property "Footprint" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide) ) (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide) ) (symbol "{name}_0_1" (rectangle (start {x0} {y0}) (end {x1} {y1}) (stroke (width 0) (type default)) (fill (type none)) ) ) (symbol "{name}_1_1" {pins} ) ) """.strip('\n') _pin = """ (pin {type} line (at {x:.02f} {y:.02f} {r}) (length {length}) (name "{name}" (effects (font (size 1.27 1.27)))) (number "{number}" (effects (font (size 1.27 1.27)))) ) """.strip('\n') def lib(symbols): return _lib.format( symbols="\n".join(symbols) ) def symbol(name, value, pins, x0, y0, x1, y1): return _symbol.format( name=name, value=value, pins="\n".join(pins), x0=x0, y0=y0, x1=x1, y1=y1 ) def pin(x, y, r, number, name, type, length=4): return _pin.format( x=x - u(length) if x < 0 else x + u(length), y=y, r=r, name=name, type=type, number=number, length=u(length) ) def u(n): mul = 1.27 return n * mul