skidl icon indicating copy to clipboard operation
skidl copied to clipboard

ORM-like definition of new parts

Open slightlynybbled opened this issue 8 years ago • 11 comments

Description

At the moment, I have to go into the KiCad library editor to create a new part. The net connections and net list are generated using skidl, but skidl is still utterly dependent on existing part libraries generated using KiCad.

I would like to see a 'model' or library that creates the part itself in python. We see similar models when we look as sqlalchemy classes which define and correspond to tables. In sqlalchemy, most users will create a models.py file which will entirely contain the SQL structure and my proposal is to implement a similar feature in skidl.

Motivation

This is OK, but it would be much more pythonic - and readable! - to create models using python syntax and use that to instantiate my part. Schematic part creation is great for those who have an existing library, but to use skidl for the workflow, it makes sense to have a 'from scratch' skidl option.

Current Part Generation

Using the example 'pic10f220-i/ot' from the documentation. The PIC10 has to be created using the schematic editor and skidl has to be configured to find that library and import it. The part definition is then entirely based on the KiCad part definition.

import skidl
pic10 = Part(lib='microchip_pic10mcu', name='pic10f220-i/ot')

Proposed Part Generation

The proposed ORM-like structure would likely consist of a custom library-like file and then the use-case (though it wouldn't have to be separated).

my_custom_parts.py

import skidl

class Pic10(BasePart):
    name = 'pic10f220-i/ot'
    pins = [
        Pin(num=1, name='ICSPDAT/AN0/GP0', funct=skidl.Pin.BIDIRECTIONAL),
        Pin(num=2, name='VSS', funct=skidl.Pin.POWER-IN),
        Pin(num=3, name='ICSPCLK/AN1/GP1', funct=skidl.Pin.BIDIRECTIONAL),
        Pin(num=4, name='T0CKI/FOSC4/GP2', funct=skidl.Pin.BIDIRECTIONAL),
        Pin(num=5, name='VDD', funct=skidl.Pin.POWER-IN),
        Pin(num=6, name='Vpp/~MCLR~/GP3', funct=skidl.Pin.INPUT)
    ]
    # more stuff could be added, but wouldn't have to be - manufacturer, part number, etc

my_circuit.py

pic10 = Part(basepart=Pic10)

Additional Features

Assuming that the proposed feature is implemented, it would also be nice to have a 'lib_to_skidl.py' script similar in functionality to the existing 'netlist_to_skidl.py' that exists now.

slightlynybbled avatar Feb 17 '17 17:02 slightlynybbled

I have started working on this on a fork. I suspect that it is quite simple if you know what you are doing, but I'm hacking my way through it.

I also added a couple of examples for my own testing. I will likely delete them once they evolve a bit, but I'm using them for my own development.

slightlynybbled avatar Feb 17 '17 20:02 slightlynybbled

Yes, this is the way to go! I started with the KiCad libraries since that's the tool I was using. But it would be much better to have a native SKiDL ORM and libraries so people don't need KiCad. And a way to convert vendor libraries into the SKiDL format, as you said.

I think the existing Part class might be the place to start. Then a library might be just a dictionary of Parts. Haven't thought about it in detail, though.

xesscorp avatar Feb 17 '17 21:02 xesscorp

Hey, I have noticed that the KiCad library is utilized in the template for Part._gen_netlist_comp_kicad(). Is this necessary or is there a valid method to dummy this part of the string?

slightlynybbled avatar Feb 20 '17 12:02 slightlynybbled

I removed the (libsource...) portion of the component definition and the resulting netlist was still accepted by PCBNEW.

xesscorp avatar Feb 20 '17 18:02 xesscorp

Hey, thanks for working on this. So, I believe that I have a prototype working, but I am having trouble finding the contribution guidelines. Could you link those from the readme?

Examples of part models:

class Resistor(PartModel):
    name = 'resistor'
    ref_prefix = 'R'

    pins = [
        Pin(num=1, name='pin1', funct=Pin.PASSIVE),
        Pin(num=2, name='pin2', funct=Pin.PASSIVE),
    ]

    manufacturer = 'Yageo'
    part_number = 'RC0402JR-0710KL'


class Capacitor(PartModel):
    name = 'capacitor'
    ref_prefix = 'C'

    pins = [
        Pin(num=1, name='pin1', funct=Pin.PASSIVE),
        Pin(num=2, name='pin2', funct=Pin.PASSIVE),
    ]

slightlynybbled avatar Feb 20 '17 18:02 slightlynybbled

There are some unit tests you can run by typing tox in the top-level directory. These probably won't test your features, so you may want to add some. You can also issue a pull request and then I can look at what you've done.

xesscorp avatar Feb 20 '17 20:02 xesscorp

Thanks. The netlist isn't generating appropriately, so I'm not going to do a pull request until I get that sorted out. Likely something simple, but I don't know. Thanks for your support.

slightlynybbled avatar Feb 21 '17 12:02 slightlynybbled

I put some code into SKiDL to allow on-the-fly creation of parts and libraries. It's similar to what you were proposing.

xesscorp avatar Apr 13 '17 04:04 xesscorp

@slightlynybbled, what happened with this? Your fork seems to be gone.

kasbah avatar Jul 23 '17 02:07 kasbah

@kasbah, the initial cut hadn't fully worked and I lost track of it, xesscorp beat me to getting this started and I simply haven't had a chance to re-check it out. I was doing some pruning of my repositories and this one got the axe since it was so far behind. Would like to give it another shot, just haven't had time.

slightlynybbled avatar Jul 24 '17 18:07 slightlynybbled

Just as an idea, it could be nice if you could use dicts instead of Pin() and simple strings for funct (maybe it looks more "pythonic" that way):

class Pic10(BasePart):
    name = 'pic10f220-i/ot'
    pins = [
        dict(num=1, name='ICSPDAT/AN0/GP0', funct='bidirectional'),
        dict(num=2, name='VSS', funct='power-in'),
        dict(num=3, name='ICSPCLK/AN1/GP1', funct='bidirectional'),
        # ...
    ]

Also, it would be great if you could create an instance of that part with:

pic10 = Pic10()

Instead of:

pic10 = Part(basepart=Pic10)

Peque avatar Sep 09 '18 21:09 Peque