← Commit history

Delete design/gen/footprints.py

John Lauer ·3ebf12af31 ·7d ago ·parent 90487ac
1 file changed −216
design/gen/footprints.pydeleted−216
@@ -1,216 +0,0 @@-#!/usr/bin/env python3-"""Project footprints for the OCP NIC 3.0 SFF to 4x OCuLink riser, written as KiCad s-expressions.--Sources (every number below is quoted from these):-  OCP NIC 3.0 Design Specification v1.6.0 (2025-03-31): Table 20 (SFF pinout), Table 8 (mating sequence),-      Fig. 8/9/10 (SFF outline, faceplate grounding pads).-  SFF-TA-1002 Rev 1.6.2a: Fig. 5-39 (AIC 4C+ mating card), Fig. 5-41 (Detail D pad dimensions).-  Amphenol drawing G14A421X1BXXXHR rev D (OCuLink 4X R/A receptacle, shell DIP; option C = 2.90 mm legs),-      'Recommended PCB layout - top view'.-"""-import os, uuid--OUT = os.path.join(os.path.dirname(__file__), "..", "kicad", "lib", "Riser.pretty")-NS = uuid.UUID("6f1c2b0e-0c3a-4b6e-9a51-6f2c1d0e4a10")---def u(*k):-    return str(uuid.uuid5(NS, "/".join(map(str, k))))---def f(v):-    s = f"{v:.4f}".rstrip("0").rstrip(".")-    return "0" if s in ("-0", "") else s---def header(name, descr, tags, attr="smd"):-    return [f'(footprint "{name}"', '  (version 20241229)', '  (generator "riser-gen")', '  (generator_version "1.0")',-            '  (layer "F.Cu")', f'  (descr "{descr}")', f'  (tags "{tags}")',-            f'  (attr {attr})']---def text(kind, val, x, y, layer, hide=False, size=0.8):-    h = " (hide yes)" if hide else ""-    return (f'  (property "{kind}" "{val}" (at {f(x)} {f(y)} 0) (layer "{layer}"){h} (uuid "{u(kind, val, x, y)}")\n'-            f'    (effects (font (size {size} {size}) (thickness {f(size*0.15)}))))')---def line(x1, y1, x2, y2, layer, w=0.12):-    return f'  (fp_line (start {f(x1)} {f(y1)}) (end {f(x2)} {f(y2)}) (stroke (width {f(w)}) (type solid)) (layer "{layer}") (uuid "{u("l", x1, y1, x2, y2, layer)}"))'---def rect(x1, y1, x2, y2, layer, w=0.05, fill=False):-    fl = "yes" if fill else "no"-    return f'  (fp_rect (start {f(x1)} {f(y1)}) (end {f(x2)} {f(y2)}) (stroke (width {f(w)}) (type solid)) (fill {fl}) (layer "{layer}") (uuid "{u("r", x1, y1, x2, y2, layer)}"))'---def smd(num, x, y, w, h, layer="F", shape="rect", extra=""):-    lay = f'"{layer}.Cu" "{layer}.Mask"' + (f' "{layer}.Paste"' if layer and "nopaste" not in extra else "")-    return f'  (pad "{num}" smd {shape} (at {f(x)} {f(y)}) (size {f(w)} {f(h)}) (layers {lay}){extra.replace("nopaste","")} (uuid "{u("p", num, x, y, layer)}"))'---def write(name, lines):-    os.makedirs(OUT, exist_ok=True)-    with open(os.path.join(OUT, name + ".kicad_mod"), "w") as fh:-        fh.write("\n".join(lines) + "\n)\n")---# ---------------------------------------------------------------- OCP 4C+ gold fingers-def ocp_edge():-    """Origin: datum F (centre of the B28/B29 key) on the card edge (datum G). -y points into the card.-    Pads: 0.38 wide (SFF-TA-1002 Fig 5-41), top end 3.00 from G; bottom end 0.88 from G for 1st-mate-    (all GND, OCP Table 8) and 1.28 from G for 2nd-mate. B pins on F.Cu, A pins on B.Cu, A under B."""-    name = "OCP_NIC3_SFF_4CPlus_CardEdge"-    L = header(name, "OCP NIC 3.0 SFF primary connector 4C+ gold fingers (SFF-TA-1002 AIC 4C+), 0.6 mm pitch, two-stage mating",-               "OCP NIC 3.0 SFF-TA-1002 4C+ card edge gold finger", "smd exclude_from_pos_files exclude_from_bom allow_soldermask_bridges")-    L.append(text("Reference", "J1", 0, -5.2, "F.SilkS", size=1.0))-    L.append(text("Value", "OCP_NIC3_4C+", 0, -3.8, "F.Fab"))-    L.append(text("Footprint", name, 0, 0, "F.Fab", hide=True))-    pins = ocp_pin_x()-    gnd = set(n for n, net in ocp_pinout().items() if net == "GND")-    for pin, x in pins.items():-        side = "F" if pin.startswith("B") or pin.startswith("OCP_B") else "B"-        first = pin in gnd-        y_top = -3.00-        y_bot = -0.88 if first else -1.28-        cy = (y_top + y_bot) / 2-        L.append(f'  (pad "{pin}" smd rect (at {f(x)} {f(cy)}) (size 0.38 {f(y_bot - y_top)}) (layers "{side}.Cu" "{side}.Mask") (uuid "{u("ocp", pin)}"))')-    # mask opening over the whole finger field (mask not closer than 2.87 mm to datum G)-    for side in ("F", "B"):-        for (a, b) in ((-31.48, -20.4 - 1.125), (-20.4 + 1.125, -0.925), (0.925, 12.26 - 1.375), (12.26 + 1.375, 31.995)):-            L.append(rect(a + 0.05, -2.95, b - 0.05, 0.0, f"{side}.Mask", w=0, fill=True))-    L.append(line(-31.48, -3.05, 31.995, -3.05, "F.Fab", 0.1))-    L.append(rect(-31.48, -7.0, 31.995, 0, "F.CrtYd", 0.05))-    write(name, L)---def ocp_pin_x():-    """x of every finger relative to datum F (SFF-TA-1002 Fig 5-39)."""-    xs = {}-    for n in range(1, 15):-        xs[f"OCP_B{n}"] = -30.400 + (n - 1) * 0.6-        xs[f"OCP_A{n}"] = -30.400 + (n - 1) * 0.6-    for n in range(1, 71):-        if n <= 28:-            x = -18.205 + (n - 1) * 0.6-        elif n <= 42:-            x = 2.005 + (n - 29) * 0.6-        else:-            x = 14.715 + (n - 43) * 0.6-        xs[f"B{n}"] = x-        xs[f"A{n}"] = x-    return xs---def ocp_pinout():-    """OCP NIC 3.0 v1.6.0 Table 20, SFF Pin Definition (x16), primary connector 4C+."""-    p = {}-    ocpB = ["NIC_PWR_GOOD0", "MAIN_PWR_EN0", "SCAN0_LD#", "SCAN0_DATA_IN", "SCAN0_DATA_OUT", "SCAN0_CLK", "SLOT_ID0",-            "FLEXIO_0_2", "FLEXIO_0_1", "GND", "REFCLKn2", "REFCLKp2", "GND", "FLEXIO_0_0"]-    ocpA = ["PERST2#", "PERST3#", "WAKE0#", "RBT0_ARB_IN", "RBT0_ARB_OUT", "SLOT_ID1", "FLEXIO_0_3", "FLEXIO_0_5",-            "FLEXIO_0_4", "GND", "REFCLKn3", "REFCLKp3", "GND", "RBT0_CLK_IN"]-    for i in range(14):-        p[f"OCP_B{i+1}"] = ocpB[i]-        p[f"OCP_A{i+1}"] = ocpA[i]-    B = {1: "+12V_EDGE", 2: "+12V_EDGE", 3: "+12V_EDGE", 4: "+12V_EDGE", 5: "+12V_EDGE", 6: "+12V_EDGE",-         7: "BIF0#", 8: "BIF1#", 9: "BIF2#", 10: "PERST0#", 11: "+3.3V_EDGE", 12: "AUX_PWR_EN0", 13: "GND",-         14: "REFCLKn0", 15: "REFCLKp0", 16: "GND", 42: "PRSNTB0#", 68: "RFU1", 69: "RFU2", 70: "PRSNTB3#"}-    A = {1: "GND", 2: "GND", 3: "GND", 4: "GND", 5: "GND", 6: "GND", 7: "SMCLK0", 8: "SMDAT0", 9: "SMRST0#",-         10: "PRSNTA0#", 11: "PERST1#", 12: "PRSNTB2#", 13: "GND", 14: "REFCLKn1", 15: "REFCLKp1", 16: "GND",-         42: "PRSNTB1#", 68: "USB_DAT0n", 69: "USB_DAT0p", 70: "PWRBRK0#"}-    lanes = []  # (n_pin, p_pin, lane)-    starts = [17, 20, 23, 26, 30, 33, 36, 39, 44, 47, 50, 53, 56, 59, 62, 65]-    for lane, s in enumerate(starts):-        B[s] = f"PETn{lane}"; B[s + 1] = f"PETp{lane}"-        A[s] = f"PERn{lane}"; A[s + 1] = f"PERp{lane}"-    for n in range(1, 71):-        p[f"B{n}"] = B.get(n, "GND")-        p[f"A{n}"] = A.get(n, "GND")-    return p---# ---------------------------------------------------------------- Amphenol G14A42111C12HR-def oculink():-    """Origin: connector centre on the PCB edge, mating face toward -y (off the board), +y into the board.-    Amphenol layout rotated 180 deg: B_n at x = 5.25 - 0.5(n-1), y = 7.37; A_n at x = 4.75 - 0.5(n-1), y = 5.18.-    Pads 0.31 x 0.91. Shell legs: plated slots 0.60 x 1.30 in 1.20 x 1.90 pads at x = +/-6.58, y = 7.05 and 2.26.-    Pegs: NPTH dia 1.00 at (+5.41, 4.46) and (-5.94, 4.46). Body 13.15 wide, 9.00 deep, front 1.98 past the edge."""-    name = "Amphenol_G14A42111C12HR_OCuLink_4X_RA"-    L = header(name, "Amphenol G14A42111C12HR OCuLink 4X (SFF-8611/8621, 42 pos) right-angle receptacle, shell DIP 2.90 mm; land pattern from Amphenol drawing G14A421X1BXXXHR rev D",-               "OCuLink SFF-8611 SFF-8621 PCIe x4 receptacle right angle Amphenol G14", "smd")-    L.append(text("Reference", "J", 0, 10.2, "F.SilkS", size=1.0))-    L.append(text("Value", "G14A42111C12HR", 0, 0.5, "F.Fab"))-    L.append(text("Footprint", name, 0, 0, "F.Fab", hide=True))-    for n in range(1, 22):-        L.append(smd(f"B{n}", 5.25 - 0.5 * (n - 1), 7.37, 0.31, 0.91))-        if n in (1, 21):-            # A1/A21 (PWR, no wire in OCuLink cables) sit 0.07/0.10 mm from the peg NPTH in Amphenol's layout; trim-            # their inner end to y >= 4.875 so the pads clear the peg holes by 0.15 mm (JLC hole clearance)-            L.append(smd(f"A{n}", 4.75 - 0.5 * (n - 1), 5.255, 0.31, 0.76))-        else:-            L.append(smd(f"A{n}", 4.75 - 0.5 * (n - 1), 5.18, 0.31, 0.91))-    for sx in (-6.58, 6.58):-        for sy in (7.05, 2.26):-            L.append(f'  (pad "SH" thru_hole oval (at {f(sx)} {f(sy)}) (size 1.2 1.9) (drill oval 0.6 1.3) (layers "*.Cu" "*.Mask") (uuid "{u("sh", sx, sy)}"))')-    for (px, py) in ((5.41, 4.46), (-5.94, 4.46)):-        L.append(f'  (pad "" np_thru_hole circle (at {f(px)} {f(py)}) (size 1.0 1.0) (drill 1.0) (layers "*.Cu" "*.Mask") (uuid "{u("peg", px)}"))')-    # body outline: 13.15 wide, front face 1.98 past the board edge, 9.00 deep-    x0, x1, y0, y1 = -6.575, 6.575, -1.98, -1.98 + 9.0-    for lay, w in (("F.Fab", 0.1),):-        L.append(rect(x0, y0, x1, y1, lay, w))-    # no body silk: the body edges run through the shell-leg pads and along the contact rows, and the receptacle-    # itself marks its place; the reference designator is the only silk-    L.append(rect(-7.28, -1.98, 7.28, 8.05, "F.CrtYd", 0.05))   # body 13.15 + shell-leg pads (+/-7.18); Amphenol 16.63 keep-out is for other parts-    L.append(line(0, -1.98, 0, -1.4, "F.Fab", 0.1))-    L.append('  (model "${KIPRJMOD}/3d/Amphenol_G14A42111C12HR.step" (offset (xyz 0 0 0)) (scale (xyz 1 1 1)) (rotate (xyz 0 0 0)))')-    write(name, L)---def faceplate_mount():-    """OCP SFF faceplate grounding: dia 3.20 PTH, dia 5.50 plated pad on top (Fig. 8), dia 7.00 on the bottom (Fig. 10)."""-    name = "OCP_SFF_Faceplate_Ground_3.2mm"-    L = header(name, "OCP NIC 3.0 SFF faceplate mounting/grounding hole: 3.20 mm PTH, 5.50 mm top pad, 7.00 mm bottom pad (OCP NIC 3.0 v1.6.0 Fig. 8 and 10)",-               "OCP faceplate mounting hole ground", "exclude_from_pos_files exclude_from_bom")-    L.append(text("Reference", "H", 0, -4.2, "F.SilkS", hide=True))-    L.append(text("Value", "Faceplate_GND", 0, 4.2, "F.Fab", hide=True))-    L.append(text("Footprint", name, 0, 0, "F.Fab", hide=True))-    L.append(f'  (pad "1" thru_hole circle (at 0 0) (size 5.5 5.5) (drill 3.2) (layers "*.Cu" "*.Mask") (uuid "{u("fp1")}"))')-    L.append(f'  (pad "1" smd circle (at 0 0) (size 7.0 7.0) (layers "B.Cu" "B.Mask") (uuid "{u("fp2")}"))')-    L.append(f'  (fp_circle (center 0 0) (end 2.85 0) (stroke (width 0.05) (type solid)) (fill no) (layer "F.CrtYd") (uuid "{u("fpc")}"))')-    L.append(f'  (fp_circle (center 0 0) (end 3.6 0) (stroke (width 0.05) (type solid)) (fill no) (layer "B.CrtYd") (uuid "{u("fpcb")}"))')-    write(name, L)---def testpad_05():-    """0.5 mm round exposed copper test pad, no paste (the adom/testpoint-pad-0-5mm land): a probe spot that sits on-    its net's existing top-layer trace, so it needs no routing of its own."""-    name = "TestPoint_Pad_D0.5mm"-    L = header(name, "0.5 mm round test pad, exposed copper, no paste (adom/testpoint-pad-0-5mm)", "test point pad probe",-               "smd exclude_from_pos_files exclude_from_bom")-    L.append(text("Reference", "TP", 0, -0.9, "F.SilkS", hide=True, size=0.5))-    L.append(text("Value", "TP", 0, 0.9, "F.Fab", hide=True, size=0.5))-    L.append(text("Footprint", name, 0, 0, "F.Fab", hide=True, size=0.5))-    L.append(f'  (pad "1" smd circle (at 0 0) (size 0.5 0.5) (layers "F.Cu" "F.Mask") (uuid "{u("tp05")}"))')-    L.append(f'  (fp_circle (center 0 0) (end 0.4 0) (stroke (width 0.05) (type solid)) (fill no) (layer "F.CrtYd") (uuid "{u("tp05c")}"))')-    write(name, L)---STD_FP = "/mnt/c/Users/john/AppData/Local/Programs/KiCad/10.0/share/kicad/footprints"---def chip_nosilk():-    """KiCad 10 stock chip R/C land patterns without their body silk: adjacent 0402 outlines overlap at this board's-    pitch. Pads, courtyard, fab and 3D model are the stock ones, unchanged."""-    import re-    for lib, name in (("Resistor_SMD", "R_0402_1005Metric"), ("Capacitor_SMD", "C_0402_1005Metric"),-                      ("Capacitor_SMD", "C_0603_1608Metric")):-        src = open(os.path.join(STD_FP, lib + ".pretty", name + ".kicad_mod")).read()-        parts = re.split(r"(?=\r?\n\t\()", src)-        keep = [q for q in parts if not (re.match(r"\r?\n\t\((fp_line|fp_poly|fp_arc|fp_circle)\b", q) and '"F.SilkS"' in q)]-        txt = "".join(keep).replace(f'(footprint "{name}"', f'(footprint "{name}_NoSilk"', 1)-        open(os.path.join(OUT, name + "_NoSilk.kicad_mod"), "w").write(txt)---if __name__ == "__main__":-    ocp_edge(); oculink(); faceplate_mount(); testpad_05(); chip_nosilk()-    print("wrote", sorted(os.listdir(OUT)))