コード例 #1
0
ファイル: part.py プロジェクト: eedin/skidl
    def generate_netlist_component(self, tool=None):
        """
        Generate the part information for inclusion in a netlist.

        Args:
            tool: The format for the netlist file (e.g., KICAD).
        """

        import skidl

        if tool is None:
            tool = skidl.get_default_tool()

        # Create part value as a string so including it in netlist isn't a problem.
        self.value_str = self._value_to_str()

        try:
            gen_func = getattr(self, "_gen_netlist_comp_{}".format(tool))
        except AttributeError:
            log_and_raise(
                logger,
                ValueError,
                "Can't generate netlist in an unknown ECAD tool format ({}).".format(
                    tool
                ),
            )

        return gen_func()
コード例 #2
0
ファイル: Net.py プロジェクト: UncleRus/skidl
    def generate_xml_net(self, tool=None):
        """
        Generate the net information for inclusion in an XML file.

        Args:
            tool: The format for the XML file (e.g., KICAD).
        """

        import skidl

        if tool is None:
            tool = skidl.get_default_tool()

        self.test_validity()

        # Don't add anything to the XML if no pins are on this net.
        if not self.get_pins():
            return

        try:
            gen_func = getattr(self, '_gen_xml_net_{}'.format(tool))
            return gen_func()
        except AttributeError:
            logger.error(
                "Can't generate XML in an unknown ECAD tool format ({}).".
                format(tool))
            raise Exception
コード例 #3
0
ファイル: Net.py プロジェクト: weimens/skidl
    def generate_netlist_net(self, tool=None):
        """
        Generate the net information for inclusion in a netlist.

        Args:
            tool: The format for the netlist file (e.g., KICAD).
        """

        import skidl

        if tool is None:
            tool = skidl.get_default_tool()

        self.test_validity()

        # Don't add anything to the netlist if no pins are on this net.
        if not self.get_pins():
            return

        try:
            gen_func = getattr(self, "_gen_netlist_net_{}".format(tool))
            return gen_func()
        except AttributeError:
            log_and_raise(
                logger,
                ValueError,
                "Can't generate netlist in an unknown ECAD tool format ({}).".
                format(tool),
            )
コード例 #4
0
    def generate_netlist(self, **kwargs):
        """
        Return a netlist and also write it to a file/stream.

        Args:
            file_: Either a file object that can be written to, or a string
                containing a file name, or None.
            tool: The EDA tool the netlist will be generated for.
            do_backup: If true, create a library with all the parts in the circuit.

        Returns:
            A netlist.
        """

        # Reset the counters to clear any warnings/errors from previous run.
        logger.error.reset()
        logger.warning.reset()

        # Before anything else, clean-up names for multi-segment nets.
        self._merge_net_names()

        import skidl

        # Extract arguments:
        #     Get EDA tool the netlist will be generated for.
        #     Get file the netlist will be stored in (if any).
        #     Get flag controlling the generation of a backup library.
        tool = kwargs.pop('tool', skidl.get_default_tool())
        file_ = kwargs.pop('file_', None)
        do_backup = kwargs.pop('do_backup', True)

        try:
            gen_func = getattr(self, '_gen_netlist_{}'.format(tool))
            netlist = gen_func(**kwargs)  # Pass any remaining arguments.
        except KeyError:
            logger.error(
                "Can't generate netlist in an unknown ECAD tool format ({}).".
                format(tool))
            raise Exception

        if (logger.error.count, logger.warning.count) == (0, 0):
            sys.stderr.write(
                '\nNo errors or warnings found during netlist generation.\n\n')
        else:
            sys.stderr.write(
                '\n{} warnings found during netlist generation.\n'.format(
                    logger.warning.count))
            sys.stderr.write(
                '{} errors found during netlist generation.\n\n'.format(
                    logger.error.count))

        with opened(file_ or (get_script_name() + '.net'), 'w') as f:
            f.write(str(netlist))

        if do_backup:
            self.backup_parts()  # Create a new backup lib for the circuit parts.
            global backup_lib  # Clear out any old backup lib so the new one
            backup_lib = None  #   will get reloaded when it's needed.

        return netlist
コード例 #5
0
    def generate_xml_net(self, tool=None):
        """
        Generate the net information for inclusion in an XML file.

        Args:
            tool: The format for the XML file (e.g., KICAD).
        """

        import skidl

        if tool is None:
            tool = skidl.get_default_tool()

        self.test_validity()

        # Don't add anything to the XML if no pins are on this net.
        if not self.get_pins():
            return

        try:
            gen_func = getattr(self, '_gen_xml_net_{}'.format(tool))
            return gen_func()
        except AttributeError:
            logger.error(
                "Can't generate XML in an unknown ECAD tool format ({}).".
                format(tool))
            raise Exception
コード例 #6
0
    def generate_netlist_net(self, tool=None):
        """NO_CONNECT nets don't generate anything for netlists."""

        import skidl

        if tool is None:
            tool = skidl.get_default_tool()

        return ''
