def BuildFootprint(self):
        """!
        Actually make the footprint. We defer all but the set-up to
        the implementing class
        """

        self.buildmessages = ""
        self.module = pcbnew.FOOTPRINT(None)  # create a new module

        # Perform default checks on all parameters
        for p in self.params:
            p.ClearErrors()
            p.Check()  # use defaults

        self.CheckParameters()  # User error checks

        if self.AnyErrors():  # Errors were detected!

            self.buildmessages = ("Cannot build footprint: "
                                  "Parameters have errors:\n")

            for p in self.params:
                if len(p.error_list) > 0:
                    self.buildmessages += "['{page}']['{name}']:\n".format(
                        page=p.page, name=p.name)

                    for error in p.error_list:
                        self.buildmessages += "\t" + error + "\n"

            return

        self.buildmessages = (
            "Building new {name} footprint with the following parameters:\n".
            format(name=self.name))

        self.buildmessages += self.Show()

        self.draw = FootprintWizardDrawingAids(self.module)

        self.module.SetValue(self.GetValue())
        self.module.SetReference("%s**" % self.GetReferencePrefix())

        fpid = pcbnew.LIB_ID("", self.module.GetValue()
                             )  # the lib name  (empty) and the name in library
        self.module.SetFPID(fpid)

        self.SetModule3DModel()  # add a 3D module if specified

        thick = self.GetTextThickness()

        self.module.Reference().SetTextThickness(thick)
        self.module.Value().SetTextThickness(thick)

        self.BuildThisFootprint()  # implementer's build function

        return
Example #2
0
    def compat_libitem_func(instance):
        try:
            test_obj = pcbnew.FPID()
        except AttributeError:
            test_obj = pcbnew.LIB_ID()

        if not hasattr(test_obj, "GetLibItemName"):
            return MethodType(lambda self, x: x.GetFootprintName(), instance)
        else:
            return MethodType(lambda self, x: x.GetLibItemName(), instance)
