improve samtec autogeneration

This commit is contained in:
Brendan Haines 2022-09-21 01:07:42 -06:00
parent cef4186044
commit 6d35a1f8a1
3 changed files with 136 additions and 13 deletions

View File

@ -1,27 +1,38 @@
import time import time
from multiprocessing import Pool from datetime import datetime
from pathlib import Path from pathlib import Path
from tempfile import TemporaryDirectory from tempfile import TemporaryDirectory
from typing import Optional, Union
from zipfile import ZipFile from zipfile import ZipFile
import numpy as np
import regex as re
from retry import retry from retry import retry
from selenium import webdriver from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC 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 from selenium.webdriver.support.wait import WebDriverWait
dir_ = Path(__file__).parent dir_ = Path(__file__).parent
rng = np.random.default_rng()
PARTS = [ 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" URL_STEP = "https://www.snapeda.com/parts/{0}/Samtec/embed/?ref=samtec"
@retry(tries=2, delay=1) # @retry(tries=10, delay=1)
def download_step(part: str): def download_step_samtec(part: str):
print(part) print(part)
with TemporaryDirectory(prefix=str(dir_ / "tmp")) as tmp: with TemporaryDirectory(prefix=str(dir_ / "tmp") + "/") as tmp:
tmp = Path(tmp) tmp = Path(tmp)
chrome_options = webdriver.ChromeOptions() chrome_options = webdriver.ChromeOptions()
@ -35,11 +46,9 @@ def download_step(part: str):
options=chrome_options, options=chrome_options,
) as browser: ) as browser:
browser.get(URL_STEP.format(part.upper())) browser.get(URL_STEP.format(part.upper()))
wait = WebDriverWait(browser, 10) wait = WebDriverWait(browser, 30)
wait.until( wait.until(
EC.element_to_be_clickable( EC.element_to_be_clickable(browser.find_element(by=By.ID, value="download_traceparts_3d_model"))
browser.find_element(by=By.ID, value="download_traceparts_3d_model")
)
).click() ).click()
wait.until( wait.until(
EC.element_to_be_clickable( EC.element_to_be_clickable(
@ -53,6 +62,7 @@ def download_step(part: str):
# wait for download to finish # wait for download to finish
while len(list((Path(tmp).glob("*.zip")))) == 0: while len(list((Path(tmp).glob("*.zip")))) == 0:
time.sleep(0.1) time.sleep(0.1)
# print(list((Path(tmp).glob("*.zip"))))
# unzip # unzip
with ZipFile(list((Path(tmp).glob("*.zip")))[0]) as zip: with ZipFile(list((Path(tmp).glob("*.zip")))[0]) as zip:
@ -60,8 +70,98 @@ def download_step(part: str):
# move # move
filename = f"{part.upper()}.stp" 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: now = datetime.now()
download_step(part) 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()

17
pyproject.toml Executable file
View File

@ -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']

6
setup.cfg Normal file
View File

@ -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/*