コード例 #7
0
ファイル: Circuit.py プロジェクト: UncleRus/skidl
    def generate_netlist(self, **kwargs):
        """
        Return a netlist and also write it to a file/stream.

        Args:
            file_: Either a file object that can be written to, or a string
                containing a file name, or None.
            tool: The EDA tool the netlist will be generated for.
            do_backup: If true, create a library with all the parts in the circuit.

        Returns:
            A netlist.
        """

        # Before anything else, clean-up names for multi-segment nets.
        self._merge_net_names()

        import skidl

        # Extract arguments:
        #     Get EDA tool the netlist will be generated for.
        #     Get file the netlist will be stored in (if any).
        #     Get flag controlling the generation of a backup library.
        tool = kwargs.pop('tool', skidl.get_default_tool())
        file_ = kwargs.pop('file_', None)
        do_backup = kwargs.pop('do_backup', True)

        try:
            gen_func = getattr(self, '_gen_netlist_{}'.format(tool))
            netlist = gen_func(**kwargs)  # Pass any remaining arguments.
        except KeyError:
            logger.error(
                "Can't generate netlist in an unknown ECAD tool format ({}).".
                format(tool))
            raise Exception

        if (logger.error.count, logger.warning.count) == (0, 0):
            sys.stderr.write(
                '\nNo errors or warnings found during netlist generation.\n\n')
        else:
            sys.stderr.write(
                '\n{} warnings found during netlist generation.\n'.format(
                    logger.warning.count))
            sys.stderr.write(
                '{} errors found during netlist generation.\n\n'.format(
                    logger.error.count))

        with opened(file_ or (get_script_name() + '.net'), 'w') as f:
            f.write(str(netlist))

        if do_backup:
            self.backup_parts(
            )  # Create a new backup lib for the circuit parts.
            global backup_lib  # Clear out any old backup lib so the new one
            backup_lib = None  #   will get reloaded when it's needed.

        return netlist
コード例 #8
0
ファイル: Net.py プロジェクト: UncleRus/skidl
    def generate_netlist_net(self, tool=None):
        """NO_CONNECT nets don't generate anything for netlists."""

        import skidl

        if tool is None:
            tool = skidl.get_default_tool()

        return ''
コード例 #9
0
ファイル: Circuit.py プロジェクト: flaviut/skidl
    def generate_xml(self, file_=None, tool=None):
        """
        Return netlist as an XML string and also write it to a file/stream.

        Args:
            file_: Either a file object that can be written to, or a string
                containing a file name, or None.

        Returns:
            A string containing the netlist.
        """

        # Reset the counters to clear any warnings/errors from previous run.
        logger.error.reset()
        logger.warning.reset()

        # Before anything else, clean-up names for multi-segment nets.
        self._merge_net_names()

        import skidl

        if tool is None:
            tool = skidl.get_default_tool()

        try:
            gen_func = getattr(self, "_gen_xml_{}".format(tool))
            netlist = gen_func()
        except KeyError:
            log_and_raise(
                logger,
                ValueError,
                "Can't generate XML in an unknown ECAD tool format ({}).".
                format(tool),
            )

        if (logger.error.count, logger.warning.count) == (0, 0):
            sys.stderr.write(
                "\nNo errors or warnings found during XML generation.\n\n")
        else:
            sys.stderr.write(
                "\n{} warnings found during XML generation.\n".format(
                    logger.warning.count))
            sys.stderr.write(
                "{} errors found during XML generation.\n\n".format(
                    logger.error.count))

        if not self.no_files:
            with opened(file_ or (get_script_name() + ".xml"), "w") as f:
                f.write(netlist)

        return netlist
コード例 #10
0
ファイル: schlib.py プロジェクト: eedin/skidl
    def __init__(self, filename=None, tool=None, lib_section=None, **attribs):
        """
        Load the parts from a library file.
        """

        import skidl

        if tool is None:
            tool = skidl.get_default_tool()

        # Library starts off empty of parts.
        self.parts = []

        # Attach attributes to the library.
        for k, v in list(attribs.items()):
            setattr(self, k, v)

        # If no filename, create an empty library.
        if not filename:
            pass

        # Load this SchLib with an existing SchLib object if the file name
        # matches one in the cache.
        elif filename in self._cache:
            self.__dict__.update(self._cache[filename].__dict__)

        # Otherwise, load from a schematic library file.
        else:
            try:
                # Use the tool name to find the function for loading the library.
                load_func = getattr(self, "_load_sch_lib_{}".format(tool))
            except AttributeError:
                # OK, that didn't work so well...
                log_and_raise(
                    logger,
                    ValueError,
                    "Unsupported ECAD tool library: {}.".format(tool),
                )
            else:
                load_func(filename,
                          skidl.lib_search_paths[tool],
                          lib_section=lib_section)
                self.filename = filename
                # Cache a reference to the library.
                self._cache[filename] = self
コード例 #11
0
ファイル: Circuit.py プロジェクト: UncleRus/skidl
    def generate_xml(self, file_=None, tool=None):
        """
        Return netlist as an XML string and also write it to a file/stream.

        Args:
            file_: Either a file object that can be written to, or a string
                containing a file name, or None.

        Returns:
            A string containing the netlist.
        """

        # Before anything else, clean-up names for multi-segment nets.
        self._merge_net_names()

        import skidl

        if tool is None:
            tool = skidl.get_default_tool()

        try:
            gen_func = getattr(self, '_gen_xml_{}'.format(tool))
            netlist = gen_func()
        except KeyError:
            logger.error(
                "Can't generate XML in an unknown ECAD tool format ({}).".
                format(tool))
            raise Exception

        if (logger.error.count, logger.warning.count) == (0, 0):
            sys.stderr.write(
                '\nNo errors or warnings found during XML generation.\n\n')
        else:
            sys.stderr.write(
                '\n{} warnings found during XML generation.\n'.format(
                    logger.warning.count))
            sys.stderr.write(
                '{} errors found during XML generation.\n\n'.format(
                    logger.error.count))

        with opened(file_ or (get_script_name() + '.xml'), 'w') as f:
            f.write(netlist)

        return netlist
