diff --git a/CHANGELOG.md b/CHANGELOG.md index b8791a69..ca782bff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.6.4] - UNRELEASED ### Added +- Command line: + - `--help-list-offsets` to list footprint offsets (JLCPCB) + - `--help-list-rotations` to list footprint rotations (JLCPCB) - Global options: - `remove_solder_mask_for_dnp` similar to `remove_solder_paste_for_dnp` but applied to the solder mask apertures. (#476) diff --git a/docs/source/usage.txt b/docs/source/usage.txt index c8ad8d4c..2c6873bd 100644 --- a/docs/source/usage.txt +++ b/docs/source/usage.txt @@ -15,7 +15,9 @@ Usage: kibot [-v...] [--rst] --help-filters kibot [-v...] [--markdown|--json|--rst] --help-dependencies kibot [-v...] [--rst] --help-global-options + kibot [-v...] --help-list-offsets kibot [-v...] [--rst] --help-list-outputs + kibot [-v...] --help-list-rotations kibot [-v...] --help-output=HELP_OUTPUT kibot [-v...] [--rst] [-d OUT_DIR] --help-outputs kibot [-v...] [--rst] --help-preflights @@ -79,6 +81,7 @@ Help options: --help-filters List supported filters and details --help-global-options List supported global variables --help-list-outputs List supported outputs + --help-list-rotations List footprint rotations (JLCPCB) --help-output HELP_OUTPUT Help for this particular output --help-outputs List supported outputs and details --help-preflights List supported preflights and details diff --git a/kibot/__main__.py b/kibot/__main__.py index 42e245e8..f439674f 100644 --- a/kibot/__main__.py +++ b/kibot/__main__.py @@ -22,7 +22,9 @@ Usage: kibot [-v...] [--rst] --help-filters kibot [-v...] [--markdown|--json|--rst] --help-dependencies kibot [-v...] [--rst] --help-global-options + kibot [-v...] --help-list-offsets kibot [-v...] [--rst] --help-list-outputs + kibot [-v...] --help-list-rotations kibot [-v...] --help-output=HELP_OUTPUT kibot [-v...] [--rst] [-d OUT_DIR] --help-outputs kibot [-v...] [--rst] --help-preflights @@ -85,7 +87,9 @@ Help options: --help-errors List of error levels --help-filters List supported filters and details --help-global-options List supported global variables + --help-list-offsets List footprint offsets (JLCPCB) --help-list-outputs List supported outputs + --help-list-rotations List footprint rotations (JLCPCB) --help-output HELP_OUTPUT Help for this particular output --help-outputs List supported outputs and details --help-preflights List supported preflights and details @@ -128,7 +132,7 @@ from .pre_base import BasePreFlight from .error import KiPlotConfigurationError, config_error from .config_reader import (CfgYamlReader, print_outputs_help, print_output_help, print_preflights_help, create_example, print_filters_help, print_global_options_help, print_dependencies, print_variants_help, - print_errors) + print_errors, print_list_rotations, print_list_offsets) from .kiplot import (generate_outputs, load_actions, config_output, generate_makefile, generate_examples, solve_schematic, solve_board_file, solve_project_file, check_board_file) from .registrable import RegOutput @@ -456,6 +460,12 @@ def main(): if args.help_dependencies: print_dependencies(args.markdown, args.json, args.rst) sys.exit(0) + if args.help_list_rotations: + print_list_rotations() + sys.exit(0) + if args.help_list_offsets: + print_list_offsets() + sys.exit(0) if args.help_banners: for c, b in enumerate(BANNERS): logger.info('Banner '+str(c)) diff --git a/kibot/config_reader.py b/kibot/config_reader.py index bf1275bf..130abd1e 100644 --- a/kibot/config_reader.py +++ b/kibot/config_reader.py @@ -23,7 +23,8 @@ import textwrap from .error import KiPlotConfigurationError, config_error from .misc import (NO_YAML_MODULE, EXIT_BAD_ARGS, EXAMPLE_CFG, WONT_OVERWRITE, W_NOOUTPUTS, W_UNKOUT, W_NOFILTERS, - W_NOVARIANTS, W_NOGLOBALS, TRY_INSTALL_CHECK, W_NOPREFLIGHTS, W_NOGROUPS, W_NEWGROUP, error_level_to_name) + W_NOVARIANTS, W_NOGLOBALS, TRY_INSTALL_CHECK, W_NOPREFLIGHTS, W_NOGROUPS, W_NEWGROUP, error_level_to_name, + DEFAULT_ROTATIONS, DEFAULT_OFFSETS) from .gs import GS from .registrable import RegOutput, RegVariant, RegFilter, RegDependency from .pre_base import BasePreFlight @@ -1363,3 +1364,31 @@ def print_errors(rst): make_title(rst, 'error levels', len(error_level_to_name), '~') for c, n in enumerate(error_level_to_name): print(f'- {c}: {n}') + + +def print_list_rotations(): + rots = sorted(DEFAULT_ROTATIONS, key=lambda x: x[0]) + w = len(max(rots, key=lambda x: len(x[0]))[0])+4 + sep = '='*w + ' ========' + f1 = f'%-{w}s' + print(sep) + print((f1+' Rotation') % 'Footprint') + print(sep) + fmt = f'{f1} %6d' + for v in rots: + print(fmt % ('``'+v[0]+'``', v[1])) + print(sep) + + +def print_list_offsets(): + offs = sorted(DEFAULT_OFFSETS, key=lambda x: x[0]) + w = len(max(offs, key=lambda x: len(x[0]))[0])+4 + sep = '='*w + ' ======== ========' + f1 = f'%-{w}s' + print(sep) + print((f1+' Offset X Offset Y') % 'Footprint') + print(sep) + fmt = f'{f1} %8.2f %8.2f' + for v in offs: + print(fmt % ('``'+v[0]+'``', v[1][0], v[1][1])) + print(sep) diff --git a/kibot/fil_rot_footprint.py b/kibot/fil_rot_footprint.py index 599669f7..71927d1c 100644 --- a/kibot/fil_rot_footprint.py +++ b/kibot/fil_rot_footprint.py @@ -13,92 +13,12 @@ from .gs import GS from .optionable import Optionable from .error import KiPlotConfigurationError from .macros import macros, document, filter_class # noqa: F401 -from .misc import W_BADANGLE, W_BADOFFSET +from .misc import W_BADANGLE, W_BADOFFSET, DEFAULT_ROTATIONS, DEFAULT_ROT_FIELDS, DEFAULT_OFFSETS, DEFAULT_OFFSET_FIELDS from . import log logger = log.get_logger() -# Known rotations for JLC -# Notes: -# - Rotations are CC (counter clock) -# - Most components has pin 1 at the top-right angle, while KiCad uses the top-left -# This is why most of the ICs has a rotation of 270 (-90) -# - The same applies to things like SOT-23-3, so here you get 180. -# - Most polarized components has pin 1 on the positive pin, becoming it the right one. -# On KiCad this is not the case, diodes follows it, but capacitors don't. So they get 180. -# - There are exceptions, like SOP-18 or SOP-4 which doesn't follow the JLC rules. -# - KiCad mirrors components on the bottom layer, but JLC doesn't. So you need to "un-mirror" them. -# - The JLC mechanism to interpret rotations changed with time -DEFAULT_ROTATIONS = [["^R_Array_Convex_", 90.0], - ["^R_Array_Concave_", 90.0], - # *SOT* seems to need 180 - ["^SOT-143", 180.0], - ["^SOT-223", 180.0], - ["^SOT-23", 180.0], - ["^SOT-353", 180.0], - ["^SOT-363", 180.0], - ["^SOT-89", 180.0], - ["^D_SOT-23", 180.0], - ["^TSOT-23", 180.0], - # Polarized capacitors - ["^CP_EIA-", 180.0], - ["^CP_Elec_", 180.0], - ["^C_Elec_", 180.0], - # Most four side components needs -90 (270) - ["^QFN-", 270.0], - ["^(.*?_|V)?QFN-(16|20|24|28|40)(-|_|$)", 270.0], - ["^DFN-", 270.0], - ["^LQFP-", 270.0], - ["^TQFP-", 270.0], - # SMD DIL packages mostly needs -90 (270) - ["^SOP-(?!(18_|4_))", 270.0], # SOP 18 and 4 excluded, wrong at JLCPCB - ["^MSOP-", 270.0], - ["^TSSOP-", 270.0], - ["^HTSSOP-", 270.0], - ["^SSOP-", 270.0], - ["^SOIC-", 270.0], - ["^SO-", 270.0], - ["^SOIC127P798X216-8N", 270.0], - ["^VSSOP-8_3.0x3.0mm_P0.65mm", 270.0], - ["^VSSOP-8_", 180.0], - ["^VSSOP-10_", 270.0], - ["^VSON-8_", 270.0], - ["^TSOP-6", 270.0], - ["^UDFN-10", 270.0], - ["^USON-10", 270.0], - ["^TDSON-8-1", 270.0], - # Misc. - ["^LED_WS2812B_PLCC4", 180.0], - ["^LED_WS2812B-2020_PLCC4_2.0x2.0mm", 90.0], - ["^Bosch_LGA-", 90.0], - ["^PowerPAK_SO-8_Single", 270.0], - ["^PUIAudio_SMT_0825_S_4_R*", 270.0], - ["^USB_C_Receptacle_HRO_TYPE-C-31-M-12*", 180.0], - ["^ESP32-W", 270.0], - ["^SW_DIP_SPSTx01_Slide_Copal_CHS-01B_W7.62mm_P1.27mm", -180.0], - ["^BatteryHolder_Keystone_1060_1x2032", -180.0], - ["^Relay_DPDT_Omron_G6K-2F-Y", 270.0], - ["^RP2040-QFN-56", 270.0], - ["^TO-277", 90.0], - ["^SW_SPST_B3", 90.0], - ["^Transformer_Ethernet_Pulse_HX0068ANL", 270.0], - ["^JST_GH_SM", 180.0], - ["^JST_PH_S", 180.0], - ["^Diodes_PowerDI3333-8", 270.0], - ["^Quectel_L80-R", 270.0], - ["^SC-74-6", 180.0], - [r"^PinHeader_2x05_P1\.27mm_Vertical", 90.0], - [r"^PinHeader_2x03_P1\.27mm_Vertical", 90.0], - ] -DEFAULT_ROT_FIELDS = ['JLCPCB Rotation Offset', 'JLCRotOffset'] -DEFAULT_OFFSETS = [["^USB_C_Receptacle_XKB_U262-16XN-4BVC11", (0.0, -1.44)], - [r"^PinHeader_2x05_P1\.27mm_Vertical", (2.54, 0.635)], - [r"^PinHeader_2x03_P1\.27mm_Vertical", (1.27, 0.635)], - ] -DEFAULT_OFFSET_FIELDS = ['JLCPCB Position Offset', 'JLCPosOffset'] - - def get_field_value(comp, field): """ Helper to process the footprint field in a special way """ field = field.lower() diff --git a/kibot/misc.py b/kibot/misc.py index 297811d6..47279b6a 100644 --- a/kibot/misc.py +++ b/kibot/misc.py @@ -314,6 +314,86 @@ KIKIT_UNIT_ALIASES = {'millimeters': 'mm', 'inches': 'inch', 'mils': 'mil'} FONT_HELP_TEXT = '\n If you use custom fonts and/or colors please consult the `resources_dir` global variable.' +# Known rotations for JLC +# Notes: +# - Rotations are CC (counter clock) +# - Most components has pin 1 at the top-right angle, while KiCad uses the top-left +# This is why most of the ICs has a rotation of 270 (-90) +# - The same applies to things like SOT-23-3, so here you get 180. +# - Most polarized components has pin 1 on the positive pin, becoming it the right one. +# On KiCad this is not the case, diodes follows it, but capacitors don't. So they get 180. +# - There are exceptions, like SOP-18 or SOP-4 which doesn't follow the JLC rules. +# - KiCad mirrors components on the bottom layer, but JLC doesn't. So you need to "un-mirror" them. +# - The JLC mechanism to interpret rotations changed with time +DEFAULT_ROTATIONS = [["^R_Array_Convex_", 90.0], + ["^R_Array_Concave_", 90.0], + # *SOT* seems to need 180 + ["^SOT-143", 180.0], + ["^SOT-223", 180.0], + ["^SOT-23", 180.0], + ["^SOT-353", 180.0], + ["^SOT-363", 180.0], + ["^SOT-89", 180.0], + ["^D_SOT-23", 180.0], + ["^TSOT-23", 180.0], + # Polarized capacitors + ["^CP_EIA-", 180.0], + ["^CP_Elec_", 180.0], + ["^C_Elec_", 180.0], + # Most four side components needs -90 (270) + ["^QFN-", 270.0], + ["^(.*?_|V)?QFN-(16|20|24|28|40)(-|_|$)", 270.0], + ["^DFN-", 270.0], + ["^LQFP-", 270.0], + ["^TQFP-", 270.0], + # SMD DIL packages mostly needs -90 (270) + ["^SOP-(?!(18_|4_))", 270.0], # SOP 18 and 4 excluded, wrong at JLCPCB + ["^MSOP-", 270.0], + ["^TSSOP-", 270.0], + ["^HTSSOP-", 270.0], + ["^SSOP-", 270.0], + ["^SOIC-", 270.0], + ["^SO-", 270.0], + ["^SOIC127P798X216-8N", 270.0], + ["^VSSOP-8_3.0x3.0mm_P0.65mm", 270.0], + ["^VSSOP-8_", 180.0], + ["^VSSOP-10_", 270.0], + ["^VSON-8_", 270.0], + ["^TSOP-6", 270.0], + ["^UDFN-10", 270.0], + ["^USON-10", 270.0], + ["^TDSON-8-1", 270.0], + # Misc. + ["^LED_WS2812B_PLCC4", 180.0], + ["^LED_WS2812B-2020_PLCC4_2.0x2.0mm", 90.0], + ["^Bosch_LGA-", 90.0], + ["^PowerPAK_SO-8_Single", 270.0], + ["^PUIAudio_SMT_0825_S_4_R*", 270.0], + ["^USB_C_Receptacle_HRO_TYPE-C-31-M-12*", 180.0], + ["^ESP32-W", 270.0], + ["^SW_DIP_SPSTx01_Slide_Copal_CHS-01B_W7.62mm_P1.27mm", -180.0], + ["^BatteryHolder_Keystone_1060_1x2032", -180.0], + ["^Relay_DPDT_Omron_G6K-2F-Y", 270.0], + ["^RP2040-QFN-56", 270.0], + ["^TO-277", 90.0], + ["^SW_SPST_B3", 90.0], + ["^Transformer_Ethernet_Pulse_HX0068ANL", 270.0], + ["^JST_GH_SM", 180.0], + ["^JST_PH_S", 180.0], + ["^Diodes_PowerDI3333-8", 270.0], + ["^Quectel_L80-R", 270.0], + ["^SC-74-6", 180.0], + [r"^PinHeader_2x05_P1\.27mm_Vertical", 90.0], + [r"^PinHeader_2x03_P1\.27mm_Vertical", 90.0], + ] +DEFAULT_ROT_FIELDS = ['JLCPCB Rotation Offset', 'JLCRotOffset'] +DEFAULT_OFFSETS = [["^USB_C_Receptacle_XKB_U262-16XN-4BVC11", (0.0, -1.44)], + [r"^PinHeader_2x05_P1\.27mm_Vertical", (2.54, 0.635)], + [r"^PinHeader_2x03_P1\.27mm_Vertical", (1.27, 0.635)], + ] +DEFAULT_OFFSET_FIELDS = ['JLCPCB Position Offset', 'JLCPosOffset'] + + class Rect(object): """ What KiCad returns isn't a real wxWidget's wxRect. Here I add what I really need """