Example #3
0
def get_via_module(board, drill, diameter, net):
    n = 'VIA-{}-{}'.format(fmt(drill), fmt(diameter))

    # instantiate new module
    m = pcbnew.MODULE(board)
    m.SetReference('REF**')
    m.SetValue(n)
    m.SetLastEditTime(pcbnew.GetNewTimeStamp())

    # adjust reference and value display settings
    r = m.Reference()
    r.SetVisible(False)
    r.SetTextSize(pcbnew.wxSize(mm2kicad(0.3), mm2kicad(0.3)))
    r.SetThickness(mm2kicad(0.075))
    v = m.Value()
    v.SetVisible(False)
    v.SetTextSize(pcbnew.wxSize(mm2kicad(0.3), mm2kicad(0.3)))
    v.SetThickness(mm2kicad(0.075))
    #v.SetLayer() # TODO: Move value to F.Fab layer (F.SilkS is default)

    lib_id = pcbnew.LIB_ID(n)
    m.SetFPID(lib_id)

    # create through-hole pad
    pad = pcbnew.D_PAD(m)
    pad.SetPadName('1')
    pad.SetNet(net)
    pad.SetPosition(pcbnew.wxPoint(0, 0))

    pad.SetShape(pcbnew.PAD_SHAPE_CIRCLE)
    pad.SetSize(pcbnew.wxSize(diameter, diameter))

    pad.SetDrillShape(pcbnew.PAD_DRILL_SHAPE_CIRCLE)
    pad.SetDrillSize(pcbnew.wxSize(drill, drill))

    pad.SetLayerSet(pcbnew.LSET.AllCuMask())
    pad.SetZoneConnection(pcbnew.PAD_ZONE_CONN_FULL)

    # add pad to module
    m.Add(pad)

    return m
    def BuildFootprint(self):
        """
        Actually make the footprint. We defer all but the setup to
        the implementing class
        """

        self.buildmessages = ""

        self.module = pcbnew.MODULE(None)  # create a new module
        # do it first, so if we return early, we don't segfault KiCad

        if not self.ProcessParameters():
            self.buildmessages = "Cannot build footprint: Parameters have errors:\n"
            self.buildmessages += self._PrintParameterErrors()
            return

        self.buildmessages = (
            "Building new %s footprint with the following parameters:\n" %
            self.name)

        self.buildmessages += self._PrintParameterTable()

        self.draw = FootprintWizardDrawingAids.FootprintWizardDrawingAids(
            self.module)

        self.module.SetValue(self.GetValue())
        self.module.SetReference("%s**" % self.GetReferencePrefix())

        fpid = pcbnew.LIB_ID(self.module.GetValue())  # the name in library
        self.module.SetFPID(fpid)

        self.SetModule3DModel()  # add a 3d module if specified

        thick = self.GetTextThickness()

        self.module.Reference().SetThickness(thick)
        self.module.Value().SetThickness(thick)

        self.BuildThisFootprint()  # implementer's build function

        return
    def Run(self):
        """
        The entry function of the plugin that is executed on user action
        """
        board = pcbnew.GetBoard()

        # TODO also aggregate and bin by optional attributes, like tolerances
        radii = set()
        circles = []

        # TODO don't add an extra hole in same place -> overwrite

        # get circles drawn on board
        # TODO maybe include some means of filtering out possible circular board outline
        drawing_list = board.DrawingsList()
        for d in drawing_list:
            if d.GetLayerName() == 'Edge.Cuts':
                # to gaurd against random stuff being on edge cuts for some reason
                # causing weird errors
                assert type(
                    d) == pcbnew.DRAWSEGMENT, 'non-DRAWSEGMENT on Edge.Cuts'
                if d.GetShapeStr() == 'Circle':
                    # TODO check these are what i want, and don't need modification
                    # w/ thickness or whatever (check using dxf import)
                    r = d.GetRadius()
                    radii.add(r)
                    c = d.GetCenter()
                    circles.append((c.x, c.y, r))

                    # TODO make optional
                    # how to do?
                    board.RemoveNative(d)

        # TODO option to use nearest hole in existing library option / next largest
        # (report error)
        # TODO easiest way to get available footprints (and their radii?)
        # TODO option to take a set of target hole sizes (for DFM purposes)
        # TODO include either global use next largest / next smallest
        # (maybe ignore locked, and say that, to complement this?)
        # or let people check for each hole whether they want to use next up or down

        # TODO option to make new hole components and put in project specific library

        # TODO include field for library to be saved to (maybe mandatory if this option?)
        # TODO fail gracefully if board filename is empty (board not saved yet)
        target_footprint_lib = '.'.join(str(board.GetFileName()).split('.')[:-1]) \
            + '.pretty'

        if not os.path.exists(target_footprint_lib):
            print('creating project specific footprint library' + \
                ' {}'.format(target_footprint_lib))
            pcbnew.PCB_IO().FootprintLibCreate(target_footprint_lib)
        else:
            print('using footprint library {}'.format(target_footprint_lib))

        # make a new footprint for each distinct hole radius we need
        # save to project specific library by default
        for r in radii:
            r_mm = nm_to_mm(r)
            print('generating footprint for hole of radius {}mm'.format(r_mm))

            footprint = pcbnew.MODULE(None)
            # for non-electronic parts like these
            footprint.SetAttributes(pcbnew.MOD_VIRTUAL)
            footprint.SetLastEditTime()
            footprint.SetKeywords('non-plated through hole NPTH')

            # TODO it looks like the module itself needs to be specified to be on F.Cu?
            # how? (see github for example output)

            # TODO set tags to include non-plated through hole, npth?
            #footprint.SetDescription('{}mm diameter non-plated through hole')
            pad = pcbnew.D_PAD(footprint)

            # other library mounting hole pads seem to have this pad number
            pad.SetName('1')

            # TODO does this change the layers and stuff automatically? pad shape?
            pad.SetAttribute(pcbnew.PAD_ATTRIB_HOLE_NOT_PLATED)
            pad.SetShape(pcbnew.PAD_SHAPE_CIRCLE)
            # TODO do i need setsize / setstartend?
            # size seems to equal (r, r) for existing npth library parts

            # all holes in KiCad currently have to reside on one of the (external?)
            # copper layers (F.Cu should be one of these layers. mask the other?)
            pad.SetLayerSet(pcbnew.D_PAD_UnplatedHoleMask())

            # TODO are holes alone actually rendered, or do you need the other stuff?

            # there seems to be a PAD_DRILL_SHAPE_CIRCLE and PAD_DRILL_SHAPE_OBLONG
            # but when are they ever not circular? oblong = limited routing?
            # would advanced circuits do oblong, for instance?
            #pad.SetDrillShape() # huh???
            # TODO why isn't this a single number? what gens (drill X)?
            # TODO why is x in (size x x) slightly larger than 1.5?
            pad.SetDrillSize(pcbnew.wxSize(r, r))
            footprint.Add(pad)

            footprint_id = 'R{}mm_NPTH'.format(r_mm)
            footprint.SetReference(footprint_id)
            '''
            footprint.Reference().SetPosition(pcbnew.wxPoint()1)
            footprint.Value().SetPosition(pcbnew.wxPoint()1)
            '''

            # aiming for a visible layer that does not translate into manufacture
            comment_layer_id = get_layer_id_by_name('Cmts.User')
            footprint.Reference().SetLayer(comment_layer_id)
            footprint.Value().SetLayer(comment_layer_id)

            # this is the filename, preceeding .kicad_mod
            fpid = pcbnew.LIB_ID(footprint_id)
            footprint.SetFPID(fpid)

            # seems to work to lock all imports by default
            footprint.SetLocked(True)

            print('saving footprint to {}'.format(os.path.join(\
                target_footprint_lib, footprint_id + '.kicad_mod')))
            pcbnew.PCB_IO().FootprintSave(target_footprint_lib, footprint)

            for x, y, r_curr in circles:
                if r == r_curr:
                    f_new = pcbnew.PCB_IO().FootprintLoad(
                        target_footprint_lib, footprint_id)
                    f_new.SetPosition(pcbnew.wxPoint(x, y))
                    board.Add(f_new)