コード例 #12
0
    def generate_xml(self, file_=None, tool=None):
        """
        Return netlist as an XML string and also write it to a file/stream.

        Args:
            file_: Either a file object that can be written to, or a string
                containing a file name, or None.

        Returns:
            A string containing the netlist.
        """

        # Before anything else, clean-up names for multi-segment nets.
        self._merge_net_names()

        import skidl

        if tool is None:
            tool = skidl.get_default_tool()

        try:
            gen_func = getattr(self, '_gen_xml_{}'.format(tool))
            netlist = gen_func()
        except KeyError:
            logger.error(
                "Can't generate XML in an unknown ECAD tool format ({}).".
                format(tool))
            raise Exception

        if (logger.error.count, logger.warning.count) == (0, 0):
            sys.stderr.write(
                '\nNo errors or warnings found during XML generation.\n\n')
        else:
            sys.stderr.write(
                '\n{} warnings found during XML generation.\n'.format(
                    logger.warning.count))
            sys.stderr.write(
                '{} errors found during XML generation.\n\n'.format(
                    logger.error.count))

        with opened(file_ or (get_script_name() + '.xml'), 'w') as f:
            f.write(netlist)

        return netlist
コード例 #13
0
def show_footprint(lib, module_name, tool=None):
    """
    Print the pads for a given module in a library.

    Args:
        lib: The name of a library.
        module_name: The name of the footprint in the library.
        tool: The ECAD tool format for the library.

    Returns:
        A Part object.
    """

    import skidl

    if tool is None:
        tool = skidl.get_default_tool()

    os.environ["KISYSMOD"] = os.pathsep.join(skidl.footprint_search_paths[tool])
    return pym.Module.from_library(lib, module_name)
コード例 #14
0
    def generate_xml_component(self, tool=None):
        """
        Generate the part information for inclusion in an XML file.

        Args:
            tool: The format for the XML file (e.g., KICAD).
        """

        import skidl

        if tool is None:
            tool = skidl.get_default_tool()

        try:
            gen_func = getattr(self, '_gen_xml_comp_{}'.format(tool))
            return gen_func()
        except AttributeError:
            logger.error(
                "Can't generate XML in an unknown ECAD tool format ({}).".
                format(tool))
            raise Exception
コード例 #15
0
ファイル: Part.py プロジェクト: UncleRus/skidl
    def generate_xml_component(self, tool=None):
        """
        Generate the part information for inclusion in an XML file.

        Args:
            tool: The format for the XML file (e.g., KICAD).
        """

        import skidl

        if tool is None:
            tool = skidl.get_default_tool()

        try:
            gen_func = getattr(self, '_gen_xml_comp_{}'.format(tool))
            return gen_func()
        except AttributeError:
            logger.error(
                "Can't generate XML in an unknown ECAD tool format ({}).".
                format(tool))
            raise Exception
コード例 #16
0
ファイル: SchLib.py プロジェクト: UncleRus/skidl
    def __init__(self, filename=None, tool=None, **attribs):
        """
        Load the parts from a library file.
        """

        import skidl

        if tool is None:
            tool = skidl.get_default_tool()

        # Library starts off empty of parts.
        self.parts = []

        # Attach attributes to the library.
        for k, v in attribs.items():
            setattr(self, k, v)

        # If no filename, create an empty library.
        if not filename:
            pass

        # Load this SchLib with an existing SchLib object if the file name
        # matches one in the cache.
        elif filename in self._cache:
            self.__dict__.update(self._cache[filename].__dict__)

        # Otherwise, load from a schematic library file.
        else:
            try:
                # Use the tool name to find the function for loading the library.
                load_func = getattr(self, '_load_sch_lib_{}'.format(tool))
            except AttributeError:
                # OK, that didn't work so well...
                logger.error('Unsupported ECAD tool library: {}.'.format(tool))
                raise Exception
            else:
                load_func(filename, skidl.lib_search_paths[tool])
                self.filename = filename
                # Cache a reference to the library.
                self._cache[filename] = self
コード例 #17
0
ファイル: part.py プロジェクト: eedin/skidl
    def generate_svg_component(self, symtx="", tool=None, net_stubs=None):
        """
        Generate the SVG for displaying a part in an SVG schematic.
        """

        import skidl

        if tool is None:
            tool = skidl.get_default_tool()

        try:
            gen_func = getattr(self, "_gen_svg_comp_{}".format(tool))
        except AttributeError:
            log_and_raise(
                logger,
                ValueError,
                "Can't generate SVG for a component in an unknown ECAD tool format({}).".format(
                    tool
                ),
            )

        return gen_func(symtx=symtx, net_stubs=net_stubs)
コード例 #18
0
ファイル: part.py プロジェクト: eedin/skidl
    def generate_pinboxes(self, tool=None):
        """
        Generate the pinboxes for arranging parts in a schematic.
        """

        import skidl

        if tool is None:
            tool = skidl.get_default_tool()

        try:
            gen_func = getattr(self, "_gen_pinboxes_{}".format(tool))
        except AttributeError:
            log_and_raise(
                logger,
                ValueError,
                "Can't generate pinboxes for a component in an unknown ECAD tool format({}).".format(
                    tool
                ),
            )

        return gen_func()
