KiBot/kibot/globals.py

220 lines
11 KiB
Python

# -*- coding: utf-8 -*-
# Copyright (c) 2020-2022 Salvador E. Tropea
# Copyright (c) 2020-2022 Instituto Nacional de Tecnología Industrial
# License: GPL-3.0
# Project: KiBot (formerly KiPlot)
import os
from .gs import GS
from .macros import macros, document # noqa: F401
from .pre_filters import FiltersOptions
from .log import get_logger, set_filters
from .misc import W_MUSTBEINT
from .kicad.sexpdata import load, SExpData, sexp_iter, Symbol
from .kicad.v6_sch import PCBLayer
class Globals(FiltersOptions):
""" Global options """
def __init__(self):
super().__init__()
with document:
self.output = ''
""" Default pattern for output file names """
self.dir = ''
""" Default pattern for the output directories """
self.out_dir = ''
""" Base output dir, same as command line `--out-dir` """
self.variant = ''
""" Default variant to apply to all outputs """
self.kiauto_wait_start = 0
""" Time to wait for KiCad in KiAuto operations """
self.kiauto_time_out_scale = 0.0
""" Time-out multiplier for KiAuto operations """
self.date_time_format = '%Y-%m-%d_%H-%M-%S'
""" Format used for the PCB and schematic date when using the file timestamp. Uses the `strftime` format """
self.date_format = '%Y-%m-%d'
""" Format used for the day we started the script.
Is also used for the PCB/SCH date formatting when `time_reformat` is enabled (default behavior).
Uses the `strftime` format """
self.time_format = '%H-%M-%S'
""" Format used for the time we started the script. Uses the `strftime` format """
self.time_reformat = True
""" Tries to reformat the PCB/SCH date using the `date_format`.
This assumes you let KiCad fill this value and hence the time is in ISO format (YY-MM-DD) """
self.pcb_material = 'FR4'
""" PCB core material. Currently used for documentation and to choose default colors.
Currently known are FR1 to FR5 """
self.solder_mask_color = 'green'
""" Color for the solder mask. Currently used for documentation and to choose default colors.
KiCad 6: you should set this in the Board Setup -> Physical Stackup.
Currently known are green, black, white, yellow, purple, blue and red """
self.solder_mask_color_top = ''
""" Color for the top solder mask. When not defined `solder_mask_color` is used.
Read `solder_mask_color` help """
self.solder_mask_color_bottom = ''
""" Color for the bottom solder mask. When not defined `solder_mask_color` is used.
Read `solder_mask_color` help """
self.silk_screen_color = 'white'
""" Color for the markings. Currently used for documentation and to choose default colors.
KiCad 6: you should set this in the Board Setup -> Physical Stackup.
Currently known are black and white """
self.silk_screen_color_top = ''
""" Color for the top silk screen. When not defined `silk_screen_color` is used.
Read `silk_screen_color` help """
self.silk_screen_color_bottom = ''
""" Color for the bottom silk screen. When not defined `silk_screen_color` is used.
Read `silk_screen_color` help """
self.pcb_finish = 'HAL'
""" Finishing used to protect pads. Currently used for documentation and to choose default colors.
KiCad 6: you should set this in the Board Setup -> Board Finish -> Copper Finish option.
Currently known are None, HAL, HASL, HAL SnPb, HAL lead-free, ENIG, ENEPIG, Hard gold, ImAg, Immersion Silver,
Immersion Ag, ImAu, Immersion Gold, Immersion Au, Immersion Tin, Immersion Nickel, OSP and HT_OSP """
self.edge_connector = 'no'
""" [yes,no,bevelled] Has the PCB edge connectors?
KiCad 6: you should set this in the Board Setup -> Board Finish -> Edge card connectors """
self.castellated_pads = False
""" Has the PCB castelletad pads?
KiCad 6: you should set this in the Board Setup -> Board Finish -> Has castellated pads """
self.edge_plating = False
""" Has the PCB a plated board edge?
KiCad 6: you should set this in the Board Setup -> Board Finish -> Plated board edge """
self.copper_finish = None
""" {pcb_finish} """
self.copper_thickness = 35
""" Copper thickness in micrometers (1 Oz is 35 micrometers).
KiCad 6: you should set this in the Board Setup -> Physical Stackup """
self.set_doc('filters', " [list(dict)] KiBot warnings to be ignored ")
self._filter_what = 'KiBot warnings'
self._unkown_is_error = True
self._error_context = 'global '
def set_global(self, opt):
current = getattr(GS, 'global_'+opt)
new_val = getattr(self, opt)
if current is not None:
logger.info('Using command line value `{}` for global option `{}`'.format(current, opt))
return current
if new_val:
return new_val
return current
def get_stack_up(self):
logger.debug("Looking for stack-up information in the PCB")
pcb = None
with open(GS.pcb_file, 'rt') as fh:
try:
pcb = load(fh)
except SExpData as e:
# Don't make it an error, will be detected and reported latter
logger.debug("- Failed to load the PCB "+str(e))
if pcb is None:
return
iter = sexp_iter(pcb, 'kicad_pcb/setup/stackup')
if iter is None:
return
sp = next(iter, None)
if sp is None:
return
logger.debug("- Found stack-up information")
stackup = []
materials = set()
thicknesses = set()
for e in sp[1:]:
if isinstance(e, list) and isinstance(e[0], Symbol):
name = e[0].value()
value = None
if len(e) > 1:
if isinstance(e[1], Symbol):
value = e[1].value()
else:
value = str(e[1])
if name == 'copper_finish':
self.pcb_finish = value
logger.debug("- Copper finish: "+self.pcb_finish)
elif name == 'edge_connector':
self.edge_connector = value
logger.debug("- Edge connector: "+self.edge_connector)
elif name == 'castellated_pads':
self.castellated_pads = value == 'yes'
logger.debug("- Castellated pads: "+value)
elif name == 'edge_plating':
self.edge_plating = value == 'yes'
logger.debug("- Edge plating: "+value)
elif name == 'layer':
ly = PCBLayer.parse(e)
stackup.append(ly)
if ly.name == "F.SilkS":
if ly.color:
self.silk_screen_color_top = ly.color.lower()
logger.debug("- F.SilkS color: "+ly.color)
elif ly.name == "B.SilkS":
if ly.color:
self.silk_screen_color_bottom = ly.color.lower()
logger.debug("- B.SilkS color: "+ly.color)
elif ly.name == "F.Mask":
if ly.color:
self.solder_mask_color_top = ly.color.lower()
logger.debug("- F.Mask color: "+ly.color)
elif ly.name == "B.Mask":
if ly.color:
self.solder_mask_color_bottom = ly.color.lower()
logger.debug("- B.Mask color: "+ly.color)
elif ly.material:
if not len(materials):
materials.add(ly.material)
self.pcb_material = ly.material
elif ly.material not in materials:
materials.add(ly.material)
self.pcb_material += ' / '+ly.material
elif ly.type == 'copper' and ly.thickness:
if not len(thicknesses):
thicknesses.add(ly.thickness)
self.copper_thickness = str(int(ly.thickness*1000))
elif ly.thickness not in thicknesses:
thicknesses.add(ly.thickness)
self.copper_thickness += ' / '+str(int(ly.thickness*1000))
if stackup:
GS.stackup = stackup
if len(materials):
logger.debug("- PCB Material/s: "+self.pcb_material)
if len(thicknesses):
logger.debug("- Copper thickness: "+self.copper_thickness)
def config(self, parent):
if GS.ki6() and GS.pcb_file and os.path.isfile(GS.pcb_file):
self.get_stack_up()
super().config(parent)
# Transfer options to the GS globals
for option in filter(lambda x: x[0] != '_', self.__dict__.keys()):
gl = 'global_'+option
if hasattr(GS, gl):
setattr(GS, gl, self.set_global(option))
# Special cases
if not GS.out_dir_in_cmd_line and self.out_dir:
GS.out_dir = os.path.join(os.getcwd(), self.out_dir)
if GS.global_kiauto_wait_start and int(GS.global_kiauto_wait_start) != GS.global_kiauto_wait_start:
GS.global_kiauto_wait_start = int(GS.global_kiauto_wait_start)
logger.warning(W_MUSTBEINT+'kiauto_wait_start must be integer, truncating to '+str(GS.global_kiauto_wait_start))
# - Solder mask
if GS.global_solder_mask_color_top and GS.global_solder_mask_color_bottom:
# Top and bottom defined, use the top as general
GS.global_solder_mask_color = GS.global_solder_mask_color_top
else:
if not GS.global_solder_mask_color_top:
GS.global_solder_mask_color_top = GS.global_solder_mask_color
if not GS.global_solder_mask_color_bottom:
GS.global_solder_mask_color_bottom = GS.global_solder_mask_color
# - Silk screen
if GS.global_silk_screen_color_top and GS.global_silk_screen_color_bottom:
GS.global_silk_screen_color = GS.global_silk_screen_color_top
else:
if not GS.global_silk_screen_color_top:
GS.global_silk_screen_color_top = GS.global_silk_screen_color
if not GS.global_silk_screen_color_bottom:
GS.global_silk_screen_color_bottom = GS.global_silk_screen_color
set_filters(self.unparsed)
logger = get_logger(__name__)
GS.global_opts_class = Globals