skidl icon indicating copy to clipboard operation
skidl copied to clipboard

generate_netlist(): Use default footprint for part if none is defined

Open shanemmattner opened this issue 3 years ago • 5 comments

Is your feature request related to a problem? Please describe. It can be a pain to find the footprint for parts so it would be nice to use the default footprint for generate_netlist() if the user doesn't define one when creating the part. Also, the code is smaller and easier to read without a footprint defined.

Describe the solution you'd like generate_netlist() should use the default footprint for a part if none is provided when the user creates the part

shanemmattner avatar Jul 06 '22 04:07 shanemmattner

# Current code required
cp2102 = Part('Interface_USB','CP2102N-Axx-xQFN24', footprint='Package_DFN_QFN:QFN-24-1EP_4x4mm_P0.5mm_EP2.6x2.6mm')
esp32 = Part('RF_Module','ESP32-WROOM-32', footprint='RF_Module:ESP32-WROOM-32')

# Proposed code required
cp2102 = Part('Interface_USB','CP2102N-Axx-xQFN24')
esp32 = Part('RF_Module','ESP32-WROOM-32')

shanemmattner avatar Jul 06 '22 04:07 shanemmattner

I pushed a commit to the development branch that loads a Part object with the default footprint from the definition if one isn't explicitly given. It seems to work with the examples you gave. Give it a try and let me know how it works for you.

devbisme avatar Jul 09 '22 19:07 devbisme

This feature works great for parts with a default footprint. However, if the part doesn't have a default footprint (ie most parts from the Device schematic library of KiCAD) the netlist gets generated but cannot be imported to KiCAD as the footprint is blank for that part.

I think generate_schematic() needs to throw an error if the part doesn't have a default footprint. Another option might be to specify default footprints for common parts (3-pin transistors default to SOT23, 2-pin passives default to 0603, etc...).

Here's the .net file (named .txt so I can upload it here). esp32.txt

Here's the skidl code:

from skidl import *


def serial_to_usb():
    cp2102 = Part('Interface_USB','CP2102N-Axx-xQFN24')

def esp32_circuit():
    # MCU
    esp32 = Part('RF_Module','ESP32-WROOM-32')

    #programming transistors
    t1 = Part('Device', 'Q_NPN_BCE')
    t2 = Part('Device', 'Q_NPN_BCE')


esp32_circuit()
serial_to_usb()


generate_netlist(file_="/home/shanemattner/Desktop/esp32/skidl_esp32/esp32_kicad/esp32.net")

shanemmattner avatar Jul 10 '22 00:07 shanemmattner

Maybe the thing to do is define a set_empty_footprint(part) function that gets called during netlist generation if the footprint is empty. Normally, the function will raise an exception, but the user can redefine it so that it substitutes a default footprint for a given type of part and raises an exception for part types it doesn't handle.

devbisme avatar Jul 10 '22 02:07 devbisme

I pushed a commit to the development branch with the empty_footprint_handler() function. Here's an example of how to use it:

import skidl

def my_empty_footprint_handler(part):
    """Function for handling parts with no footprint.

    Args:
        part (Part): Part with no footprint.
    """
    ref_prefix = part.ref_prefix.upper()

    if ref_prefix in ("R", "C", "L") and len(part.pins) == 2:
        # Resistor, capacitors, inductors default to 0805 SMD footprint.
        part.footprint = 'Resistor_SMD:R_0805_2012Metric'

    elif ref_prefix in ('Q',) and len(part.pins) == 3:
        # Transistors default to SOT-23 footprint.
        part.footprint = 'Package_TO_SOT_SMD:SOT-23'

    else:
        # Everything else goes to the default empty footprint handler.
        skidl.default_empty_footprint_handler(part)

# Replace the default empty footprint handler with your own handler.
skidl.empty_footprint_handler = my_empty_footprint_handler

# Create parts with no footprints.
r = skidl.PartTmplt("Device", "R")
r1, r2 = r(), r()
r2.footprint='Resistor_SMD:R_1206_3216Metric'

# Generate a netlist. R1 has no footprint so it will be assigned an 0805.
# R2 already has a footprint so it will not change because it is not passed
# to the empty footprint handler.
skidl.generate_netlist()

devbisme avatar Jul 16 '22 15:07 devbisme

我使用该功能将提交推送到开发分支empty_footprint_handler()。以下是如何使用它的示例:

import skidl

def my_empty_footprint_handler(part):
    """Function for handling parts with no footprint.

    Args:
        part (Part): Part with no footprint.
    """
    ref_prefix = part.ref_prefix.upper()

    if ref_prefix in ("R", "C", "L") and len(part.pins) == 2:
        # Resistor, capacitors, inductors default to 0805 SMD footprint.
        part.footprint = 'Resistor_SMD:R_0805_2012Metric'

    elif ref_prefix in ('Q',) and len(part.pins) == 3:
        # Transistors default to SOT-23 footprint.
        part.footprint = 'Package_TO_SOT_SMD:SOT-23'

    else:
        # Everything else goes to the default empty footprint handler.
        skidl.default_empty_footprint_handler(part)

# Replace the default empty footprint handler with your own handler.
skidl.empty_footprint_handler = my_empty_footprint_handler

# Create parts with no footprints.
r = skidl.PartTmplt("Device", "R")
r1, r2 = r(), r()
r2.footprint='Resistor_SMD:R_1206_3216Metric'

# Generate a netlist. R1 has no footprint so it will be assigned an 0805.
# R2 already has a footprint so it will not change because it is not passed
# to the empty footprint handler.
skidl.generate_netlist()

I run this code ,but r1 footprint still None

In [9]: netlist.parts[0]
Out[9]: ParseResults(['R1', 'R', 'None', 'NO_LIB', 'R', ParseResults(['/top/16994989231103746699', '/top/16994989231103746699'], {'names': '/top/16994989231103746699', 'tstamps': '/top/16994989231103746699'})], {'ref': 'R1', 'value': 'R', 'footprint': 'None', 'lib': 'NO_LIB', 'name': 'R', 'sheetpath': {'names': '/top/16994989231103746699', 'tstamps': '/top/16994989231103746699'}})


In [10]: netlist.parts[1]
Out[10]: ParseResults(['R2', 'R', 'Resistor_SMD:R_1206_3216Metric', 'NO_LIB', 'R', ParseResults(['/top/2256062772261245475', '/top/2256062772261245475'], {'names': '/top/2256062772261245475', 'tstamps': '/top/2256062772261245475'})], {'ref': 'R2', 'value': 'R', 'footprint': 'Resistor_SMD:R_1206_3216Metric', 'lib': 'NO_LIB', 'name': 'R', 'sheetpath': {'names': '/top/2256062772261245475', 'tstamps': '/top/2256062772261245475'}})

QGB avatar Nov 05 '22 06:11 QGB

I've re-run the code listing using the development branch of skidl and there were no errors and the netlist had the correct footprints.

It's not clear how you are running the script. Where does the netlist variable come from? Why is it of type ParseResults? Can you show exactly how you're running the program?

devbisme avatar Nov 07 '22 20:11 devbisme

I'm going to assume the empty_footprint_handler() fixes this issue.

devbisme avatar Nov 23 '22 15:11 devbisme