コード例 #19
0
def show_part(lib, part_name, tool=None):
    """
    Print the I/O pins for a given part in a library.

    Args:
        lib: Either a SchLib object or the name of a library.
        part_name: The name of the part in the library.
        tool: The ECAD tool format for the library.

    Returns:
        A Part object.
    """

    import skidl
    from .Part import Part
    from .defines import TEMPLATE

    if tool is None:
        tool = skidl.get_default_tool()
    try:
        return Part(lib, re.escape(part_name), tool=tool, dest=TEMPLATE)
    except Exception:
        return None
コード例 #20
0
ファイル: part_query.py プロジェクト: UncleRus/skidl
def show(lib, part_name, tool=None):
    """
    Print the I/O pins for a given part in a library.

    Args:
        lib: Either a SchLib object or the name of a library.
        part_name: The name of the part in the library.
        tool: The ECAD tool format for the library.

    Returns:
        A Part object.
    """

    import skidl
    from .Part import Part
    from .defines import TEMPLATE

    if tool is None:
        tool = skidl.get_default_tool()
    try:
        return Part(
            lib, re.escape(part_name), tool=tool, dest=TEMPLATE)
    except Exception:
        return None
コード例 #21
0
    def __init__(self,
                 lib=None,
                 name=None,
                 dest=NETLIST,
                 tool=None,
                 connections=None,
                 part_defn=None,
                 circuit=None,
                 **attribs):

        import skidl
        from .SchLib import SchLib

        super().__init__()

        if tool is None:
            tool = skidl.get_default_tool()

        # Setup some part attributes that might be overwritten later on.
        self.do_erc = True  # Allow part to be included in ERC.
        self.unit = {
        }  # Dictionary for storing subunits of the part, if desired.
        self.pins = []  # Start with no pins, but a place to store them.
        self.p = PinNumberSearch(
            self)  # Does pin search using only pin numbers.
        self.n = PinNameSearch(self)  # Does pin search using only pin names.
        self.name = name  # Assign initial part name.
        self.description = ""  # Make sure there is a description, even if empty.
        self._ref = ""  # Provide a member for holding a reference.
        self.ref_prefix = ""  # Provide a member for holding the part reference prefix.
        self.tool = tool  # Initial type of part (SKIDL, KICAD, etc.)
        self.circuit = None  # Part starts off unassociated with any circuit.
        self.match_pin_substring = False  # Only select pins with exact name matches.

        # Create a Part from a library entry.
        if lib:
            # If the lib argument is a string, then create a library using the
            # string as the library file name.
            if isinstance(lib, basestring):
                libname = lib
                try:
                    lib = SchLib(filename=libname, tool=tool)
                except FileNotFoundError as e:
                    if skidl.QUERY_BACKUP_LIB:
                        logger.warning(
                            'Could not load KiCad schematic library "{}", falling back to backup library.'
                            .format(libname))
                        lib = skidl.load_backup_lib()
                        if not lib:
                            raise e
                    else:
                        raise e

            # Make a copy of the part from the library but don't add it to the netlist.
            part = lib[name].copy(dest=TEMPLATE)

            # Overwrite self with the new part.
            self.__dict__.update(part.__dict__)

            # Replace the fields with a copy that points to self.
            self.fields = part.fields.copy(attr_obj=self)

            # Make sure all the pins have a valid reference to this part.
            self.associate_pins()

            # Store the library name of this part.
            self.lib = getattr(lib, "filename", None)

        # Otherwise, create a Part from a part definition. If the part is
        # destined for a library, then just get its name. If it's going into
        # a netlist, then parse the entire part definition.
        elif part_defn:
            self.part_defn = part_defn
            self.parse(get_name_only=(dest != NETLIST))

        # If the part is destined for a SKiDL library, then it will be defined
        # by the additional attribute values that are passed.
        elif tool == SKIDL and name:
            pass

        else:
            log_and_raise(
                logger,
                ValueError,
                "Can't make a part without a library & part name or a part definition.",
            )

        # If the part is going to be an element in a circuit, then add it to the
        # the circuit and make any indicated pin/net connections.
        if dest != LIBRARY:
            # If no Circuit object is given, then use the default Circuit that always exists.
            circuit = circuit or default_circuit
            if dest == NETLIST:
                circuit += self
            elif dest == TEMPLATE:
                # If this is just a part template, don't add the part to the circuit.
                # Just place the reference to the Circuit object in the template.
                self.circuit = circuit

            # Add any net/pin connections to this part that were passed as arguments.
            if isinstance(connections, dict):
                for pin, net in list(connections.items()):
                    net += self[pin]

        # Add any XSPICE I/O as pins. (This only happens with SPICE simulations.)
        self.add_xspice_io(attribs.pop("io", []))

        # Add any other passed-in attributes to the part.
        for k, v in list(attribs.items()):
            setattr(self, k, v)
