Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions docs/fabrication/gatema.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Fabrication: Gatema PCB

The basic usage of this exporter is:
```
kikit fab gatema [OPTIONS] BOARD OUTPUTDIR
```

When you run this command, you will find file `gerbers.zip` in `OUTPUTDIR`. This
file can be directly uploaded to Gatema PCB site. KiKit automatically detects the
number of layers. If you would like to include the project name in the archive
name, you can supply `--autoname`

If you want to name your files differently, you can specify `--nametemplate`.
This option takes a string that should contain `{}`. This string will be
replaced by `gerber`, `pos` or `bom` in the out file names. The extension is
appended automatically.
1 change: 1 addition & 0 deletions docs/fabrication/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ See documentation for the individual manufacturer below:
Note: click on the name of the manufacturer to see corresponding documentation:

- [JLC PCB](jlcpcb.md): board manufacturing, SMD assembly. [https://jlcpcb.com/](https://jlcpcb.com/)
- [Gatema](gatema.md): board manufacturing. [https://gatemapcb.cz/](https://gatemapcb.cz/)
- [PCBWay](pcbway.md): board manufacturing, assembly. [https://www.pcbway.com/](https://www.pcbway.com/)
- [OSH Park](oshpark.md): board manufacturing. [https://oshpark.com/](https://oshpark.com/)
- [Neoden YY1](neodenyy1.md): desktop PCB assembly. [https://neodenusa.com/neoden-yy1-pick-place-machine](https://neodenusa.com/neoden-yy1-pick-place-machine)
Expand Down
2 changes: 1 addition & 1 deletion kikit/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import traceback
from typing import List, Optional, Tuple, Union, Callable
from kikit.defs import Layer
from kikit.typing import Box
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this correct?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see. You renamed the file kikit.typing to kikit.kityping - why? This breaks other places where the file is imported.

from kikit.kityping import Box
from pcbnewTransition import pcbnew, kicad_major
from kikit.intervals import AxialLine
from pcbnewTransition.pcbnew import BOX2I, VECTOR2I, EDA_ANGLE
Expand Down
11 changes: 11 additions & 0 deletions kikit/export.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@
"SubstractMaskFromSilk": True
}

exportSettingsGatema = {
"UseGerberProtelExtensions": True,
"UseAuxOrigin": True,
"ExcludeEdgeLayer": True,
"MinimalHeader": False,
"NoSuffix": False,
"MergeNPTH": False,
"MapFileFormat": PLOT_FORMAT_GERBER,
"ZerosFormat": GENDRILL_WRITER_BASE.DECIMAL_FORMAT,
}

exportSettingsPcbway = {
"UseGerberProtelExtensions": True,
"UseAuxOrigin": False,
Expand Down
132 changes: 132 additions & 0 deletions kikit/fab/gatema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import click
from pcbnewTransition import pcbnew
import csv
import os
import sys
import shutil
from pathlib import Path
from kikit.fab.common import *
from kikit.common import *
from kikit.export import gerberImpl
from kikit.export import exportSettingsGatema

#def collectBom(components, lscsFields, ignore):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, no commented-out code.

# bom = {}
# for c in components:
# if getUnit(c) != 1:
# continue
# reference = getReference(c)
# if reference.startswith("#PWR") or reference.startswith("#FL"):
# continue
# if reference in ignore:
# continue
# if getField(c, "JLCPCB_IGNORE") is not None and getField(c, "JLCPCB_IGNORE") != "":
# continue
# if hasattr(c, "in_bom") and not c.in_bom:
# continue
# if hasattr(c, "on_board") and not c.on_board:
# continue
# if hasattr(c, "dnp") and c.dnp:
# continue
# orderCode = None
# for fieldName in lscsFields:
# orderCode = getField(c, fieldName)
# if orderCode is not None and orderCode.strip() != "":
# break
# cType = (
# getField(c, "Value"),
# getField(c, "Footprint"),
# orderCode
# )
# bom[cType] = bom.get(cType, []) + [reference]
# return bom

#def bomToCsv(bomData, filename):
# with open(filename, "w", newline="", encoding="utf-8") as csvfile:
# writer = csv.writer(csvfile)
# writer.writerow(["Comment", "Designator", "Footprint", "LCSC"])
# for cType, references in bomData.items():
# # JLCPCB allows at most 200 components per line so we have to split
# # the BOM into multiple lines. Let's make the chunks by 100 just to
# # be sure.
# CHUNK_SIZE = 100
# sortedReferences = sorted(references, key=naturalComponentKey)
# for i in range(0, len(references), CHUNK_SIZE):
# refChunk = sortedReferences[i:i+CHUNK_SIZE]
# value, footprint, lcsc = cType
# writer.writerow([value, ",".join(refChunk), footprint, lcsc])

def exportGatema(board, outputdir, ignore, nametemplate, drc,
autoname):
"""
Prepare fabrication files for Gatema PCB
"""
ensureValidBoard(board)
loadedBoard = pcbnew.LoadBoard(board)

if drc:
ensurePassingDrc(loadedBoard)

refsToIgnore = parseReferences(ignore)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you are not doing assembly, I think this is not needed.

removeComponents(loadedBoard, refsToIgnore)
Path(outputdir).mkdir(parents=True, exist_ok=True)

gerberdir = os.path.join(outputdir, "gerber")
shutil.rmtree(gerberdir, ignore_errors=True)
gerberImpl(board, gerberdir, settings=exportSettingsGatema)
ext_list = [("-CuTop.gtl", ".top"), ("-CuBottom.gbl", ".bot"), ("-MaskTop.gts", ".smt"), ("-MaskBottom.gbs", ".smb"), ("-NPTH.drl", ".mill"), ("-PTH.drl", ".pth"), ("-SilkTop.gto", ".plt"), ("-SilkBottom.gbo", ".plb"), ("-EdgeCuts.gm1", ".dim"), ("-PasteTop.gtp", ".pastetop"), ("-PasteBottom.gbp", ".pastebot")]
for f in os.listdir(gerberdir):
unneded = True
# mayby drrilling should be using the map - not tested
for old, new in ext_list:
if f.endswith(old):
unneded = False
newname = f.replace(old, new)
os.rename(os.path.join(gerberdir, f), os.path.join(gerberdir, newname))
break
if unneded:
os.remove(os.path.join(gerberdir, f)) # remove unneeded files


if autoname:
boardName = os.path.basename(board.replace(".kicad_pcb", ""))
archiveName = expandNameTemplate(nametemplate, boardName + "-gerbers", loadedBoard)
else:
archiveName = expandNameTemplate(nametemplate, "gerbers", loadedBoard)
shutil.make_archive(os.path.join(outputdir, archiveName), "zip", outputdir, "gerber")

# if not assembly:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No commented-out code, please

# return
# if schematic is None:
# raise RuntimeError("When outputing assembly data, schematic is required")
#
# ensureValidSch(schematic)
#
# correctionFields = [x.strip() for x in corrections.split(",")]
# components = extractComponents(schematic)
# ordercodeFields = [x.strip() for x in field.split(",")]
# bom = collectBom(components, ordercodeFields, refsToIgnore)
#
# bom_refs = set(x for xs in bom.values() for x in xs)
# bom_components = [c for c in components if getReference(c) in bom_refs]
#
# posData = collectPosData(loadedBoard, correctionFields,
# bom=bom_components, posFilter=noFilter, correctionFile=correctionpatterns,
# orientationHandling=FootprintOrientationHandling.MirrorBottom)
# boardReferences = set([x[0] for x in posData])
# bom = {key: [v for v in val if v in boardReferences] for key, val in bom.items()}
# bom = {key: val for key, val in bom.items() if len(val) > 0}
#
#
# missingFields = False
# for type, references in bom.items():
# _, _, lcsc = type
# if not lcsc:
# missingFields = True
# for r in references:
# print(f"WARNING: Component {r} is missing ordercode")
# if missingFields and missingerror:
# sys.exit("There are components with missing ordercode, aborting")
#
# posDataToFile(posData, os.path.join(outputdir, expandNameTemplate(nametemplate, "pos", loadedBoard) + ".csv"))
# bomToCsv(bom, os.path.join(outputdir, expandNameTemplate(nametemplate, "bom", loadedBoard) + ".csv"))
15 changes: 15 additions & 0 deletions kikit/fab_ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,20 @@ def jlcpcb(**kwargs):
app = fakeKiCADGui()
return execute_with_debug(jlcpcb.exportJlcpcb, kwargs)

@click.command()
@fabCommand
@click.option("--ignore", type=str, default="", help="Comma separated list of designators to exclude from SMT assembly")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As Gatema doesn't do assembly, why one would need an option to ignore components?

@click.option("--autoname/--no-autoname", is_flag=True, help="Automatically name the output files based on the board name")
def gatema(**kwargs):
"""
Prepare fabrication files for Gatema PCB
"""
from kikit.fab import gatema
from kikit.common import fakeKiCADGui
app = fakeKiCADGui()
return execute_with_debug(gatema.exportGatema, kwargs)


@click.command()
@fabCommand
@click.option("--assembly/--no-assembly", help="Generate files for SMT assembly (schematics is required)")
Expand Down Expand Up @@ -120,6 +134,7 @@ def fab():
pass

fab.add_command(jlcpcb)
fab.add_command(gatema)
fab.add_command(pcbway)
fab.add_command(oshpark)
fab.add_command(neodenyy1)
Expand Down
2 changes: 1 addition & 1 deletion kikit/intervals.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations
import typing
from typing import Any, Dict, List, Optional, Union, Tuple, Callable, Iterable
from kikit.typing import Box, T, ComparableT
from kikit.kityping import Box, T, ComparableT
from itertools import islice, chain
from math import isclose
from copy import copy
Expand Down
File renamed without changes.
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ nav:
- Introduction: fabrication/intro.md
- Fab houses:
- JLC PCB: fabrication/jlcpcb.md
- Gatema: fabrication/gatema.md
- Pcb Way: fabrication/pcbway.md
- OSH Park: fabrication/oshpark.md
- Multiboard workflow: multiboard.md
Expand Down