diff --git a/scripting/plugins/OutputGeneration/AsyOutputs.py b/scripting/plugins/OutputGeneration/AsyOutputs.py new file mode 100644 index 0000000..87db33a --- /dev/null +++ b/scripting/plugins/OutputGeneration/AsyOutputs.py @@ -0,0 +1,16 @@ +import pcbnew + +__all__ = ["AsyOutputs"] + +class AsyOutputs(pcbnew.ActionPlugin): + def defaults(self): + self.name = "Generate Assembly Outputs" + self.category = "Output Generation" + self.description = "Generate CSV BOM, Drawings, and add to pdf" + + self.pcbnew_icon_support = hasattr(self, "show_toolbar_button") + self.show_toolbar_button = True + + def Run(self): + # The entry function of the plugin that is executed on user action + print("Hello World - AsyOutputs") \ No newline at end of file diff --git a/scripting/plugins/OutputGeneration/FabOutputs.py b/scripting/plugins/OutputGeneration/FabOutputs.py new file mode 100644 index 0000000..41b8107 --- /dev/null +++ b/scripting/plugins/OutputGeneration/FabOutputs.py @@ -0,0 +1,186 @@ +import pcbnew +import os +from datetime import datetime +from pathlib import Path + +__all__ = ["FabOutputs"] + + +class FabOutputs(pcbnew.ActionPlugin): + def defaults(self): + self.name = "Generate Outputs" + self.category = "Output Generation" + self.description = "Generate Gerbers, BOM, Drawings, etc and add to pdf/zip" + + self.pcbnew_icon_support = hasattr(self, "show_toolbar_button") + self.show_toolbar_button = True + + def Run(self): + # ================ + # General Data + # ================ + + now = datetime.now() + pcb = pcbnew.GetBoard() + path_cwd = Path.cwd() + path_pcb = Path(pcb.GetFileName()) + dir_pcb = path_pcb.parent + dir_fab = dir_pcb / "FabricationOutputs" + dir_asy = dir_pcb / "AssemblyOutputs" + + project_name = path_pcb.stem + part_number = pcb.GetTitleBlock().GetTitle() + rev = str.upper(pcb.GetTitleBlock().GetRevision()) + + suffix = "" + suffix += f"_REV{rev}" + suffix += f"_{now.strftime('%Y%m%d_%H%M%S')}" + + layer_count = pcb.GetDesignSettings().GetCopperLayerCount() + + layer_info = [ + ("Front Paste", "gtp", pcbnew.F_Paste), + ("Front Silkscreen", "gto", pcbnew.F_SilkS), + ("Front Mask", "gts", pcbnew.F_Mask), + ("Front Copper", "gtl", pcbnew.F_Cu), + *[(f'Inner Layer {layer} Copper', f'g{layer}', layer) for layer in range(1, layer_count-1)], + ('Back Copper', 'gbl', pcbnew.B_Cu), + ('Back Mask', 'gbs', pcbnew.B_Mask), + ('Back SilkScreen', 'gbo', pcbnew.B_SilkS), + ('Back Paste', 'gbp', pcbnew.B_Paste), + ('Edges Cuts', 'gm1', pcbnew.Edge_Cuts), + ('Drill', 'drl', None), + ] + + stackup = [ + # [pcbnew layer, file extension, thickness, comment] + [pcbnew.F_Paste, 'gtp', None, "SN63/PB37"], + [pcbnew.F_SilkS, 'gto', None, "White"], + [pcbnew.F_Mask, 'gts', 1, "Explicit mask material"], + [None, None, None, "ENIG"], + [pcbnew.F_Cu, 'gtl', 2.1, "copper roughness"], + [None, None, 10, "Dielectric stuff"], + [1, 'g1', 0.7, "Copper roughness"], + [None, None, 24, "Dielectric stuff"], + [None, None, 12, "Dielectric stuff"], + [2, 'g2', 0.7, "Copper roughness"], + [None, None, 10, "Dielectric stuff"], + [pcbnew.B_Cu, 'gbl', 2.1, "copper roughness"], + [None, None, None, "ENIG"], + [pcbnew.B_Mask, 'gbs', 1, "Explicit mask material"], + [pcbnew.B_SilkS, 'gbo', None, "White"], + [pcbnew.B_Paste, 'gbp', None, "SN63/PB37"], + ] + + board_features = { + "core cap": True, + "castellated": False, + "plated board edge": False, + "copper finish": "ENIG", + "hard gold": False, + "bevelled edge": False, + "soldermask defined": None, # TODO: how do I want to determine this? + } + + + # ================ + # Gerbers + # ================ + + plot_controller = pcbnew.PLOT_CONTROLLER(pcb) + plot_options = plot_controller.GetPlotOptions() + + # Set General Options: + plot_options.SetOutputDirectory(dir_fab) + plot_options.SetPlotFrameRef(False) + plot_options.SetPlotValue(False) + plot_options.SetPlotReference(True) + plot_options.SetPlotInvisibleText(False) + plot_options.SetPlotViaOnMaskLayer(False) + plot_options.SetExcludeEdgeLayer(True) + plot_options.SetUseAuxOrigin(False) + plot_options.SetMirror(False) + plot_options.SetNegative(False) + #plot_options.SetDrillMarksType(PLOT_DRILL_MARKS_TYPE) + #plot_options.SetScale(PLOT_SCALE) + plot_options.SetAutoScale(True) + #plot_options.SetPlotMode(PLOT_MODE) + #plot_options.SetLineWidth(pcbnew.FromMM(PLOT_LINE_WIDTH)) + plot_options.SetUseGerberAttributes(True) + plot_options.SetUseGerberProtelExtensions(False) + plot_options.SetCreateGerberJobFile(False) + plot_options.SetSubtractMaskFromSilk(True) + plot_options.SetIncludeGerberNetlistInfo(False) + + + plot_plan = [ + # ( layer ID, file extension, description) + ( pcbnew.F_Paste, 'gtp', 'Front Paste' ), + ( pcbnew.F_SilkS, 'gto', 'Front SilkScreen' ), + ( pcbnew.F_Mask, 'gts', 'Front Mask' ), + ( pcbnew.F_Cu, 'gtl', 'Front Copper' ), + *[(layer, f'g{layer}', f'Inner Layer {layer} Copper') for layer in range(1, layer_count-1)], + ( pcbnew.B_Cu, 'gbl', 'Back Copper' ), + ( pcbnew.B_Mask, 'gbs', 'Back Mask' ), + ( pcbnew.B_SilkS, 'gbo', 'Back SilkScreen' ), + ( pcbnew.B_Paste, 'gbp', 'Back Paste' ), + ( pcbnew.Edge_Cuts, 'gm1', 'Edges Cuts' ), + ] + + + for layer_info in plot_plan: + plot_controller.SetLayer(layer_info[0]) + plot_controller.OpenPlotfile('', pcbnew.PLOT_FORMAT_GERBER, layer_info[2]) + plot_controller.PlotLayer() + + os.rename(dir_fab / f"{project_name}.gbr", dir_fab / f"{project_name}{suffix}.{layer_info[1]}") + + plot_controller.ClosePlot() + + # ================ + # Drill Files + # ================ + + METRIC = True + ZERO_FORMAT = pcbnew.GENDRILL_WRITER_BASE.DECIMAL_FORMAT + INTEGER_DIGITS = 3 + MANTISSA_DIGITS = 3 + MIRROR_Y_AXIS = False + HEADER = True + OFFSET = pcbnew.wxPoint(0,0) + MERGE_PTH_NPTH = True + DRILL_FILE = True + MAP_FILE = False + REPORTER = None + + drill_writer = pcbnew.EXCELLON_WRITER(pcb) + drill_writer.SetFormat(METRIC, ZERO_FORMAT, INTEGER_DIGITS, MANTISSA_DIGITS) + drill_writer.SetOptions(MIRROR_Y_AXIS, HEADER, OFFSET, MERGE_PTH_NPTH) + drill_writer.CreateDrillandMapFilesSet(str(dir_fab), DRILL_FILE, MAP_FILE, REPORTER) + + os.rename(dir_fab / f"{project_name}.drl", dir_fab / f"{project_name}{suffix}.drl") + + # ================ + # Pick and Place + # ================ + + # TODO + + # ================ + # Fab Drawing + # ================ + + with open(dir_fab / f"README_FABRICATION{suffix}.TXT", "w") as f: + f.write(f"{project_name}-REV{rev}\n") + f.write(f"Layer Order\n") + # for layer in plot_plan: + + + # ================ + # Assembly Drawing + # ================ + + with open(dir_asy / f"README_ASSEMBLY{suffix}.TXT", "w") as f: + f.write(f"{project_name}-REV{rev}\n") + f.write(f"Layer Order\n") + # for layer in plot_plan: \ No newline at end of file diff --git a/scripting/plugins/OutputGeneration/__init__.py b/scripting/plugins/OutputGeneration/__init__.py new file mode 100644 index 0000000..e4058a9 --- /dev/null +++ b/scripting/plugins/OutputGeneration/__init__.py @@ -0,0 +1,5 @@ +from .FabOutputs import FabOutputs +from .AsyOutputs import AsyOutputs + +FabOutputs().register() # Instantiate and register to Pcbnew +AsyOutputs().register() # Instantiate and register to Pcbnew \ No newline at end of file diff --git a/scripting/plugins/OutputGeneration/__pycache__/AsyOutputs.cpython-38.pyc b/scripting/plugins/OutputGeneration/__pycache__/AsyOutputs.cpython-38.pyc new file mode 100644 index 0000000..3c47e0a Binary files /dev/null and b/scripting/plugins/OutputGeneration/__pycache__/AsyOutputs.cpython-38.pyc differ diff --git a/scripting/plugins/OutputGeneration/__pycache__/FabOutputs.cpython-38.pyc b/scripting/plugins/OutputGeneration/__pycache__/FabOutputs.cpython-38.pyc new file mode 100644 index 0000000..c569440 Binary files /dev/null and b/scripting/plugins/OutputGeneration/__pycache__/FabOutputs.cpython-38.pyc differ diff --git a/scripting/plugins/OutputGeneration/__pycache__/__init__.cpython-38.pyc b/scripting/plugins/OutputGeneration/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..d1e76e3 Binary files /dev/null and b/scripting/plugins/OutputGeneration/__pycache__/__init__.cpython-38.pyc differ diff --git a/scripting/plugins/TestPlugin/TestPlugin/TestPlugin_action.py b/scripting/plugins/TestPlugin/TestPlugin/TestPlugin_action.py new file mode 100644 index 0000000..2a7e038 --- /dev/null +++ b/scripting/plugins/TestPlugin/TestPlugin/TestPlugin_action.py @@ -0,0 +1,17 @@ +import pcbnew +import os + +class TestPlugin(pcbnew.ActionPlugin): + def defaults(self): + self.name = "TestPlugin" + self.category = "A descriptive category name" + self.description = "A description of the plugin and what it does" + + # self.pcbnew_icon_support = hasattr(self, "show_toolbar_button") + # self.show_toolbar_button = True + # icon_dir = os.path.dirname(os.path.dirname(__file__)) + # self.icon_file_name = os.path.join(icon_dir, 'icon.png') + + def Run(self): + # The entry function of the plugin that is executed on user action + print("Hello World - testplugin") \ No newline at end of file diff --git a/scripting/plugins/TestPlugin/TestPlugin/__init__.py b/scripting/plugins/TestPlugin/TestPlugin/__init__.py new file mode 100644 index 0000000..abf8753 --- /dev/null +++ b/scripting/plugins/TestPlugin/TestPlugin/__init__.py @@ -0,0 +1,3 @@ +from .TestPlugin_action import TestPlugin +plugin = TestPlugin() +plugin.register() \ No newline at end of file diff --git a/scripting/plugins/TestPlugin/TestPlugin/__pycache__/TestPlugin_action.cpython-38.pyc b/scripting/plugins/TestPlugin/TestPlugin/__pycache__/TestPlugin_action.cpython-38.pyc new file mode 100644 index 0000000..1fb5e18 Binary files /dev/null and b/scripting/plugins/TestPlugin/TestPlugin/__pycache__/TestPlugin_action.cpython-38.pyc differ diff --git a/scripting/plugins/TestPlugin/TestPlugin/__pycache__/__init__.cpython-38.pyc b/scripting/plugins/TestPlugin/TestPlugin/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..faf4ed7 Binary files /dev/null and b/scripting/plugins/TestPlugin/TestPlugin/__pycache__/__init__.cpython-38.pyc differ diff --git a/scripting/plugins/TestPlugin/TestPlugin/icon.png b/scripting/plugins/TestPlugin/TestPlugin/icon.png new file mode 100644 index 0000000..37907aa Binary files /dev/null and b/scripting/plugins/TestPlugin/TestPlugin/icon.png differ diff --git a/scripting/plugins/TestPlugin/__init__.py b/scripting/plugins/TestPlugin/__init__.py new file mode 100644 index 0000000..019288b --- /dev/null +++ b/scripting/plugins/TestPlugin/__init__.py @@ -0,0 +1 @@ +from .TestPlugin import plugin \ No newline at end of file diff --git a/scripting/plugins/TestPlugin/__pycache__/__init__.cpython-38.pyc b/scripting/plugins/TestPlugin/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..5d7af29 Binary files /dev/null and b/scripting/plugins/TestPlugin/__pycache__/__init__.cpython-38.pyc differ