コード例 #22
0
ファイル: part_query.py プロジェクト: weimens/skidl
def search(term, tool=None):
    """
    Print a list of components with the regex term within their name, alias, description or keywords.
    """

    import skidl
    from .SchLib import SchLib

    def search_libraries(term, tool):
        """Search for a regex term in part libraries."""

        # Set of parts and their containing libraries found with the term.
        parts = set()

        for lib_dir in skidl.lib_search_paths[tool]:

            # Get all the library files in the search path.
            try:
                lib_files = os.listdir(lib_dir)
            except (FileNotFoundError, OSError):
                logger.warning("Could not open directory '{}'".format(lib_dir))
                lib_files = list()  # Empty list since library directory was not found.

            lib_files = [l for l in lib_files if l.endswith(skidl.lib_suffixes[tool])]

            for lib_file in lib_files:

                print(" " * 79, "\rSearching {} ...".format(lib_file), end="\r")

                lib = SchLib(
                    os.path.join(lib_dir, lib_file), tool=tool
                )  # Open the library file.

                def mk_list(l):
                    """Make a list out of whatever is given."""
                    if isinstance(l, (list, tuple)):
                        return l
                    if not l:
                        return []
                    return [l]

                # Search the current library for parts with the given term in
                # each of the these categories.
                for category in ["name", "aliases", "description", "keywords"]:
                    for part in mk_list(
                        lib.get_parts(use_backup_lib=False, **{category: term})
                    ):
                        # Parse the part to instantiate the complete object.
                        part.parse(get_name_only=True)
                        # Store the library name and part object.
                        parts.add((lib_file, part))

                print(" " * 79, end="\r")

        # Return the list of parts and their containing libraries.
        return list(parts)

    if tool is None:
        tool = skidl.get_default_tool()

    term = ".*" + term + ".*"  # Use the given term as a substring.
    parts = search_libraries(term, tool)  # Search for parts with that substring.

    # Print each part name sorted by the library where it was found.
    for lib_file, p in sorted(parts, key=lambda p: p[0]):
        print(
            "{}: {} ({})".format(
                lib_file, getattr(p, "name", "???"), getattr(p, "description", "???")
            )
        )
コード例 #23
0
def search_parts_iter(terms, tool=None):
    """Return a list of (lib, part) sequences that match a regex term."""

    import skidl
    from .SchLib import SchLib

    if tool is None:
        tool = skidl.get_default_tool()

    terms = parse_search_terms(terms)

    def mk_list(l):
        """Make a list out of whatever is given."""
        if isinstance(l, (list, tuple)):
            return l
        if not l:
            return []
        return [l]

    # Gather all the lib files from all the directories in the search paths.
    lib_files = list()
    for lib_dir in skidl.lib_search_paths[tool]:

        # Get all the library files in the search path.
        try:
            files = os.listdir(lib_dir)
        except (FileNotFoundError, OSError):
            logger.warning("Could not open directory '{}'".format(lib_dir))
            files = []

        files = [(lib_dir, l) for l in files if l.endswith(skidl.lib_suffixes[tool])]
        lib_files.extend(files)

    num_lib_files = len(lib_files)

    # Now search through the lib files for parts that match the search terms.
    for idx, (lib_dir, lib_file) in enumerate(lib_files):

        # If just entered a new lib file, yield the name of the file and
        # where it is within the total number of files to search.
        # (This is used for progress indicators.)
        yield "LIB", lib_file, idx + 1, num_lib_files

        # Parse the lib file to create a part library.
        lib = SchLib(
            os.path.join(lib_dir, lib_file), tool=tool
        )  # Open the library file.

        # Search the current library for parts with the given terms.
        for part in mk_list(
            # Get any matching parts from the library file.
            lib.get_parts(use_backup_lib=False, search_text=terms)
        ):
            # Parse the part to instantiate the complete object.
            part.parse(get_name_only=True)

            # Yield the part and its containing library.
            yield "PART", lib_file, part, part.name

            # Also return aliases.
            for alias in list(part.aliases):
                yield "PART", lib_file, part, alias
コード例 #24
0
def search_footprints_iter(terms, tool=None):
    """Return a list of (lib, footprint) sequences that match a regex term."""

    import skidl

    if tool is None:
        tool = skidl.get_default_tool()

    terms = parse_search_terms(terms)

    # If the cache isn't valid, then make it valid by gathering all the
    # footprint files from all the directories in the search paths.
    if not footprint_cache.valid:
        footprint_cache.clear()
        for path in skidl.footprint_search_paths[tool]:
            footprint_cache.load(os.path.join(path, "fp-lib-table"))

    # Get the number of footprint libraries to be searched..
    num_fp_libs = len(footprint_cache)

    # Now search through the libraries for footprints that match the search terms.
    for idx, fp_lib in enumerate(footprint_cache):

        # If just entered a new library, yield the name of the lib and
        # where it is within the total number of libs to search.
        # (This is used for progress indicators.)
        yield "LIB", fp_lib, idx + 1, num_fp_libs

        # Get path to library directory and dict of footprint modules.
        path = footprint_cache[fp_lib]["path"]
        modules = footprint_cache[fp_lib]["modules"]

        # Search each module in the library.
        for module_name in modules:

            # If the cache isn't valid, then read each footprint file and store
            # it's contents in the cache.
            if not footprint_cache.valid:
                file = os.path.join(path, module_name + ".kicad_mod")
                with open(file, "r") as fp:
                    try:
                        # Remove any linefeeds that would interfere with fullmatch() later on.
                        modules[module_name] = [l.rstrip() for l in fp.readlines()]
                    except UnicodeDecodeError:
                        try:
                            modules[module_name] = [
                                l.decode("utf-8").rstrip() for l in fp.readlines()
                            ]
                        except AttributeError:
                            modules[module_name] = ""

            # Get the contents of the footprint file from the cache.
            module_text = tuple(modules[module_name])

            # Count the pads so it can be added to the text being searched.
            # Join all the module text lines, search for the number of
            # occurrences of "(pad", and then count them.
            # A set is used so pads with the same num/name are only counted once.
            # Place the pad count before everything else so the space that
            # terminates it won't be stripped off later. This is necessary
            # so (for example) "#pads=20 " won't match "#pads=208".
            num_pads = len(
                set(re.findall(r"\(\s*pad\s+([^\s)]+)", " ".join(module_text)))
            )
            num_pads_str = "#pads={}".format(num_pads)

            # Create a string with the module name, library name, number of pads,
            # description and tags.
            search_text = "\n".join([num_pads_str, fp_lib, module_name])
            for line in module_text:
                if "(descr " in line or "(tags " in line:
                    search_text = "\n".join([search_text, line])

            # Search the string for a match with the search terms.
            if fullmatch(
                terms, search_text, flags=re.IGNORECASE | re.MULTILINE | re.DOTALL
            ):
                yield "MODULE", fp_lib, module_text, module_name

    # At the end, all modules have been scanned and the footprint cache is valid.
    footprint_cache.valid = True
