INTI-CMNB / KiBot

KiCad automation utility
GNU Affero General Public License v3.0
571 stars 67 forks source link

Custom output/custom command #109

Open mdeweerd opened 2 years ago

mdeweerd commented 2 years ago

The goal of custom output is to run a custom executable command. This could allow making a copy of a file to the output directory, parse a template, run a script under development, etc.

outputs:
 - name: '3d_view_export'
    comment: 'Exports the PCB to the most common exhange format. Suitable for printing.'
    type: 'custom'
    dir: "%f_%r_%d%v/PCBA"  # Passed to the script if the args_format is json
    args_format: json|string # when JSON all options to the target and several internal values are passed as JSON, when string, it's interpreted as a format.  For instance "{dir} {myarg} {otherarg}"
    command: NAMEOFTHEEXECUTABLE
    myarg: "Value for myarg"
    otherarg: "Value for otherarg"
    unusedarg: dummy # not used when args_format=string because its not in "{dir} {myarg} {otherarg}"

I thought of this while thinking of a way to execute the "3D Viewer" image export script that I created.

set-soft commented 2 years ago

Is a good idea, but needs changes in some classes, so it can be applied to schematic, PCB and 3D variants. I'll look into it after finishing some KiCost plug-ins.

mdeweerd commented 2 years ago

Ok, no hurry ;-). I was thinking this could even be a base class with common options and build (refactor) the other tools on it.

richardbarlow commented 2 years ago

I'd be very interested in this feature too. Since I am using KiBot to generate my final fabiration datapacks I need the ability to execute a custom script or two during the process to perform a little extra processing of generated files before they get compressed into a zip. Having the ability to have a 'custom command' output would work perfectly.

For reference, the extra processing I am looking to perform right now is to create a single assembly PDF by combining/merging multiple PDFs (not just concatenate pages like the 'pdfunite' output does).

set-soft commented 2 years ago

For reference, the extra processing I am looking to perform right now is to create a single assembly PDF by combining/merging multiple PDFs (not just concatenate pages like the 'pdfunite' output does).

Can you comment more about it? May be we can add more stuff to the report output so it can do what you want. It can currently nicely join the PCB/SCH print outputs.

richardbarlow commented 2 years ago

Can you comment more about it? May be we can add more stuff to the report output so it can do what you want. It can currently nicely join the PCB/SCH print outputs.

So the thing I am trying to achieve at the moment is to generate a single PDF that has two pages (one front and one back) on each page I would like to have the F.Fab layer + a couple of other layers visible (all overlayed). Unfortunately, the two mechanisms that KiCAD has at the moment (print and plot) have different features/limitations that means it is not possible to do this. The pdfunite output allows a front and back PDF to be combined into one - so KiBot helps with that, however the 'print' mechanism does not have as much flexibility as the 'plot' mechanism. For example you cannot suppress the visibility of the 'value' field on the fab layer with the 'print' mechanism.

Ultimately, this requires changes/improvements in KiCAD, which is no bad thing. However, this will not be quick and I must have a mechanism to enable me to work-around problems like this until the 'proper' solution is implemented in KiCAD/KiBot. My desire with the custom command functionality is to allow me to implement short-term workarounds and I would always strive to get the functionality implemented into KiCAD/KiBot in parallel.

set-soft commented 2 years ago

Hi @richardbarlow ! Take a look at the last commit, is WIP, but I think you'll get the idea. Is a new way to print the PCB using Board2Pdf, it generates the PDF using the plot functionality, but composing the output PDF using PyPDF2 (allows to combine and concatenate PDFs).

set-soft commented 2 years ago

For example you cannot suppress the visibility of the 'value' field on the fab layer with the 'print' mechanism.

With the new pcb_print output now you can.

matthiesenj commented 2 years ago

I would like a "runner" output as well, for running a script/executable/whatever.. My use case is to manipulate the generated BOM and position csv files, because a footprint I use actually needs multiple connectors placed on the board during assembly.

set-soft commented 2 years ago

Hi @matthiesenj ! The BoM currently supports multiple parts for the same symbol. Take a look at the subparts filter. It implements the concept found on KiCost. About the position: Are you sure this isn't solved using more than one footprint? Please elaborate.

matthiesenj commented 2 years ago

Hi @matthiesenj ! The BoM currently supports multiple parts for the same symbol. Take a look at the subparts filter. It implements the concept found on KiCost. About the position: Are you sure this isn't solved using more than one footprint? Please elaborate.

The footprint in question is a Raspberry Pi Compute Module.. It is a single KiCad footprint, but has 4 mounting holes and two identical connectors. The reason it is designed as a single footprint is so it is easy to place and move on the pcb, I suppose. I need to replace the footprint with 2 connectors and 4 SMD solderable spacers in the bom and position files. The position data for these 6 added parts will need to have their xy data generated from the parent footprint. Is something like this possible using subparts?

Footprint: image

What I would like to place on the board (3D): image

set-soft commented 2 years ago

Hi @matthiesenj ! The BoM part is possible, the footprint isn't. But I think your problem can be solved in the following way:

  1. Create a virtual footprint with the Silkscreen part, just like a logo
  2. Use separated footprints for each element, 6 of them.
  3. Use the virtual component as an alignment guide, it will help to keep the distances

