From e9711e5be7e3627c366674792240309b69e67600 Mon Sep 17 00:00:00 2001 From: Richard Lin Date: Wed, 10 Apr 2024 12:00:11 -0700 Subject: [PATCH] refactor wip --- electronics_model/SvgPcbBackend.py | 115 ----------------------- electronics_model/SvgPcbTemplateBlock.py | 15 ++- electronics_model/__init__.py | 1 - 3 files changed, 12 insertions(+), 119 deletions(-) delete mode 100644 electronics_model/SvgPcbBackend.py diff --git a/electronics_model/SvgPcbBackend.py b/electronics_model/SvgPcbBackend.py deleted file mode 100644 index 1f66b4137..000000000 --- a/electronics_model/SvgPcbBackend.py +++ /dev/null @@ -1,115 +0,0 @@ -import importlib -import inspect -from typing import List, Tuple, Dict, NamedTuple - -import edgir -from edg_core import BaseBackend, CompiledDesign, TransformUtil -from .NetlistGenerator import NetlistTransform, NetBlock, NetPin -from .SvgPcbTemplateBlock import SvgPcbTemplateBlock - - -class SvgPcbBackend(BaseBackend): - """Backend that generates SVG-PCB (https://github.com/leomcelroy/svg-pcb) layout code for a board, - using block templates (if available) or bare footprints for other components. - """ - @classmethod - def _block_matches_prefixes(cls, block: NetBlock, prefixes: List[List[str]]): - for prefix in prefixes: - if block.path[0:min(len(block.path), len(prefix))] == prefix: - return True - return False - - @classmethod - def _filter_blocks_by_pathname(cls, blocks: List[NetBlock], exclude_prefixes: List[List[str]]) -> List[NetBlock]: - return [block for block in blocks - if not cls._block_matches_prefixes(block, exclude_prefixes)] - - @classmethod - def _pathname_to_svbpcb(cls, path: TransformUtil.Path) -> str: - return '_'.join(path.to_tuple()) - - @classmethod - def _footprint_to_svgpcb(cls, footprint: str) -> str: - # TODO needs to be consistent w/ svgpcb rules - return footprint.split(':')[-1].replace('-', '_').replace(' ', '_').replace('.', '_') - - def run(self, design: CompiledDesign, args: Dict[str, str] = {}) -> List[Tuple[edgir.LocalPath, str]]: - svgpcb_blocks = SvgPcbTransform(design).run() - svgpcb_block_prefixes = [list(path.to_tuple()) for path, block in svgpcb_blocks] - netlist = NetlistTransform(design).run() - other_blocks = self._filter_blocks_by_pathname(netlist.blocks, svgpcb_block_prefixes) - - functions_definitions = '\n'.join([block.svgpcb_code for path, block in svgpcb_blocks]) - svgpcb_block_instantiations = ''.join([ - f"const {self._pathname_to_svbpcb(path)} = {block.fn_name}(pt(0, 0))\n" - for path, block in svgpcb_blocks - ]) - other_block_instantiations = ''.join([ - f"""\ -const {self._pathname_to_svbpcb(block.full_path)} = board.add({self._footprint_to_svgpcb(block.footprint)}, {{ - translate: pt(0, 0), rotate: 0, - id: '{self._pathname_to_svbpcb(block.full_path)}' -}})\n""" - for block in other_blocks - ]) - - nets_pins_code = {net.name: ', '.join([ - f"""["{self._pathname_to_svbpcb(pin.block_path)}", "{pin.pin_name}"]""" - for pin in net.pins - ]) - for net in netlist.nets} - nets_code = [f"""\ - {{ - name: "{net_name}", - pads: [{net_code}] - }}""" - for net_name, net_code in nets_pins_code.items()] - sep = ',\n' # get past backslashes not allowed in f-strings - netlist_code = f"""\ -board.setNetlist([ -{sep.join(nets_code)} -]) -""" - - return [ - (edgir.LocalPath(), functions_definitions), - (edgir.LocalPath(), svgpcb_block_instantiations + other_block_instantiations), - (edgir.LocalPath(), netlist_code), - ] - - -class SvgPcbGeneratedBlock(NamedTuple): - fn_name: str - svgpcb_code: str - - -class SvgPcbTransform(TransformUtil.Transform): - """Collects all SVGPCB blocks and initializes them.""" - def __init__(self, design: CompiledDesign): - self.design = design - self._svgpcb_blocks: List[Tuple[TransformUtil.Path, SvgPcbGeneratedBlock]] = [] - - def visit_block(self, context: TransformUtil.TransformContext, block: edgir.BlockTypes) -> None: - # ignore root, bit of a heuristic hack since importing the toplevel script can be brittle - if context.path == TransformUtil.Path.empty(): - return - - # TODO: dedup w/ class_from_library in edg_hdl_server - elt_split = block.self_class.target.name.split('.') - elt_module = importlib.import_module('.'.join(elt_split[:-1])) - assert inspect.ismodule(elt_module) - cls = getattr(elt_module, elt_split[-1]) - if issubclass(cls, SvgPcbTemplateBlock): - generator_obj = cls() - generator_obj._svgpcb_init(context.path, self.design) - self._svgpcb_blocks.append((context.path, - SvgPcbGeneratedBlock( - generator_obj._svgpcb_fn_name(), - generator_obj._svgpcb_template(), - ))) - else: - pass - - def run(self) -> List[Tuple[TransformUtil.Path, SvgPcbGeneratedBlock]]: - self.transform_design(self.design.design) - return self._svgpcb_blocks diff --git a/electronics_model/SvgPcbTemplateBlock.py b/electronics_model/SvgPcbTemplateBlock.py index c161744de..1d8a778a2 100644 --- a/electronics_model/SvgPcbTemplateBlock.py +++ b/electronics_model/SvgPcbTemplateBlock.py @@ -10,7 +10,17 @@ class SvgPcbTemplateBlock(Block): A Block that can generate a SVG-PCB (https://github.com/leomcelroy/svg-pcb) layout template. This defines the per-class methods (including per-class code generation), the actual board-level code composition - and generation of non-templated footprints exists in the backend.""" + and generation of non-templated footprints exists in the backend. + + This defines the interface and supporting utilities only.""" + @staticmethod + def _svgpcb_pathname_to_svgpcb(path: TransformUtil.Path): + return '_'.join(path.to_tuple()) + + @staticmethod + def _svgpcb_footprint_to_svgpcb(footprint: str) -> str: # KiCad footprint name to SVGPCB reference + return footprint.split(':')[-1].replace('-', '_').replace(' ', '_').replace('.', '_') + def _svgpcb_init(self, pathname: TransformUtil.Path, design: CompiledDesign) -> None: """Initializes this Block for SVGPCB template generation. Called from the backend.""" self._svgpcb_pathname_data = pathname @@ -19,8 +29,7 @@ def _svgpcb_init(self, pathname: TransformUtil.Path, design: CompiledDesign) -> def _svgpcb_pathname(self) -> str: """Infrastructure method, returns the pathname for this Block as a JS-code-friendly string.""" - from .SvgPcbBackend import SvgPcbBackend - return SvgPcbBackend._pathname_to_svbpcb(self._svgpcb_pathname_data) + return self._svgpcb_pathname_to_svgpcb(self._svgpcb_pathname_data) def _svgpcb_get(self, param: ConstraintExpr[Any, Any]) -> Optional[str]: """Infrastructure method, returns the value of the ConstraintExpr as a JS literal. diff --git a/electronics_model/__init__.py b/electronics_model/__init__.py index 5d6f584df..a4e7c1fc0 100644 --- a/electronics_model/__init__.py +++ b/electronics_model/__init__.py @@ -46,5 +46,4 @@ from .NetlistBackend import NetlistBackend from .PinAssignmentUtil import PinAssignmentUtil, AnyPinAssign, PeripheralPinAssign, NotConnectedPin, AnyPin -from .SvgPcbBackend import SvgPcbBackend from .SvgPcbTemplateBlock import SvgPcbTemplateBlock