From 2efdbe6d172962dcd42bc31cabb8c79d9bcf3e48 Mon Sep 17 00:00:00 2001 From: Andrew Collins Date: Mon, 17 Feb 2025 04:53:56 +0000 Subject: [PATCH 01/11] Fixed up pre-push hook --- .scripts/ki-ntree | 2 +- .scripts/post_panel.py | 2 ++ default.kibot.yaml | 7 +++++++ hooks/pre-push | 2 +- kibot-ci.yml | 21 +++++++++++++-------- 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/.scripts/ki-ntree b/.scripts/ki-ntree index 26ff988..c66d40d 160000 --- a/.scripts/ki-ntree +++ b/.scripts/ki-ntree @@ -1 +1 @@ -Subproject commit 26ff98818f03b57fa29b7d6d1a3ff301caf7794e +Subproject commit c66d40daf798f7d876e2213f15f004e8f253672b diff --git a/.scripts/post_panel.py b/.scripts/post_panel.py index c4e905d..812700d 100644 --- a/.scripts/post_panel.py +++ b/.scripts/post_panel.py @@ -25,6 +25,8 @@ src = json.loads(json_str) json_file = open(proj) json_str = json_file.read() dest = json.loads(json_str) +dest["board"]["design_settings"]["rule_severities"]["duplicate_footprints"] = "ignore" +dest["board"]["design_settings"]["rule_severities"]["extra_footprint"] = "ignore" dest["board"]["design_settings"]["rule_severities"]["lib_footprint_issues"] = "ignore" dest["board"]["design_settings"]["rule_severities"]["lib_footprint_mismatch"] = "ignore" dest["board"]["design_settings"]["rule_severities"]["hole_near_hole"] = "ignore" diff --git a/default.kibot.yaml b/default.kibot.yaml index df37db6..74623da 100644 --- a/default.kibot.yaml +++ b/default.kibot.yaml @@ -255,6 +255,13 @@ groups: - stencil - interactive_bom + - name: pcb_panel + outputs: + - JLCPCB_compress + - neo_position + - print_pcb + - interactive_bom + - name: sch outputs: - bom_csv diff --git a/hooks/pre-push b/hooks/pre-push index 957611a..19e1085 100755 --- a/hooks/pre-push +++ b/hooks/pre-push @@ -1,6 +1,6 @@ #!/bin/sh -kimelon unlock all +kimelon git unlock all command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting '.git/hooks/pre-push'.\n"; exit 2; } git lfs pre-push "$@" diff --git a/kibot-ci.yml b/kibot-ci.yml index bfe9f89..4aa745b 100644 --- a/kibot-ci.yml +++ b/kibot-ci.yml @@ -75,7 +75,6 @@ image: - !reference [.commands, sch_from_pro] - sch_arr=($SCHEMS) - | - cd $CI_PROJECT_DIR for i in $(seq 1 $END) do if [[ ${dir_arr[i-1]} == "./Frame" ]]; then @@ -93,6 +92,7 @@ image: - 'SEARCH="_panel.json"' - !reference [.commands, get_dirs] - | + mkdir panels cd $CI_PROJECT_DIR for d in $DIRS do @@ -103,14 +103,17 @@ image: NAME=$(echo "${FILE%.json}") PCB=$(find $d/*.kicad_pcb) echo "mkdring" - mkdir $NAME + mkdir -p panels/$NAME echo "panelising" - kikit panelize -p $JSON $PCB $NAME/$NAME.kicad_pcb - cp .gitlab/micromelon_default/micromelon_default.kicad_sch $NAME/$NAME.kicad_sch - cp $d/fp-lib-table $NAME/ - python3 .gitlab/.scripts/post_panel.py $NAME/$NAME.kicad_pro $PCB + kikit panelize -p $JSON $PCB panels/$NAME/$NAME.kicad_pcb + cp .gitlab/micromelon_default/micromelon_default.kicad_sch panels/$NAME/$NAME.kicad_sch + cp $d/fp-lib-table panels/$NAME/ + python3 .gitlab/.scripts/post_panel.py panels/$NAME/$NAME.kicad_pro $PCB done - - cd $CI_PROJECT_DIR + - cd panels || true + - !reference [.commands, kibot] + - mv panels/* . + - rm -rf panels/ neo: - 'SEARCH=".kicad_pro"' @@ -268,13 +271,15 @@ outputs_all: variables: SUFF_SCH: drc sch SUFF_PCB: erc,update_xml,set_text_variables pcb + SUFF_PANEL: erc,update_xml,set_text_variables pcb_panel script: - !reference [.commands, git_tag] - SUFFIX=$SUFF_SCH - !reference [.commands, kibot] - SUFFIX=$SUFF_PCB - - !reference [.commands, panel] - !reference [.commands, kibot] + - SUFFIX=$SUFF_PANEL + - !reference [.commands, panel] - !reference [.commands, neo] - ls Fabrication/ From cc3ba0907f1c632541812f18fb0937a18f1572d9 Mon Sep 17 00:00:00 2001 From: andrewc Date: Thu, 27 Feb 2025 10:17:42 +1000 Subject: [PATCH 02/11] FIX: search api uses manufacturer properly --- .scripts/ki-ntree | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.scripts/ki-ntree b/.scripts/ki-ntree index c66d40d..f1e2306 160000 --- a/.scripts/ki-ntree +++ b/.scripts/ki-ntree @@ -1 +1 @@ -Subproject commit c66d40daf798f7d876e2213f15f004e8f253672b +Subproject commit f1e2306633a3c4a0a7e60f8c08ed9bcca06d7e16 From 18a9c83ca7ceac36bc47990b3fe11ad4bd8c0286 Mon Sep 17 00:00:00 2001 From: andrewc Date: Tue, 18 Mar 2025 18:23:38 +1000 Subject: [PATCH 03/11] FIX: corrected syntax in `foot_gen` script, and stopped leaving one footprint unprocessed. --- .scripts/foot_gen.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.scripts/foot_gen.py b/.scripts/foot_gen.py index 0eed083..4aaf4e8 100644 --- a/.scripts/foot_gen.py +++ b/.scripts/foot_gen.py @@ -95,7 +95,7 @@ for d in brd_drawings: # Keep only required foots saved = [] -while len(pcb.Footprints()) > 1: +while len(pcb.Footprints()) > 0: foot = pcb.Footprints().pop() if foot.GetReference() in new_foots.keys(): saved.append(foot) @@ -323,7 +323,7 @@ for [foot, pad_map] in sorted_foots: elif shape_type == pcbnew.PAD_SHAPE_CUSTOM: pad_shape = Pad.SHAPE_CUSTOM for d in foot.GraphicalItems(): - if type(d) is pcbnew.FP_TEXT and "User.Drawings" in d.GetLayerName(): + if type(d) is pcbnew.PCB_TEXT and "User.Drawings" in d.GetLayerName(): txt_sp = d.GetText().split(':',1) if pad_number != txt_sp[0]: continue From f17468f13befe145a9024bbcf3be823e6b42d67b Mon Sep 17 00:00:00 2001 From: ac Date: Tue, 13 May 2025 16:16:05 +1000 Subject: [PATCH 04/11] FEAT: module footprint generation now has silkscreen visible --- .scripts/foot_gen.py | 12 +++++++----- default.kibot.yaml | 1 + 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.scripts/foot_gen.py b/.scripts/foot_gen.py index 4aaf4e8..179bfdb 100644 --- a/.scripts/foot_gen.py +++ b/.scripts/foot_gen.py @@ -153,6 +153,7 @@ for foot in saved: pad_map[pad.GetNumber()] = match_num sorted_foots.append([load_foot, pad_map]) + print("Added: ", load_foot) pcb.Add(load_foot) @@ -160,13 +161,13 @@ for foot in saved: # sorted_foots.sort(key=lambda foot: foot[0].GetY()) # Export the step file -os.system("kicad-cli pcb export step -f --no-dnp --subst-models --user-origin " + str(ToMM(brd_cent.x)) + "x" + str(ToMM(brd_cent.y)) + "mm -o /tmp/dummy.step " + sys.argv[1]) +os.system("kicad-cli pcb export vrml --units 'tenths' -f --user-origin " + str(ToMM(brd_cent.x)) + "x" + str(ToMM(brd_cent.y)) + "mm -o /tmp/dummy.wrl " + sys.argv[1]) # Import the 3d model of the actual PCB dummy = FOOTPRINT(pcb) dummy.SetPosition(brd_cent) dummy_model = FP_3DMODEL() -dummy_model.m_Filename = "/tmp/dummy.step" +dummy_model.m_Filename = "/tmp/dummy.wrl" dummy_model.m_Offset = VECTOR3D(0.0, 0.0, z_offset) dummy.Add3DModel(dummy_model) pcb.Add(dummy) @@ -177,8 +178,8 @@ pcb.Add(dummy) # Save and export step of board + mating connectors SaveBoard("test/test.kicad_pcb", pcb) -final_model_path = sys.path[0] + "/../../libs/melon3d/" + foot_path + ".3dshapes/" + foot_name + ".step" -os.system("kicad-cli pcb export step -f --subst-models --user-origin " + str(ToMM(brd_cent.x)) + "x" + str(ToMM(brd_cent.y)) + "mm -o " + final_model_path + " test/test.kicad_pcb") +final_model_path = sys.path[0] + "/../../libs/melon3d/" + foot_path + ".3dshapes/" + foot_name + ".wrl" +os.system("kicad-cli pcb export vrml -f --units 'mm' --user-origin " + str(ToMM(brd_cent.x)) + "x" + str(ToMM(brd_cent.y)) + "mm -o " + final_model_path + " test/test.kicad_pcb") # Generate footprint @@ -249,6 +250,7 @@ for [foot, pad_map] in sorted_foots: # start = [cent_mm[0] - size_mm[0], cent_mm[1] - size_mm[1]] # end = [cent_mm[0] + size_mm[0], cent_mm[1] + size_mm[1]] # kicad_mod.append(RectLine(start=start, end=end, layer='F.Silkscreen', width=0.05, offset=0.2)) + # elif shape_type == pcbnew.SHAPE_T_CIRCLE: # start = [cent_mm[0], cent_mm[1] + size_mm[1]/2] # end = [start[0], start[1]] @@ -410,7 +412,7 @@ for i in range(len(corners)): # kicad_mod.append(RectLine(start=[-brd_width/2,-brd_height/2], end=[brd_width/2,brd_height/2], layer='F.SilkS', width=0.15)) -final_model_path = "${KIPRJMOD}/../libs/melon3d/" + foot_path + ".3dshapes/" + foot_name + ".step" +final_model_path = "${KIPRJMOD}/../libs/melon3d/" + foot_path + ".3dshapes/" + foot_name + ".wrl" kicad_mod.append(Model(filename=final_model_path ,at=[0,0,-1.6] ,scale=[1,1,1] diff --git a/default.kibot.yaml b/default.kibot.yaml index 74623da..b71eb39 100644 --- a/default.kibot.yaml +++ b/default.kibot.yaml @@ -260,6 +260,7 @@ groups: - JLCPCB_compress - neo_position - print_pcb + - step - interactive_bom - name: sch From 266fad8b9c5bd75edc6356e7e8ce90f4dd88ac4e Mon Sep 17 00:00:00 2001 From: ac Date: Thu, 29 May 2025 13:29:57 +1000 Subject: [PATCH 05/11] FIX: export both vrml and step files of generated footprints --- .scripts/foot_gen.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.scripts/foot_gen.py b/.scripts/foot_gen.py index 179bfdb..bef59ec 100644 --- a/.scripts/foot_gen.py +++ b/.scripts/foot_gen.py @@ -162,6 +162,7 @@ for foot in saved: # Export the step file os.system("kicad-cli pcb export vrml --units 'tenths' -f --user-origin " + str(ToMM(brd_cent.x)) + "x" + str(ToMM(brd_cent.y)) + "mm -o /tmp/dummy.wrl " + sys.argv[1]) +os.system("kicad-cli pcb export step -f --subst-models --user-origin " + str(ToMM(brd_cent.x)) + "x" + str(ToMM(brd_cent.y)) + "mm -o /tmp/dummy.stp " + sys.argv[1]) # Import the 3d model of the actual PCB dummy = FOOTPRINT(pcb) @@ -179,7 +180,9 @@ pcb.Add(dummy) # Save and export step of board + mating connectors SaveBoard("test/test.kicad_pcb", pcb) final_model_path = sys.path[0] + "/../../libs/melon3d/" + foot_path + ".3dshapes/" + foot_name + ".wrl" +final_model_path_stp = sys.path[0] + "/../../libs/melon3d/" + foot_path + ".3dshapes/" + foot_name + ".stp" os.system("kicad-cli pcb export vrml -f --units 'mm' --user-origin " + str(ToMM(brd_cent.x)) + "x" + str(ToMM(brd_cent.y)) + "mm -o " + final_model_path + " test/test.kicad_pcb") +os.system("kicad-cli pcb export step -f --subst-models --user-origin " + str(ToMM(brd_cent.x)) + "x" + str(ToMM(brd_cent.y)) + "mm -o " + final_model_path_stp + " test/test.kicad_pcb") # Generate footprint From b9ceec5389b30e8d92435c5b5ddf7bd39a405a23 Mon Sep 17 00:00:00 2001 From: ac Date: Thu, 29 May 2025 14:11:29 +1000 Subject: [PATCH 06/11] FIX: change generated footprint model back to step by default --- .scripts/foot_gen.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.scripts/foot_gen.py b/.scripts/foot_gen.py index bef59ec..d415114 100644 --- a/.scripts/foot_gen.py +++ b/.scripts/foot_gen.py @@ -181,7 +181,7 @@ pcb.Add(dummy) SaveBoard("test/test.kicad_pcb", pcb) final_model_path = sys.path[0] + "/../../libs/melon3d/" + foot_path + ".3dshapes/" + foot_name + ".wrl" final_model_path_stp = sys.path[0] + "/../../libs/melon3d/" + foot_path + ".3dshapes/" + foot_name + ".stp" -os.system("kicad-cli pcb export vrml -f --units 'mm' --user-origin " + str(ToMM(brd_cent.x)) + "x" + str(ToMM(brd_cent.y)) + "mm -o " + final_model_path + " test/test.kicad_pcb") +os.system("kicad-cli pcb export vrml -f --units 'tenths' --user-origin " + str(ToMM(brd_cent.x)) + "x" + str(ToMM(brd_cent.y)) + "mm -o " + final_model_path + " test/test.kicad_pcb") os.system("kicad-cli pcb export step -f --subst-models --user-origin " + str(ToMM(brd_cent.x)) + "x" + str(ToMM(brd_cent.y)) + "mm -o " + final_model_path_stp + " test/test.kicad_pcb") # Generate footprint @@ -415,7 +415,7 @@ for i in range(len(corners)): # kicad_mod.append(RectLine(start=[-brd_width/2,-brd_height/2], end=[brd_width/2,brd_height/2], layer='F.SilkS', width=0.15)) -final_model_path = "${KIPRJMOD}/../libs/melon3d/" + foot_path + ".3dshapes/" + foot_name + ".wrl" +final_model_path = "${KIPRJMOD}/../libs/melon3d/" + foot_path + ".3dshapes/" + foot_name + ".stp" kicad_mod.append(Model(filename=final_model_path ,at=[0,0,-1.6] ,scale=[1,1,1] From 003b7401311f42db72195846e451c76e8c1ce03d Mon Sep 17 00:00:00 2001 From: andrewc Date: Tue, 3 Jun 2025 07:49:31 +1000 Subject: [PATCH 07/11] WIP: pre-panel script to parse and impl panel info --- .scripts/post_panel.py | 4 +- .scripts/pre_panel.py | 98 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 .scripts/pre_panel.py diff --git a/.scripts/post_panel.py b/.scripts/post_panel.py index 812700d..ae457c5 100644 --- a/.scripts/post_panel.py +++ b/.scripts/post_panel.py @@ -33,8 +33,8 @@ dest["board"]["design_settings"]["rule_severities"]["hole_near_hole"] = "ignore" dest["board"]["design_settings"]["rule_severities"]["silk_overlap"] = "ignore" dest["board"]["design_settings"]["rule_severities"]["silk_over_copper"] = "ignore" dest["board"]["design_settings"]["rule_severities"]["drill_out_of_range"] = "ignore" -# This one is just until kibot image is updated to 7.0.5 -dest["board"]["design_settings"]["rule_severities"]["copper_sliver"] = "ignore" +# # This one is just until kibot image is updated to 7.0.5 +# dest["board"]["design_settings"]["rule_severities"]["copper_sliver"] = "ignore" dest["net_settings"]["classes"] = src["net_settings"]["classes"] dest["net_settings"]["netclass_patterns"] = src["net_settings"]["netclass_patterns"] diff --git a/.scripts/pre_panel.py b/.scripts/pre_panel.py new file mode 100644 index 0000000..dbebfd6 --- /dev/null +++ b/.scripts/pre_panel.py @@ -0,0 +1,98 @@ +import json +import sys +import shutil + +proj_file = sys.argv[1] +pcb_file = sys.argv[2] +panel_file = sys.argv[3] + +def num_to_mm(input: str) -> float: + input = input.lower() + # Panic, should all be in mm for sanity's sake + if "mm" not in input: + print(input, "not in mm") + exit(1) + return float(input.replace("mm", "")) + + +class Text: + def __init__(self, text: str, anchor: str, offset: (float, float), rot: float, size: (float, float, float), just: (str, str)): + self.text = text + self.anchor = anchor + self.hoff = offset[0] + self.voff = offset[1] + self.rot = str(rot)+"deg" + self.width = size[0] + self.height = size[1] + self.thickness = size[2] + self.hjust = just[0] + self.vjust = just[1] + + # def to_json(self) -> + + +class Frame: + def __init__(self, ftype: str, width: str, spacing: str): + self.ftype = ftype.lower() + self.width = num_to_mm(width) + self.spacing = num_to_mm(spacing) + +class Panel: + def __init__(self, spacing: str, frame: Frame): + self.spacing = num_to_mm(spacing) + self.frame = frame + + self.text = "{boardTitle}-{boardRevision}" + if "frame" in self.frame.ftype or "tb" in self.frame.ftype: + if "frame" in self.frame.ftype: + else: + self.text2 = None + self.text3 = None + +print("Starting post_panel script") + +dest_folder = '/'.join(proj_file.split('/')[:-1]) +dest_name = proj_file.split('/')[-1].removesuffix(".kicad_pro") + +src_name = pcb_file.removesuffix(".kicad_pcb") +src_proj = src_name + ".kicad_pro" + +try: + shutil.copy(src_name + ".kicad_dru", dest_folder + "/" + dest_name + ".kicad_dru") +except Exception: + pass + +json_file = open(panel_file) +json_str = json_file.read() +panel_json = json.loads(json_str) + +frame = Frame(panel_json["framing"]["type"], panel_json["framing"]["width"], panel_json["framing"]["spacing"]) +panel = Panel(panel_json["layout"]["space"], frame) + + + +json_file = open(src_proj) +json_str = json_file.read() +src = json.loads(json_str) + +json_file = open(proj_file) +json_str = json_file.read() +dest = json.loads(json_str) + +# dest["board"]["design_settings"]["rule_severities"]["duplicate_footprints"] = "ignore" +# dest["board"]["design_settings"]["rule_severities"]["extra_footprint"] = "ignore" +# dest["board"]["design_settings"]["rule_severities"]["lib_footprint_issues"] = "ignore" +# dest["board"]["design_settings"]["rule_severities"]["lib_footprint_mismatch"] = "ignore" +# dest["board"]["design_settings"]["rule_severities"]["hole_near_hole"] = "ignore" +# dest["board"]["design_settings"]["rule_severities"]["silk_overlap"] = "ignore" +# dest["board"]["design_settings"]["rule_severities"]["silk_over_copper"] = "ignore" +# dest["board"]["design_settings"]["rule_severities"]["drill_out_of_range"] = "ignore" +# # # This one is just until kibot image is updated to 7.0.5 +# # dest["board"]["design_settings"]["rule_severities"]["copper_sliver"] = "ignore" +# dest["net_settings"]["classes"] = src["net_settings"]["classes"] +# dest["net_settings"]["netclass_patterns"] = src["net_settings"]["netclass_patterns"] + +with open(proj_file, mode="w") as json_file: + json.dump(dest, json_file, indent=2) + +print("Finished post_panel script") From 538c109b25fc86264b3e99ae885bd7ba2f54305e Mon Sep 17 00:00:00 2001 From: ac Date: Tue, 3 Jun 2025 13:58:58 +1000 Subject: [PATCH 08/11] Panel info generation operational, need to integrate into CI --- .scripts/pre_panel.py | 173 ++++++++++++++++++++++++++++++++---------- 1 file changed, 131 insertions(+), 42 deletions(-) diff --git a/.scripts/pre_panel.py b/.scripts/pre_panel.py index dbebfd6..7ee3f67 100644 --- a/.scripts/pre_panel.py +++ b/.scripts/pre_panel.py @@ -2,11 +2,17 @@ import json import sys import shutil +from kikit.panelize import Origin,getOriginCoord +from kikit.common import findBoardBoundingBox +from pcbnewTransition.pcbnew import LoadBoard + +PCB_DIV_MM = 1000000 + proj_file = sys.argv[1] pcb_file = sys.argv[2] panel_file = sys.argv[3] -def num_to_mm(input: str) -> float: +def str_mm_to_float(input: str) -> float: input = input.lower() # Panic, should all be in mm for sanity's sake if "mm" not in input: @@ -14,42 +20,129 @@ def num_to_mm(input: str) -> float: exit(1) return float(input.replace("mm", "")) +def float_to_str_mm(input: float, n: int=0) -> str: + return "{:.2f}".format(input).zfill(n+3)+"mm" + +def float_to_deg(input: float, n: int=0) -> str: + return "{:.2f}".format(input).zfill(n+3)+"deg" + class Text: - def __init__(self, text: str, anchor: str, offset: (float, float), rot: float, size: (float, float, float), just: (str, str)): + def __init__(self, text: str, anchor: str, offset: tuple[float, float], rot: float, size: tuple[float, float, float] = (1.0, 1.0, 0.16), just: tuple[str, str] = ('center', 'center')): self.text = text self.anchor = anchor - self.hoff = offset[0] - self.voff = offset[1] + self.hoff = float_to_str_mm(offset[0]) + self.voff = float_to_str_mm(offset[1]) self.rot = str(rot)+"deg" - self.width = size[0] - self.height = size[1] - self.thickness = size[2] + self.width = float_to_str_mm(size[0]) + self.height = float_to_str_mm(size[1]) + self.thickness = float_to_str_mm(size[2]) self.hjust = just[0] self.vjust = just[1] - # def to_json(self) -> + def to_dict(self, n: int) -> dict: + if n == 0: + str_n = '' + else: + str_n = str(n + 1) + + return { + "text" + str_n: + { + "type": "simple", + "text": self.text, + "anchor": self.anchor, + "hoffset": self.hoff, + "voffset": self.voff, + "orientation": self.rot, + "width": self.width, + "height": self.height, + "hjustify": self.hjust, + "vjustify": self.vjust, + "thickness": self.thickness, + } + } class Frame: def __init__(self, ftype: str, width: str, spacing: str): self.ftype = ftype.lower() - self.width = num_to_mm(width) - self.spacing = num_to_mm(spacing) + self.width = str_mm_to_float(width) + self.spacing = str_mm_to_float(spacing) + if "frame" in self.ftype: + self.extra_d = [(self.width + self.spacing)*2, (self.width + self.spacing)*2] + elif "tb" in self.ftype: + self.extra_d = [0, (self.width + self.spacing)*2] + else: + self.extra_d = [(self.width + self.spacing)*2, 0] + +class Board: + def __init__(self, fids: list[tuple[float, float]], rot: float, dims: tuple[float, float]): + fid_list = [] + for f in fids: + fid_list.append("(" + float_to_str_mm(f[0]) + ", " + float_to_str_mm(f[1]) + ")") + self.fids = ",".join(fid_list) + self.rot = rot + self.dims = dims + class Panel: - def __init__(self, spacing: str, frame: Frame): - self.spacing = num_to_mm(spacing) + def __init__(self, spacing: str, grid: (int, int), frame: Frame, board: Board): + self.spacing = str_mm_to_float(spacing) + self.grid = grid + self.gaps = (grid[0] - 1, grid[1] - 1) self.frame = frame + self.text = None + self.text2 = None + self.text3 = None + self.text4 = None - self.text = "{boardTitle}-{boardRevision}" - if "frame" in self.frame.ftype or "tb" in self.frame.ftype: - if "frame" in self.frame.ftype: + self.dims = [self.gaps[i]*self.spacing + self.grid[i]*board.dims[i] + frame.extra_d[i] for i in range(0,2)] + + arrow_off = [frame.spacing + frame.width, frame.width] + text_off = [arrow_off[0] + 2, frame.width/2] + + if "frame" in frame.ftype or "tb" in frame.ftype: + txt_loc = ('mt', 'bl') + txt_off = ((0, text_off[1]), (text_off[0], -text_off[1])) + txt_just = (('center', 'center'), ('left', 'center')) + txt_rot = 0 else: - self.text2 = None - self.text3 = None + txt_loc = ('ml', 'br') + txt_off = ((text_off[1], 0), (text_off[1], text_off[0])) + txt_just = (('center', 'center'), ('center', 'center')) + txt_rot = 90 -print("Starting post_panel script") + self.text = Text("{boardTitle}-{boardRevision}", txt_loc[0], txt_off[0], txt_rot, just=txt_just[0]).to_dict(0) + + spacer = " " + txt =\ + "PNL (x,y) : (" + "x: " +float_to_str_mm(self.dims[0],4) + ", " + float_to_str_mm(self.dims[1],4) + ")\n" +\ + "BRD (x,y),r: (" + float_to_str_mm(board.dims[0],4) + ", " + float_to_str_mm(board.dims[1],4) + "), " +\ + float_to_deg(board.rot, 3) + "\n" +\ + "FIDS (x,y) : " + board.fids + + + self.text2 = Text(txt, txt_loc[1], txt_off[1], txt_rot, just=txt_just[1]).to_dict(1) + if "frame" in self.frame.ftype: + self.text3 = Text("ORIGY ->", "bl", (arrow_off[1], -arrow_off[0]), 0, just=("right", "center")).to_dict(2) + self.text4 = Text("ORIGX ->", "bl", (arrow_off[0], -arrow_off[1]), 90, just=("right", "center")).to_dict(3) + +print("Starting pre_panel script") + +board = LoadBoard(pcb_file) +sourceArea = findBoardBoundingBox(board) +# bottomOrig = [(a - b)/10**6 for a,b in zip(*[list(getOriginCoord(o, sourceArea)) for o in [Origin.BottomRight, Origin.BottomLeft]])] +# print("bottom Orig: ", bottomOrig) + + +fids = [] +for foot in board.Footprints(): + if "FID" in foot.GetReference(): + cent = foot.GetBoundingBox().GetCenter() + fids.append(tuple([cent[i]/PCB_DIV_MM for i in range(0,2)])) + +print("Fids:", fids) dest_folder = '/'.join(proj_file.split('/')[:-1]) dest_name = proj_file.split('/')[-1].removesuffix(".kicad_pro") @@ -66,33 +159,29 @@ json_file = open(panel_file) json_str = json_file.read() panel_json = json.loads(json_str) -frame = Frame(panel_json["framing"]["type"], panel_json["framing"]["width"], panel_json["framing"]["spacing"]) -panel = Panel(panel_json["layout"]["space"], frame) +print(panel_json) + +frame = Frame(panel_json["framing"]["type"], panel_json["framing"]["width"], panel_json["framing"]["space"]) +board = Board(fids, panel_json["layout"].get("rotation", "0deg"), (sourceArea.GetWidth()/PCB_DIV_MM, sourceArea.GetHeight()/PCB_DIV_MM)) +panel = Panel(panel_json["layout"]["space"], (int(panel_json["layout"]["rows"]), int(panel_json["layout"]["rows"])) ,frame, board) -json_file = open(src_proj) -json_str = json_file.read() -src = json.loads(json_str) -json_file = open(proj_file) -json_str = json_file.read() -dest = json.loads(json_str) +for t in [panel.text, panel.text2, panel.text3, panel.text4]: + if t is not None: + panel_json.update(t) +# panel_json.update(panel.text3) -# dest["board"]["design_settings"]["rule_severities"]["duplicate_footprints"] = "ignore" -# dest["board"]["design_settings"]["rule_severities"]["extra_footprint"] = "ignore" -# dest["board"]["design_settings"]["rule_severities"]["lib_footprint_issues"] = "ignore" -# dest["board"]["design_settings"]["rule_severities"]["lib_footprint_mismatch"] = "ignore" -# dest["board"]["design_settings"]["rule_severities"]["hole_near_hole"] = "ignore" -# dest["board"]["design_settings"]["rule_severities"]["silk_overlap"] = "ignore" -# dest["board"]["design_settings"]["rule_severities"]["silk_over_copper"] = "ignore" -# dest["board"]["design_settings"]["rule_severities"]["drill_out_of_range"] = "ignore" -# # # This one is just until kibot image is updated to 7.0.5 -# # dest["board"]["design_settings"]["rule_severities"]["copper_sliver"] = "ignore" -# dest["net_settings"]["classes"] = src["net_settings"]["classes"] -# dest["net_settings"]["netclass_patterns"] = src["net_settings"]["netclass_patterns"] +# json_file = open(src_proj) +# json_str = json_file.read() +# src = json.loads(json_str) +# +# json_file = open(proj_file) +# json_str = json_file.read() +# dest = json.loads(json_str) +# +json_file = open(panel_file, mode="w") +json.dump(panel_json, json_file, indent=4) -with open(proj_file, mode="w") as json_file: - json.dump(dest, json_file, indent=2) - -print("Finished post_panel script") +print("Finished pre_panel script") From f73d59d2e308f6be3f4a9cff9377ab92e6c8cb5b Mon Sep 17 00:00:00 2001 From: ac Date: Tue, 3 Jun 2025 14:50:54 +1000 Subject: [PATCH 09/11] Cleaned up script, integrated into CI --- .scripts/pre_panel.py | 51 ++++++------------------------------------- kibot-ci.yml | 1 + 2 files changed, 8 insertions(+), 44 deletions(-) diff --git a/.scripts/pre_panel.py b/.scripts/pre_panel.py index 7ee3f67..7072905 100644 --- a/.scripts/pre_panel.py +++ b/.scripts/pre_panel.py @@ -1,16 +1,13 @@ import json import sys -import shutil -from kikit.panelize import Origin,getOriginCoord from kikit.common import findBoardBoundingBox from pcbnewTransition.pcbnew import LoadBoard PCB_DIV_MM = 1000000 -proj_file = sys.argv[1] -pcb_file = sys.argv[2] -panel_file = sys.argv[3] +pcb_file = sys.argv[1] +panel_file = sys.argv[2] def str_mm_to_float(input: str) -> float: input = input.lower() @@ -45,7 +42,6 @@ class Text: str_n = '' else: str_n = str(n + 1) - return { "text" + str_n: { @@ -87,7 +83,7 @@ class Board: class Panel: - def __init__(self, spacing: str, grid: (int, int), frame: Frame, board: Board): + def __init__(self, spacing: str, grid: tuple[int, int], frame: Frame, board: Board): self.spacing = str_mm_to_float(spacing) self.grid = grid self.gaps = (grid[0] - 1, grid[1] - 1) @@ -96,7 +92,6 @@ class Panel: self.text2 = None self.text3 = None self.text4 = None - self.dims = [self.gaps[i]*self.spacing + self.grid[i]*board.dims[i] + frame.extra_d[i] for i in range(0,2)] arrow_off = [frame.spacing + frame.width, frame.width] @@ -109,21 +104,20 @@ class Panel: txt_rot = 0 else: txt_loc = ('ml', 'br') - txt_off = ((text_off[1], 0), (text_off[1], text_off[0])) - txt_just = (('center', 'center'), ('center', 'center')) + txt_off = ((text_off[1], 0), (-text_off[1], -text_off[0])) + txt_just = (('center', 'center'), ('left', 'center')) txt_rot = 90 self.text = Text("{boardTitle}-{boardRevision}", txt_loc[0], txt_off[0], txt_rot, just=txt_just[0]).to_dict(0) spacer = " " txt =\ - "PNL (x,y) : (" + "x: " +float_to_str_mm(self.dims[0],4) + ", " + float_to_str_mm(self.dims[1],4) + ")\n" +\ + "PNL (x,y) : (" + float_to_str_mm(self.dims[0],4) + ", " + float_to_str_mm(self.dims[1],4) + ")\n" +\ "BRD (x,y),r: (" + float_to_str_mm(board.dims[0],4) + ", " + float_to_str_mm(board.dims[1],4) + "), " +\ float_to_deg(board.rot, 3) + "\n" +\ "FIDS (x,y) : " + board.fids - - self.text2 = Text(txt, txt_loc[1], txt_off[1], txt_rot, just=txt_just[1]).to_dict(1) + if "frame" in self.frame.ftype: self.text3 = Text("ORIGY ->", "bl", (arrow_off[1], -arrow_off[0]), 0, just=("right", "center")).to_dict(2) self.text4 = Text("ORIGX ->", "bl", (arrow_off[0], -arrow_off[1]), 90, just=("right", "center")).to_dict(3) @@ -132,55 +126,24 @@ print("Starting pre_panel script") board = LoadBoard(pcb_file) sourceArea = findBoardBoundingBox(board) -# bottomOrig = [(a - b)/10**6 for a,b in zip(*[list(getOriginCoord(o, sourceArea)) for o in [Origin.BottomRight, Origin.BottomLeft]])] -# print("bottom Orig: ", bottomOrig) - - fids = [] for foot in board.Footprints(): if "FID" in foot.GetReference(): cent = foot.GetBoundingBox().GetCenter() fids.append(tuple([cent[i]/PCB_DIV_MM for i in range(0,2)])) -print("Fids:", fids) - -dest_folder = '/'.join(proj_file.split('/')[:-1]) -dest_name = proj_file.split('/')[-1].removesuffix(".kicad_pro") - -src_name = pcb_file.removesuffix(".kicad_pcb") -src_proj = src_name + ".kicad_pro" - -try: - shutil.copy(src_name + ".kicad_dru", dest_folder + "/" + dest_name + ".kicad_dru") -except Exception: - pass - json_file = open(panel_file) json_str = json_file.read() panel_json = json.loads(json_str) -print(panel_json) - frame = Frame(panel_json["framing"]["type"], panel_json["framing"]["width"], panel_json["framing"]["space"]) - - board = Board(fids, panel_json["layout"].get("rotation", "0deg"), (sourceArea.GetWidth()/PCB_DIV_MM, sourceArea.GetHeight()/PCB_DIV_MM)) panel = Panel(panel_json["layout"]["space"], (int(panel_json["layout"]["rows"]), int(panel_json["layout"]["rows"])) ,frame, board) - for t in [panel.text, panel.text2, panel.text3, panel.text4]: if t is not None: panel_json.update(t) -# panel_json.update(panel.text3) -# json_file = open(src_proj) -# json_str = json_file.read() -# src = json.loads(json_str) -# -# json_file = open(proj_file) -# json_str = json_file.read() -# dest = json.loads(json_str) -# json_file = open(panel_file, mode="w") json.dump(panel_json, json_file, indent=4) diff --git a/kibot-ci.yml b/kibot-ci.yml index 30b3155..1a4f235 100644 --- a/kibot-ci.yml +++ b/kibot-ci.yml @@ -105,6 +105,7 @@ image: echo "mkdring" mkdir -p panels/$NAME echo "panelising" + python3 .gitlab/.scripts/pre_panel.py $PCB $JSON kikit panelize -p $JSON $PCB panels/$NAME/$NAME.kicad_pcb cp .gitlab/micromelon_default/micromelon_default.kicad_sch panels/$NAME/$NAME.kicad_sch cp $d/fp-lib-table panels/$NAME/ From 03225edd05f51a901d6f2f26bb09773469ab37e0 Mon Sep 17 00:00:00 2001 From: ac Date: Wed, 2 Jul 2025 08:57:46 +1000 Subject: [PATCH 10/11] Added spacing text and aligned text better --- .scripts/pre_panel.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.scripts/pre_panel.py b/.scripts/pre_panel.py index 7072905..578eb90 100644 --- a/.scripts/pre_panel.py +++ b/.scripts/pre_panel.py @@ -93,6 +93,7 @@ class Panel: self.text3 = None self.text4 = None self.dims = [self.gaps[i]*self.spacing + self.grid[i]*board.dims[i] + frame.extra_d[i] for i in range(0,2)] + self.spacing = [self.spacing + board.dims[i] for i in range(0,2)] arrow_off = [frame.spacing + frame.width, frame.width] text_off = [arrow_off[0] + 2, frame.width/2] @@ -112,7 +113,8 @@ class Panel: spacer = " " txt =\ - "PNL (x,y) : (" + float_to_str_mm(self.dims[0],4) + ", " + float_to_str_mm(self.dims[1],4) + ")\n" +\ + "PNL (x,y): (" + float_to_str_mm(self.dims[0],4) + ", " + float_to_str_mm(self.dims[1],4) + ")\n" +\ + "SPA (x,y): (" + float_to_str_mm(self.spacing[0],2) + ", " + float_to_str_mm(self.spacing[1],2) +")\n" +\ "BRD (x,y),r: (" + float_to_str_mm(board.dims[0],4) + ", " + float_to_str_mm(board.dims[1],4) + "), " +\ float_to_deg(board.rot, 3) + "\n" +\ "FIDS (x,y) : " + board.fids From 284f4a075aab563e0fcfc54d9c7c4612915fb1fc Mon Sep 17 00:00:00 2001 From: andrewc Date: Wed, 2 Jul 2025 13:57:49 +1000 Subject: [PATCH 11/11] Panel text addition now has to be done using the post panel script process, as too many text fields required --- .scripts/pre_panel.py | 88 +++++++++++++++++++++++++++++-------------- 1 file changed, 60 insertions(+), 28 deletions(-) diff --git a/.scripts/pre_panel.py b/.scripts/pre_panel.py index 578eb90..d761e18 100644 --- a/.scripts/pre_panel.py +++ b/.scripts/pre_panel.py @@ -2,6 +2,9 @@ import json import sys from kikit.common import findBoardBoundingBox +from kikit.panelize_ui_impl import buildText +from kikit.panelize_ui_sections import ppText +from kikit.defs import * from pcbnewTransition.pcbnew import LoadBoard PCB_DIV_MM = 1000000 @@ -26,6 +29,7 @@ def float_to_deg(input: float, n: int=0) -> str: class Text: def __init__(self, text: str, anchor: str, offset: tuple[float, float], rot: float, size: tuple[float, float, float] = (1.0, 1.0, 0.16), just: tuple[str, str] = ('center', 'center')): + self.layer=Layer.F_SilkS self.text = text self.anchor = anchor self.hoff = float_to_str_mm(offset[0]) @@ -37,6 +41,13 @@ class Text: self.hjust = just[0] self.vjust = just[1] + def flip(self): + self.layer=Layer.B_SilkS + rot = float(self.rot.replace("deg", "")) + rot += 180.0 + self.rot = str(rot)+"deg" + return self + def to_dict(self, n: int) -> dict: if n == 0: str_n = '' @@ -56,6 +67,7 @@ class Text: "hjustify": self.hjust, "vjustify": self.vjust, "thickness": self.thickness, + "layer": int(self.layer), } } @@ -88,10 +100,7 @@ class Panel: self.grid = grid self.gaps = (grid[0] - 1, grid[1] - 1) self.frame = frame - self.text = None - self.text2 = None - self.text3 = None - self.text4 = None + self.text = {} self.dims = [self.gaps[i]*self.spacing + self.grid[i]*board.dims[i] + frame.extra_d[i] for i in range(0,2)] self.spacing = [self.spacing + board.dims[i] for i in range(0,2)] @@ -109,7 +118,7 @@ class Panel: txt_just = (('center', 'center'), ('left', 'center')) txt_rot = 90 - self.text = Text("{boardTitle}-{boardRevision}", txt_loc[0], txt_off[0], txt_rot, just=txt_just[0]).to_dict(0) + self.text.update(Text("{boardTitle}-{boardRevision}", txt_loc[0], txt_off[0], txt_rot, just=txt_just[0]).to_dict(len(self.text))) spacer = " " txt =\ @@ -118,35 +127,58 @@ class Panel: "BRD (x,y),r: (" + float_to_str_mm(board.dims[0],4) + ", " + float_to_str_mm(board.dims[1],4) + "), " +\ float_to_deg(board.rot, 3) + "\n" +\ "FIDS (x,y) : " + board.fids - self.text2 = Text(txt, txt_loc[1], txt_off[1], txt_rot, just=txt_just[1]).to_dict(1) + self.text.update(Text(txt, txt_loc[1], txt_off[1], txt_rot, just=txt_just[1]).to_dict(1)) if "frame" in self.frame.ftype: - self.text3 = Text("ORIGY ->", "bl", (arrow_off[1], -arrow_off[0]), 0, just=("right", "center")).to_dict(2) - self.text4 = Text("ORIGX ->", "bl", (arrow_off[0], -arrow_off[1]), 90, just=("right", "center")).to_dict(3) + txt_orig = [ +Text("ORIGX ->", "bl", (arrow_off[0], -arrow_off[1]), 90, just=("right", "center")), +Text("ORIGY ->", "bl", (arrow_off[1], -arrow_off[0]), 0, just=("right", "center")) + ] + for txt in txt_orig: + self.text.update(txt.to_dict(len(self.text))) + self.text.update(txt.flip().to_dict(len(self.text))) -print("Starting pre_panel script") +def kikitPostprocess(panel, arg): + print("arg:", arg) + text_dict = eval(arg) + for t in text_dict.values(): + ppText(t) + print(t["thickness"]) + t["plugin"] = None + buildText(t,panel) + # panel.addText(t.text, position=, orientation=t.rot, + # width=t.width, height=t.height, thickness=t.thickness, + # hJustify=t.hjustify, + # vJustify=t.vjustify, + # layer=t.layer): -board = LoadBoard(pcb_file) -sourceArea = findBoardBoundingBox(board) -fids = [] -for foot in board.Footprints(): - if "FID" in foot.GetReference(): - cent = foot.GetBoundingBox().GetCenter() - fids.append(tuple([cent[i]/PCB_DIV_MM for i in range(0,2)])) + print("Finished post panel script") -json_file = open(panel_file) -json_str = json_file.read() -panel_json = json.loads(json_str) +if __name__ == '__main__': + print("Starting pre_panel script") -frame = Frame(panel_json["framing"]["type"], panel_json["framing"]["width"], panel_json["framing"]["space"]) -board = Board(fids, panel_json["layout"].get("rotation", "0deg"), (sourceArea.GetWidth()/PCB_DIV_MM, sourceArea.GetHeight()/PCB_DIV_MM)) -panel = Panel(panel_json["layout"]["space"], (int(panel_json["layout"]["rows"]), int(panel_json["layout"]["rows"])) ,frame, board) + board = LoadBoard(pcb_file) + sourceArea = findBoardBoundingBox(board) + fids = [] + for foot in board.Footprints(): + if "FID" in foot.GetReference(): + cent = foot.GetBoundingBox().GetCenter() + fids.append(tuple([cent[i]/PCB_DIV_MM for i in range(0,2)])) -for t in [panel.text, panel.text2, panel.text3, panel.text4]: - if t is not None: - panel_json.update(t) + json_file = open(panel_file) + json_str = json_file.read() + panel_json = json.loads(json_str) -json_file = open(panel_file, mode="w") -json.dump(panel_json, json_file, indent=4) + frame = Frame(panel_json["framing"]["type"], panel_json["framing"]["width"], panel_json["framing"]["space"]) + board = Board(fids, panel_json["layout"].get("rotation", "0deg"), (sourceArea.GetWidth()/PCB_DIV_MM, sourceArea.GetHeight()/PCB_DIV_MM)) + panel = Panel(panel_json["layout"]["space"], (int(panel_json["layout"]["rows"]), int(panel_json["layout"]["rows"])) ,frame, board) -print("Finished pre_panel script") + import pathlib + + panel_json["post"]["script"] = str(pathlib.Path(__file__).resolve()) + panel_json["post"]["scriptarg"] = str(panel.text) + + json_file = open(panel_file, mode="w") + json.dump(panel_json, json_file, indent=4) + + print("Finished pre_panel script")