I know that moving it in the PCB isn't simple, but the solution will be consistent with KiCad workflow. The symbol for the virtual footprint could be something that helps to make the other symbols coherent. This solution will keep all the information in the KiCad files, no external magic. You'll most probably need some DRC exceptions to allow the integration because the virtual component will be over the others, but perhaps it isn't needed if the courtyard allows it.

matthiesenj commented 2 years ago

Hi @matthiesenj ! The BoM part is possible, the footprint isn't. But I think your problem can be solved in the following way:

1. Create a virtual footprint with the Silkscreen part, just like a logo

2. Use separated footprints for each element, 6 of them.

3. Use the virtual component as an alignment guide, it will help to keep the distances

I know that moving it in the PCB isn't simple, but the solution will be consistent with KiCad workflow. The symbol for the virtual footprint could be something that helps to make the other symbols coherent. This solution will keep all the information in the KiCad files, no external magic. You'll most probably need some DRC exceptions to allow the integration because the virtual component will be over the others, but perhaps it isn't needed if the courtyard allows it.

Your suggestion could work for the spacers, but not the connectors, I think - how would they get associated with the schematic symbol pins (the symbol has 200 pins, 100 for each connector) ?

set-soft commented 2 years ago

Your suggestion could work for the spacers, but not the connectors, I think - how would they get associated with the schematic symbol pins (the symbol has 200 pins, 100 for each connector) ?

Why not? Just use 2 connectors, lets name them A and B, both with pin numbers 1 to 100. Half of the connections goes to connA and half to connB.

set-soft commented 2 years ago

BTW: KiCad 6 can make footprint groups, so you should be able to align the parts, create a group and then move the whole group. Avoiding misalignments.

matthiesenj commented 2 years ago

Why not? Just use 2 connectors, lets name them A and B, both with pin numbers 1 to 100. Half of the connections goes to connA and half to connB.

This would require using two distinct 100 pin schematic symbols, which would be a massive step backwards, considering the symbol I'm using has 10 functional units covering all 200 pins, and not something I would consider changing at this stage of the design. cm4_footprint.pdf

BTW: KiCad 6 can make footprint groups, so you should be able to align the parts, create a group and then move the whole group. Avoiding misalignments.

Interesting - might come in handy when I switch to KiCad 6 at some point.

set-soft commented 2 years ago

This would require using two distinct 100 pin schematic symbols, which would be a massive step backwards, considering the symbol I'm using has 10 functional units covering all 200 pins, and not something I would consider changing at this stage of the design.

We use a script to generate these symbols, is now outdated, but I'll add support to KiCad 6 next time I need to use it.

#!/usr/bin/perl
##############################################################################
#
# Copyright (c) 2014 David M. Caruso <daviud en inti gov ar>
# Copyright (c) 2015-2019 Salvador E. Tropea <salvador en inti gov ar>
# Copyright (c) 2014-2019 Instituto Nacional de Tecnología Industrial
#
##############################################################################
#
# Target:           Any
# Language:         Perl
# Interpreter used: v5.6.1/v5.8.4
# Text editor:      SETEdit 0.5.5
#
##############################################################################
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA
#
##############################################################################
#
# Description: Component Schematic Generator for Kicad
#
##############################################################################

#Usar una hash, para barrer los datos
#para el footprint barrer bolita por bolita.

use POSIX qw(strftime);
use Sort::Versions;

use Getopt::Long;
use Locale::TextDomain('kicad_tools');
$version='1.1.1';

ParseCommandLine();
#use constant AGE => 2;
$fecha = strftime "%e/%m/%Y-%H:%M:%S", localtime;

%kicadel = ('Input/Output','B',
            'Power Input','W',
            'Power Output','w',
            'NC','N',
            'Input','I',
            'Output','O',
            'Input Clock','I C',
            'Input Clock Negated','I IC',
            'Input Negated','I I',
            'Output Negated','O I',
            'Input/Output Negated','B I',
            'Output Clock','O C',
            'Output Clock Negated','O IC',
            'Tri-state Negated','T I',
            'Tri-state','T',
            'Passive','P'
           );

