From 055e8326703b5d4b2e7d5aabb30b459ee1013c28 Mon Sep 17 00:00:00 2001 From: "Salvador E. Tropea" Date: Mon, 31 Jul 2023 11:15:37 -0300 Subject: [PATCH] [BoM][Added] Support for ${field} expansion Closes #471 --- CHANGELOG.md | 2 ++ kibot/gs.py | 2 ++ kibot/kicad/config.py | 5 ++- kibot/kiplot.py | 35 ++++++++++++++++--- kibot/out_bom.py | 7 ++-- tests/board_samples/kicad_5/merge_2.sch | 3 +- tests/board_samples/kicad_7/merge_1.kicad_sch | 11 +++++- 7 files changed, 53 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c2a530b2..e805dcae8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.6.4] - UNRELEASED ### Added +- BoM: + - Support for ${field} expansion. (#471) - iBoM: - `forced_name` option to force the name displayed at the top left corner (#470) diff --git a/kibot/gs.py b/kibot/gs.py index 6ec59bd4e..e380382a1 100644 --- a/kibot/gs.py +++ b/kibot/gs.py @@ -115,6 +115,8 @@ class GS(object): kikit_units_to_kicad = {'mm': IU_PER_MM, 'cm': 10*IU_PER_MM, 'dm': 100*IU_PER_MM, 'm': 1000*IU_PER_MM, 'mil': IU_PER_MILS, 'inch': 1000*IU_PER_MILS, 'in': 1000*IU_PER_MILS} + # Maximum recursive replace + MAXDEPTH = 20 # # Global defaults # diff --git a/kibot/kicad/config.py b/kibot/kicad/config.py index cf8bf7975..575802b2d 100644 --- a/kibot/kicad/config.py +++ b/kibot/kicad/config.py @@ -43,7 +43,6 @@ SYM_LIB_TABLE = 'sym-lib-table' FP_LIB_TABLE = 'fp-lib-table' KICAD_COMMON = 'kicad_common' -MAXDEPTH = 20 SUP_VERSION = 7 reported = set() @@ -88,10 +87,10 @@ def expand_env(val, env, extra_env, used_extra=None): success = replaced = True depth = 0 ori_val = val - while success and replaced and depth < MAXDEPTH: + while success and replaced and depth < GS.MAXDEPTH: replaced = False depth += 1 - if depth == MAXDEPTH: + if depth == GS.MAXDEPTH: logger.warning(W_MAXDEPTH+'Too much nested variables replacements, possible loop ({})'.format(ori_val)) success = False for var in re.findall(r'\$\{(\S+?)\}', val): diff --git a/kibot/kiplot.py b/kibot/kiplot.py index 3a711eef3..791cf7462 100644 --- a/kibot/kiplot.py +++ b/kibot/kiplot.py @@ -8,7 +8,8 @@ """ Main KiBot code """ - +from copy import deepcopy +from collections import OrderedDict import os import re from sys import exit @@ -18,7 +19,6 @@ from subprocess import run, PIPE, STDOUT, Popen, CalledProcessError from glob import glob from importlib.util import spec_from_file_location, module_from_spec -from collections import OrderedDict from .gs import GS from .registrable import RegOutput @@ -26,7 +26,7 @@ EXIT_BAD_CONFIG, WRONG_INSTALL, UI_SMD, UI_VIRTUAL, TRY_INSTALL_CHECK, MOD_SMD, MOD_THROUGH_HOLE, MOD_VIRTUAL, W_PCBNOSCH, W_NONEEDSKIP, W_WRONGCHAR, name2make, W_TIMEOUT, W_KIAUTO, W_VARSCH, NO_SCH_FILE, NO_PCB_FILE, W_VARPCB, NO_YAML_MODULE, WRONG_ARGUMENTS, FAILED_EXECUTE, - MOD_EXCLUDE_FROM_POS_FILES, MOD_EXCLUDE_FROM_BOM, MOD_BOARD_ONLY, hide_stderr) + MOD_EXCLUDE_FROM_POS_FILES, MOD_EXCLUDE_FROM_BOM, MOD_BOARD_ONLY, hide_stderr, W_MAXDEPTH) from .error import PlotError, KiPlotConfigurationError, config_error from .config_reader import CfgYamlReader from .pre_base import BasePreFlight @@ -34,7 +34,7 @@ import kibot.dep_downloader as dep_downloader from .kicad.v5_sch import Schematic, SchFileError, SchError from .kicad.v6_sch import SchematicV6 -from .kicad.config import KiConfError +from .kicad.config import KiConfError, KiConf, expand_env from . import log logger = log.get_logger() @@ -330,6 +330,33 @@ def get_board_comps_data(comps): c.in_pcb_only = True +def expand_comp_fields(c, env): + extra_env = {f.name: f.value for f in c.fields} + for f in c.fields: + new_value = f.value + depth = 1 + used_extra = [False] + while depth < GS.MAXDEPTH: + new_value = expand_env(new_value, env, extra_env, used_extra=used_extra) + if not used_extra[0]: + break + depth += 1 + if depth == GS.MAXDEPTH: + logger.warning(W_MAXDEPTH+'Too much nested variables replacements, possible loop ({})'.format(f.value)) + if new_value != f.value: + c.set_field(f.name, new_value) + + +def expand_fields(comps, dont_copy=False): + if not dont_copy: + comps = deepcopy(comps) + env = KiConf.kicad_env + env.update(GS.load_pro_variables()) + for c in comps: + expand_comp_fields(c, env) + return comps + + def preflight_checks(skip_pre, targets): logger.debug("Preflight checks") diff --git a/kibot/out_bom.py b/kibot/out_bom.py index bbcb6d393..104660b45 100644 --- a/kibot/out_bom.py +++ b/kibot/out_bom.py @@ -26,7 +26,7 @@ from .optionable import Optionable, BaseOptions from .registrable import RegOutput from .error import KiPlotConfigurationError -from .kiplot import get_board_comps_data, load_any_sch, register_xmp_import +from .kiplot import get_board_comps_data, load_any_sch, register_xmp_import, expand_fields from .kicad.v5_sch import SchematicComponent, SchematicField from .bom.columnlist import ColumnList, BoMError from .bom.bom import do_bom @@ -867,7 +867,7 @@ def aggregate_comps(self, comps): prj.sch = load_any_sch(prj.file, prj.name) else: prj.sch = self.load_csv(prj.file, prj.name, prj.delimiter) - new_comps = prj.sch.get_components() + new_comps = expand_fields(prj.sch.get_components(), dont_copy=True) for c in new_comps: c.ref = prj.ref_id+c.ref c.ref_id = prj.ref_id @@ -889,7 +889,8 @@ def run(self, output): self.kicad_version = GS.kicad_version self.conv_units = GS.unit_name_to_scale_factor(self.units) # Get the components list from the schematic - comps = GS.sch.get_components() + # We use a copy because we could expand the field values using ${VAR} + comps = expand_fields(GS.sch.get_components()) get_board_comps_data(comps) if self.count_smd_tht and not GS.pcb_file: logger.warning(W_NEEDSPCB+"`count_smd_tht` is enabled, but no PCB provided") diff --git a/tests/board_samples/kicad_5/merge_2.sch b/tests/board_samples/kicad_5/merge_2.sch index 1b8da3606..a95317558 100644 --- a/tests/board_samples/kicad_5/merge_2.sch +++ b/tests/board_samples/kicad_5/merge_2.sch @@ -18,10 +18,11 @@ L Device:R R1 U 1 1 60116835 P 2500 1900 F 0 "R1" H 2570 1946 50 0000 L CNN -F 1 "10k" H 2570 1855 50 0000 L CNN +F 1 "${resistance}" H 2570 1855 50 0000 L CNN F 2 "" V 2430 1900 50 0001 C CNN F 3 "~" H 2500 1900 50 0001 C CNN F 4 "RC0805JR-0710KL" H 2100 1700 50 0001 C CNN "manf#" +F 5 "10k" H 2100 1700 50 0001 C CNN "resistance" 1 2500 1900 1 0 0 -1 $EndComp diff --git a/tests/board_samples/kicad_7/merge_1.kicad_sch b/tests/board_samples/kicad_7/merge_1.kicad_sch index d9c996b6b..a31d447f8 100644 --- a/tests/board_samples/kicad_7/merge_1.kicad_sch +++ b/tests/board_samples/kicad_7/merge_1.kicad_sch @@ -138,7 +138,7 @@ (property "Reference" "R2" (at 77.978 47.0916 0) (effects (font (size 1.27 1.27)) (justify left)) ) - (property "Value" "1k" (at 77.978 49.403 0) + (property "Value" "${resistance}" (at 77.978 49.403 0) (effects (font (size 1.27 1.27)) (justify left)) ) (property "Footprint" "" (at 74.422 48.26 90) @@ -150,6 +150,15 @@ (property "manf#" "RC0805JR-071KL" (at 53.34 53.34 0) (effects (font (size 1.27 1.27)) hide) ) + (property "resistance" "${mag}${mult}" (at 53.34 53.34 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "mag" "1" (at 53.34 53.34 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "mult" "k" (at 53.34 53.34 0) + (effects (font (size 1.27 1.27)) hide) + ) (pin "1" (uuid ddf0cbdf-337f-4f75-b87c-643f7eb59917)) (pin "2" (uuid 49265804-0096-4217-9537-f218fbd69c52)) (instances