[Copy_Files] Now you can copy the 3D models

- Also save a PCB modified to use them
- Changed the syntax so we can copy other stuff
This commit is contained in:
Salvador E. Tropea 2022-09-20 13:13:12 -03:00
parent 39eabd996f
commit e2fdf87d6b
17 changed files with 798 additions and 72 deletions

View File

@ -20,7 +20,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
import). (#296)
- New outputs:
- PCB_Variant: saves a PCB with filters and variants applied.
- File_Copy: used to copy files to the output directory. (#279)
- Copy_Files: used to copy files to the output directory. (#279)
You can also copy the 3D models.
- Support for Eurocircuits drill adjust to fix small OARs.
Option `eurocircuits_reduce_holes`. (#227)
- Global options:

View File

@ -1611,18 +1611,32 @@ Notes:
- **`name`**: [string=''] Used to identify this particular output definition.
- **`options`**: [dict] Options for the `copy_files` output.
* Valid keys:
- **`download`**: [boolean=true] Downloads missing 3D models from KiCad git. Only applies to models in KISYS3DMOD.
- **`files`**: [list(dict)] Which files will be included.
* Valid keys:
- **`from_output`**: [string=''] Collect files from the selected output.
When used the `source` option is ignored.
- **`source`**: [string='*'] File names to add, wildcards allowed. Use ** for recursive match.
By default this pattern is applied to the current working dir.
See the `from_outdir` option.
- `dest`: [string=''] Destination directory inside the output dir, empty means the same of the file.
- **`source_type`**: [string='files'] [files,out_files,output,3d_models] How to interpret `source`.
`files`: is a pattern for files relative to the working directory.
`out_files`: is a pattern for files relative to output dir specified
with `-d` command line option.
`output`: is the name of an `output`.
`3d_models`: is a pattern to match the name of the 3D models extracted
from the PCB..
- `dest`: [string=''] Destination directory inside the output dir, empty means the same of the file
relative to the source directory.
For the `3d_models` type you can use DIR+ to create subdirs under DIR.
- `filter`: [string='.*'] A regular expression that source files must match.
- `from_outdir`: [boolean=false] Use the output dir specified with `-d` command line option, not the working dir.
- `save_pcb`: [boolean=false] Only usable for the `3d_models` mode.
Save a PCB copy modified to use the copied 3D models.
- **`no_virtual`**: [boolean=false] Used to exclude 3D models for components with 'virtual' attribute.
- `dnf_filter`: [string|list(string)='_none'] Name of the filter to mark components as not fitted.
A short-cut to use for simple cases where a variant is an overkill.
- `follow_links`: [boolean=true] Store the file pointed by symlinks, not the symlink.
- `kicad_3d_url`: [string='https://gitlab.com/kicad/libraries/kicad-packages3D/-/raw/master/'] Base URL for the KiCad 3D models.
- `link_no_copy`: [boolean=false] Create symlinks instead of copying files.
- `variant`: [string=''] Board variant to apply.
- `category`: [string|list(string)=''] The category for this output. If not specified an internally defined category is used.
Categories looks like file system paths, i.e. PCB/fabrication/gerber.
- `disable_run_by_default`: [string|boolean] Use it to disable the `run_by_default` status of other output.

View File

@ -426,25 +426,44 @@ outputs:
type: 'copy_files'
dir: 'Example/copy_files_dir'
options:
# [string|list(string)='_none'] 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: '_none'
# [boolean=true] Downloads missing 3D models from KiCad git. Only applies to models in KISYS3DMOD
download: true
# [list(dict)] Which files will be included
files:
# [string=''] Destination directory inside the output dir, empty means the same of the file
# relative to the source directory.
# For the `3d_models` type you can use DIR+ to create subdirs under DIR
- dest: ''
# [string='.*'] A regular expression that source files must match
filter: '.*'
# [boolean=false] Use the output dir specified with `-d` command line option, not the working dir
from_outdir: false
# [string=''] Collect files from the selected output.
# When used the `source` option is ignored
from_output: ''
# [boolean=false] Only usable for the `3d_models` mode.
# Save a PCB copy modified to use the copied 3D models
save_pcb: false
# [string='*'] File names to add, wildcards allowed. Use ** for recursive match.
# By default this pattern is applied to the current working dir.
# See the `from_outdir` option
source: '*'
# [string='files'] [files,out_files,output,3d_models] How to interpret `source`.
# `files`: is a pattern for files relative to the working directory.
# `out_files`: is a pattern for files relative to output dir specified
# with `-d` command line option.
# `output`: is the name of an `output`.
# `3d_models`: is a pattern to match the name of the 3D models extracted
# from the PCB.
source_type: 'files'
# [boolean=true] Store the file pointed by symlinks, not the symlink
follow_links: true
# [string='https://gitlab.com/kicad/libraries/kicad-packages3D/-/raw/master/'] Base URL for the KiCad 3D models
kicad_3d_url: 'https://gitlab.com/kicad/libraries/kicad-packages3D/-/raw/master/'
# [boolean=false] Create symlinks instead of copying files
link_no_copy: false
# [boolean=false] Used to exclude 3D models for components with 'virtual' attribute
no_virtual: false
# [string=''] Board variant to apply
variant: ''
# Diff:
# Recursive git submodules aren't supported (submodules inside submodules)
- name: 'diff_example'

View File

@ -44,8 +44,8 @@ class Environment(Optionable):
if self.symbols:
defs['KICAD_SYMBOL_DIR'] = self.symbols
if self.footprints:
defs['KICAD_FOOTPRINT_DIR'] = self.symbols
defs['KISYSMOD'] = self.symbols
defs['KICAD_FOOTPRINT_DIR'] = self.footprints
defs['KISYSMOD'] = self.footprints
if self.models_3d:
defs['KISYS3DMOD'] = self.models_3d
if self.templates:
@ -57,7 +57,7 @@ class Environment(Optionable):
if self.symbols:
defs['KICAD6_SYMBOL_DIR'] = self.symbols
if self.footprints:
defs['KICAD6_FOOTPRINT_DIR'] = self.symbols
defs['KICAD6_FOOTPRINT_DIR'] = self.footprints
if self.models_3d:
defs['KICAD6_3DMODEL_DIR'] = self.models_3d
if self.templates:

View File

@ -145,6 +145,8 @@ class KiConf(object):
sym_lib_dir = None
template_dir = None
footprint_dir = None
models_3d_dir = None
party_3rd_dir = None
kicad_env = {}
lib_aliases = {}
aliases_3D = {}
@ -399,6 +401,7 @@ class KiConf(object):
os.environ[old] = val
else:
logger.warning(W_NOLIBS + 'Unable to find KiCad '+desc)
return val
def load_kicad_common():
# Try to figure out KiCad configuration file
@ -583,11 +586,13 @@ class KiConf(object):
return KiConf.fix_page_layout_k5(project, dry)
return KiConf.fix_page_layout_k6(project, dry)
def expand_env(name, used_extra=None):
def expand_env(name, used_extra=None, ref_dir=None):
if used_extra is None:
used_extra = [False]
if not name:
return name
expanded = expand_env(un_quote(name), KiConf.kicad_env, GS.load_pro_variables(), used_extra)
# Don't try to get the absolute path for something that starts with a variable that we couldn't expand
return expanded if expanded.startswith('${') else os.path.abspath(expanded)
if ref_dir is None:
ref_dir = os.getcwd()
return expanded if expanded.startswith('${') else os.path.normpath(os.path.join(ref_dir, expanded))

View File

@ -232,6 +232,7 @@ W_MAXDEPTH = '(W096) '
W_3DRESVER = '(W097) '
W_DOWN3D = '(W098) '
W_MISSREF = '(W099) '
W_COPYOVER = '(W100) '
# Somehow arbitrary, the colors are real, but can be different
PCB_MAT_COLORS = {'fr1': "937042", 'fr2': "949d70", 'fr3': "adacb4", 'fr4': "332B16", 'fr5': "6cc290"}
PCB_FINISH_COLORS = {'hal': "8b898c", 'hasl': "8b898c", 'imag': "8b898c", 'enig': "cfb96e", 'enepig': "cfb96e",

View File

@ -3,6 +3,7 @@
# Copyright (c) 2020-2022 Instituto Nacional de Tecnología Industrial
# License: GPL-3.0
# Project: KiBot (formerly KiPlot)
from fnmatch import fnmatch
import os
import requests
import tempfile
@ -30,7 +31,7 @@ def do_expand_env(fname, used_extra, extra_debug):
force_used_extra = True
if extra_debug:
logger.debug("- Replaced alias {} -> {}".format(alias_name+':'+rest, fname))
full_name = KiConf.expand_env(fname, used_extra)
full_name = KiConf.expand_env(fname, used_extra, ref_dir=GS.pcb_dir)
if extra_debug:
logger.debug("- Expanded {} -> {}".format(fname, full_name))
if os.path.isfile(full_name) or ':' not in fname or GS.global_disable_3d_alias_as_env:
@ -64,15 +65,20 @@ class Base3DOptions(VariantOptions):
super().__init__()
self._expand_id = '3D'
def download_model(self, url, fname):
def download_model(self, url, fname, rel_dirs):
""" Download the 3D model from the provided URL """
logger.debug('Downloading `{}`'.format(url))
r = requests.get(url, allow_redirects=True)
if r.status_code != 200:
failed = False
try:
r = requests.get(url, allow_redirects=True)
except Exception:
failed = True
if failed or r.status_code != 200:
logger.warning(W_FAILDL+'Failed to download `{}`'.format(url))
return None
if self._tmp_dir is None:
self._tmp_dir = tempfile.mkdtemp()
rel_dirs.append(self._tmp_dir)
logger.debug('Using `{}` as temporal dir for downloaded files'.format(self._tmp_dir))
dest = os.path.join(self._tmp_dir, fname)
os.makedirs(os.path.dirname(dest), exist_ok=True)
@ -80,7 +86,7 @@ class Base3DOptions(VariantOptions):
f.write(r.content)
return dest
def download_models(self):
def download_models(self, rename_filter=None, rename_function=None, rename_data=None):
""" Check we have the 3D models.
Inform missing models.
Try to download the missing models
@ -90,6 +96,10 @@ class Base3DOptions(VariantOptions):
KiConf.init(GS.pcb_file)
# List of models we already downloaded
downloaded = set()
# For the mode where we copy the 3D models
source_models = set()
is_copy_mode = rename_filter is not None
rel_dirs = getattr(rename_data, 'rel_dirs', [])
extra_debug = GS.debug_level > 3
# Look for all the footprints
for m in GS.get_modules():
@ -106,9 +116,13 @@ class Base3DOptions(VariantOptions):
if extra_debug:
logger.debug("- Skipping {} (disabled)".format(m3d.m_Filename))
continue
if is_copy_mode and not fnmatch(m3d.m_Filename, rename_filter):
# Skip filtered footprints
continue
used_extra = [False]
full_name = do_expand_env(m3d.m_Filename, used_extra, extra_debug)
if not os.path.isfile(full_name):
logger.debugl(2, 'Missing 3D model file {} ({})'.format(full_name, m3d.m_Filename))
# Missing 3D model
if self.download and (m3d.m_Filename.startswith('${KISYS3DMOD}/') or
m3d.m_Filename.startswith('${KICAD6_3DMODEL_DIR}/')):
@ -121,26 +135,33 @@ class Base3DOptions(VariantOptions):
else:
# Download the model
url = self.kicad_3d_url+fname
replace = self.download_model(url, fname)
replace = self.download_model(url, fname, rel_dirs)
if replace:
# Successfully downloaded
downloaded.add(full_name)
self.undo_3d_models[replace] = m3d.m_Filename
# If this is a .wrl also download the .step
if url.endswith('.wrl'):
url = url[:-4]+'.step'
fname = fname[:-4]+'.step'
self.download_model(url, fname)
self.download_model(url, fname, rel_dirs)
if replace:
m3d.m_Filename = replace
source_models.add(replace)
old_name = m3d.m_Filename
new_name = replace if not is_copy_mode else rename_function(rename_data, replace)
self.undo_3d_models[new_name] = old_name
m3d.m_Filename = new_name
models_replaced = True
if full_name not in downloaded:
logger.warning(W_MISS3D+'Missing 3D model for {}: `{}`'.format(ref, full_name))
else: # File was found
if used_extra[0]:
if used_extra[0] or is_copy_mode:
# The file is there, but we got it expanding a user defined text
# This is completely valid for KiCad, but kicad2step doesn't support it
m3d.m_Filename = full_name
source_models.add(full_name)
old_name = m3d.m_Filename
new_name = full_name if not is_copy_mode else rename_function(rename_data, full_name)
self.undo_3d_models[new_name] = old_name
m3d.m_Filename = new_name
if not models_replaced and extra_debug:
logger.debug('- Modifying models with text vars')
models_replaced = True
@ -149,7 +170,7 @@ class Base3DOptions(VariantOptions):
models.push_front(model)
if downloaded:
logger.warning(W_DOWN3D+' {} 3D models downloaded'.format(len(downloaded)))
return models_replaced
return models_replaced if not is_copy_mode else list(source_models)
def list_models(self):
""" Get the list of 3D models """

View File

@ -3,17 +3,19 @@
# Copyright (c) 2022 Instituto Nacional de Tecnología Industrial
# License: GPL-3.0
# Project: KiBot (formerly KiPlot)
from collections import OrderedDict
import fnmatch
import glob
import os
import re
from shutil import copy2
from shutil import copy2, rmtree
from sys import exit
from .error import KiPlotConfigurationError
from .gs import GS
from .kiplot import config_output, get_output_dir, run_output
from .misc import WRONG_ARGUMENTS, INTERNAL_ERROR
from .optionable import Optionable, BaseOptions
from .kicad.config import KiConf
from .misc import WRONG_ARGUMENTS, INTERNAL_ERROR, W_COPYOVER
from .optionable import Optionable
from .out_base_3d import Base3DOptions
from .registrable import RegOutput
from .macros import macros, document, output_class # noqa: F401
from . import log
@ -21,6 +23,13 @@ from . import log
logger = log.get_logger()
def may_be_rel(file):
rel_file = os.path.relpath(file)
if len(rel_file) < len(file):
return rel_file
return file
class FilesList(Optionable):
def __init__(self):
super().__init__()
@ -29,18 +38,43 @@ class FilesList(Optionable):
""" *File names to add, wildcards allowed. Use ** for recursive match.
By default this pattern is applied to the current working dir.
See the `from_outdir` option """
self.from_outdir = False
""" Use the output dir specified with `-d` command line option, not the working dir """
self.from_output = ''
""" *Collect files from the selected output.
When used the `source` option is ignored """
self.source_type = 'files'
""" *[files,out_files,output,3d_models] How to interpret `source`.
`files`: is a pattern for files relative to the working directory.
`out_files`: is a pattern for files relative to output dir specified
with `-d` command line option.
`output`: is the name of an `output`.
`3d_models`: is a pattern to match the name of the 3D models extracted
from the PCB. """
self.filter = '.*'
""" A regular expression that source files must match """
self.dest = ''
""" Destination directory inside the output dir, empty means the same of the file """
""" Destination directory inside the output dir, empty means the same of the file
relative to the source directory.
For the `3d_models` type you can use DIR+ to create subdirs under DIR """
self.save_pcb = False
""" Only usable for the `3d_models` mode.
Save a PCB copy modified to use the copied 3D models """
def apply_rename(self, fname):
is_abs = os.path.isabs(fname)
append_mode = self.dest and self.dest[-1] == '+'
if self.dest and not append_mode:
# A destination specified by the user
dest = os.path.basename(fname)
elif is_abs:
for d in self.rel_dirs:
if d is not None and fname.startswith(d):
dest = os.path.relpath(fname, d)
break
else:
dest = os.path.basename(fname)
else:
dest = os.path.relpath(fname, os.getcwd())
return os.path.join(self.output_dir, dest)
class Copy_FilesOptions(BaseOptions):
class Copy_FilesOptions(Base3DOptions):
def __init__(self):
with document:
self.files = FilesList
@ -58,38 +92,88 @@ class Copy_FilesOptions(BaseOptions):
if isinstance(self.files, type):
KiPlotConfigurationError('No files provided')
def get_from_output(self, f, no_out_run):
from_output = f.source
logger.debugl(2, '- From output `{}`'.format(from_output))
out = RegOutput.get_output(from_output)
if out is not None:
config_output(out)
out_dir = get_output_dir(out.dir, out, dry=True)
files_list = out.get_targets(out_dir)
logger.debugl(2, '- List of files: {}'.format(files_list))
else:
logger.error('Unknown output `{}` selected in {}'.format(from_output, self._parent))
exit(WRONG_ARGUMENTS)
# Check if we must run the output to create the files
if not no_out_run:
for file in files_list:
if not os.path.isfile(file):
# The target doesn't exist
if not out._done:
# The output wasn't created in this run, try running it
run_output(out)
if not os.path.isfile(file):
# Still missing, something is wrong
logger.error('Unable to generate `{}` from {}'.format(file, out))
exit(INTERNAL_ERROR)
return files_list
def get_3d_models(self, f):
""" Look for the 3D models and make a list, optionally download them """
GS.check_pcb()
dest_dir = f.dest
if dest_dir and dest_dir[-1] == '+':
dest_dir = dest_dir[:-1]
f.output_dir = dest_dir
# Apply any variant
self.filter_pcb_components(GS.board, do_3D=True, do_2D=True)
# Download missing models and rename all collect 3D models (renamed)
f.rel_dirs = self.rel_dirs
files_list = self.download_models(rename_filter=f.source, rename_function=FilesList.apply_rename, rename_data=f)
if f.save_pcb:
fname = os.path.join(self.output_dir, os.path.basename(GS.pcb_file))
logger.debug('Saving the PCB to '+fname)
GS.board.Save(fname)
GS.copy_project(fname)
if not self._comps:
# We must undo the download/rename
self.undo_3d_models_rename(GS.board)
else:
self.unfilter_pcb_components(GS.board, do_3D=True, do_2D=True)
# Also include the step/wrl counterpart
new_list = []
for fn in files_list:
if fn.endswith('.wrl'):
fn = fn[:-4]+'.step'
if os.path.isfile(fn):
new_list.append(fn)
elif fn.endswith('.step'):
fn = f[:-5]+'.wrl'
if os.path.isfile(fn):
new_list.append(fn)
return files_list+fnmatch.filter(new_list, f.source)
def get_files(self, no_out_run=False):
files = OrderedDict()
files = []
src_dir_cwd = os.getcwd()
src_dir_outdir = self.expand_filename_sch(GS.out_dir)
self.rel_dirs = [os.path.normpath(os.path.join(GS.pcb_dir, KiConf.models_3d_dir)),
os.path.normpath(os.path.join(GS.pcb_dir, KiConf.party_3rd_dir)),
GS.pcb_dir]
for f in self.files:
src_dir = src_dir_outdir if f.from_outdir else src_dir_cwd
from_outdir = False
if f.source_type == 'out_files' or f.source_type == 'output':
from_outdir = True
src_dir = src_dir_outdir if from_outdir else src_dir_cwd
mode_3d = f.source_type == '3d_models'
mode_3d_append = mode_3d and f.dest and f.dest[-1] == '+'
# Get the list of candidates
files_list = None
if f.from_output:
logger.debugl(2, '- From output `{}`'.format(f.from_output))
out = RegOutput.get_output(f.from_output)
if out is not None:
config_output(out)
out_dir = get_output_dir(out.dir, out, dry=True)
files_list = out.get_targets(out_dir)
logger.debugl(2, '- List of files: {}'.format(files_list))
else:
logger.error('Unknown output `{}` selected in {}'.format(f.from_output, self._parent))
exit(WRONG_ARGUMENTS)
# Check if we must run the output to create the files
if not no_out_run:
for file in files_list:
if not os.path.isfile(file):
# The target doesn't exist
if not out._done:
# The output wasn't created in this run, try running it
run_output(out)
if not os.path.isfile(file):
# Still missing, something is wrong
logger.error('Unable to generate `{}` from {}'.format(file, out))
exit(INTERNAL_ERROR)
else:
if f.source_type == 'output':
files_list = self.get_from_output(f, no_out_run)
elif mode_3d:
files_list = self.get_3d_models(f)
else: # files and out_files
source = f.expand_filename_both(f.source, make_safe=False)
files_list = glob.iglob(os.path.join(src_dir, source), recursive=True)
if GS.debug_level > 1:
@ -100,11 +184,25 @@ class Copy_FilesOptions(BaseOptions):
fname_real = os.path.realpath(fname) if self.follow_links else os.path.abspath(fname)
# Compute the destination directory
dest = fname
if f.dest:
is_abs = os.path.isabs(fname)
if f.dest and not mode_3d_append:
# A destination specified by the user
dest = os.path.join(f.dest, os.path.basename(fname))
elif mode_3d and is_abs:
for d in self.rel_dirs:
if d is not None and fname.startswith(d):
dest = os.path.relpath(dest, d)
break
else:
logger.error(fname)
logger.error(self.rel_dirs)
dest = os.path.basename(fname)
if mode_3d_append:
dest = os.path.join(f.dest[:-1], dest)
else:
dest = os.path.relpath(dest, src_dir)
files[fname_real] = dest
files.append((fname_real, dest))
return files
def get_targets(self, out_dir):
@ -122,19 +220,27 @@ class Copy_FilesOptions(BaseOptions):
files = self.get_files()
logger.debug('Copying files')
output += os.path.sep
for k, v in files.items():
src = k
dest = os.path.join(output, v)
copied = {}
for (src, dst) in files:
dest = os.path.join(output, dst)
dest_dir = os.path.dirname(dest)
if not os.path.isdir(dest_dir):
os.makedirs(dest_dir)
logger.debug('- {} -> {}'.format(src, dest))
if dest in copied:
logger.warning(W_COPYOVER+'`{}` and `{}` both are copied to `{}`'.
format(may_be_rel(src), may_be_rel(copied[dest]), may_be_rel(dest)))
if os.path.isfile(dest) or os.path.islink(dest):
os.remove(dest)
if self.link_no_copy:
os.symlink(os.path.relpath(src, os.path.dirname(dest)), dest)
else:
copy2(src, dest)
copied[dest] = src
# Remove the downloaded 3D models
if self._tmp_dir:
rmtree(self._tmp_dir)
self._tmp_dir = None
@output_class
@ -159,4 +265,5 @@ class Copy_Files(BaseOutput): # noqa: F821
def run(self, output_dir):
# No output member, just a dir
self.options.output_dir = output_dir
self.options.run(output_dir)

View File

@ -40,6 +40,7 @@ class Download_Datasheets_Options(VariantOptions):
""" Instead of download things we already downloaded use symlinks """
# Used to collect the targets
self._dry = False
self._unkown_is_error = True
def config(self, parent):
super().config(parent)

View File

@ -111,7 +111,8 @@ class PositionOptions(VariantOptions):
topf = open(topf_name, 'w')
botf = open(botf_name, 'w')
else:
bothf = open(self.expand_filename(output_dir, self.output, 'both_pos', 'pos'), 'w')
fname = self.expand_filename(output_dir, self.output, 'both_pos', 'pos')
bothf = open(fname, 'w')
files = [f for f in [topf, botf, bothf] if f is not None]
for f in files:

View File

@ -0,0 +1 @@
Hola!

View File

@ -0,0 +1 @@
Chau!

View File

@ -0,0 +1,411 @@
(kicad_pcb (version 20211014) (generator pcbnew)
(general
(thickness 1.6)
)
(paper "A4")
(layers
(0 "F.Cu" signal)
(31 "B.Cu" signal)
(32 "B.Adhes" user "B.Adhesive")
(33 "F.Adhes" user "F.Adhesive")
(34 "B.Paste" user)
(35 "F.Paste" user)
(36 "B.SilkS" user "B.Silkscreen")
(37 "F.SilkS" user "F.Silkscreen")
(38 "B.Mask" user)
(39 "F.Mask" user)
(40 "Dwgs.User" user "User.Drawings")
(41 "Cmts.User" user "User.Comments")
(42 "Eco1.User" user "User.Eco1")
(43 "Eco2.User" user "User.Eco2")
(44 "Edge.Cuts" user)
(45 "Margin" user)
(46 "B.CrtYd" user "B.Courtyard")
(47 "F.CrtYd" user "F.Courtyard")
(48 "B.Fab" user)
(49 "F.Fab" user)
)
(setup
(pad_to_mask_clearance 0)
(pcbplotparams
(layerselection 0x00010fc_ffffffff)
(disableapertmacros false)
(usegerberextensions false)
(usegerberattributes true)
(usegerberadvancedattributes true)
(creategerberjobfile true)
(svguseinch false)
(svgprecision 6)
(excludeedgelayer true)
(plotframeref false)
(viasonmask false)
(mode 1)
(useauxorigin false)
(hpglpennumber 1)
(hpglpenspeed 20)
(hpglpendiameter 15.000000)
(dxfpolygonmode true)
(dxfimperialunits true)
(dxfusepcbnewfont true)
(psnegative false)
(psa4output false)
(plotreference true)
(plotvalue true)
(plotinvisibletext false)
(sketchpadsonfab false)
(subtractmaskfromsilk false)
(outputformat 1)
(mirror false)
(drillshape 1)
(scaleselection 1)
(outputdirectory "")
)
)
(net 0 "")
(net 1 "Net-(C1-Pad2)")
(net 2 "Net-(C1-Pad1)")
(net 3 "Net-(C2-Pad2)")
(net 4 "Net-(C2-Pad1)")
(net 5 "Net-(C3-Pad2)")
(net 6 "Net-(C3-Pad1)")
(net 7 "Net-(C4-Pad2)")
(net 8 "Net-(C4-Pad1)")
(net 9 "Net-(R1-Pad2)")
(net 10 "Net-(R1-Pad1)")
(net 11 "Net-(R2-Pad2)")
(net 12 "Net-(R2-Pad1)")
(net 13 "Net-(R3-Pad2)")
(net 14 "Net-(R3-Pad1)")
(net 15 "Net-(R4-Pad2)")
(net 16 "Net-(R4-Pad1)")
(footprint "Capacitor_SMD:C_0805_2012Metric" (layer "F.Cu")
(tedit 5F68FEEE) (tstamp 00000000-0000-0000-0000-00006223ab1c)
(at 128.25 93 90)
(descr "Capacitor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC_7351 nominal, (Body size source: IPC-SM-782 page 76, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf, https://docs.google.com/spreadsheets/d/1BsfQQcO9C6DZCsRaXUlFlo91Tg2WpOkGARC1WS5S8t0/edit?usp=sharing), generated with kicad-footprint-generator")
(tags "capacitor")
(path "/00000000-0000-0000-0000-00006223ba95")
(attr smd)
(fp_text reference "C1" (at -1 -1.68 90) (layer "F.SilkS")
(effects (font (size 1 1) (thickness 0.15)))
(tstamp 48ab88d7-7084-4d02-b109-3ad55a30bb11)
)
(fp_text value "1u" (at 0 1.68 90) (layer "F.Fab")
(effects (font (size 1 1) (thickness 0.15)))
(tstamp f71da641-16e6-4257-80c3-0b9d804fee4f)
)
(fp_text user "${REFERENCE}" (at 0 0 90) (layer "F.Fab")
(effects (font (size 0.5 0.5) (thickness 0.08)))
(tstamp fd470e95-4861-44fe-b1e4-6d8a7c66e144)
)
(fp_line (start -0.261252 0.735) (end 0.261252 0.735) (layer "F.SilkS") (width 0.12) (tstamp c41b3c8b-634e-435a-b582-96b83bbd4032))
(fp_line (start -0.261252 -0.735) (end 0.261252 -0.735) (layer "F.SilkS") (width 0.12) (tstamp ce83728b-bebd-48c2-8734-b6a50d837931))
(fp_line (start 1.7 -0.98) (end 1.7 0.98) (layer "F.CrtYd") (width 0.05) (tstamp 0f22151c-f260-4674-b486-4710a2c42a55))
(fp_line (start -1.7 -0.98) (end 1.7 -0.98) (layer "F.CrtYd") (width 0.05) (tstamp 1831fb37-1c5d-42c4-b898-151be6fca9dc))
(fp_line (start -1.7 0.98) (end -1.7 -0.98) (layer "F.CrtYd") (width 0.05) (tstamp 9340c285-5767-42d5-8b6d-63fe2a40ddf3))
(fp_line (start 1.7 0.98) (end -1.7 0.98) (layer "F.CrtYd") (width 0.05) (tstamp fe8d9267-7834-48d6-a191-c8724b2ee78d))
(fp_line (start 1 -0.625) (end 1 0.625) (layer "F.Fab") (width 0.1) (tstamp 0eaa98f0-9565-4637-ace3-42a5231b07f7))
(fp_line (start 1 0.625) (end -1 0.625) (layer "F.Fab") (width 0.1) (tstamp 181abe7a-f941-42b6-bd46-aaa3131f90fb))
(fp_line (start -1 -0.625) (end 1 -0.625) (layer "F.Fab") (width 0.1) (tstamp 704d6d51-bb34-4cbf-83d8-841e208048d8))
(fp_line (start -1 0.625) (end -1 -0.625) (layer "F.Fab") (width 0.1) (tstamp 8174b4de-74b1-48db-ab8e-c8432251095b))
(pad "1" smd roundrect locked (at -0.95 0 90) (size 1 1.45) (layers "F.Cu" "F.Paste" "F.Mask") (roundrect_rratio 0.25)
(net 2 "Net-(C1-Pad1)") (tstamp 3cd1bda0-18db-417d-b581-a0c50623df68))
(pad "2" smd roundrect locked (at 0.95 0 90) (size 1 1.45) (layers "F.Cu" "F.Paste" "F.Mask") (roundrect_rratio 0.25)
(net 1 "Net-(C1-Pad2)") (tstamp 0b21a65d-d20b-411e-920a-75c343ac5136))
(model "${KISYS3DMOD}/Resistor_SMD.3dshapes/R_0805_2012Metrico.wrl"
(offset (xyz 0 0 0))
(scale (xyz 1 1 1))
(rotate (xyz 0 0 0))
)
)
(footprint "Capacitor_SMD:C_0805_2012Metric" (layer "F.Cu")
(tedit 5F68FEEE) (tstamp 00000000-0000-0000-0000-00006223ab2d)
(at 133 93.25 90)
(descr "Capacitor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC_7351 nominal, (Body size source: IPC-SM-782 page 76, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf, https://docs.google.com/spreadsheets/d/1BsfQQcO9C6DZCsRaXUlFlo91Tg2WpOkGARC1WS5S8t0/edit?usp=sharing), generated with kicad-footprint-generator")
(tags "capacitor")
(path "/00000000-0000-0000-0000-00006223bc65")
(attr smd)
(fp_text reference "C2" (at 0 -1.68 90) (layer "F.SilkS")
(effects (font (size 1 1) (thickness 0.15)))
(tstamp 3b838d52-596d-4e4d-a6ac-e4c8e7621137)
)
(fp_text value "2u" (at 0 1.68 90) (layer "F.Fab")
(effects (font (size 1 1) (thickness 0.15)))
(tstamp cbdcaa78-3bbc-413f-91bf-2709119373ce)
)
(fp_text user "${REFERENCE}" (at 0 0 90) (layer "F.Fab")
(effects (font (size 0.5 0.5) (thickness 0.08)))
(tstamp 1e1b062d-fad0-427c-a622-c5b8a80b5268)
)
(fp_line (start -0.261252 -0.735) (end 0.261252 -0.735) (layer "F.SilkS") (width 0.12) (tstamp 5038e144-5119-49db-b6cf-f7c345f1cf03))
(fp_line (start -0.261252 0.735) (end 0.261252 0.735) (layer "F.SilkS") (width 0.12) (tstamp ac264c30-3e9a-4be2-b97a-9949b68bd497))
(fp_line (start -1.7 0.98) (end -1.7 -0.98) (layer "F.CrtYd") (width 0.05) (tstamp 54365317-1355-4216-bb75-829375abc4ec))
(fp_line (start -1.7 -0.98) (end 1.7 -0.98) (layer "F.CrtYd") (width 0.05) (tstamp a3e4f0ae-9f86-49e9-b386-ed8b42e012fb))
(fp_line (start 1.7 -0.98) (end 1.7 0.98) (layer "F.CrtYd") (width 0.05) (tstamp a690fc6c-55d9-47e6-b533-faa4b67e20f3))
(fp_line (start 1.7 0.98) (end -1.7 0.98) (layer "F.CrtYd") (width 0.05) (tstamp c144caa5-b0d4-4cef-840a-d4ad178a2102))
(fp_line (start 1 0.625) (end -1 0.625) (layer "F.Fab") (width 0.1) (tstamp 2e642b3e-a476-4c54-9a52-dcea955640cd))
(fp_line (start -1 -0.625) (end 1 -0.625) (layer "F.Fab") (width 0.1) (tstamp 30f15357-ce1d-48b9-93dc-7d9b1b2aa048))
(fp_line (start 1 -0.625) (end 1 0.625) (layer "F.Fab") (width 0.1) (tstamp 87371631-aa02-498a-998a-09bdb74784c1))
(fp_line (start -1 0.625) (end -1 -0.625) (layer "F.Fab") (width 0.1) (tstamp d8603679-3e7b-4337-8dbc-1827f5f54d8a))
(pad "1" smd roundrect locked (at -0.95 0 90) (size 1 1.45) (layers "F.Cu" "F.Paste" "F.Mask") (roundrect_rratio 0.25)
(net 4 "Net-(C2-Pad1)") (tstamp 5fc27c35-3e1c-4f96-817c-93b5570858a6))
(pad "2" smd roundrect locked (at 0.95 0 90) (size 1 1.45) (layers "F.Cu" "F.Paste" "F.Mask") (roundrect_rratio 0.25)
(net 3 "Net-(C2-Pad2)") (tstamp efeac2a2-7682-4dc7-83ee-f6f1b23da506))
(model "${KISYS3DMOD}/Capacitor_SMD.3dshapes/C_0805_2012Metric.wrl"
(offset (xyz 0 0 0))
(scale (xyz 1 1 1))
(rotate (xyz 0 0 0))
)
)
(footprint "Resistor_SMD:R_0805_2012Metric" (layer "F.Cu")
(tedit 5F68FEEE) (tstamp 00000000-0000-0000-0000-00006223ab60)
(at 128.25 99)
(descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC_7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator")
(tags "resistor")
(path "/00000000-0000-0000-0000-00006223a923")
(attr smd)
(fp_text reference "R1" (at 0 -1.65) (layer "F.SilkS")
(effects (font (size 1 1) (thickness 0.15)))
(tstamp a03e565f-d8cd-4032-aae3-b7327d4143dd)
)
(fp_text value "1" (at 0 1.65) (layer "F.Fab")
(effects (font (size 1 1) (thickness 0.15)))
(tstamp 5b2b5c7d-f943-4634-9f0a-e9561705c49d)
)
(fp_text user "${REFERENCE}" (at 0 0) (layer "F.Fab")
(effects (font (size 0.5 0.5) (thickness 0.08)))
(tstamp c70d9ef3-bfeb-47e0-a1e1-9aeba3da7864)
)
(fp_line (start -0.227064 -0.735) (end 0.227064 -0.735) (layer "F.SilkS") (width 0.12) (tstamp d1262c4d-2245-4c4f-8f35-7bb32cd9e21e))
(fp_line (start -0.227064 0.735) (end 0.227064 0.735) (layer "F.SilkS") (width 0.12) (tstamp d22e95aa-f3db-4fbc-a331-048a2523233e))
(fp_line (start -1.68 0.95) (end -1.68 -0.95) (layer "F.CrtYd") (width 0.05) (tstamp 0d0bb7b2-a6e5-46d2-9492-a1aa6e5a7b2f))
(fp_line (start 1.68 0.95) (end -1.68 0.95) (layer "F.CrtYd") (width 0.05) (tstamp 15875808-74d5-4210-b8ca-aa8fbc04ae21))
(fp_line (start 1.68 -0.95) (end 1.68 0.95) (layer "F.CrtYd") (width 0.05) (tstamp 81bbc3ff-3938-49ac-8297-ce2bcc9a42bd))
(fp_line (start -1.68 -0.95) (end 1.68 -0.95) (layer "F.CrtYd") (width 0.05) (tstamp b1169a2d-8998-4b50-a48d-c520bcc1b8e1))
(fp_line (start 1 0.625) (end -1 0.625) (layer "F.Fab") (width 0.1) (tstamp 0147f16a-c952-4891-8f53-a9fb8cddeb8d))
(fp_line (start -1 0.625) (end -1 -0.625) (layer "F.Fab") (width 0.1) (tstamp 4e3d7c0d-12e3-42f2-b944-e4bcdbbcac2a))
(fp_line (start 1 -0.625) (end 1 0.625) (layer "F.Fab") (width 0.1) (tstamp 6a44418c-7bb4-4e99-8836-57f153c19721))
(fp_line (start -1 -0.625) (end 1 -0.625) (layer "F.Fab") (width 0.1) (tstamp aa02e544-13f5-4cf8-a5f4-3e6cda006090))
(pad "1" smd roundrect locked (at -0.9125 0) (size 1.025 1.4) (layers "F.Cu" "F.Paste" "F.Mask") (roundrect_rratio 0.243902)
(net 10 "Net-(R1-Pad1)") (tstamp 0a3cc030-c9dd-4d74-9d50-715ed2b361a2))
(pad "2" smd roundrect locked (at 0.9125 0) (size 1.025 1.4) (layers "F.Cu" "F.Paste" "F.Mask") (roundrect_rratio 0.243902)
(net 9 "Net-(R1-Pad2)") (tstamp dd00c2e1-6027-4717-b312-4fab3ee52002))
(model "ALIAS1:test.wrl"
(offset (xyz 0 0 0))
(scale (xyz 1 1 1))
(rotate (xyz 0 0 0))
)
)
(footprint "Resistor_SMD:R_0805_2012Metric" (layer "F.Cu")
(tedit 5F68FEEE) (tstamp 00000000-0000-0000-0000-00006223ab71)
(at 133 98.5)
(descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC_7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator")
(tags "resistor")
(path "/00000000-0000-0000-0000-00006223adf1")
(attr smd)
(fp_text reference "R2" (at 0 -1.65) (layer "F.SilkS")
(effects (font (size 1 1) (thickness 0.15)))
(tstamp b3d08afa-f296-4e3b-8825-73b6331d35bf)
)
(fp_text value "2" (at 0 1.65) (layer "F.Fab")
(effects (font (size 1 1) (thickness 0.15)))
(tstamp 98e81e80-1f85-4152-be3f-99785ea97751)
)
(fp_text user "${REFERENCE}" (at 0 0) (layer "F.Fab")
(effects (font (size 0.5 0.5) (thickness 0.08)))
(tstamp 842e430f-0c35-45f3-a0b5-95ae7b7ae388)
)
(fp_line (start -0.227064 0.735) (end 0.227064 0.735) (layer "F.SilkS") (width 0.12) (tstamp 58dc14f9-c158-4824-a84e-24a6a482a7a4))
(fp_line (start -0.227064 -0.735) (end 0.227064 -0.735) (layer "F.SilkS") (width 0.12) (tstamp dde3dba8-1b81-466c-93a3-c284ff4da1ef))
(fp_line (start 1.68 -0.95) (end 1.68 0.95) (layer "F.CrtYd") (width 0.05) (tstamp 13475e15-f37c-4de8-857e-1722b0c39513))
(fp_line (start 1.68 0.95) (end -1.68 0.95) (layer "F.CrtYd") (width 0.05) (tstamp 2732632c-4768-42b6-bf7f-14643424019e))
(fp_line (start -1.68 -0.95) (end 1.68 -0.95) (layer "F.CrtYd") (width 0.05) (tstamp b635b16e-60bb-4b3e-9fc3-47d34eef8381))
(fp_line (start -1.68 0.95) (end -1.68 -0.95) (layer "F.CrtYd") (width 0.05) (tstamp f976e2cc-36f9-4479-a816-2c74d1d5da6f))
(fp_line (start -1 -0.625) (end 1 -0.625) (layer "F.Fab") (width 0.1) (tstamp 03d88a85-11fd-47aa-954c-c318bb15294a))
(fp_line (start 1 0.625) (end -1 0.625) (layer "F.Fab") (width 0.1) (tstamp 0dcdf1b8-13c6-48b4-bd94-5d26038ff231))
(fp_line (start 1 -0.625) (end 1 0.625) (layer "F.Fab") (width 0.1) (tstamp 1a2f72d1-0b36-4610-afc4-4ad1660d5d3b))
(fp_line (start -1 0.625) (end -1 -0.625) (layer "F.Fab") (width 0.1) (tstamp 51c4dc0a-5b9f-4edf-a83f-4a12881e42ef))
(pad "1" smd roundrect locked (at -0.9125 0) (size 1.025 1.4) (layers "F.Cu" "F.Paste" "F.Mask") (roundrect_rratio 0.243902)
(net 12 "Net-(R2-Pad1)") (tstamp 120a7b0f-ddfd-4447-85c1-35665465acdb))
(pad "2" smd roundrect locked (at 0.9125 0) (size 1.025 1.4) (layers "F.Cu" "F.Paste" "F.Mask") (roundrect_rratio 0.243902)
(net 11 "Net-(R2-Pad2)") (tstamp 854dd5d4-5fd2-4730-bd49-a9cd8299a065))
(model "ALIAS2:test.wrl"
(offset (xyz 0 0 0))
(scale (xyz 1 1 1))
(rotate (xyz 0 0 0))
)
)
(footprint "Capacitor_SMD:C_0805_2012Metric" (layer "B.Cu")
(tedit 5F68FEEE) (tstamp 00000000-0000-0000-0000-00006223ab3e)
(at 128.25 93.25 -90)
(descr "Capacitor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC_7351 nominal, (Body size source: IPC-SM-782 page 76, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf, https://docs.google.com/spreadsheets/d/1BsfQQcO9C6DZCsRaXUlFlo91Tg2WpOkGARC1WS5S8t0/edit?usp=sharing), generated with kicad-footprint-generator")
(tags "capacitor")
(path "/00000000-0000-0000-0000-00006223c1b3")
(attr smd)
(fp_text reference "C3" (at 0 1.68 -90) (layer "B.SilkS")
(effects (font (size 1 1) (thickness 0.15)) (justify mirror))
(tstamp bb7f0588-d4d8-44bf-9ebf-3c533fe4d6ae)
)
(fp_text value "3u" (at 0 -1.68 -90) (layer "B.Fab")
(effects (font (size 1 1) (thickness 0.15)) (justify mirror))
(tstamp f1830a1b-f0cc-47ae-a2c9-679c82032f14)
)
(fp_text user "${REFERENCE}" (at 0 0 -90) (layer "B.Fab")
(effects (font (size 0.5 0.5) (thickness 0.08)) (justify mirror))
(tstamp 6a955fc7-39d9-4c75-9a69-676ca8c0b9b2)
)
(fp_line (start -0.261252 0.735) (end 0.261252 0.735) (layer "B.SilkS") (width 0.12) (tstamp 10109f84-4940-47f8-8640-91f185ac9bc1))
(fp_line (start -0.261252 -0.735) (end 0.261252 -0.735) (layer "B.SilkS") (width 0.12) (tstamp 55e740a3-0735-4744-896e-2bf5437093b9))
(fp_line (start 1.7 0.98) (end 1.7 -0.98) (layer "B.CrtYd") (width 0.05) (tstamp 47baf4b1-0938-497d-88f9-671136aa8be7))
(fp_line (start 1.7 -0.98) (end -1.7 -0.98) (layer "B.CrtYd") (width 0.05) (tstamp 77ed3941-d133-4aef-a9af-5a39322d14eb))
(fp_line (start -1.7 0.98) (end 1.7 0.98) (layer "B.CrtYd") (width 0.05) (tstamp c022004a-c968-410e-b59e-fbab0e561e9d))
(fp_line (start -1.7 -0.98) (end -1.7 0.98) (layer "B.CrtYd") (width 0.05) (tstamp f4f99e3d-7269-4f6a-a759-16ad2a258779))
(fp_line (start 1 -0.625) (end -1 -0.625) (layer "B.Fab") (width 0.1) (tstamp 71c31975-2c45-4d18-a25a-18e07a55d11e))
(fp_line (start 1 0.625) (end 1 -0.625) (layer "B.Fab") (width 0.1) (tstamp 746ba970-8279-4e7b-aed3-f28687777c21))
(fp_line (start -1 0.625) (end 1 0.625) (layer "B.Fab") (width 0.1) (tstamp e10b5627-3247-4c86-b9f6-ef474ca11543))
(fp_line (start -1 -0.625) (end -1 0.625) (layer "B.Fab") (width 0.1) (tstamp e8314017-7be6-4011-9179-37449a29b311))
(pad "1" smd roundrect locked (at -0.95 0 270) (size 1 1.45) (layers "B.Cu" "B.Paste" "B.Mask") (roundrect_rratio 0.25)
(net 6 "Net-(C3-Pad1)") (tstamp 4fb02e58-160a-4a39-9f22-d0c75e82ee72))
(pad "2" smd roundrect locked (at 0.95 0 270) (size 1 1.45) (layers "B.Cu" "B.Paste" "B.Mask") (roundrect_rratio 0.25)
(net 5 "Net-(C3-Pad2)") (tstamp e615f7aa-337e-474d-9615-2ad82b1c44ca))
(model "${KISYS3DMOD}/Capacitor_SMD.3dshapes/C_0805_2012Metric.wrl"
(offset (xyz 0 0 0))
(scale (xyz 1 1 1))
(rotate (xyz 0 0 0))
)
)
(footprint "Capacitor_SMD:C_0805_2012Metric" (layer "B.Cu")
(tedit 5F68FEEE) (tstamp 00000000-0000-0000-0000-00006223ab4f)
(at 127.75 99 90)
(descr "Capacitor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC_7351 nominal, (Body size source: IPC-SM-782 page 76, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf, https://docs.google.com/spreadsheets/d/1BsfQQcO9C6DZCsRaXUlFlo91Tg2WpOkGARC1WS5S8t0/edit?usp=sharing), generated with kicad-footprint-generator")
(tags "capacitor")
(path "/00000000-0000-0000-0000-00006223c217")
(attr smd)
(fp_text reference "C4" (at 0 1.68 90) (layer "B.SilkS")
(effects (font (size 1 1) (thickness 0.15)) (justify mirror))
(tstamp 67f6e996-3c99-493c-8f6f-e739e2ed5d7a)
)
(fp_text value "4u" (at 0 -1.68 90) (layer "B.Fab")
(effects (font (size 1 1) (thickness 0.15)) (justify mirror))
(tstamp 32667662-ae86-4904-b198-3e95f11851bf)
)
(fp_text user "${REFERENCE}" (at 0 0 90) (layer "B.Fab")
(effects (font (size 0.5 0.5) (thickness 0.08)) (justify mirror))
(tstamp a05d7640-f2f6-4ba7-8c51-5a4af431fc13)
)
(fp_line (start -0.261252 -0.735) (end 0.261252 -0.735) (layer "B.SilkS") (width 0.12) (tstamp 94c158d1-8503-4553-b511-bf42f506c2a8))
(fp_line (start -0.261252 0.735) (end 0.261252 0.735) (layer "B.SilkS") (width 0.12) (tstamp 9ccf03e8-755a-4cd9-96fc-30e1d08fa253))
(fp_line (start -1.7 -0.98) (end -1.7 0.98) (layer "B.CrtYd") (width 0.05) (tstamp 23bb2798-d93a-4696-a962-c305c4298a0c))
(fp_line (start 1.7 0.98) (end 1.7 -0.98) (layer "B.CrtYd") (width 0.05) (tstamp 6e105729-aba0-497c-a99e-c32d2b3ddb6d))
(fp_line (start -1.7 0.98) (end 1.7 0.98) (layer "B.CrtYd") (width 0.05) (tstamp 78cbdd6c-4878-4cc5-9a58-0e506478e37d))
(fp_line (start 1.7 -0.98) (end -1.7 -0.98) (layer "B.CrtYd") (width 0.05) (tstamp 983c426c-24e0-4c65-ab69-1f1824adc5c6))
(fp_line (start -1 -0.625) (end -1 0.625) (layer "B.Fab") (width 0.1) (tstamp 13abf99d-5265-4779-8973-e94370fd18ff))
(fp_line (start 1 -0.625) (end -1 -0.625) (layer "B.Fab") (width 0.1) (tstamp 46918595-4a45-48e8-84c0-961b4db7f35f))
(fp_line (start -1 0.625) (end 1 0.625) (layer "B.Fab") (width 0.1) (tstamp a7520ad3-0f8b-4788-92d4-8ffb277041e6))
(fp_line (start 1 0.625) (end 1 -0.625) (layer "B.Fab") (width 0.1) (tstamp a795f1ba-cdd5-4cc5-9a52-08586e982934))
(pad "1" smd roundrect locked (at -0.95 0 90) (size 1 1.45) (layers "B.Cu" "B.Paste" "B.Mask") (roundrect_rratio 0.25)
(net 8 "Net-(C4-Pad1)") (tstamp e9bb29b2-2bb9-4ea2-acd9-2bb3ca677a12))
(pad "2" smd roundrect locked (at 0.95 0 90) (size 1 1.45) (layers "B.Cu" "B.Paste" "B.Mask") (roundrect_rratio 0.25)
(net 7 "Net-(C4-Pad2)") (tstamp c1d83899-e380-49f9-a87d-8e78bc089ebf))
(model "${KISYS3DMOD}/Capacitor_SMD.3dshapes/C_0805_2012Metric.wrl"
(offset (xyz 0 0 0))
(scale (xyz 1 1 1))
(rotate (xyz 0 0 0))
)
)
(footprint "Resistor_SMD:R_0805_2012Metric" (layer "B.Cu")
(tedit 5F68FEEE) (tstamp 00000000-0000-0000-0000-00006223ab82)
(at 133 93.75)
(descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC_7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator")
(tags "resistor")
(path "/00000000-0000-0000-0000-00006223b0e5")
(attr smd)
(fp_text reference "R3" (at -0.5 1.65) (layer "B.SilkS")
(effects (font (size 1 1) (thickness 0.15)) (justify mirror))
(tstamp afd3dbad-e7a8-4e4c-b77c-4065a69aefa2)
)
(fp_text value "3" (at 0 -1.65) (layer "B.Fab")
(effects (font (size 1 1) (thickness 0.15)) (justify mirror))
(tstamp 1b54105e-6590-4d26-a763-ecfcf81eedc4)
)
(fp_text user "${REFERENCE}" (at 0 0) (layer "B.Fab")
(effects (font (size 0.5 0.5) (thickness 0.08)) (justify mirror))
(tstamp 0f41a909-27c4-4be2-9d5e-9ae2108c8ff5)
)
(fp_line (start -0.227064 0.735) (end 0.227064 0.735) (layer "B.SilkS") (width 0.12) (tstamp dabe541b-b164-4180-97a4-5ca761b86800))
(fp_line (start -0.227064 -0.735) (end 0.227064 -0.735) (layer "B.SilkS") (width 0.12) (tstamp e12e827e-36be-4503-8eef-6fc7e8bc5d49))
(fp_line (start 1.68 -0.95) (end -1.68 -0.95) (layer "B.CrtYd") (width 0.05) (tstamp 0088d107-13d8-496c-8da6-7bbeb9d096b0))
(fp_line (start -1.68 0.95) (end 1.68 0.95) (layer "B.CrtYd") (width 0.05) (tstamp 417f13e4-c121-485a-a6b5-8b55e70350b8))
(fp_line (start -1.68 -0.95) (end -1.68 0.95) (layer "B.CrtYd") (width 0.05) (tstamp 9dab0cb7-2557-4419-963b-5ae736517f62))
(fp_line (start 1.68 0.95) (end 1.68 -0.95) (layer "B.CrtYd") (width 0.05) (tstamp c201e1b2-fc01-4110-bdaa-a33290468c83))
(fp_line (start -1 0.625) (end 1 0.625) (layer "B.Fab") (width 0.1) (tstamp 35354519-a28c-40c4-befd-0943e98dea53))
(fp_line (start 1 0.625) (end 1 -0.625) (layer "B.Fab") (width 0.1) (tstamp 38f2d955-ea7a-4a21-aba6-02ae23f1bd4a))
(fp_line (start -1 -0.625) (end -1 0.625) (layer "B.Fab") (width 0.1) (tstamp 632acde9-b7fd-4f04-8cb4-d2cbb06b3595))
(fp_line (start 1 -0.625) (end -1 -0.625) (layer "B.Fab") (width 0.1) (tstamp 6b25f522-8e2d-4cd8-9d5d-a2b80f60133b))
(pad "1" smd roundrect locked (at -0.9125 0) (size 1.025 1.4) (layers "B.Cu" "B.Paste" "B.Mask") (roundrect_rratio 0.243902)
(net 14 "Net-(R3-Pad1)") (tstamp 68e09be7-3bbc-4443-a838-209ce20b2bef))
(pad "2" smd roundrect locked (at 0.9125 0) (size 1.025 1.4) (layers "B.Cu" "B.Paste" "B.Mask") (roundrect_rratio 0.243902)
(net 13 "Net-(R3-Pad2)") (tstamp 6a780180-586a-4241-a52d-dc7a5ffcc966))
(model "${KISYS3DMOD}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl"
(offset (xyz 0 0 0))
(scale (xyz 1 1 1))
(rotate (xyz 0 0 0))
)
)
(footprint "Resistor_SMD:R_0805_2012Metric" (layer "B.Cu")
(tedit 5F68FEEE) (tstamp 00000000-0000-0000-0000-00006223ab93)
(at 133 98.5)
(descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC_7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator")
(tags "resistor")
(path "/00000000-0000-0000-0000-00006223b0ef")
(attr smd)
(fp_text reference "R4" (at 0 1.65) (layer "B.SilkS")
(effects (font (size 1 1) (thickness 0.15)) (justify mirror))
(tstamp 9702d639-3b1f-4825-8985-b32b9008503d)
)
(fp_text value "4" (at 0 -1.65) (layer "B.Fab")
(effects (font (size 1 1) (thickness 0.15)) (justify mirror))
(tstamp 0d35483a-0b12-46cc-b9f2-896fd6831779)
)
(fp_text user "${REFERENCE}" (at 0 0) (layer "B.Fab")
(effects (font (size 0.5 0.5) (thickness 0.08)) (justify mirror))
(tstamp 4e66a44f-7fa6-4e16-bf9b-62ec864301a5)
)
(fp_line (start -0.227064 -0.735) (end 0.227064 -0.735) (layer "B.SilkS") (width 0.12) (tstamp a9ec539a-d80d-40cc-803c-12b6adefe42a))
(fp_line (start -0.227064 0.735) (end 0.227064 0.735) (layer "B.SilkS") (width 0.12) (tstamp ef1b4b98-541b-4673-a04f-2043250fc40a))
(fp_line (start -1.68 0.95) (end 1.68 0.95) (layer "B.CrtYd") (width 0.05) (tstamp 2bf3f24b-fd30-41a7-a274-9b519491916b))
(fp_line (start 1.68 0.95) (end 1.68 -0.95) (layer "B.CrtYd") (width 0.05) (tstamp 4831966c-bb32-4bc8-a400-0382a02ffa1c))
(fp_line (start -1.68 -0.95) (end -1.68 0.95) (layer "B.CrtYd") (width 0.05) (tstamp c264c438-a475-4ad4-9915-0f1e6ecf3053))
(fp_line (start 1.68 -0.95) (end -1.68 -0.95) (layer "B.CrtYd") (width 0.05) (tstamp e25ce415-914a-48fe-bf09-324317917b2e))
(fp_line (start 1 -0.625) (end -1 -0.625) (layer "B.Fab") (width 0.1) (tstamp 34871042-9d5c-4e29-abdd-a168368c3c22))
(fp_line (start -1 -0.625) (end -1 0.625) (layer "B.Fab") (width 0.1) (tstamp 4412226e-d975-40a2-921f-502ff4129a95))
(fp_line (start 1 0.625) (end 1 -0.625) (layer "B.Fab") (width 0.1) (tstamp 53c85970-3e21-4fae-a84f-721cfc0513b5))
(fp_line (start -1 0.625) (end 1 0.625) (layer "B.Fab") (width 0.1) (tstamp 7447a6e7-8205-46ba-afca-d0fa8f90c95a))
(pad "1" smd roundrect locked (at -0.9125 0) (size 1.025 1.4) (layers "B.Cu" "B.Paste" "B.Mask") (roundrect_rratio 0.243902)
(net 16 "Net-(R4-Pad1)") (tstamp 9762c9ed-64d8-4f3e-baf6-f6ba6effc919))
(pad "2" smd roundrect locked (at 0.9125 0) (size 1.025 1.4) (layers "B.Cu" "B.Paste" "B.Mask") (roundrect_rratio 0.243902)
(net 15 "Net-(R4-Pad2)") (tstamp 4d4b0fcd-2c79-4fc3-b5fa-7a0741601344))
(model "${KISYS3DMOD}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl"
(offset (xyz 0 0 0))
(scale (xyz 1 1 1))
(rotate (xyz 0 0 0))
)
)
(gr_line (start 125 102) (end 125 91) (layer "Edge.Cuts") (width 0.05) (tstamp 00000000-0000-0000-0000-00006223ae41))
(gr_line (start 136 91) (end 136 102) (layer "Edge.Cuts") (width 0.05) (tstamp 29e78086-2175-405e-9ba3-c48766d2f50c))
(gr_line (start 125 91) (end 136 91) (layer "Edge.Cuts") (width 0.05) (tstamp 94a873dc-af67-4ef9-8159-1f7c93eeb3d7))
(gr_line (start 136 102) (end 125 102) (layer "Edge.Cuts") (width 0.05) (tstamp a1823eb2-fb0d-4ed8-8b96-04184ac3a9d5))
)

View File

@ -1413,3 +1413,59 @@ def test_diff_file_sch_1(test_dir):
ctx.expect_out_file(prj+'-diff_sch_FILE-Current.pdf')
ctx.compare_pdf(prj+'-diff_sch.pdf')
ctx.clean_up(keep_project=True)
@pytest.mark.skipif(context.ki5(), reason="KiCad 6 aliases used")
def test_copy_files_1(test_dir):
""" Copy files and 3D models """
prj = 'copy_files'
ctx = context.TestContext(test_dir, prj, 'copy_files_1', 'test.files')
ctx.run(kicost=True) # We use the fake web server
# The modified PCB
ctx.expect_out_file(prj+'.kicad_pcb', sub=True)
# The 3D models
ctx.expect_out_file('3d_models/C_0805_2012Metric.wrl', sub=True)
ctx.expect_out_file('3d_models/R_0805_2012Metric.wrl', sub=True)
ctx.expect_out_file('3d_models/R_0805_2012Metrico.wrl', sub=True)
ctx.expect_out_file('3d_models/test.wrl', sub=True)
# From output with dest
ctx.expect_out_file('my_position/'+prj+'-both_pos.pos', sub=True)
# From output without dest
ctx.expect_out_file('positiondir/'+prj+'-both_pos.pos', sub=True)
# From output dir
ctx.expect_out_file('my_position2/'+prj+'-both_pos.pos', sub=True)
# From outside the output dir
ctx.expect_out_file('source/test_v5.sch', sub=True)
ctx.expect_out_file('source/deeper.sch', sub=True)
ctx.expect_out_file('source/sub-sheet.sch', sub=True)
ctx.expect_out_file('source/test_v5.kicad_pcb', sub=True)
# Some warnings
ctx.search_err([r'WARNING:\(W098\) 2 3D models downloaded', # 2 models are missing and they are downloaded
r'WARNING:\(W100\)']) # 2 models has the same name
ctx.clean_up()
@pytest.mark.skipif(context.ki5(), reason="KiCad 6 aliases used")
def test_copy_files_2(test_dir):
""" Copy files and 3D models """
prj = 'copy_files'
ctx = context.TestContext(test_dir, prj, 'copy_files_2', 'test.files')
ctx.run(kicost=True) # We use the fake web server
# The modified PCB
ctx.expect_out_file(prj+'.kicad_pcb', sub=True)
# The 3D models
MODELS = ['3d_models/3d/1/test.wrl', '3d_models/3d/2/test.wrl',
'3d_models/Resistor_SMD.3dshapes/R_0805_2012Metrico.step',
'3d_models/Resistor_SMD.3dshapes/R_0805_2012Metrico.wrl',
'3d_models/Capacitor_SMD.3dshapes/C_0805_2012Metric.step',
'3d_models/Capacitor_SMD.3dshapes/C_0805_2012Metric.wrl',
'3d_models/Resistor_SMD.3dshapes/R_0805_2012Metric.step',
'3d_models/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl']
for m in MODELS:
ctx.expect_out_file(m, sub=True)
# Make sure the PCB points to them
ctx.search_in_file(prj+'.kicad_pcb', ['model "{}"'.format(m) for m in MODELS if m.endswith('wrl')], sub=True)
# Some warnings
ctx.search_err(r'WARNING:\(W098\) 2 3D models downloaded') # 2 models are missing and they are downloaded
ctx.search_err(r'WARNING:\(W100\)', invert=True) # 2 models has the same name, but goes to different target
ctx.clean_up()

View File

@ -442,9 +442,9 @@ class TestContext(object):
logging.debug('error match: `{}` (`{}`) OK'.format(text, m.group(0)))
return m
def search_in_file(self, file, texts):
def search_in_file(self, file, texts, sub=False):
logging.debug('Searching in "'+file+'" output')
with open(self.get_out_path(file)) as f:
with open(self.get_out_path(file, sub=sub)) as f:
txt = f.read()
res = []
for t in texts:

View File

@ -0,0 +1,51 @@
# Example KiBot config file
kibot:
version: 1
global:
environment:
# Relative to the PCB file
models_3d: '../../data/metrico/'
aliases_for_3d_models:
- name: ALIAS1
value: '3d/1'
- name: ALIAS2
value: '3d/2'
outputs:
- name: 'position'
comment: "Pick and place file"
type: position
dir: positiondir
options:
format: ASCII # CSV or ASCII format
units: millimeters # millimeters or inches
separate_files_for_front_and_back: false
only_smd: true
- name: result
comment: 'Copy files from source, output and 3D models'
type: copy_files
dir: 'test.%x'
options:
# link_no_copy: true
kicad_3d_url: 'http://localhost:8000/'
files:
- source: tests/board_samples/kicad_5/test_v5.*
dest: source
- source: tests/board_samples/kicad_5/deeper.sch
dest: source
- source: tests/board_samples/kicad_5/sub-sheet.sch
dest: source
- source: position
source_type: output
dest: my_position
- source: position
source_type: output
- source: positiondir/*.pos
source_type: out_files
dest: my_position2
- source: '*.wrl'
source_type: 3d_models
dest: 3d_models
save_pcb: true

View File

@ -0,0 +1,36 @@
# Example KiBot config file
kibot:
version: 1
global:
environment:
# Relative to the PCB file
models_3d: '../../data/metrico/'
aliases_for_3d_models:
- name: ALIAS1
value: '3d/1'
- name: ALIAS2
value: '3d/2'
outputs:
- name: 'position'
comment: "Pick and place file"
type: position
dir: positiondir
options:
format: ASCII # CSV or ASCII format
units: millimeters # millimeters or inches
separate_files_for_front_and_back: false
only_smd: true
- name: result
comment: 'Copy files from source, output and 3D models'
type: copy_files
dir: 'test.%x'
options:
# link_no_copy: true
kicad_3d_url: 'http://localhost:8000/'
files:
- source_type: 3d_models
dest: 3d_models+
save_pcb: true