Added variants suport to out_position

Also: we never include virtual components.
This commit is contained in:
Salvador E. Tropea 2020-09-02 18:08:50 -03:00
parent 5e11b325a1
commit 26ee971e26
5 changed files with 145 additions and 3 deletions

View File

@ -827,11 +827,14 @@ Next time you need this list just use an alias, like this:
- `name`: [string=''] Used to identify this particular output definition.
- `options`: [dict] Options for the `position` output.
* Valid keys:
- `dnf_filter`: [string|list(string)=''] Name of the filter to mark components as not fitted.
A short-cut to use for simple cases where a variant is an overkill.
- `format`: [string='ASCII'] [ASCII,CSV] format for the position file.
- `only_smd`: [boolean=true] only include the surface mount components.
- `output`: [string='%f-%i%v.%x'] output file name (%i='top_pos'|'bottom_pos'|'both_pos', %x='pos'|'csv'). Affected by global options.
- `separate_files_for_front_and_back`: [boolean=true] generate two separated files, one for the top and another for the bottom.
- `units`: [string='millimeters'] [millimeters,inches] units used for the positions.
- `variant`: [string=''] Board variant(s) to apply.
* PS (Postscript)
* Type: `ps`

View File

@ -634,6 +634,9 @@ outputs:
type: 'position'
dir: 'Example/position_dir'
options:
# [string|list(string)=''] Name of the filter to mark components as not fitted.
# A short-cut to use for simple cases where a variant is an overkill
dnf_filter: ''
# [string='ASCII'] [ASCII,CSV] format for the position file
format: 'ASCII'
# [boolean=true] only include the surface mount components
@ -644,6 +647,8 @@ outputs:
separate_files_for_front_and_back: true
# [string='millimeters'] [millimeters,inches] units used for the positions
units: 'millimeters'
# [string=''] Board variant(s) to apply
variant: ''
# PS (Postscript):
# This output is what you get from the File/Plot menu in pcbnew.

View File

