From aa6b542d76c07d6364811b06a5cb09700851a74b Mon Sep 17 00:00:00 2001 From: napowderly Date: Mon, 20 Nov 2023 10:23:51 -0800 Subject: [PATCH] adding .ato file generation as an optional export --- easyeda2kicad/__main__.py | 58 ++++++++++++++++- easyeda2kicad/atopile/export_ato.py | 98 +++++++++++++++++++++++++++++ requirements.txt | 2 +- 3 files changed, 154 insertions(+), 4 deletions(-) create mode 100644 easyeda2kicad/atopile/export_ato.py diff --git a/easyeda2kicad/__main__.py b/easyeda2kicad/__main__.py index a4bec62..97374f3 100644 --- a/easyeda2kicad/__main__.py +++ b/easyeda2kicad/__main__.py @@ -6,6 +6,7 @@ import sys from textwrap import dedent from typing import List +from pathlib import Path from easyeda2kicad import __version__ from easyeda2kicad.easyeda.easyeda_api import EasyedaApi @@ -26,6 +27,7 @@ from easyeda2kicad.kicad.export_kicad_footprint import ExporterFootprintKicad from easyeda2kicad.kicad.export_kicad_symbol import ExporterSymbolKicad from easyeda2kicad.kicad.parameters_kicad_symbol import KicadVersion +from easyeda2kicad.atopile.export_ato import ExporterAto def get_parser() -> argparse.ArgumentParser: @@ -39,6 +41,18 @@ def get_parser() -> argparse.ArgumentParser: parser.add_argument("--lcsc_id", help="LCSC id", required=True, type=str) + parser.add_argument( + "--ato", help="Get atopile file definition of this id", required=False, action="store_true" + ) + + parser.add_argument( + "--ato_file_path", + required=False, + metavar="file.ato", + help="Output dir for .ato file", + type=str, + ) + parser.add_argument( "--symbol", help="Get symbol of this id", required=False, action="store_true" ) @@ -114,9 +128,9 @@ def valid_arguments(arguments: dict) -> bool: return False if arguments["full"]: - arguments["symbol"], arguments["footprint"], arguments["3d"] = True, True, True + arguments["ato"], arguments["symbol"], arguments["footprint"], arguments["3d"] = True, True, True, True - if not any([arguments["symbol"], arguments["footprint"], arguments["3d"]]): + if not any([arguments["ato"], arguments["symbol"], arguments["footprint"], arguments["3d"]]): logging.error( "Missing action arguments\n" " easyeda2kicad --lcsc_id=C2040 --footprint\n" @@ -158,7 +172,7 @@ def valid_arguments(arguments: dict) -> bool: "easyeda2kicad", ) if not os.path.isdir(default_folder): - os.makedirs(default_folder, exist_ok=True) + os.mkdir(default_folder) base_folder = default_folder lib_name = "easyeda2kicad" @@ -254,6 +268,44 @@ def main(argv: List[str] = sys.argv[1:]) -> int: logging.error(f"Failed to fetch data from EasyEDA API for part {component_id}") return 1 + + # ---------------- ATOPILE ---------------- + if arguments["ato"]: + importer = EasyedaSymbolImporter(easyeda_cp_cad_data=cad_data) + easyeda_symbol: EeSymbol = importer.get_symbol() + # print(easyeda_symbol) + component_name=easyeda_symbol.info.name + # ato file path should be the the base directory of output argument /elec/src + ato_full_path = f"{arguments['ato_file_path']}/{component_name}.ato" + is_ato_already_in_lib_folder = os.path.isfile(ato_full_path) + + if not arguments["overwrite"] and is_ato_already_in_lib_folder: + logging.error("Use --overwrite to update the older ato file") + return 1 + + footprint_importer = EasyedaFootprintImporter(easyeda_cp_cad_data=cad_data) + easyeda_footprint = footprint_importer.get_footprint() + package_name=easyeda_footprint.info.name + + exporter = ExporterAto( + symbol = easyeda_symbol, + component_id = component_id, + component_name = component_name, + footprint = package_name + ) + # print(exporter.output) + exporter.export( + ato_full_path = ato_full_path + ) + + + logging.info( + f"Created Atopile file for ID : {component_id}\n" + f" Symbol name : {easyeda_symbol.info.name}\n" + f" Library path : {ato_full_path}" + ) + + # ---------------- SYMBOL ---------------- if arguments["symbol"]: importer = EasyedaSymbolImporter(easyeda_cp_cad_data=cad_data) diff --git a/easyeda2kicad/atopile/export_ato.py b/easyeda2kicad/atopile/export_ato.py new file mode 100644 index 0000000..161046f --- /dev/null +++ b/easyeda2kicad/atopile/export_ato.py @@ -0,0 +1,98 @@ +# Global imports +import logging +from pathlib import Path + +log = logging.getLogger(__name__) + +from easyeda2kicad.easyeda.parameters_easyeda import ( + EasyedaPinType, + EeSymbol, +) + +ee_pin_type_to_ato_pin_type = { + EasyedaPinType.unspecified: None, + EasyedaPinType._input: "input", + EasyedaPinType.output: "output", + EasyedaPinType.bidirectional: "bidirectional", + EasyedaPinType.power: "power", +} +ee_pin_rotation_to_vis_side = {0: "right", 90: "bottom", 180: "left", 270: "top"} + + +def add_pin_vis(name, pos): + return f""" + - name: {name} + index: 0 + private: false + port: {pos}""" + + +def convert_to_ato( + ee_symbol: EeSymbol, component_id: str, component_name: str, footprint: str +) -> str: + # replace spaces, dashes and slashes with underscores in component_name + component_name = component_name.replace(" ", "_").replace("-", "_").replace("/", "_") + ato_str = f"component {component_name}:\n" + ato_str += f' footprint = "{footprint}"\n' + ato_str += f' lcsc_id = "{component_id}"\n' + ato_str += f" # pins\n" + ato_str_types = " # pin types\n" + ato_str_vis = """ +STM32F103C8T6: + ports: + - name: top + location: top + - name: right + location: right + - name: left + location: left + - name: bottom + location: bottom + pins:""" + for ee_pin in ee_symbol.pins: + signal = ee_pin.name.text.replace(" ", "").replace("-", "_").replace("/", "_") + # add an underscore to the start of the signal name if it starts with a number + if signal[0].isdigit(): + signal = "_" + signal + pin = ee_pin.settings.spice_pin_number.replace(" ", "") + ato_str += f" signal {signal} ~ pin p{pin}\n" + ato_pin_type = ee_pin_type_to_ato_pin_type[ee_pin.settings.type] + if ato_pin_type: + ato_str_types += f" {signal}.type = {ato_pin_type}\n" + location = ee_pin_rotation_to_vis_side[ee_pin.settings.rotation] + ato_str_vis += add_pin_vis(signal, location) + + return ato_str + "\n" + ato_str_types, ato_str_vis + + +class ExporterAto: + def __init__(self, symbol, component_id: str, component_name: str, footprint: str): + self.input: EeSymbol = symbol + self.output = ( + convert_to_ato( + ee_symbol=self.input, + component_id=component_id, + component_name=component_name, + footprint=footprint, + ) + if isinstance(self.input, EeSymbol) + else logging.error("Unknown input symbol format") + ) + + def export(self, ato_full_path: str) -> str: + # Get the directory of the file + ato_dir = Path(ato_full_path).parent + ato_dir.mkdir(parents=True, exist_ok=True) + log.log(level=logging.INFO, msg=ato_full_path) + with open(file=ato_full_path, mode="w", encoding="utf-8") as my_lib: + my_lib.write(self.output[0]) + log.log(level=logging.INFO, msg="ATO file written") + + ato_vis_path = ato_full_path.split(".ato")[0] + ".vis.yaml" + log.log(level=logging.INFO, msg=ato_vis_path) + with open( + file=ato_vis_path, + mode="w", + encoding="utf-8", + ) as my_lib: + my_lib.write(self.output[1]) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 20893eb..7238d4c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -pre-commit>=2.17.0 pydantic>=2.0.0 requests>2.0.0 +pre-commit>=2.17.0 \ No newline at end of file