コード例 #25
0
ファイル: part_query.py プロジェクト: UncleRus/skidl
def search(term, tool=None):
    """
    Print a list of components with the regex term within their name, alias, description or keywords.
    """

    import skidl
    from .SchLib import SchLib

    def search_libraries(term, tool):
        """Search for a regex term in part libraries."""

        parts = set(
        )  # Set of parts and their containing libraries found with the term.

        for lib_dir in skidl.lib_search_paths[tool]:
            print('lib_dir = {}'.format(lib_dir))
            # Get all the library files in the search path.
            try:
                lib_files = os.listdir(lib_dir)
            except (FileNotFoundError, OSError):
                logger.warning("Could not open directory '{}'".format(lib_dir))
                lib_files = list(
                )  # Empty list since library directory was not found.
            lib_files = [
                l for l in lib_files if l.endswith(skidl.lib_suffixes[tool])
            ]

            for lib_file in lib_files:
                print(
                    ' ' * 79, '\rSearching {} ...'.format(lib_file), end='\r')
                lib = SchLib(
                    os.path.join(lib_dir, lib_file),
                    tool=tool)  # Open the library file.

                def mk_list(l):
                    """Make a list out of whatever is given."""
                    if isinstance(l, (list, tuple)):
                        return l
                    if not l:
                        return []
                    return [l]

                # Search the current library for parts with the given term in
                # each of the these categories.
                for category in ['name', 'alias', 'description', 'keywords']:
                    for part in mk_list(lib.get_parts(**{category: term})):
                        # Parse the part to instantiate the complete object.
                        part.parse()
                        # Store the library name and part object.
                        parts.add((lib_file, part))
                print(' ' * 79, end='\r')

        # Return the list of parts and their containing libraries.
        return list(parts)

    if tool is None:
        tool = skidl.get_default_tool()

    term = '.*' + term + '.*'  # Use the given term as a substring.
    parts = search_libraries(term,
                             tool)  # Search for parts with that substring.

    # Print each part name sorted by the library where it was found.
    for lib_file, p in sorted(parts, key=lambda p: p[0]):
        print('{}: {} ({})'.format(lib_file, getattr(p, 'name', '???'),
                                   getattr(p, 'description', '???')))
コード例 #26
0
    def __init__(self,
                 lib=None,
                 name=None,
                 dest=NETLIST,
                 tool=None,
                 connections=None,
                 part_defn=None,
                 circuit=None,
                 **attribs):

        import skidl
        from .SchLib import SchLib
        from .defines import TEMPLATE, NETLIST, LIBRARY, SKIDL

        super(Part, self).__init__()

        if tool is None:
            tool = skidl.get_default_tool()

        # Setup some part attributes that might be overwritten later on.
        self.do_erc = True  # Allow part to be included in ERC.
        self.unit = {
        }  # Dictionary for storing subunits of the part, if desired.
        self.pins = []  # Start with no pins, but a place to store them.
        self.name = name  # Assign initial part name. (Must come after circuit is assigned.)
        self.description = ''  # Make sure there is a description, even if empty.
        self._ref = ''  # Provide a member for holding a reference.
        self.ref_prefix = ''  # Provide a member for holding the part reference prefix.
        self.tool = tool  # Initial type of part (SKIDL, KICAD, etc.)
        self.circuit = None  # Part starts off unassociated with any circuit.

        # Create a Part from a library entry.
        if lib:
            # If the lib argument is a string, then create a library using the
            # string as the library file name.
            if isinstance(lib, basestring):
                try:
                    libname = lib
                    lib = SchLib(filename=libname, tool=tool)
                except Exception as e:
                    if skidl.QUERY_BACKUP_LIB:
                        logger.warning(
                            'Could not load KiCad schematic library "{}", falling back to backup library.'
                            .format(libname))
                        lib = skidl.load_backup_lib()
                        if not lib:
                            raise e
                    else:
                        raise e

            # Make a copy of the part from the library but don't add it to the netlist.
            part = lib[name].copy(dest=TEMPLATE)

            # Overwrite self with the new part.
            self.__dict__.update(part.__dict__)

            # Make sure all the pins have a valid reference to this part.
            self.associate_pins()

            # Store the library name of this part.
            self.lib = getattr(lib, 'filename', None)

        # Otherwise, create a Part from a part definition. If the part is
        # destined for a library, then just get its name. If it's going into
        # a netlist, then parse the entire part definition.
        elif part_defn:
            self.part_defn = part_defn
            self.parse(just_get_name=(dest != NETLIST))

        # If the part is destined for a SKiDL library, then it will be defined
        # by the additional attribute values that are passed.
        elif tool == SKIDL and name:
            pass

        else:
            logger.error(
                "Can't make a part without a library & part name or a part definition."
            )
            raise Exception

        # If the part is going to be an element in a circuit, then add it to the
        # the circuit and make any indicated pin/net connections.
        if dest != LIBRARY:
            if dest == NETLIST:
                # If no Circuit object is given, then use the default Circuit that always exists.
                # Always set circuit first because naming the part requires a lookup
                # of existing names in the circuit.
                if not circuit:
                    circuit = default_circuit  # pylint: disable=undefined-variable
                circuit += self
            elif dest == TEMPLATE:
                # If this is just a part template, don't add the part to the circuit.
                # Just place the reference to the Circuit object in the template.
                if not circuit:
                    self.circuit = default_circuit  # pylint: disable=undefined-variable
                self.circuit = circuit

            # Add any net/pin connections to this part that were passed as arguments.
            if isinstance(connections, dict):
                for pin, net in connections.items():
                    net += self[pin]

            # Add any other passed-in attributes to the part.
            for k, v in attribs.items():
                setattr(self, k, v)
