From 6d35a1f8a12a3ad5db56127085d1c7af645d1efb Mon Sep 17 00:00:00 2001 From: Brendan Haines Date: Wed, 21 Sep 2022 01:07:42 -0600 Subject: [PATCH] improve samtec autogeneration --- generate.py | 126 ++++++++++++++++++++++++++++++++++++++++++++----- pyproject.toml | 17 +++++++ setup.cfg | 6 +++ 3 files changed, 136 insertions(+), 13 deletions(-) create mode 100755 pyproject.toml create mode 100644 setup.cfg diff --git a/generate.py b/generate.py index d595b56..7467b4f 100644 --- a/generate.py +++ b/generate.py @@ -1,27 +1,38 @@ import time -from multiprocessing import Pool +from datetime import datetime from pathlib import Path from tempfile import TemporaryDirectory +from typing import Optional, Union from zipfile import ZipFile +import numpy as np +import regex as re from retry import retry from selenium import webdriver from selenium.webdriver.support import expected_conditions as EC -from selenium.webdriver.support.select import By, Select +from selenium.webdriver.support.select import By from selenium.webdriver.support.wait import WebDriverWait dir_ = Path(__file__).parent +rng = np.random.default_rng() PARTS = [ - *[f"TSW-1{i:02d}-05-G-S" for i in range(1, 10)], + *[f"TSW-1{i:02d}-07-L-S" for i in range(1, 50)], + *[f"TSW-1{i:02d}-07-L-D" for i in range(1, 50)], + *[f"TSW-1{i:02d}-07-L-T" for i in range(1, 50)], + *[f"TSW-1{i:02d}-07-L-Q" for i in range(1, 50)], + *[f"TSW-2{i:02d}-07-L-S" for i in range(2, 25)], + *[f"TSW-2{i:02d}-07-L-D" for i in range(2, 25)], + *[f"TSW-2{i:02d}-07-L-T" for i in range(2, 25)], + *[f"TSW-2{i:02d}-07-L-Q" for i in range(2, 25)], ] URL_STEP = "https://www.snapeda.com/parts/{0}/Samtec/embed/?ref=samtec" -@retry(tries=2, delay=1) -def download_step(part: str): +# @retry(tries=10, delay=1) +def download_step_samtec(part: str): print(part) - with TemporaryDirectory(prefix=str(dir_ / "tmp")) as tmp: + with TemporaryDirectory(prefix=str(dir_ / "tmp") + "/") as tmp: tmp = Path(tmp) chrome_options = webdriver.ChromeOptions() @@ -35,11 +46,9 @@ def download_step(part: str): options=chrome_options, ) as browser: browser.get(URL_STEP.format(part.upper())) - wait = WebDriverWait(browser, 10) + wait = WebDriverWait(browser, 30) wait.until( - EC.element_to_be_clickable( - browser.find_element(by=By.ID, value="download_traceparts_3d_model") - ) + EC.element_to_be_clickable(browser.find_element(by=By.ID, value="download_traceparts_3d_model")) ).click() wait.until( EC.element_to_be_clickable( @@ -53,6 +62,7 @@ def download_step(part: str): # wait for download to finish while len(list((Path(tmp).glob("*.zip")))) == 0: time.sleep(0.1) + # print(list((Path(tmp).glob("*.zip")))) # unzip with ZipFile(list((Path(tmp).glob("*.zip")))[0]) as zip: @@ -60,8 +70,98 @@ def download_step(part: str): # move filename = f"{part.upper()}.stp" - (Path(tmp) / filename).rename(dir_ / "3dshapes" / filename) + # if filename not in list(Path(tmp).glob("*.stp")): + # raise ValueError( + # f"Name mismatch: {filename} does not exist. Found {[f.name for f in list(Path(tmp).glob('*.stp'))]}" + # ) + (Path(tmp) / filename).rename(dir_ / "samtec.pretty" / "3dshapes" / filename) -for part in PARTS: - download_step(part) +now = datetime.now() +INCH = 25.4 +SILK_WIDTH = 0.007 * INCH + + +def footprint_samtec(part: str, lib: Optional[Union[Path, str]] = None) -> str: + if part[:4].upper() == "TSW-": + # pinheader + match = re.match( + r"(H?)TSW-([12])(\d\d)-(\d\d)-([FLGT])-([SDTQ])(-RA)?(-RE)?(-NA)?(-LL)?(-LC)?(-LA)?(-(\d\d\d))?", + part.upper(), + ) + high_temp = match[1] != "" + spacing = int(match[2]) + rows = int(match[3]) + # lead_style = { + # 5: + # }[int(match[4])] + plating = { + "F": "Gold flash on post, Matte Tin on tail", + "L": '10 µ" (0.25 µm) Gold on post, Matte Tin on tail', + "G": '10 µ" (0.25 µm) Gold on post, Gold flash on balance', + "T": "Matte Tin", + }[match[5]] + cols = {"S": 1, "D": 2, "T": 3, "Q": 4}[match[6]] + + strobe = [(2 if cols == 4 else 1) * 0.1 * INCH, spacing * 0.1 * INCH] + if cols == 4: + # only outer columns filled + cols = 2 + fp_name = f"PinHeader_{cols}x{rows:02d}_0.1in_{part}" + hole_diam = 0.040 * INCH + pad_size = 0.075 * INCH + + center = [strobe[0] * (cols - 1) / 2, strobe[1] * (rows - 1) / 2] + + if lib is None: + lib = dir_ / "samtec.pretty" + lib = Path(lib) + with open(lib / f"{fp_name}.kicad_mod", "w") as f: + f.write( + "\n".join( + ( + f'(footprint "{fp_name}" (version {now.strftime("%Y%m%d")}) (generator pcbnew) (layer "F.Cu")', + r" (attr through_hole)", + f' (fp_text reference "REF**" (at {center[0]} {-2.032}) (layer "F.SilkS")', + r" (effects (font (size 0.762 0.762) (thickness 0.127)))", + r" )", + f' (fp_text value "VAL**" (at {center[0]} {center[1]} 90) (layer "F.Fab") hide', + r" (effects (font (size 0.762 0.762) (thickness 0.127)))", + r" )", + r' (fp_text user "${REFERENCE}" ' f'(at {center[0]} {center[1]} 90) (layer "F.Fab")', + r" (effects (font (size 1 1) (thickness 0.15)))", + r" )", + f" (fp_rect (start {-0.05 * INCH} {-0.05 * INCH}) (end {0.05 * INCH + strobe[0] * (cols - 1)} {0.05 * INCH + strobe[1] * (rows - 1)})", + f' (stroke (width {SILK_WIDTH}) (type default)) (fill none) (layer "F.SilkS")' r" )", + f' (fp_line (start {-0.05 * INCH} {0.05 * INCH}) (end {0.05 * INCH} {0.05 * INCH}) (layer "F.SilkS") (width {SILK_WIDTH}))', + f' (fp_line (start {0.05 * INCH} {-0.05 * INCH}) (end {0.05 * INCH} {0.05 * INCH}) (layer "F.SilkS") (width {SILK_WIDTH}))', + *[ + f' (pad "{pad + 1}" thru_hole {"rect" if pad == 0 else "circle"} ' + f"(at {strobe[0] * (pad % cols)} {strobe[1] * int(pad / cols)}) (size {pad_size} {pad_size}) (drill {hole_diam}) (layers *.Cu *.Mask))" + for pad in range(rows * cols) + ], + f' (model "/home/brendan/Documents/projects/kicad/samtec.pretty/3dshapes/{part}.stp"', + f" (offset (xyz {center[0]} {-center[1]} 0))", + r" (scale (xyz 1 1 1))", + r" (rotate (xyz -90 0 90))", + r" )", + r")", + ) + ) + + "\n" + ) + else: + raise ValueError(f"Unknown part family for {part}") + + +if __name__ == "__main__": + for part in PARTS: + time.sleep(rng.random() * 3) + download_step_samtec(part) + footprint_samtec(part) + + # from multiprocessing import Pool + # pool = Pool(10) + # pool.map(download_step_samtec, PARTS) + # pool.map(footprint_samtec, PARTS) + # pool.close() diff --git a/pyproject.toml b/pyproject.toml new file mode 100755 index 0000000..bda033d --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,17 @@ +[build-system] +requires = [ + "setuptools>=42", + "wheel" +] +build-backend = "setuptools.build_meta" + +[tool.pylint.messages_control] +disable = "C0330, C0326" + +[tool.pylint.format] +max-line-length = "100" + +[tool.black] +line-length = 120 +organize-imports = true +target-version = ['py38'] \ No newline at end of file diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..cf611c1 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,6 @@ +[flake8] +max-line-length = 120 +extend-ignore = E203 +per-file-ignores = + __init__.py: F401, F403 +exclude = **/*__init__.py,.venv/*,tox/*,build/*,dist/* \ No newline at end of file