131 lines
5.9 KiB
Python
131 lines
5.9 KiB
Python
"""工程符号库:从参考设计的 .kicad_sch 抽符号,或按引脚表程序化生成方框符号。
|
|
|
|
from schgen.symgen import grab_from_sch, box_symbol, write_lib
|
|
blocks = [grab_from_sch(r"...\\SMOD\\07_PWR.kicad_sch", "IC_SCH:root_0_TPS7A92_IC_SCH.SchLib",
|
|
"TPS7A9201DSK"),
|
|
box_symbol("TPS65235", ref="U", value="TPS65235",
|
|
left=[("2", "VIN", "power_in"), ...], right=[...], top=[...], bottom=[...])]
|
|
write_lib(r"...\\lib\\myboard.kicad_sym", blocks)
|
|
|
|
先查参考设计有没有现成符号(抄过来最省事、引脚最不容易错),没有才自己生成。
|
|
"""
|
|
import io
|
|
import re
|
|
|
|
from .kicad_lib import balanced
|
|
|
|
PIN_TYPES = {"input", "output", "bidirectional", "tri_state", "passive", "free",
|
|
"unspecified", "power_in", "power_out", "open_collector", "open_emitter",
|
|
"no_connect"}
|
|
|
|
|
|
def rename(block, old, new):
|
|
"""把顶层符号名和子单元名 old_x_y 一并改掉。"""
|
|
block = block.replace('(symbol "%s"' % old, '(symbol "%s"' % new, 1)
|
|
for o in (old.split(':')[-1], old):
|
|
block = re.sub(r'\(symbol "%s(_\d+_\d+)"' % re.escape(o),
|
|
lambda m: '(symbol "%s%s"' % (new, m.group(1)), block)
|
|
return block
|
|
|
|
|
|
def grab_from_sch(sch_path, lib_id, new_name):
|
|
"""从 .kicad_sch 的 lib_symbols 段里按 lib_id 抽出符号并改名。"""
|
|
t = io.open(sch_path, encoding="utf-8").read()
|
|
i = t.find('(symbol "%s"' % lib_id)
|
|
if i < 0:
|
|
raise KeyError("%s 里没有 %s" % (sch_path, lib_id))
|
|
return rename(balanced(t, i), lib_id, new_name)
|
|
|
|
|
|
def pin_count(block):
|
|
return len(re.findall(r'\(pin\s+\w+\s+\w+', block))
|
|
|
|
|
|
def box_symbol(name, ref="U", value=None, desc="", left=(), right=(), top=(), bottom=(),
|
|
pitch=2.54, pin_len=5.08, min_w=15.24, min_h=10.16, hidden_num=False,
|
|
footprint=""):
|
|
"""方框符号。每边是 [(号, 名[, 类型]), ...],按顺序从上到下 / 从左到右排开;
|
|
号为 None 表示那一格留空(用来把引脚分组)。宽高按引脚名长度与数量自动撑开。"""
|
|
value = value or name
|
|
|
|
def norm(side):
|
|
out = []
|
|
for p in side:
|
|
if p is None:
|
|
out.append(None)
|
|
continue
|
|
num, nm = p[0], p[1]
|
|
typ = p[2] if len(p) > 2 else "passive"
|
|
assert typ in PIN_TYPES, typ
|
|
out.append((num, nm, typ))
|
|
return out
|
|
|
|
L, Rr, T, B = norm(left), norm(right), norm(top), norm(bottom)
|
|
# pitch 可以是一个数,也可以按边分别给:{"left":7.62,"right":5.08,"top":12.7,"bottom":12.7}
|
|
pd = pitch if isinstance(pitch, dict) else {}
|
|
pl, pr_, pt, pb = (pd.get(k, 2.54) if pd else pitch for k in ("left", "right", "top", "bottom"))
|
|
namew = lambda side: max([len(p[1]) for p in side if p] or [0]) * 1.1
|
|
nh = max(len(T), len(B), 0)
|
|
h = max(min_h, (len(L) + 1) * pl, (len(Rr) + 1) * pr_)
|
|
w = max(min_w, namew(L) + namew(Rr) + 5.08, (len(T) + 1) * pt, (len(B) + 1) * pb,
|
|
(max([len(p[1]) for p in T + B if p] or [0]) * 1.1 + 2.54) * 2 if nh else 0)
|
|
w = round(w / 2.54 / 2 + 0.49) * 2.54 * 2 # 宽高取 2.54 的偶数倍,引脚落格点
|
|
h = round(h / 2.54 / 2 + 0.49) * 2.54 * 2
|
|
hw, hh = w / 2.0, h / 2.0
|
|
lines = [' (symbol "%s"' % name,
|
|
' (pin_names (offset 0.762))%s' % (' (pin_numbers hide)' if hidden_num else ''),
|
|
' (exclude_from_sim no) (in_bom yes) (on_board yes)',
|
|
' (property "Reference" "%s" (at %.2f %.2f 0)'
|
|
' (effects (font (size 1.27 1.27)) (justify left)))' % (ref, -hw, hh + 1.27),
|
|
' (property "Value" "%s" (at %.2f %.2f 0)'
|
|
' (effects (font (size 1.27 1.27)) (justify left)))' % (value, -hw, -hh - 1.27),
|
|
' (property "Footprint" "%s" (at 0 0 0) (effects (font (size 1.27 1.27)) hide))'
|
|
% footprint,
|
|
' (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide))',
|
|
' (property "Description" "%s" (at 0 0 0) (effects (font (size 1.27 1.27)) hide))'
|
|
% desc.replace('"', "'"),
|
|
' (symbol "%s_0_1"' % name,
|
|
' (rectangle (start %.2f %.2f) (end %.2f %.2f)'
|
|
' (stroke (width 0.254) (type default)) (fill (type background)))' % (-hw, hh, hw, -hh),
|
|
' )',
|
|
' (symbol "%s_1_1"' % name]
|
|
|
|
def pin(num, nm, typ, x, y, ang):
|
|
lines.append(' (pin %s line (at %.2f %.2f %d) (length %.2f)' % (typ, x, y, ang, pin_len))
|
|
lines.append(' (name "%s" (effects (font (size 1.27 1.27))))' % nm)
|
|
lines.append(' (number "%s" (effects (font (size 1.27 1.27)))))' % num)
|
|
|
|
def col(n, pitch): # 竖边:从上往下,居中
|
|
top_y = (n - 1) * pitch / 2.0
|
|
return [round((top_y - k * pitch) / 1.27) * 1.27 for k in range(n)]
|
|
|
|
def row(n, pitch):
|
|
x0 = -(n - 1) * pitch / 2.0
|
|
return [round((x0 + k * pitch) / 1.27) * 1.27 for k in range(n)]
|
|
|
|
for p, y in zip(L, col(len(L), pl)):
|
|
if p:
|
|
pin(p[0], p[1], p[2], -hw - pin_len, y, 0)
|
|
for p, y in zip(Rr, col(len(Rr), pr_)):
|
|
if p:
|
|
pin(p[0], p[1], p[2], hw + pin_len, y, 180)
|
|
for p, x in zip(T, row(len(T), pt)):
|
|
if p:
|
|
pin(p[0], p[1], p[2], x, hh + pin_len, 270)
|
|
for p, x in zip(B, row(len(B), pb)):
|
|
if p:
|
|
pin(p[0], p[1], p[2], x, -hh - pin_len, 90)
|
|
lines += [' )', ' )']
|
|
return "\n".join(lines)
|
|
|
|
|
|
def write_lib(path, blocks):
|
|
out = ['(kicad_symbol_lib (version 20231120) (generator "kicad_flow_schgen") (generator_version "8.0")']
|
|
out += blocks
|
|
out.append(')')
|
|
io.open(path, "w", encoding="utf-8").write("\n".join(out) + "\n")
|
|
names = [re.match(r'\s*\(symbol "([^"]+)"', b).group(1) for b in blocks]
|
|
for b, n in zip(blocks, names):
|
|
print(" 符号 %-24s 引脚 %3d" % (n, pin_count(b)))
|
|
return path
|