コード例 #27
0
ファイル: Part.py プロジェクト: UncleRus/skidl
    def __init__(self,
                 lib=None,
                 name=None,
                 dest=NETLIST,
                 tool=None,
                 connections=None,
                 part_defn=None,
                 circuit=None,
                 **attribs):

        import skidl
        from .SchLib import SchLib
        from .defines import TEMPLATE, NETLIST, LIBRARY, SKIDL

        if tool is None:
            tool = skidl.get_default_tool()

        # Setup some part attributes that might be overwritten later on.
        self.do_erc = True  # Allow part to be included in ERC.
        self.unit = {
        }  # Dictionary for storing subunits of the part, if desired.
        self.pins = []  # Start with no pins, but a place to store them.
        self.name = name  # Assign initial part name. (Must come after circuit is assigned.)
        self.description = ''  # Make sure there is a description, even if empty.
        self._ref = ''  # Provide a member for holding a reference.
        self.ref_prefix = ''  # Provide a member for holding the part reference prefix.
        self.tool = tool  # Initial type of part (SKIDL, KICAD, etc.)
        self.circuit = None  # Part starts off unassociated with any circuit.

        # Create a Part from a library entry.
        if lib:
            # If the lib argument is a string, then create a library using the
            # string as the library file name.
            if isinstance(lib, basestring):
                try:
                    libname = lib
                    lib = SchLib(filename=libname, tool=tool)
                except Exception as e:
                    if skidl.QUERY_BACKUP_LIB:
                        logger.warning(
                            'Could not load KiCad schematic library "{}", falling back to backup library.'
                            .format(libname))
                        lib = skidl.load_backup_lib()
                        if not lib:
                            raise e
                    else:
                        raise e

            # Make a copy of the part from the library but don't add it to the netlist.
            part = lib[name].copy(dest=TEMPLATE)

            # Overwrite self with the new part.
            self.__dict__.update(part.__dict__)

            # Make sure all the pins have a valid reference to this part.
            self.associate_pins()

            # Store the library name of this part.
            self.lib = getattr(lib, 'filename', None)

        # Otherwise, create a Part from a part definition. If the part is
        # destined for a library, then just get its name. If it's going into
        # a netlist, then parse the entire part definition.
        elif part_defn:
            self.part_defn = part_defn
            self.parse(just_get_name=(dest != NETLIST))

        # If the part is destined for a SKiDL library, then it will be defined
        # by the additional attribute values that are passed.
        elif tool == SKIDL and name:
            pass

        else:
            logger.error(
                "Can't make a part without a library & part name or a part definition."
            )
            raise Exception

        # If the part is going to be an element in a circuit, then add it to the
        # the circuit and make any indicated pin/net connections.
        if dest != LIBRARY:
            if dest == NETLIST:
                # If no Circuit object is given, then use the default Circuit that always exists.
                # Always set circuit first because naming the part requires a lookup
                # of existing names in the circuit.
                if not circuit:
                    circuit = default_circuit  # pylint: disable=undefined-variable
                circuit += self
            elif dest == TEMPLATE:
                # If this is just a part template, don't add the part to the circuit.
                # Just place the reference to the Circuit object in the template.
                if not circuit:
                    self.circuit = default_circuit  # pylint: disable=undefined-variable
                self.circuit = circuit

            # Add any net/pin connections to this part that were passed as arguments.
            if isinstance(connections, dict):
                for pin, net in connections.items():
                    net += self[pin]

            # Add any other passed-in attributes to the part.
            for k, v in attribs.items():
                setattr(self, k, v)
コード例 #28
0
def search(term, tool=None):
    """
    Print a list of components with the regex term within their name, alias, description or keywords.
    """

    import skidl
    from .SchLib import SchLib

    def search_libraries(term, tool):
        """Search for a regex term in part libraries."""

        parts = set(
        )  # Set of parts and their containing libraries found with the term.

        for lib_dir in skidl.lib_search_paths[tool]:
            print('lib_dir = {}'.format(lib_dir))
            # Get all the library files in the search path.
            try:
                lib_files = os.listdir(lib_dir)
            except (FileNotFoundError, OSError):
                logger.warning("Could not open directory '{}'".format(lib_dir))
                lib_files = list(
                )  # Empty list since library directory was not found.
            lib_files = [
                l for l in lib_files if l.endswith(skidl.lib_suffixes[tool])
            ]

            for lib_file in lib_files:
                print(' ' * 79,
                      '\rSearching {} ...'.format(lib_file),
                      end='\r')
                lib = SchLib(os.path.join(lib_dir, lib_file),
                             tool=tool)  # Open the library file.

                def mk_list(l):
                    """Make a list out of whatever is given."""
                    if isinstance(l, (list, tuple)):
                        return l
                    if not l:
                        return []
                    return [l]

                # Search the current library for parts with the given term in
                # each of the these categories.
                for category in ['name', 'alias', 'description', 'keywords']:
                    for part in mk_list(lib.get_parts(**{category: term})):
                        part.parse(
                        )  # Parse the part to instantiate the complete object.
                        parts.add(
                            (lib_file,
                             part))  # Store the library name and part object.
                print(' ' * 79, end='\r')

        return list(
            parts)  # Return the list of parts and their containing libraries.

    if tool is None:
        tool = skidl.get_default_tool()

    term = '.*' + term + '.*'  # Use the given term as a substring.
    parts = search_libraries(term,
                             tool)  # Search for parts with that substring.

    # Print each part name sorted by the library where it was found.
    for lib_file, p in sorted(parts, key=lambda p: p[0]):
        print('{}: {} ({})'.format(lib_file, getattr(p, 'name', '???'),
                                   getattr(p, 'description', '???')))