#-----------------------------------------------------------------------------
# Read File and order data
#-----------------------------------------------------------------------------
open(F,"$filein") || die "Can't open $filein";
$pinnum=0;
$ind_field=0;
@exfield;
@namexfield;
%hGrupo=();
# %hBall=();
# %hBalldie=();
$NumGroup=0;
while ($line=<F>)
  {
   if ($line=~/\"?([^\"]*)\"?,\"?([^\"]*)\"?,,,,,,/)
     {
      $exfield[$ind_field]=$2;
      $namexfield[$ind_field]=$1;
      print "$1: $2\n";
      $ind_field++;
     }
   elsif ($line=~/\"?([^\"]*)\"?,\"?([^\"]*)\"?,\"?([^\"]*)\"?,\"?([^\"]*)\"?,\"?([^\"]*)\"?,\"?([^\"]*)\"?,\"?([^\"]*)\"?,\"?([^\"]*)\"?/)
     {#Pin,Pin Name,Description,Input/Output,Sub-Grupo,Grupo,Dominio de Alimentacion,L die
      # 1     2          3           4           5       6
      #print "<$1>: <$2>\n";
      if (($1 ne "Pin") && ($2 ne "Pin Name"))
         {# Descarta la línea separadora de los nombres
          $pinnum++;
          push(@Ll,"$6;-;$5;-;$2;-;$1;-;$4"); # array a ordenar para el esquemático
          $Grupo=$6;
          $Grupo=~s/ /_/g; # Quita espacios del Nombre del Grupo
          unless ($hGrupo{$Grupo}) # Se fija si el grupo existe
            {
             if (($Grupo ne 'NC') || $withnc)
               {
                $hGrupo{$Grupo}=1;
                $NumGroup++;
               }
            }
          else {$hGrupo{$Grupo}++;}
         }
     }
   else
     {
      print "** line = \"$line\"\n";
      die "** Error de parseo en el CSV\n";
     }
  }
close $F;
print "Reading: $pinnum pins\n";
if ($NumGroup>26)
  {
   die "** Error: The maximum number of groups is 26, not $NumGroup\n";
  }
print "There are: $NumGroup groups of pins\n";
#Orden de los datos parseados
$pin_grp=0;
$pin_sgrp=1;
$pin_name=2;
$pin_ord=3;
$pin_io=4;

#-----------------------------------------------------------------------------
# Schematic .lib
#-----------------------------------------------------------------------------

# Config Constants:
$sep = 50;         # Separation pin
$rsizex=$cwidth;   # Component width
$txtsig=40;        # Text Size for signal
$txtcmp=60;        # Text Size for component
$txtgroup=70;      # Text Size for group
$pinlarge=$pinl;   # Pin Large
# Ordeno por grupo de señal, luego por subgrupo, luego por nombre de señal
#@Ll = sort {$a cmp $b} @Ll;
@Ll = sort {versioncmp($a,$b)} @Ll;
@colm=split(";-;",$Ll[0]); # Divide las columnas con el nuevo orden.
$colm[$pin_grp] =~s/ /_/g; # Quita espacios del Nombre del Grupo
$colm[$pin_sgrp] =~s/ /_/g; # Quita espacios del Nombre del Sub-Grupo
unless ($parted){$rsizey = int(3+$pinnum/2) * $sep}
else {$rsizey = int(3+$hGrupo{$colm[pin_grp]}/2) * $sep;}
$pinxpos=$pinlarge+$rsizex;
$part=1;
$yauxr=$rsizey; # Indice derecho
$yauxl=$rsizey; # Indice izquierdo
$yaux =$rsizey; # Arranca por el lado derecho
$sidetxt = "$pinlarge L";
$xside= $pinxpos;
$newGroup= $colm[$pin_grp];
$newSGroup= $colm[$pin_sgrp];
$indg=1;

open(S,">$outdir\/$lib\.lib") || die "Can't create $outdir\/$lib\.lib";
print S "EESchema-LIBRARY Version 2.3  Date: $fecha\n".
       "#\n# $lib\n#\n";
unless ($parted){print S "DEF $lib U 0 40 Y Y 1 F N\n";}
else {print S "DEF $lib U 0 40 Y Y $NumGroup L N\n";}
print S "F0 \"U\" 0 100 $txtcmp H V C CNN\n";
print S "F1 \"$lib\" 0 0 $txtcmp H V C CNN\n";   #Nombre
if ($withexfield)
  {
   print S "F2 \"$exfield[0]\" 0 -100 $txtcmp H I C CNN\n". # Footprint
           "F3 \"$exfield[4]\" 0 -100 $txtcmp H I C CNN\n". # Hoja de datos
           "F4 \"$exfield[1]\" 0 -100 $txtcmp H I C CNN \"$namexfield[1]\"\n". # Descripción
           "F5 \"$exfield[2]\" 0 -100 $txtcmp H I C CNN \"$namexfield[2]\"\n". # Fabricante
           "F6 \"$exfield[3]\" 0 -100 $txtcmp H I C CNN \"$namexfield[3]\"\n". # Numero de Parte
           "F7 \"$exfield[5]\" 0 -100 $txtcmp H I C CNN \"$namexfield[5]\"\n"; # Codigo
   if (scalar(@exfield)>6)
     {# Otros
      my ($i, $c);
      $c=scalar(@exfield);
      for ($i=6; $i<$c; $i++)
         {
          print S "F".($i+2)." \"".$exfield[$i]."\" 0 -100 $txtcmp H I C CNN \"".$namexfield[$i]."\"\n";
         }
     }
  }
print S "DRAW\n";

for ($ind=0;$ind<=$#Ll;$ind++)
   {
    @colm=split(";-;",$Ll[$ind]); # Divide las columnas con el nuevo orden.
    $colm[$pin_grp] =~s/ /_/g; # Quita espacios del Nombre del Grupo
    $colm[$pin_sgrp] =~s/ /_/g; # Quita espacios del Nombre del Sub-Grupo
    unless($kicadel{$colm[$pin_io]})
       {
        die "** Error: Incorrect I/O specification for Pin: $colm[$pin_ord], name $colm[$pin_name], I/O: $colm[$pin_io]\n";
       }
    if (($colm[$pin_grp] ne 'NC') || $withnc)
      {
       if ($newSGroup ne $colm[$pin_sgrp])
         {
          $newSGroup = $colm[$pin_sgrp];
          if ($xside<0){$yauxl=$yaux- ($sep * 2);}
          else {$yauxr=$yaux- ($sep * 2);}
          if ($yauxr<$yauxl)
            {
             $sidetxt = "$pinlarge R";
             $xside=-$pinxpos;
             $yaux = $yauxl;
            }
          else
            {
             $sidetxt = "$pinlarge L";
             $xside=$pinxpos;
             $yaux = $yauxr;
            }
         }
       if ($parted)
         {
          if ($newGroup ne $colm[$pin_grp])
            {
             $yaux=$yauxr<$yauxl ? $yauxr : $yauxl;
             if ($xside==$pinxpos)
               {# Estábamos de la izquierda
                $yaux-=$sep if $yauxl>yauxr;
               }
             else
               {# Estábamos de la derecha
                $yaux-=$sep if $yauxr>yauxl;
               }
             print S "S -$rsizex $rsizey $rsizex $yaux $part 0 0 N\n"; # Dibuja la caja
             $yaux-=2*$sep;
             print S "T 0 0 $yaux $txtgroup 0 $part 0 $newGroup Normal 0 C C\n";
             $newGroup = $colm[$pin_grp];
             $rsizey = int(3+$hGrupo{$newGroup}/2) * $sep;
             $yauxr=$rsizey; # Indice derecho
             $yauxl=$rsizey; # Indice izquierdo
             $yaux =$rsizey; # Arranca por el lado derecho
             $sidetxt = "$pinlarge L";
             $xside=$pinxpos;
             $part++;
             $indg = 1;
            }
          }
       $yaux=$yaux-2*$sep;
       $indg++;
       print S "X $colm[$pin_name] $colm[$pin_ord] $xside $yaux $sidetxt $txtsig $txtsig $part 1 $kicadel{$colm[$pin_io]}\n";
      }
   }

$yaux=$yauxr if $yauxr<$yaux;
$yaux=$yauxl if $yauxl<$yaux;
$yaux-=2*$sep;
print S "S -$rsizex $rsizey $rsizex $yaux $part 0 0 N\n"; # Dibuja la caja
$yaux-=2*$sep;
if ($parted){print S "T 0 0 $yaux $txtgroup 0 $part 0 $newGroup Normal 0 C C\n";}
else {print S "T 0 0 $yaux $txtgroup 0 $part 0 $lib Normal 0 C C\n";}

print S "ENDDRAW\n".
        "ENDDEF\n";
print S "#\n#End Library";

close S;

#-----------------------------------------------------------------------------
# ParseCommandLine:
#   Parser
#-----------------------------------------------------------------------------

sub ParseCommandLine
{
 GetOptions("verbose|v=i"   => \$verbosity,
            "version"       => \$showVersion,
            "part"          => \$parted,
            "input=s"       => \$filein,
            "dir=s"         => \$outdir,
            "wdcomp=i"      => \$cwidth,
            "pinl=i"        => \$pinl,
            "withnc"        => \$withnc,
            "withexfield"   => \$withexfield,
            "docfile=s"     => \$docfile,
            "lib=s"         => \$lib,
            "help|?"        => \$help) or ShowHelp();
 if ($showVersion)
   {
    print "comp_gen.pl (kicad_tools) $version\n".
          "Copyright (c) 2014-2015 David M. Caruso/Salvador E. Tropea/INTI\n".
          "License GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl.html>\n".
          __("This is free software: you are free to change and redistribute it.\n".
             "There is NO WARRANTY, to the extent permitted by law.\n\n").
          __("Written by")." David M. Caruso.\n";
    exit(0);
   }
 print "Component Schematic Generator for Kicad v$version Copyright (c) 2014-2015 David M. Caruso/SET/INTI\n";
 ShowHelp() if $help;
 unless($filein)
   {
    print "You must specify an input file name.\n";
    ShowHelp();
   }
 unless($lib)
   {
    print "You must specify an library name.\n";
    ShowHelp();
   }
 if ($outdir && !(-e "$outdir"))
   {
    system "mkdir $outdir";
   }
 unless ($outdir)
   {
    $outdir='.'; # Si no se especifica el directorio, asigna el actual
   }
 unless ($docfile)
   {
    $docfile=$filein;
   }
 unless ($cwidth)
   {
    $cwidth=900;
   }
 unless ($pinl)
   {
    $pinl=400;
   }
}

sub ShowHelp
{
 print __"Usage: bga_gen.pl [options]\n";
 print __"\nAvailable options:\n";
 print __"--version            Outputs version information and exit.\n";
 print __"--input=name         Input File with ball description\n";
 print __"--dir=name           Output Directory for component, Default=Current\n";
 print __"--lib=name           Library Name\n";
 print __"--wdcomp=value       Width Schematic Component\n";
 print __"--pinl=value         Pin length\n";
 print __"--part               Component Schematic in parts\n";
 print __"--withnc             Include NC pins\n";
 print __"--help               Prints this text.\n\n";

 exit 1;
}

It takes a CSV like this:

Footprint,TQFP-144,,,,,,
Descripcion,iCE40 High Speed FPGA,,,,,,
Fabricante,Lattice,,,,,,
Numero de parte,iCE40HX1K,,,,,,
Hoja de datos,-,,,,,,
Codigo,iCE40HX1K,,,,,,
Pin,Pin Name,Description,Input/Output,Sub-Grupo,Grupo,Dominio de Alimentacion,L die
1,IOL1A/2A,I/O 1/2A Bank3,Input/Output,DPIO,Bank_3,VCCIO_3,0
2,IOL1B/2B,I/O 1/2B Bank3,Input/Output,DPIO,Bank_3,VCCIO_3,0
3,IOL2A/3A,I/O 2/3A Bank3,Input/Output,DPIO,Bank_3,VCCIO_3,0
4,IOL2B/3B,I/O 2/3B Bank3,Input/Output,DPIO,Bank_3,VCCIO_3,0
5,GND,Ground,Power Input,GND,Power,VCCIO,0
6,VCCIO_3,Bank 3 Vcc,Power Input,VCCIO,Power,VCCIO_3,0
7,IOL3A/4A,I/O 3/4A Bank3,Input/Output,DPIO,Bank_3,VCCIO_3,0
8,IOL3B/4B,I/O 3/4B Bank3,Input/Output,DPIO,Bank_3,VCCIO_3,0
9,IOL4A/5A,I/O 4/5A Bank3,Input/Output,DPIO,Bank_3,VCCIO_3,0
10,IOL4B/5B,I/O 4/5B Bank3,Input/Output,DPIO,Bank_3,VCCIO_3,0
11,IOL5A/8A,I/O 5/8A Bank3,Input/Output,DPIO,Bank_3,VCCIO_3,0
12,IOL5B/8B,I/O 5/8B Bank3,Input/Output,DPIO,Bank_3,VCCIO_3,0
13,GND,Ground,Power Input,GND,Power,VCCIO,0
14,GND,Ground,Power Input,GND,Power,VCCIO,0
15,NC/IOL10A,I/O 10A Bank3,Input/Output,DPIO,Bank_3,VCCIO_3,0
16,NC/IOL10B,I/O 10B Bank3,Input/Output,DPIO,Bank_3,VCCIO_3,0
17,NC/IOL12A,I/O 12A Bank3,Input/Output,DPIO,Bank_3,VCCIO_3,0
18,NC/IOL12B,I/O 12B Bank3,Input/Output,DPIO,Bank_3,VCCIO_3,0
19,IOL6A/13A,I/O 6/13A Bank3,Input/Output,DPIO,Bank_3,VCCIO_3,0
20,G7(IOL6B/13B),I/O 6/13B Bank3 - GBIN7,Input/Output,GBIN,Bank_3,VCCIO_3,0
21,G6(IOL7A/14A),I/O 7/14A Bank3 - GBIN6,Input/Output,GBIN,Bank_3,VCCIO_3,0
22,IOL7B/14B,I/O 7/14B Bank3,Input/Output,DPIO,Bank_3,VCCIO_3,0
23,IOL8A/17A,I/O 8/17A Bank3,Input/Output,DPIO,Bank_3,VCCIO_3,0
24,IOL8B/17B,I/O 8/17B Bank3,Input/Output,DPIO,Bank_3,VCCIO_3,0
25,IOL9A/18A,I/O 9/18A Bank3,Input/Output,DPIO,Bank_3,VCCIO_3,0
26,IOL9B/18B,I/O 9/18B Bank3,Input/Output,DPIO,Bank_3,VCCIO_3,0
27,VCC,Core Vcc,Power Input,VCC,Power,VCC,0
28,IOL10A/23A,I/O 10/23A Bank3,Input/Output,DPIO,Bank_3,VCCIO_3,0
29,IOL10B/23B,I/O 10/23B Bank3,Input/Output,DPIO,Bank_3,VCCIO_3,0
30,VCCIO_3,Bank 3 Vcc,Power Input,VCCIO,Power,VCCIO_3,0
31,IOL11A/24A,I/O 11/24A Bank3,Input/Output,DPIO,Bank_3,VCCIO_3,0
32,IOL11B/24B,I/O 11/24B Bank3,Input/Output,DPIO,Bank_3,VCCIO_3,0
33,IOL12A/25A,I/O 12/25A Bank3,Input/Output,DPIO,Bank_3,VCCIO_3,0
34,IOL12B/25B,I/O 12/25B Bank3,Input/Output,DPIO,Bank_3,VCCIO_3,0
35,GNDPLL/NC,PLL Ground,Power Input,PLL,Power,VCCPLL,0
36,VCCPLL/NC,PLL Vcc,Power Input,PLL,Power,VCCPLL,0
37,IOB24/56,I/O 24/56 Bank2,Input/Output,PIO,Bank_2,VCCIO_2,0
38,IOB25/57,I/O 25/57 Bank2,Input/Output,PIO,Bank_2,VCCIO_2,0
39,IOB26/61,I/O 26/61 Bank2,Input/Output,PIO,Bank_2,VCCIO_2,0
40,NC/VCC,Core Vcc,Power Input,VCC,Power,VCC,0
41,IOB27/63,I/O 27/63 Bank2,Input/Output,PIO,Bank_2,VCCIO_2,0
42,IOB28/64,I/O 28/64 Bank2,Input/Output,PIO,Bank_2,VCCIO_2,0
43,IOB29/71,I/O 29/71 Bank2,Input/Output,PIO,Bank_2,VCCIO_2,0
44,IOB30/72,I/O 30/72 Bank2,Input/Output,PIO,Bank_2,VCCIO_2,0
45,IOB31/73,I/O 31/73 Bank2,Input/Output,PIO,Bank_2,VCCIO_2,0
46,VCCIO_2,Bank 2 Vcc,Power Input,VCCIO,Power,VCCIO_2,0
47,IOB32/79,I/O 32/79 Bank2,Input/Output,PIO,Bank_2,VCCIO_2,0
48,IOB33/80,I/O 33/80 Bank2,Input/Output,PIO,Bank_2,VCCIO_2,0
49,G5(IOB35/81),I/O 35/81 Bank2 - GBIN5,Input/Output,GBIN,Bank_2,VCCIO_2,0
50,G4(IOB36)/NC,I/O 36 Bank2 - GBIN4,Input/Output,GBIN,Bank_2,VCCIO_2,0
51,VCC/NC,Core Vcc,Power Input,VCC,Power,VCC,0
52,IOB34/G4(IOB82),I/O 34/82 Bank2 - GBIN4,Input/Output,GBIN,Bank_2,VCCIO_2,0
53,NC/GNDPLL0,PLL Ground,Power Input,PLL0,Power,VCCPLL0,0
54,NC/VCCPLL0,PLL Vcc,Power Input,PLL0,Power,VCCPLL0,0
55,NC/IOB91,I/O 91 Bank2,Input/Output,PIO,Bank_2,VCCIO_2,0
56,IOB37/94,I/O 37/94 Bank2,Input/Output,PIO,Bank_2,VCCIO_2,0
57,VCCIO_2,Bank 2 Vcc,Power Input,VCCIO,Power,VCCIO_2,0
58,IOB38/NC,I/O 38 Bank2,Input/Output,PIO,Bank_2,VCCIO_2,0
59,GND,Ground,Power Input,GND,Power,VCCIO,0
60,IOB39/95,I/O 39/95 Bank2,Input/Output,PIO,Bank_2,VCCIO_2,0
61,IOB40/96,I/O 40/96 Bank2,Input/Output,PIO,Bank_2,VCCIO_2,0
62,IOB41/102,I/O 41/102 Bank2,Input/Output,PIO,Bank_2,VCCIO_2,0
63,IOB42/103_C0,I/O 42/103 Bank2 - CBSEL0,Input/Output,PIO,Bank_2,VCCIO_2,0
64,IOB43/104_C1,I/O 43/104 Bank2 - CBSEL1,Input/Output,PIO,Bank_2,VCCIO_2,0
65,CDONE,Configuration Done,Output,CONFIG,CONFIG,VCCIO_2,0
66,CRESET_B,Configuration Reset,Input,CONFIG,CONFIG,VCCIO_2,0
67,SDO(IOB44/105),I/O 44/105 Bank2 - MISO,Input/Output,SPI,CONFIG,VCCIO_2,0
68,SDI(IOB45/106),I/O 45/106 Bank2 - MOSI,Input/Output,SPI,CONFIG,VCCIO_2,0
69,GND,Ground,Power Input,GND,Power,VCCIO,0
70,SCK(IOB46/107),I/O 46/107 Bank2 - SCK,Input/Output,SPI,CONFIG,VCCIO_2,0
71,SS(IOB47/108),I/O 47/108 Bank2 - SS,Input/Output,SPI,CONFIG,VCCIO_2,0
72,VCC_SPI,SPI Vcc,Power Input,VCCIO,Power,VCC_SPI,0
73,IOR48/109,I/O 48/109 Bank1,Input/Output,PIO,Bank_1,VCCIO_1,0
74,IOR49/110,I/O 49/110 Bank1,Input/Output,PIO,Bank_1,VCCIO_1,0
75,IOR50/111,I/O 50/111 Bank1,Input/Output,PIO,Bank_1,VCCIO_1,0
76,IOR51/112,I/O 51/112 Bank1,Input/Output,PIO,Bank_1,VCCIO_1,0
77,NC,No Connection,NC,NC,NC,NC,0
78,IOR52/114,I/O 52/114 Bank1,Input/Output,PIO,Bank_1,VCCIO_1,0
79,IOR53/115,I/O 53/115 Bank1,Input/Output,PIO,Bank_1,VCCIO_1,0
80,IOR54/116,I/O 54/116 Bank1,Input/Output,PIO,Bank_1,VCCIO_1,0
81,IOR55/117,I/O 55/117 Bank1,Input/Output,PIO,Bank_1,VCCIO_1,0
82,NC/IOR118,I/O 118 Bank1,Input/Output,PIO,Bank_1,VCCIO_1,0
83,NC/IOR119,I/O 119 Bank1,Input/Output,PIO,Bank_1,VCCIO_1,0
84,NC/IOR120,I/O 120 Bank1,Input/Output,PIO,Bank_1,VCCIO_1,0
85,NC/IOR128,I/O 128 Bank1,Input/Output,PIO,Bank_1,VCCIO_1,0
86,GND,Ground,Power Input,GND,Power,VCCIO,0
87,IOR56/136,I/O 56/136 Bank1,Input/Output,PIO,Bank_1,VCCIO_1,0
88,IOR57/137,I/O 57/137 Bank1,Input/Output,PIO,Bank_1,VCCIO_1,0
89,VCCIO_1,Bank 1 Vcc,Power Input,VCCIO,Power,VCCIO_1,0
90,IOR58/138,I/O 58/138 Bank1,Input/Output,PIO,Bank_1,VCCIO_1,0
91,IOR59/139,I/O 59/139 Bank1,Input/Output,PIO,Bank_1,VCCIO_1,0
92,VCC,Core Vcc,Power Input,VCC,Power,VCC,0
93,G3(IOR60/140),I/O 60/140 Bank1 - GBIN3,Input/Output,GBIN,Bank_1,VCCIO_1,0
94,G2(IOR61/141),I/O 61/141 Bank1 - GBIN2,Input/Output,GBIN,Bank_1,VCCIO_1,0
95,IOR62/144,I/O 62/144 Bank1,Input/Output,PIO,Bank_1,VCCIO_1,0
96,IOR63/146,I/O 62/146 Bank1,Input/Output,PIO,Bank_1,VCCIO_1,0
97,IOR64/147,I/O 62/147 Bank1,Input/Output,PIO,Bank_1,VCCIO_1,0
98,IOR65/148,I/O 62/148 Bank1,Input/Output,PIO,Bank_1,VCCIO_1,0
99,IOR66/152,I/O 62/152 Bank1,Input/Output,PIO,Bank_1,VCCIO_1,0
100,VCCIO_1,Bank 1 Vcc,Power Input,VCCIO,Power,VCCIO_1,0
101,IOR67/160,I/O 67/160 Bank1,Input/Output,PIO,Bank_1,VCCIO_1,0
102,IOR68/161,I/O 68/161 Bank1,Input/Output,PIO,Bank_1,VCCIO_1,0
103,GND,Ground,Power Input,GND,Power,VCCIO,0
104,IOR69/164,I/O 69/164 Bank1,Input/Output,PIO,Bank_1,VCCIO_1,0
105,IOR70/165,I/O 70/165 Bank1,Input/Output,PIO,Bank_1,VCCIO_1,0
106,IOR71/166,I/O 71/166 Bank1,Input/Output,PIO,Bank_1,VCCIO_1,0
107,IOR72/167,I/O 72/167 Bank1,Input/Output,PIO,Bank_1,VCCIO_1,0
108,VPP_2V5,NVCM Vpp,Power Input,VCCIO,Power,VPP_2V5,0
109,VPP_FAST,Fast NVCM Vpp,Power Input,VCCIO,Power,VPP_FAST,0
110,NC/IOT168,I/O 168 Bank0,Input/Output,PIO,Bank_0,VCCIO_0,0
111,VCC,Core Vcc,Power Input,VCC,Power,VCC,0
112,IOT73/169,I/O 73/169 Bank0,Input/Output,PIO,Bank_0,VCCIO_0,0
113,IOT74/170,I/O 74/170 Bank0,Input/Output,PIO,Bank_0,VCCIO_0,0
114,IOT75/171,I/O 75/171 Bank0,Input/Output,PIO,Bank_0,VCCIO_0,0
115,IOT76/172,I/O 76/172 Bank0,Input/Output,PIO,Bank_0,VCCIO_0,0
116,IOT77/173,I/O 77/173 Bank0,Input/Output,PIO,Bank_0,VCCIO_0,0
117,IOT78/174,I/O 78/174 Bank0,Input/Output,PIO,Bank_0,VCCIO_0,0
118,IOT79/177,I/O 79/177 Bank0,Input/Output,PIO,Bank_0,VCCIO_0,0
119,IOT80/178,I/O 80/178 Bank0,Input/Output,PIO,Bank_0,VCCIO_0,0
120,IOT81/179,I/O 81/179 Bank0,Input/Output,PIO,Bank_0,VCCIO_0,0
121,IOT82/181,I/O 82/181 Bank0,Input/Output,PIO,Bank_0,VCCIO_0,0
122,IOT83/190,I/O 83/190 Bank0,Input/Output,PIO,Bank_0,VCCIO_0,0
123,VCCIO_0,Bank 0 Vcc,Power Input,VCCIO,Power,VCCIO_0,0
124,NC/IOT191,I/O 191 Bank0,Input/Output,PIO,Bank_0,VCCIO_0,0
125,NC/IOT192,I/O 192 Bank0,Input/Output,PIO,Bank_0,VCCIO_0,0
126,NC/VCCPLL1,PLL Vcc,Power Input,PLL1,Power,VCCPLL0,0
127,NC/GNDPLL1,PLL Ground,Power Input,PLL1,Power,VCCPLL0,0
128,G1(IOT84/197),I/O 84/197 Bank0 - GBIN1,Input/Output,GBIN,Bank_0,VCCIO_0,0
129,G0(IOT85/198),I/O 85/198 Bank0 - GBIN0,Input/Output,GBIN,Bank_0,VCCIO_0,0
130,NC/IOT206,I/O 206 Bank0,Input/Output,PIO,Bank_0,VCCIO_0,0
131,NC/VCCIO_0,Bank 0 Vcc,Power Input,VCCIO,Power,VCCIO_0,0
132,GND,Ground,Power Input,GND,Power,VCCIO,0
133,VCCIO_0/NC,Bank 0 Vcc,Power Input,VCCIO,Power,VCCIO_0,0
134,IOT87/212,I/O 87/212 Bank0,Input/Output,PIO,Bank_0,VCCIO_0,0
135,IOT88/213,I/O 88/213 Bank0,Input/Output,PIO,Bank_0,VCCIO_0,0
136,IOT89/214,I/O 89/214 Bank0,Input/Output,PIO,Bank_0,VCCIO_0,0
137,IOT90/215,I/O 90/215 Bank0,Input/Output,PIO,Bank_0,VCCIO_0,0
138,IOT91/216,I/O 91/216 Bank0,Input/Output,PIO,Bank_0,VCCIO_0,0
139,IOT92/217,I/O 92/217 Bank0,Input/Output,PIO,Bank_0,VCCIO_0,0
140,GND,Ground,Power Input,GND,Power,VCCIO,0
141,IOT93/219,I/O 93/219 Bank0,Input/Output,PIO,Bank_0,VCCIO_0,0
142,IOT94/220,I/O 94/220 Bank0,Input/Output,PIO,Bank_0,VCCIO_0,0
143,IOT95/221,I/O 95/221 Bank0,Input/Output,PIO,Bank_0,VCCIO_0,0
144,IOT96/222,I/O 96/222 Bank0,Input/Output,PIO,Bank_0,VCCIO_0,0

Then you call it like this:

$ perl comp_gen.pl -input iCE40HX1-4K.csv -lib iCE40HX1-4K -dir . -part -wdcomp 1200 -withexfield -pinl 150
Component Schematic Generator for Kicad v1.1.1 Copyright (c) 2014-2015 David M. Caruso/SET/INTI
Footprint: TQFP-144
Descripcion: iCE40 High Speed FPGA
Fabricante: Lattice
Numero de parte: iCE40HX1K
Hoja de datos: -
Codigo: iCE40HX1K
Reading: 144 pins
There are: 6 groups of pins

And you get the 6 defined groups: Esquema.pdf

Generating big components, and maintaining them, is much more easy this way.

matthiesenj commented 2 years ago

That's very nice - I think many of the original KiCad symbols are created in a similar fashion. Since you get one symbol with multiple units, it would still map to just a single footprint, though. To use two footprints, it would have to be two distinct symbols, each mapping 1:1 to a footprint, but then you loose the ability to use functional units - at least that's my understanding of how KiCad 5 works.

My schematic is finished by now, so I'm not going to rip it all up by changing it to two separate 100 pin symbols. I have been aware of this problem since I started using the symbol, but have just been putting dealing with transforming it into two footprints off until now.

set-soft commented 2 years ago

Since you get one symbol with multiple units, it would still map to just a single footprint, though.

In this case, when you realize you need 2 footprints, you just split the CSV in 2, adjust the pin numbers (can be done with a script or just a spreadsheet) and generate 2 symbols. Each symbols with N sub-symbols. The number will be automatically computed according to the groups you defined.

Unichord commented 1 year ago

I'd be really interested in this feature too. This would open basically infinite possibilities on what to automate.

I don't know if you're familiar with Vivado workflows, in which there are so-called "hooks" between each FPGA implementation step (executed sequentially):

pre_hook_1
operation_1
post_hook_1

pre_hook_2
operation_2
post_hook_2

So for example pre_hook_2 is bound to operation_2 and will be executed every time before operation_2, whether operation_2 is run after operation_1 or in a stand-alone fashion. This is very customizable and convenient, since you can reuse the same scripts for different outputs. Also, every operation is independent and called from different scripts depending on the scenario. For example I plan on having different script which generate different outputs (gen_all, gen_only_bom, gen_gerbers, etc), and this would make that super easy. I don't know if it would be easy to implement, though.

Executing custom scripts would be extremely useful for variable replacing, text manipulation outside of KiCad, file copy, etc. For example I'd like to automate KiKit to panelize PCBs, which can be easily done by custom scripting. I also plan to make a small database with all the boards we have, and external scripting would be handy to populate or extract data from it. Again, the possibilities would be endless.

set-soft commented 1 year ago

Hi @Unichord !

Executing custom scripts would be extremely useful for variable replacing, text manipulation outside of KiCad, file copy, etc.

Which of these operations can't be currently done?

For example I'd like to automate KiKit to panelize PCBs, which can be easily done by custom scripting. I also plan to make a small database with all the boards we have, and external scripting would be handy to populate or extract data from it. Again, the possibilities would be endless.

Panelizing is in my TODO list. In general: why not writing a new output, and perhaps contribute it?

Unichord commented 1 year ago

Hi @Unichord !

Executing custom scripts would be extremely useful for variable replacing, text manipulation outside of KiCad, file copy, etc.

Which of these operations can't be currently done?

Maybe I just don't know KiBot deeply enough and all these features are already there. I'd like to extract data from a db, edit CSVs which are not related to the KiCad project I'm using KiBot on, copy and rename files, using paths which are defined in another file, doing conditional operations. Basically I want to have a configuration file in each project, and extract information from there (about panelization, series, suppliers, internal information, whatever). As far as I can see, KiBot is awesome for KiCad operations, but of course lacks the "side operations" part. Integrating all the features I'm asking would be really complex and basically wouldn't make sense, since they're specific to my use case. But I think opening up to external scripting would solve this problem for everyone.

For example I'd like to automate KiKit to panelize PCBs, which can be easily done by custom scripting. I also plan to make a small database with all the boards we have, and external scripting would be handy to populate or extract data from it. Again, the possibilities would be endless.

Panelizing is in my TODO list. In general: why not writing a new output, and perhaps contribute it?

That is really good news. I can contribute, but I don't know Python (it's in my todo list). At the moment I plan on using bash/batch/tcl, depending on the operation. Also, as I said above, my use case would be a very narrow one, so I don't know how much it can be useful to others.

set-soft commented 1 year ago

Hi @Unichord !

The dev branch now has support for KiKit panelization. You can find examples here (panelize* files)