import zipfile from pathlib import Path from tempfile import TemporaryDirectory from typing import Optional, Union import regex as re import requests from fp_generator import INCH, Footprint dir_ = Path(__file__).parent PARTS = [ # Micro-Fit 3.0 Single Row Headers # *[f"43650-{i:02d}10" for i in range(2, 13)], # 1 row, RA, press-fit retention clip # *[f"43650-{i:02d}13" for i in range(2, 13)], # 1 row, RA, solder tab # *[f"43650-{i:02d}22" for i in range(2, 13)], # 1 row, Vertical, press-fit retention clip # *[f"43650-{i:02d}25" for i in range(2, 13)], # 1 row, RA, solder tab # # Micro-Fit 3.0 Dual Row Headers # *[f"43045-{i:02d}07" for i in range(2, 25, 2)], # 2 row, RA, press-fit retention clip # *[f"43045-{i:02d}10" for i in range(2, 25, 2)], # 2 row, RA, solder tab # *[f"43045-{i:02d}16" for i in range(2, 25, 2)], # 2 row, Vertical, press-fit retention clip # *[f"43045-{i:02d}19" for i in range(2, 25, 2)], # 2 row, RA, solder tab # Eurostyle 5.08mm Headers # [f"39531-00{i:02d}" for i in range(2, 24)], # 1 row, Vertical # *[f"39532-00{i:02d}" for i in range(2, 24)], # 1 row, Horizontal # Eurostyle 5.08mm Plugs *[f"39530-00{i:02d}" for i in range(2, 24)], ] def download_step_molex(part: Union[str, int]) -> None: # remove dash part = f'{int(str(part).replace("-", "")):09d}' print(part) with TemporaryDirectory(prefix=str(dir_ / "tmp") + "/") as tmp: tmp = Path(tmp) for p in [part, part[:5] + "-" + part[5:]]: try: zipname = f"{part}_stp.zip" # download with open(tmp / zipname, "wb") as f: url = f"https://www.molex.com/pdm_docs/stp/{p}_stp.zip" f.write(requests.get(url, timeout=10).content) # unzip with zipfile.ZipFile(tmp / zipname) as zip: zip.extractall(path=str(tmp)) # move filename = f"{part}.stp" (Path(tmp) / filename).rename(dir_ / "molex.pretty" / "step" / filename) return except requests.exceptions.ReadTimeout: # pass except zipfile.BadZipFile: print(f"zip does not exist for part {p}") raise ValueError(f"Could not download .stp for part {part}") def footprint(part: str, lib: Optional[Union[Path, str]] = None): # remove dash part = f'{int(str(part).replace("-", "")):09d}' print(part) if lib is None: lib = dir_ / "molex.pretty" lib = Path(lib) if part.startswith("43650"): match = re.match(r"43650(\d\d)(\d\d)", part) pins = int(match[1]) flavor = int(match[2]) if flavor == 10: fp = Footprint( part, lib=lib, description=f"connector, Micro-Fit 3.0, 1x{pins:02f}, RA, press-fit retention clip" ) fp.add_text("reference", "REF**", -(6.93 + (0.025 + 0.005) * INCH), 0, rotation=90, layer="F.SilkS") fp.add_text("value", "VAL**", -0.025 * INCH, 0, rotation=90, layer="F.Fab") fp.add_text("user", r"${REFERENCE}**", 0.025 * INCH, 0, rotation=90, layer="F.Fab") # fp.add_rect( # [-0.05 * INCH] * 2, # (0.05 * INCH + strobe[0] * (cols - 1), 0.05 * INCH + strobe[1] * (rows - 1)), # layer="F.SilkS", # ) # fp.add_line((-0.05 * INCH, 0.05 * INCH), (0.05 * INCH, 0.05 * INCH), layer="F.SilkS") # fp.add_line((0.05 * INCH, -0.05 * INCH), (0.05 * INCH, 0.05 * INCH), layer="F.SilkS") a, b, c = { 2: (0.380, 0.118, 0.287), 3: (0.498, 0.236, 0.405), 4: (0.616, 0.354, 0.524), 5: (0.734, 0.472, 0.642), 6: (0.852, 0.591, 0.760), 7: (0.970, 0.709, 0.878), 8: (1.088, 0.827, 0.996), 9: (1.206, 0.945, 1.114), 10: (1.325, 1.063, 1.232), 11: (1.443, 1.181, 1.350), 12: (1.561, 1.299, 1.469), }[pins] a *= INCH b *= INCH c *= INCH for pad in range(pins): fp.add_pad( pad + 1, (-0.273 + 0.115 / 2) * INCH, -3.0 * (pins - 1) / 2 + 3.0 * pad, size=(0.115 * INCH, 0.050 * INCH), shape="rect", ) # mechanical holes for s in [1, -1]: fp.add_pad(0, 0, s * c / 2, size=(0.095 + 0.050) * INCH, hole=0.095 * INCH, shape="circle") fp.add_model( lib / "step" / f"{part}.stp", (4.6, 0, 0.5), rotate=(0, 0, -90), ) fp.add_rect((4.6 - 9.9, -a / 2), (4.6, a / 2), layer="F.Fab") fp.write() else: raise NotImplementedError elif part.startswith("39532"): # Eurostyle match = re.match(r"39532(\d\d)(\d\d)", part) flavor = int(match[1]) pins = int(match[2]) if flavor == 00: fp = Footprint(part, lib=lib, description=f"connector, Eurostyle, 5.08mm, 1x{pins:02f}, RA, Black, Tin") else: raise NotImplementedError fp.add_text("reference", "REF**", -(6.93 + (0.025 + 0.005) * INCH), 0, rotation=90, layer="F.SilkS") fp.add_text("value", "VAL**", -0.025 * INCH, 0, rotation=90, layer="F.Fab") fp.add_text("user", r"${REFERENCE}**", 0.025 * INCH, 0, rotation=90, layer="F.Fab") a, b = [0.200 * pins, 0.200 * (pins - 1)] a *= INCH b *= INCH for pad in range(pins): fp.add_pad( pad + 1, (-0.273 + 0.115 / 2) * INCH, -b / 2 + 0.200 * pad * INCH, size=0.12 * INCH, hole=0.063 * INCH, shape="circle", ) fp.add_model( lib / "step" / f"{part}.stp", (4.6, 0, 0.5), rotate=(0, 0, -90), ) fp.add_rect((4.6 - 9.9, -a / 2), (4.6, a / 2), layer="F.Fab") fp.write() elif part.startswith("39530"): # free-hanging plug doesn't need footprint pass else: raise NotImplementedError if __name__ == "__main__": from multiprocessing import Pool pool = Pool(10) pool.map(download_step_molex, PARTS) for part in PARTS: footprint(part) pool.close()