@ -8,9 +8,19 @@
import operator
from datetime import datetime
from pcbnew import (IU_PER_MM, IU_PER_MILS)
from .optionable import BaseOptions
from .optionable import BaseOptions, Optionable
from .registrable import RegOutput
from .gs import GS
from .kiplot import load_sch
from .macros import macros, document, output_class # noqa: F401
from .fil_base import BaseFilter, apply_fitted_filter
from . import log
logger = log.get_logger(__name__)
# KiCad 5 GUI values for the attribute
UI_THT = 0
UI_SMD = 1
UI_VIRTUAL = 2
class PositionOptions(BaseOptions):
@ -26,8 +36,18 @@ class PositionOptions(BaseOptions):
""" output file name (%i='top_pos'|'bottom_pos'|'both_pos', %x='pos'|'csv') """
self.units = 'millimeters'
""" [millimeters,inches] units used for the positions """
self.variant = ''
""" Board variant(s) to apply """
self.dnf_filter = Optionable
""" [string|list(string)=''] Name of the filter to mark components as not fitted.
A short-cut to use for simple cases where a variant is an overkill """
super().__init__()
def config(self):
super().config()
self.variant = RegOutput.check_variant(self.variant)
self.dnf_filter = BaseFilter.solve_filter(self.dnf_filter, 'dnf_filter')
def _do_position_plot_ascii(self, board, output_dir, columns, modulesStr, maxSizes):
topf = None
botf = None
@ -120,6 +140,18 @@ class PositionOptions(BaseOptions):
bothf.close()
def run(self, output_dir, board):
comps = None
if self.dnf_filter or self.variant:
load_sch()
# Get the components list from the schematic
comps = GS.sch.get_components()
# Apply the filter
apply_fitted_filter(comps, self.dnf_filter)
# Apply the variant
if self.variant:
# Apply the variant
self.variant.filter(comps)
comps_hash = {c.ref: c for c in comps}
columns = ["Ref", "Val", "Package", "PosX", "PosY", "Rot", "Side"]
colcount = len(columns)
# Note: the parser already checked the units are milimeters or inches
@ -131,12 +163,22 @@ class PositionOptions(BaseOptions):
# Format all strings
modules = []
for m in sorted(board.GetModules(), key=operator.methodcaller('GetReference')):
if (self.only_smd and m.GetAttributes() == 1) or not self.only_smd:
ref = m.GetReference()
# Apply any filter or variant data
if comps:
c = comps_hash.get(ref, None)
if c:
logger.debug("{} {} {}".format(ref, c.fitted, c.in_bom))
if c and not c.fitted:
continue
# If passed check the position options
if (self.only_smd and m.GetAttributes() == UI_SMD) or \
(not self.only_smd and m.GetAttributes() != UI_VIRTUAL):
center = m.GetCenter()
# See PLACE_FILE_EXPORTER::GenPositionData() in
# export_footprints_placefile.cpp for C++ version of this.
modules.append([
"{}".format(m.GetReference()),
"{}".format(ref),
"{}".format(m.GetValue()),
"{}".format(m.GetFPID().GetLibItemName()),
"{:.4f}".format(center.x * conv),

View File

@ -20,6 +20,7 @@ pytest-3 --log-cli-level debug
import os
import sys
import logging
# Look for the 'utils' module from where the script is running
prev_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if prev_dir not in sys.path:
@ -145,3 +146,26 @@ def test_3Rs_position_inches_csv():
expect_position(ctx, pos_top, ['R1'], ['R2', 'R3'], inches=True, csv=True)
expect_position(ctx, pos_bot, ['R2'], ['R1', 'R3'], inches=True, csv=True)
ctx.clean_up()
def check_comps(rows, comps):
assert len(rows) == len(comps)
logging.debug('{} components OK'.format(len(rows)))
col1 = [r[0] for r in rows]
assert col1 == comps
logging.debug('Components list {} OK'.format(comps))
def test_position_variant_t2i():
prj = 'kibom-variant_3'
ctx = context.TestContext('test_position_variant_t2i', prj, 'simple_position_t2i', POS_DIR)
ctx.run()
rows, header, info = ctx.load_csv(prj+'-both_pos.csv')
check_comps(rows, ['R1', 'R2', 'R3'])
rows, header, info = ctx.load_csv(prj+'-both_pos_[2].csv')
check_comps(rows, ['R1', 'R2', 'R3'])
rows, header, info = ctx.load_csv(prj+'-both_pos_(production).csv')
check_comps(rows, ['C2', 'R1', 'R2', 'R3'])
rows, header, info = ctx.load_csv(prj+'-both_pos_(test).csv')
check_comps(rows, ['C2', 'R1', 'R3'])
ctx.clean_up()

View File

@ -0,0 +1,68 @@
# Example KiBot config file
kibot:
version: 1
variants:
- name: 'production'
comment: 'Production variant'
type: ibom
file_id: '_(production)'
variants_blacklist: T2
- name: 'test'
comment: 'Test variant'
type: ibom
file_id: '_(test)'
variants_blacklist: T1
- name: 'default'
comment: 'Default variant'
type: ibom
variants_blacklist: T2,T3
- name: 'default2'
comment: 'Default variant 2'
type: ibom
file_id: '_[2]'
variants_whitelist: T1, Default
outputs:
- name: 'bom_internal'
comment: "Bill of Materials in CSV format"
type: position
dir: positiondir
options:
format: CSV
separate_files_for_front_and_back: false
only_smd: false
variant: default
- name: 'bom_internal2'
comment: "Bill of Materials in CSV format (2)"
type: position
dir: positiondir
options:
format: CSV
separate_files_for_front_and_back: false
only_smd: false
variant: default2
- name: 'bom_internal_production'
comment: "Bill of Materials in CSV format for production"
type: position
dir: positiondir
options:
format: CSV
separate_files_for_front_and_back: false
only_smd: false
variant: production
- name: 'bom_internal_test'
comment: "Bill of Materials in CSV format for test"
type: position
dir: positiondir
options:
format: CSV
separate_files_for_front_and_back: false
only_smd: false
variant: test