"""Generate the custom STEP models used by the OptoTest PCB libraries. The coordinate system follows Altium's usual convention: XY is the PCB plane and Z points away from the top side of the PCB. All dimensions are in millimetres. """ from pathlib import Path import sys CADQUERY_PATH = Path.home() / "AppData/Local/Temp/codex-cadquery" if CADQUERY_PATH.exists(): sys.path.insert(0, str(CADQUERY_PATH)) import cadquery as cq OUT_DIR = Path(__file__).resolve().parent def box(x, y, z, cx=0.0, cy=0.0, bottom=0.0): return cq.Workplane("XY").box(x, y, z).translate((cx, cy, bottom + z / 2)) def cylinder(diameter, height, cx=0.0, cy=0.0, bottom=0.0): return ( cq.Workplane("XY") .circle(diameter / 2) .extrude(height) .translate((cx, cy, bottom)) ) def add_dip8_precision_socket(assembly): """7.62-mm-row precision/turned-pin DIP-8 socket seated on the PCB.""" black = cq.Color(0.055, 0.055, 0.060) gold = cq.Color(0.78, 0.55, 0.12) dark = cq.Color(0.015, 0.015, 0.018) # Two turned-pin carrier rails and end bridges. The centre remains open, # matching the precision socket used by the SN75451 model. assembly.add(box(2.35, 10.15, 3.65, -3.81, 0, 0.35), color=black) assembly.add(box(2.35, 10.15, 3.65, +3.81, 0, 0.35), color=black) assembly.add(box(5.30, 1.15, 1.10, 0, -4.50, 0.35), color=black) assembly.add(box(5.30, 1.15, 1.10, 0, +4.50, 0.35), color=black) for x in (-3.81, 3.81): for y in (-3.81, -1.27, 1.27, 3.81): assembly.add(cylinder(0.50, 3.15, x, y, -2.80), color=gold) assembly.add(cylinder(1.22, 3.20, x, y, 0.55), color=gold) assembly.add(cylinder(0.70, 3.23, x, y, 0.57), color=dark) def make_opa380_adapter(): assembly = cq.Assembly(name="OPA380_SOIC8_ADAPTER_DIP8_PRECISION_SOCKET") add_dip8_precision_socket(assembly) green = cq.Color(0.035, 0.30, 0.12) copper = cq.Color(0.72, 0.43, 0.12) silver = cq.Color(0.72, 0.74, 0.76) black = cq.Color(0.035, 0.035, 0.040) marking = cq.Color(0.82, 0.82, 0.78) # DIP-8/SOIC-8 adapter. Its lower pins plug into the precision socket. for x in (-3.81, 3.81): for y in (-3.81, -1.27, 1.27, 3.81): assembly.add(cylinder(0.46, 3.30, x, y, 2.80), color=copper) assembly.add(box(10.25, 10.25, 1.20, 0, 0, 6.00), color=green) # Visible DIP pads on the adapter PCB. for x in (-3.81, 3.81): for y in (-3.81, -1.27, 1.27, 3.81): assembly.add(cylinder(1.30, 0.06, x, y, 7.20), color=copper) # OPA380 in TI D (SOIC-8): nominal 3.9 x 4.9 mm body, 1.27-mm pitch. body = box(3.90, 4.90, 1.55, 0, 0, 7.33) try: body = body.edges("|Z").fillet(0.18) except Exception: pass assembly.add(body, color=black) # Gull-wing leads. Pin 1 is at the lower-left corner in top view. for x in (-2.55, 2.55): for y in (-1.905, -0.635, 0.635, 1.905): assembly.add(box(1.25, 0.42, 0.16, x, y, 7.25), color=silver) assembly.add(cylinder(0.42, 0.035, -1.28, -1.55, 8.88), color=marking) output = OUT_DIR / "OPA380_SOIC8_ADAPTER_DIP8_PRECISION_SOCKET.step" assembly.save(str(output), mode="default") return output def make_bpw34_vertical(): assembly = cq.Assembly(name="BPW34_VERTICAL_P5.08mm") silver = cq.Color(0.72, 0.74, 0.76) clear = cq.Color(0.72, 0.78, 0.80, 0.58) die = cq.Color(0.10, 0.16, 0.19) cathode_mark = cq.Color(0.25, 0.28, 0.30) # Leads occupy footprint positions 1 and 3. Position 2 (x=0) is omitted. # Centre-to-centre distance is therefore exactly 2 x 2.54 = 5.08 mm. for x in (-2.54, 2.54): assembly.add(box(0.50, 0.38, 5.30, x, 0, -2.60), color=silver) # Upright BPW34 body, based on Vishay drawing 6.544-5315.01-4: # 4.65-mm face width, 4.3-mm face height and 2.0-mm package depth. # The leads are deliberately formed out to the requested 5.08-mm spacing. body = box(4.65, 2.00, 4.30, 0, 0, 2.15) try: body = body.edges("|Z").fillet(0.25) except Exception: pass assembly.add(body, color=clear) # Visible detector die and bond area inside the transparent package. assembly.add(box(3.00, 0.12, 3.00, 0, -0.89, 2.80), color=die) # Cathode-side stripe, located by footprint pad 1 (left in top/front view). assembly.add(box(0.22, 0.08, 3.55, -2.16, -1.06, 2.50), color=cathode_mark) output = OUT_DIR / "BPW34_VERTICAL_P5.08mm.step" assembly.save(str(output), mode="default") return output if __name__ == "__main__": for model in (make_opa380_adapter(), make_bpw34_vertical()): print(model)