コード例 #29
0
ファイル: part.py プロジェクト: eedin/skidl
    def __init__(
        self,
        lib=None,
        name=None,
        dest=NETLIST,
        tool=None,
        connections=None,
        part_defn=None,
        circuit=None,
        **kwargs
    ):

        import skidl
        from .schlib import SchLib

        super().__init__()

        if tool is None:
            tool = skidl.get_default_tool()

        # Setup some part attributes that might be overwritten later on.
        self.do_erc = True  # Allow part to be included in ERC.
        self.unit = {}  # Dictionary for storing subunits of the part, if desired.
        self.pins = []  # Start with no pins, but a place to store them.
        self.p = PinNumberSearch(self)  # Does pin search using only pin numbers.
        self.n = PinNameSearch(self)  # Does pin search using only pin names.
        self.name = name  # Assign initial part name.
        self.description = ""  # Make sure there is a description, even if empty.
        self._ref = ""  # Provide a member for holding a reference.
        self.ref_prefix = ""  # Provide a member for holding the part reference prefix.
        self.tool = tool  # Initial type of part (SKIDL, KICAD, etc.)
        self.circuit = None  # Part starts off unassociated with any circuit.
        self.match_pin_regex = False  # Don't allow regex matches of pin names.

        # Remove a part reference if it has been explicitly set as None.
        # Otherwise, this causes the assigned part reference to be incremented twice:
        # once by Circuit.add_parts() and again by setattr().
        ref = kwargs.pop("ref", None)
        if ref:
            kwargs["ref"] = ref

        # Create a Part from a library entry.
        if lib:
            # If the lib argument is a string, then create a library using the
            # string as the library file name.
            if isinstance(lib, basestring):
                libname = lib
                try:
                    lib = SchLib(filename=libname, tool=tool)
                except FileNotFoundError as e:
                    if skidl.QUERY_BACKUP_LIB:
                        logger.warning(
                            'Could not load KiCad schematic library "{}", falling back to backup library.'.format(
                                libname
                            )
                        )
                        lib = skidl.load_backup_lib()
                        if not lib:
                            raise e
                    else:
                        raise e

            # Make a copy of the part from the library but don't add it to the netlist.
            part = lib[name].copy(dest=TEMPLATE)

            # Overwrite self with the new part.
            self.__dict__.update(part.__dict__)

            # Make sure all the pins have a valid reference to this part.
            self.associate_pins()

            # Copy part units so all the pin and part references stay valid.
            self.copy_units(part)

        # Otherwise, create a Part from a part definition. If the part is
        # destined for a library, then just get its name. If it's going into
        # a netlist, then parse the entire part definition.
        elif part_defn:
            self.part_defn = part_defn

            # If given, set the tool version before parsing the part definition.
            # At this time, this is done to support differences between KiCad V5 and V6.
            tool_version = kwargs.pop("tool_version", None)
            if tool_version:
                self.tool_version = tool_version

            self.parse(get_name_only=(dest != NETLIST))

        # If the part is destined for a SKiDL library, then it will be defined
        # by the additional attribute values that are passed.
        elif tool == SKIDL and name:
            pass

        else:
            log_and_raise(
                logger,
                ValueError,
                "Can't make a part without a library & part name or a part definition.",
            )

        # Split multi-part pin names into individual pin aliases.
        self.split_pin_names(kwargs.pop("pin_splitters", None))

        # Setup the tag for tieing the part to a footprint in a pcb editor.
        # Use the user specified tag if present.
        tag = kwargs.pop("tag", None)
        if tag is not None:
            self.tag = tag
        else:
            self.tag = str(randint(0, 2 ** 64 - 1))

        if dest != LIBRARY:
            if dest == NETLIST:
                # If the part is going to be an element in a circuit, then add it to the
                # the circuit and make any indicated pin/net connections.
                # If no Circuit object is given, then use the default Circuit that always exists.
                circuit = circuit or default_circuit
                circuit += self
            elif dest == TEMPLATE:
                # If this is just a part template, don't add the part to the circuit.
                self.circuit = None

            # Add any net/pin connections to this part that were passed as arguments.
            if isinstance(connections, dict):
                for pin, net in list(connections.items()):
                    net += self[pin]

        # Add any XSPICE I/O as pins. (This only happens with SPICE simulations.)
        self.add_xspice_io(kwargs.pop("io", []))

        # Add any other passed-in attributes to the part.
        for k, v in list(kwargs.items()):
            setattr(self, k, v)