Add TI VQFN package generator
authorDan White <dan@whiteaudio.com>
Tue, 14 Feb 2012 19:28:10 +0000 (13:28 -0600)
committerDan White <dan@whiteaudio.com>
Tue, 14 Feb 2012 19:28:10 +0000 (13:28 -0600)
sch-pcb/fp/Pcb-letter.pdf [new file with mode: 0644]
sch-pcb/fp/Pcb_9.pm [new file with mode: 0644]
sch-pcb/fp/VQFN-50P-400W-400L-24N-245WT-245LT__TI_RGE_Package.fp [new file with mode: 0644]
sch-pcb/fp/pcb-example-hdr1 [new file with mode: 0755]
sch-pcb/fp/pcb-example-hdr2 [new file with mode: 0755]
sch-pcb/fp/pcb-example-res [new file with mode: 0755]
sch-pcb/fp/pcb-example-smd [new file with mode: 0755]
sch-pcb/fp/pcb-example-tqfn [new file with mode: 0755]
sch-pcb/fp/ti_rge.pl [new file with mode: 0755]

diff --git a/sch-pcb/fp/Pcb-letter.pdf b/sch-pcb/fp/Pcb-letter.pdf
new file mode 100644 (file)
index 0000000..f1ab9a2
Binary files /dev/null and b/sch-pcb/fp/Pcb-letter.pdf differ
diff --git a/sch-pcb/fp/Pcb_9.pm b/sch-pcb/fp/Pcb_9.pm
new file mode 100644 (file)
index 0000000..cfce576
--- /dev/null
@@ -0,0 +1,1224 @@
+# Copyright (C) 2007 John C. Luciani Jr. 
+
+# This program may be distributed or modified under the terms of
+# version 0.2 of the No-Fee Software License published by
+# John C. Luciani Jr.
+
+# A copy of the license is at the end of this file.
+
+package        Pcb_9;
+require        Exporter;
+use vars       qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
+@ISA         = qw(Exporter);
+@EXPORT      = qw(get_field_format scaled_value flag_value_element flags);
+@EXPORT_OK   = qw(element_get_field_names dim_field_p element_get_names element_str 
+                  ELEMENT_NAME_HIDDEN ELEMENT_SELECTED ELEMENT_SOLDER_SIDE
+                  PIN_MASK PIN_ALWAYS_SET PIN_CONNECTED PIN_MOUNTING_HOLE PIN_DISPLAY_NAME
+                  PIN_SELECTED PIN_SQUARE PIN_OCTAGONAL PIN_ROUND PIN_SHAPE_MASK 
+                  PAD_CONNECTED PAD_DISPLAY_NAME PAD_SELECTED PAD_SOLDER_SIDE PAD_SQUARE
+                  PAD_ROUNDED TEXT_ON_SOLDER_SIDE);
+%EXPORT_TAGS = (flags => [qw(ELEMENT_NAME_HIDDEN ELEMENT_SELECTED ELEMENT_SOLDER_SIDE
+                             PIN_MASK PIN_ALWAYS_SET PIN_CONNECTED PIN_MOUNTING_HOLE PIN_DISPLAY_NAME
+                             PIN_SELECTED PIN_SQUARE PIN_OCTAGONAL PIN_ROUND PIN_SHAPE_MASK 
+                             PAD_CONNECTED PAD_DISPLAY_NAME PAD_SELECTED PAD_SOLDER_SIDE PAD_SQUARE
+                             PAD_ROUNDED TEXT_ON_SOLDER_SIDE)]);
+
+use strict;
+use warnings;
+use Carp;
+use POSIX;
+use Data::Dumper;
+
+### \title{Creating PCB Elements with Perl}
+### \author{John C. Luciani Jr.}
+### \date{\today}
+### \maketitle
+
+### \section{Change Log}
+
+### \begin{tabular}{lccp{4in}}
+### {\tt Pcb\_9} & ???               & {\tt jcl}   &%
+###       1. Fixed a dimension scaling bug in element\_add\_lines.
+###          The scaling routine now scales an array of points.
+###          This bug was reported by Ben Jackson.\\
+###   &&& 2. The scaling routines now accept a dimension suffix which will 
+###          override the default dimension.\\
+### {\tt Pcb\_8} & 19-Mar-2007       & {\tt jcl}   &%
+###       1. Removed the export of element\_add\_arc. Not necessary (OO).\\
+###   &&& 2. Corrected the mask and clearance parameters in the pin, pad and pin\_oval procedures.\\
+###   &&& 3. Removed the Mark command since the mark data is now in the Element header.\\
+###   &&& 4. Exported element\_str and added a scale\_factor parameter (default value of 100)\\
+###   &&& 5. the key to specify dimensional units (input\_dim) was changed to dim\\
+###   &&& 6. Fixed the dimension scaling problem in {\tt add\_element\_lines}\\
+###   &&& 7. Corrected the documentation for {\tt element\_add\_pin\_oval}\\
+### {\tt Pcb\_7} & 25 March 2005       & {\tt jcl}   &%
+###       1. changed the definition of the mask and clearance.\\
+###   &&& 2. Fixed the mask and clearance parameters in the pin, pad and pin\_oval procedures.\\
+### {\tt Pcb\_6} & 22 March 2005 & {\tt jcl} &%
+###       1. The {\tt element\_add\_rectangle} command now uses the {\tt x} and {\tt y}
+###          parameters. The center of the rectangle was always placed at (0,0)\\
+###   &&& 2. The {\tt pin\_one\_square} key-value pair was not getting properly tested
+###          in the {\tt element\_add\_pin} procedure.\\
+###   &&& 3. Added the {\tt clearance} and the {\tt mask} parameters to {\tt element\_add\_pad\_rectangle}.\\
+### {\tt Pcb\_5} & 6 March 2005 & {\tt jcl} &%
+###       1. Added the {\tt element\_add\_lines} command.\\
+###   &&& 2. added the {\tt element\_add\_pin\_oval} command.\\
+###   &&& 3. Modified the debug print messages.\\
+###   &&& 4. Fixed constant for octagonal pads.\\
+###   &&& 5. Fixed errors in the EXPORT\_OK and EXPORT\_TAGS declarations.\\
+###   &&& 6. Added {\tt element\_get\_names}.\\
+### {\tt Pcb\_4} & 27 February 2005     & {\tt jcl} &% 
+###    1. Modified the debug strings to output mm and mils.\\
+
+###    &&& 2. Fixed the {\tt scale\_factor} subroutine. {\tt
+###    scale\_factor} did not correctly convert from mils to mm. I did
+###    not test (or use) the conversion to mm until I modified the
+###    debug strings\\
+
+### {\tt Pcb\_3} & 7 February 2005 & {\tt jcl } & Initial Release\\
+### \end{tabular}
+
+### \section{Pcb\_9}
+
+### This document describes a set of Perl routines that can be used to
+### create component footprints for the circuit board layout program
+### \href{http://bach.ece.jhu.edu/~haceaton/pcb}{PCB}. These routines
+### reside in a file called |Pcb_|\<n>|.pm| where \<n> is the current
+### revision number of the package. Only the new format of PCB
+### elements is output. The differences (that I am aware of) between
+### the old and new formats are:
+
+### \begin{itemize}
+### \item Dimensions are in hundreths of a mil.
+### \item The argument delimiters are square brackets |[]|
+### \item The element command adds the |mark_x| and |mark_y| parameters
+### \item The pin and pad command add clearance and mask parameters.
+### \end{itemize}
+###\par
+
+### \subsection*{Requirements}
+
+### These routines should run with a standard Perl distribution. The
+### only packages used are |POSIX| and |Carp|.\par
+
+### \subsection*{Usage} 
+
+### These routines are object oriented. A PCB object is created using
+### |new| and all subsequent method calls use this
+### object. |element_begin| starts a new element. |element_output|
+### outputs the element file. |element_add_mark| sets the component
+### centroid. |element_set_text_xy| sets the text position for the
+### reference designator. The names of the methods used to draw
+### elements all start with the string |element_add|. Arguments for
+### the method calls are key-value pairs. The keys are parameter
+### strings defined in
+### \href{http://pcb.sourceforge.net/pcb-20050127.html/index.html}{pcb.html}.\par
+
+### \medskip\noindent To use these routines in a Perl script to create a PCB element:
+
+### \begin{enumerate}
+### \item Include the PCB routines |use Pcb_|\<n>|;|
+### \item Create a PCB object using |new|
+### \item Begin an element using |element_begin|
+### \item Add copper to the element using |element_add_pin| or |element_add_pad|
+### \item Add silkcreen elements using |element_add_line|, |element_add_arc|,
+### \item Mark the centroid using |element_add_mark|. The mark can
+###       also be set using parameters of the |element_begin| method.
+### \item Add the text location for the reference designator using |element_set_text_xy|
+###       The text location can also be set using parameters of the |element_begin| method.
+### \item Output the element to a file using |element_output|
+### \end{enumerate}
+
+### The simple example in \autoref{lst:res example} creates a
+### quarter~watt through-hole resistor.  The example in
+### \autoref{lst:smd example} creates a variety of two terminal SMD
+### footprints ranging in size from |0402| to |2512|. The example in
+### \autoref{lst:th example} creates Molex 8624 series header
+### connector footprints. The example in \autoref{lst:tqfn example}
+### creates TQFN footprints for a variety of Maxim parts.
+
+### These examples place files in the directory |./tmp|. This can be
+### easily changed by changing the |element_begin| call.
+
+###\lstinputlisting[%
+###     label=lst:res example,%
+###     caption=1/4 Watt Resistor Example]{pcb-example-res}
+
+### \section{Examples}
+### \label{sec:examples}
+
+###\lstinputlisting[%
+###     label=lst:to220 example,%
+###     caption=TO220 Pads]{pcb-example-TO220-pads}
+
+### \newpage
+###\lstinputlisting[%
+###     label=lst:smd example,%
+###     caption=SMD Element Creation Example]{pcb-example-smd}
+
+###\newpage
+###\lstinputlisting[%
+###     label=lst:th example,%
+###     caption=Header Connector Creation Example 1]{pcb-example-hdr1}
+
+###\newpage
+###\lstinputlisting[%
+###     label=lst:th example,%
+###     caption=Header Connector Creation Example 2]{pcb-example-hdr2}
+
+###\newpage
+###\lstinputlisting[%
+###     label=lst:tqfn example,%
+###     caption=TQFN Element Creation Example]{pcb-example-tqfn}
+
+### \section{Element Flags}
+
+### The element flag field determines the state of an element. The bit
+### values are:
+
+### @key_value_table@ 
+use constant ELEMENT_NAME_HIDDEN => 0x10;  ###    bit 4:  the element name is hidden
+use constant ELEMENT_SELECTED    => 0x40;  ###    bit 6:  element has been selected
+use constant ELEMENT_SOLDER_SIDE => 0x80;  ###    bit 7:  element is located on the solder side
+### @end_key_value_table@ Element Flags 
+
+### \section{Text Flags}
+
+### @begin_key_value_table@ 
+use constant TEXT_DIRECTION_0   => 0;  ### Horizontal
+use constant TEXT_DIRECTION_90  => 1;  ### 90  degrees counter-clockwise
+use constant TEXT_DIRECTION_180 => 2;  ### 180 degrees counter-clockwise
+use constant TEXT_DIRECTION_270 => 3;  ### 270 degrees counter-clockwise
+### @end_key_value_table@ Text Direction Flags
+
+### @begin_key_value_table@ 
+use constant TEXT_SELECTED       => 0x40;  ###   bit 6:  the text has been selected
+use constant TEXT_ON_SOLDER_SIDE => 0x80;  ###   bit 7:  the text is on the solder (back) side of the board
+use constant TEXT_ON_SILKSCREEN  => 0x400; ###   bit 10: the text is on the silkscreen layer
+### @end_key_value_table@ Text Flags
+
+### \section{Pin Flags}
+
+### @key_value_table@ 
+use constant PIN_MASK          => 0xFFFD;  ###
+use constant PIN_ALWAYS_SET    => 0x0001;  ###    bit 0:  always set
+                                           ###    bit 1:  always clear
+use constant PIN_CONNECTED     => 0x0004;  ###    bit 2:  set if pin was found during a connection search
+use constant PIN_MOUNTING_HOLE => 0x0008;  ###    bit 3:  set if pin is only a mounting hole (no copper annulus)
+use constant PIN_DISPLAY_NAME  => 0x0020;  ###    bit 5:  display the pins name
+use constant PIN_SELECTED      => 0x0040;  ###    bit 6:  pin has been selected
+use constant PIN_SQUARE        => 0x0100;  ###    bit 8:  pin is drawn as a square
+use constant PIN_OCTAGONAL     => 0x0800;  ###    bit 12: set if pin is drawn with an octagonal shape
+use constant PIN_ROUND         => 0x0000;  ###
+use constant PIN_SHAPE_MASK    => 0xEEFF;  ###
+### @end_key_value_table@ Pin Flags
+
+### \section{Pad Flags}
+
+### @key_value_table@ 
+use constant PAD_CONNECTED    => 0x0004; ###    bit 2:  set if pad was found during a connection search
+use constant PAD_DISPLAY_NAME => 0x0020; ###    bit 5:  display the pads name
+use constant PAD_SELECTED     => 0x0040; ###    bit 6:  pad has been selected
+use constant PAD_SOLDER_SIDE  => 0x0080; ###    bit 7:  pad is located on the solder side
+use constant PAD_SQUARE       => 0x0100; ###    
+use constant PAD_ROUNDED      => 0x0800; ###    bit 11: pad has rounded corners
+### @end_key_value_table@ Pad Flags
+
+### \Method new\\
+
+### \Usage Pcb_9 -> new\\
+
+### \Description
+
+### Creates an object that is used to make PCB element files. Default
+### parameters for the various element drawing commands can be
+### initialized using a key-value parameter list.
+
+### \medskip\noindent The valid keys and default values are in
+### \autoref{tab:kv new}
+
+sub new {
+    my $class = shift;
+    my $self = { 
+                 ### @key_value_table@ 
+                 line_thickness => 10,    ### thickness used in drawing silkscreen lines
+                 arc_thickness => 10,     ### thickness used in drawing silkscreen arcs
+                 thickness => 10,         ### thickness used in drawing any silkscreen line
+                 pin_flags => 0,          ### flags used in creating element pins (See \autoref{tab:kv pin flags})
+                 pad_flags => PAD_SQUARE, ### flags used in creating pads
+                 font_size => 50,         ### size in ??? of the silkscreen found
+                 clearance => 10,         ### \clearanceDEF
+                 mask      => 10,         ### \maskDEF
+                 debug => 0,              ### debug messages. no messages (0). object methods (1). object methods + internal subroutines (2)
+                 ### @end_key_value_table@ Keys for Method new | new
+                 &_scale_dim(dim => 'mils', @_),
+               };
+    bless $self, $class; # bless $self into the designated class
+
+    printf("(new) Creating a new Pcb object\n")
+        if $self -> debug_p;
+
+    # initialization
+
+    return $self;
+}
+
+### \Example
+
+### To create a new object that will display object method debugging
+### messages:\par
+### \medskip\noindent
+### \begin{lstlisting}[numbers=none,frame=none]
+### my $Pcb = Pcb_9 -> new(debug => 1);
+### \end{lstlisting}
+
+
+
+
+### \Method element_begin\\
+
+### \Usage Pcb -> element_begin\\
+
+### \Description
+
+### Initializes a new Pcb element. If an element was previously
+### created but not output a call to |element_begin| will remove it.
+
+### \medskip\noindent The valid keys and default values are in
+### \autoref{tab:kv element-begin}
+
+sub element_begin {
+    my $self = shift;
+    $self->{element} = 
+    { 
+        ### @key_value_table@ 
+        flags => 0,                        ### \elementflagsDEF
+        description => '',                 ### \descriptionDEF
+        layout_name => '',                 ### \layoutnameDEF
+        value => '',                       ### \valueDEF
+        mark_x => 0,                       ### \markxDEF
+        mark_y => 0,                       ### \markyDEF
+        text_x => 0,                       ### \textxDEF
+        text_y => 0,                       ### \textyDEF
+        direction => 0,                    ### \directionDEF
+        scale => 100,                      ### \scaleDEF
+        text_flags => 0,                   ### \textflagsDEF
+        output_file => 'PCB_ELEMENT.TMP',  ### Element filename
+        pin_one_square => 0,               ### Sets a default value that is used when creating a pin.
+        dim => 'mils',                     ### units default to mils
+        ### @end_key_value_table@ Keys for Method element\_begin | element-begin
+        _elements => [],
+        $self -> scale_dim(@_)
+    };
+
+    printf("(element_begin) Creating element file %s\n", $self -> element_get('output_file'))
+        if $self -> debug_p;
+
+}       
+
+### \Example
+
+### To begin a 1/4 Watt resistor element with dimension values in mils:\par
+### \medskip\noindent
+### \begin{lstlisting}[numbers=none,frame=none]
+### $Pcb -> element_begin(description => 'resistor',
+###                       output_file => '025W',
+###                       dim   => 'mils');
+### \end{lstlisting}
+
+
+### \Method element_output\\
+
+### \Usage Pcb -> element_output\\
+
+### \Description
+
+### |element_output| outputs the element drawing commands to a
+### file. At this time there are no parameters that are valid for the
+### \<parameter list>.
+
+sub element_output ($) { 
+    my ($self) = @_;
+    my $ref = $self->{element};
+    if (defined $ref->{output_file}) {
+        my $output_file = $ref->{output_file};
+        open(OUTFILE, ">$output_file") or 
+            croak "(Pcb) (element_output) Could not open $output_file for output";
+        printf(OUTFILE "Element[0x%x \"%s\" \"%s\" \"%s\" %i %i %i %i %i %i 0x%x]\n",
+               hex($ref->{flags}),
+               $ref->{description},
+               $ref->{layout_name},
+               $ref->{value},
+               $ref->{mark_x} * 100,
+               $ref->{mark_y} * 100,
+               $ref->{text_x} * 100,
+               $ref->{text_y} * 100,
+               $ref->{direction},
+               $ref->{scale},
+               hex($ref->{text_flags}));
+        printf(OUTFILE "(\n");
+        foreach (@ { $ref->{_elements} }) {
+            printf(OUTFILE "   %s\n", &element_str(@$_));
+        }
+        printf(OUTFILE ")\n");
+        close(OUTFILE) or croak "(Pcb) (element_output) Could not close $output_file";
+    } else {
+        carp "(Pcb) (element_output) Element filename was not defined";
+    }
+}
+
+### \Method element_add_line\\
+
+### \Usage Pcb -> element_add_line\\
+
+### \Description
+
+### Creates a silkscreen line of a specified thickness (|thickness|)
+### between two \points.
+
+### \BeginKVTable
+###  x1 & & \xoneDEF \\
+###  y1 & & \yoneDEF \\
+###  x2 & & \xtwoDEF \\
+###  y2 & & \ytwoDEF \\
+###  thickness & & \thicknessDEF \\
+### \EndKVTable{Keys for Method element\_add\_line}{element-add-line}
+
+sub element_add_line ($%) { 
+    my $self = shift;
+    my %v = (thickness => $self -> element_get('line_thickness'),
+             $self -> scale_dim(@_));
+    printf("   (element_add_line) adding line from %s to %s with thickness %s\n",
+           &_debug_str_point($v{x1}, $v{y1}),
+           &_debug_str_point($v{x2}, $v{y2}),
+           &_debug_str_dim($v{thickness}))
+        if $self -> debug_p;
+    $self -> _element_add('ElementLine', %v);
+}
+
+### \Example
+
+### To create a 200mil long silkscreen line that is centered at |(0,0)| that is
+### 10 mils thick\par
+### \medskip\noindent
+### \begin{lstlisting}[numbers=none,frame=none]
+### $Pcb -> element_add_line(x1 => -100, y1 => 0, 
+###                          x2 =>  100, y2 => 0,
+###                          thickness => 10);
+### \end{lstlisting}
+
+
+### \Method element_add_arc\\
+
+### \Usage Pcb -> element_add_arc\\
+
+### \Description
+
+### Creates a silkscreen arc with a specified |width| and |length|
+### centered at a \point. 
+
+### \BeginKVTable
+### x & & \xDEF\\
+### y & & \yDEF\\
+### width & & horizontal width of the arc\\
+### height & & vertical length of the arc\\
+### start\_angle & & Starting angle of the arc (degrees) \\
+### delta\_angle & & Angle swept by the arc (degrees)\\
+### thickness & & line thickness\\
+### \EndKVTable{Keys for Method element\_add\_arc}{element-add-arc}
+
+
+sub element_add_arc ($%) { 
+    my $self = shift;
+    my %v = (thickness => $self -> get('arc_thickness'),
+             $self -> scale_dim(@_));
+    printf("   (element_add_arc) center at %s, start angle=%.0f, delta angle=%.0f\n",
+           &_debug_str_point($v{x}, $v{y}),
+           map { $v{$_} } qw(start_angle delta_angle)) 
+        if $self -> debug_p;
+    $self -> _element_add('ElementArc', %v);
+}
+
+### \Example
+
+### To create a silkscreen circular arc centered at |(0,0)| with a
+### line thickness of 10 mils, radius of 200 mils that starts at
+### 45$\Deg$ and sweeps for 135$\Deg$:\par
+
+### \medskip\noindent
+### \begin{lstlisting}[numbers=none,frame=none]
+### $Pcb -> element_add_arc(start_angle => 45, 
+###                         delta_angle => 135,
+###                         x => 0,
+###                         y => 0,
+###                         width => 200,
+###                         height => 200,
+###                         thickness => 10);
+### \end{lstlisting}
+
+### For an ellipse set the width and height to unequal values.
+
+
+### \Method element_add_pin\\
+
+### \Usage Pcb -> element_add_pin\\
+
+### \Description
+
+### Adds a pin to an element
+
+### \BeginKVTable
+### x & & \xDEF\\
+### y & & \yDEF\\
+### thickness & & width of the copper pad\\
+### clearance & & \clearanceDEF\\
+### mask      & & \maskDEF\\
+### drill\_hole & & diameter of the hole that is drilled at the center of the pad\\
+### name        & & string\\
+### pin\_number  & & \pinnumberDEF\\
+### flags       & & See \autoref{tab:kv pin flags}\\
+### \EndKVTable{Keys for Method element\_add\_pin}{element-add-pin}
+
+sub element_add_pin {
+    my $self = shift;
+    my %v = ( clearance => $self -> get('clearance'),
+              mask      => $self -> get('mask'),
+              name      => '',
+              flags     => $self -> get('pin_flags'),
+              $self -> scale_dim(@_));
+
+    if ($v{pin_number} == 1 && $self -> element_get('pin_one_square')) {
+        $v{flags} &= PIN_SHAPE_MASK;
+        $v{flags} |= PIN_SQUARE;
+    }
+    $v{flags} &= PIN_MASK;
+    $v{flags} |= PIN_ALWAYS_SET;
+
+    # The mask parameter that was passed as an argument is the
+    # clearance between the edge of the copper and the edge of the
+    # masking material. The mask value that PCB wants is the total
+    # diameter of hole in the mask.
+
+    $v{mask} = $v{mask} * 2 + $v{thickness};
+    $v{clearance} *= 2;
+
+    printf("   (element_add_pin) center at %s, diameter=%s, pin_number=%s, flags=0x%x\n",
+           &_debug_str_point($v{x}, $v{y}),
+           &_debug_str_dim($v{thickness}),
+           defined $v{pin_number} ? sprintf("%i", $v{pin_number}) : '?',
+           $v{flags})
+        if $self -> debug_p;
+
+    $self -> _element_add('Pin', %v);
+}
+
+### \Example
+### 
+### To place a pin with a round pad at |(-100,0)| with a pad diameter of 55 mils, a drill hole diameter
+### of 35 mils, soldermask clearance of 10 mils, a copper clearance of 9 mils, and a pin number of one:\par
+### \medskip\noindent
+### \begin{lstlisting}[numbers=none,frame=none]
+### $Pcb -> element_add_pin(x => -100, y => 0,
+###                         thickness  => 55,
+###                         drill_hole => 35,
+###                         mask => 10,
+###                         clearance => 9,
+###                         pin_number => 1);
+### \end{lstlisting}
+
+### \Method element_add_pad\\
+
+### \Usage Pcb -> element_add_pad\\
+
+### \Description
+
+### Pads are created by drawing a line, with a specified thickness,
+### between two points.  The line is drawn with a square nib and
+### extends beyond each end point by a distance of ${\tt
+### thickess}\over 2$.
+
+### \BeginKVTable
+###  x1 & & \xoneDEF \\
+###  y1 & & \yoneDEF \\
+###  x2 & & \xtwoDEF \\
+###  y2 & & \ytwoDEF \\
+###  thickness & & \thicknessDEF \\
+###  clearance & & \clearanceDEF\\
+###  mask      & & \maskDEF\\
+###  name      & & \padnameDEF\\
+###  pad\_number & & \padnumberDEF\\
+###  flags       & & See \autoref{tab:kv pad flags}\\
+### \EndKVTable{Keys for Method element\_add\_line}{element-add-line}
+
+sub element_add_pad {
+    my $self = shift;
+    my %v = (flags     => $self -> get('pad_flags'),
+             clearance => $self -> get('clearance'),
+             mask      => $self -> get('mask'),
+             $self -> scale_dim(@_));
+    printf("   (element_add_pad) from %s to %s with thickness %s\n",
+           &_debug_str_point($v{x1}, $v{y1}),
+           &_debug_str_point($v{x2}, $v{y2}),
+           &_debug_str_dim($v{thickness}))
+        if $self -> debug_p;
+
+    $v{mask} = $v{mask} * 2 + $v{thickness};
+    $v{clearance} *= 2;
+
+    $self -> _element_add('Pad', %v);
+    
+}
+
+### \Example
+
+### To create a pad that is centered at |(0,0)| that is 100 mils long and 50 mils thick\par
+### has a soldermask clearance of 10 mils, a copper clearance of 9 mils and is numbered one:\par
+### \medskip\noindent
+### \begin{lstlisting}[numbers=none,frame=none]
+### $Pcb -> element_add_pad(x1 => -25, y1 => 0, 
+###                         x2 => 25,  y2 => 0,
+###                         thickness  => 50,
+###                         mask       => 10,
+###                         clearance  => 9,
+###                         pad_number => 1);
+### \end{lstlisting}
+
+
+
+
+### \Method element_add_pad_rectangle\\
+
+### \Usage Pcb -> element_add_pad_rectangle\\
+
+### \Description
+
+### Create a pad with a specified width and length that is centered at
+### a point |(x,y)|. The length is in x-direction and the width is in
+### the y-direction.
+
+### \BeginKVTable
+### x           &  & \xDEF\\
+### y           &  & \yDEF\\
+### width       &  & \widthDEF\\
+### length      &  & \lengthDEF\\
+### clearance   &  & \clearanceDEF\\
+### mask        &  & \maskDEF\\
+### name        &  & \padnameDEF\\
+### pin\_number &  & \pinnumberDEF\\
+### \EndKVTable{Keys for Method element\_add\_pad\_rectangle}{element-add-pad-rectangle}
+
+
+sub _print_missing_fields  { 
+    my ($sub_name, $ref, @fields) = @_;
+    my $missing_fields = 0;
+    foreach (@fields) {
+       next if defined $ref->{$_};
+       printf("(%s) field %s is undefined\n", $sub_name, $_);
+       $missing_fields = 1;
+    }
+    return($missing_fields);
+}
+
+
+sub element_add_pad_rectangle { 
+    my $self = shift;
+    my %v = (flags => $self -> get('pad_flags'),
+             clearance => $self -> get('clearance'),
+             mask      => $self -> get('mask'),
+             $self -> scale_dim(@_));
+
+    die if &_print_missing_fields('element_add_pad_rectangle', 
+                                 \%v, 
+                                 qw(width length x y name pin_number clearance mask));
+
+    my ($x1, $x2, $y1, $y2);
+    my $thickness;
+    if ($v{width} < $v{length}) {
+        $thickness = $v{width};
+        $y1 = $v{y}; $y2 = $v{y};
+        $x1 = $v{x} - ($v{length} - $thickness) / 2;
+        $x2 = $v{x} + ($v{length} - $thickness) / 2;
+    } else {
+        $thickness = $v{length};
+        $x1 = $v{x}; $x2 = $v{x};
+        $y1 = $v{y} - ($v{width} - $thickness) / 2;
+        $y2 = $v{y} + ($v{width} - $thickness) / 2;
+    }
+
+    printf("   (element_add_pad_rectangle) width = %s, length = %s, center at %s\n",
+           &_debug_str_dim($v{width}),
+           &_debug_str_dim($v{length}),
+           &_debug_str_point($v{x}, $v{y}))
+        if $self -> debug_p;
+
+    $self -> element_add_pad(x1 => $x1, x2 => $x2,
+                             y1 => $y1, y2 => $y2,
+                             thickness => $thickness,
+                             name => $v{name},
+                             pin_number => $v{pin_number},
+                             clearance => $v{clearance},
+                             mask => $v{mask},
+                            flags => $v{flags},
+                             dim => 'mils');
+}
+
+
+
+### \Method element_add_pin_oval\\
+
+### \Usage Pcb -> element_add_pin_oval\\
+
+### \Description
+
+### Create a pad with a specified width and length that is centered at
+### a point |(x,y)|. The length is in x-direction and the width is in
+### the y-direction. The corners of the pad are rounded.\par
+
+### \medskip\noindent This is actually a hybrid object consisting of a
+### component side pad, a solder side pad and a pin placed at the same
+### center point.
+
+### \BeginKVTable
+### x           &  & \xDEF\\
+### y           &  & \yDEF\\
+### width       &  & \widthDEF\\
+### length      &  & \lengthDEF\\
+### drill\_hole &  & diameter of the hole that is drilled at the center of the pad\\
+### name        &  & \padnameDEF\\
+### pin\_number &  & \pinnumberDEF\\
+### \EndKVTable{Keys for Method element\_add\_pin\_oval}{element-add-pin-oval}
+
+sub element_add_pin_oval { 
+    my $self = shift;
+    my %v = ( clearance => $self -> get('clearance'),
+              mask      => $self -> get('mask'),
+              $self -> scale_dim(@_));
+    my ($x1, $x2, $y1, $y2);
+    my $thickness;
+    if ($v{width} < $v{length}) {
+        $thickness = $v{width};
+        $y1 = $v{y}; $y2 = $v{y};
+        $x1 = $v{x} - ($v{length} - $thickness) / 2;
+        $x2 = $v{x} + ($v{length} - $thickness) / 2;
+    } else {
+        $thickness = $v{length};
+        $x1 = $v{x}; $x2 = $v{x};
+        $y1 = $v{y} - ($v{width} - $thickness) / 2;
+        $y2 = $v{y} + ($v{width} - $thickness) / 2;
+    }
+
+    printf("   (element_add_pad_oval) width = %s, length = %s, center at %s\n",
+           &_debug_str_dim($v{width}),
+           &_debug_str_dim($v{length}),
+           &_debug_str_point($v{x}, $v{y}))
+        if $self -> debug_p;
+
+
+    $self -> element_add_pad(x1 => $x1, x2 => $x2,
+                             y1 => $y1, y2 => $y2,
+                             thickness => $thickness,
+                             flags => PAD_ROUNDED,
+                             dim => 'mils',
+                             map { $_ => $v{$_} } qw(name pin_number clearance mask));
+
+    $self -> element_add_pad(x1 => $x1, x2 => $x2,
+                             y1 => $y1, y2 => $y2,
+                             thickness => $thickness,
+                             flags => PAD_ROUNDED | PAD_SOLDER_SIDE,
+                             dim => 'mils',
+                             map { $_ => $v{$_} } qw(name pin_number clearance mask));
+
+
+    $self -> element_add_pin(x => ($x1 + $x2) / 2,
+                             y => ($y1 + $y2) / 2,
+                             name => '', 
+                             pin_number => $v{pin_number},
+                             thickness => $thickness,
+                             dim => 'mils',
+                             drill_hole => $v{drill_hole},
+                             mask => $v{mask},
+                             flags => 0,
+                             clearance => $v{clearance});
+}
+
+### \Example
+
+### To place a pin with an oval pad at |(-100,0)| with a pad diameter
+### of 55 mils, a drill hole diameter of 35 mils, soldermask clearance
+### of 10 mils, a copper clearance of 9 mils, and a pin number of
+### one:\par
+
+### \medskip\noindent
+### \begin{lstlisting}[numbers=none,frame=none]
+### $Pcb -> element_add_pin_oval(x => -100, y => 0,
+###                              thickness  => 55,
+###                              drill_hole => 35,
+###                              mask       => 10,
+###                              clearance  => 9,
+###                              pin_number => 1);
+### \end{lstlisting}
+
+
+### \Method element_add_mark\\
+
+### \Usage Pcb -> element_add_mark\\
+
+### \Description
+
+### The mark is a positioning hint. |element_add_mark| places the mark at 
+### at a \point.
+
+### \BeginKVTable
+###  x & & \xDEF \\
+###  y & & \yDEF \\
+### \EndKVTable{Keys for Method element\_add\_mark}{element-add-mark}
+
+sub element_add_mark ($%) { 
+    my $self = shift;
+    my %v = $self -> scale_dim(@_);
+    printf("   (element_add_mark) mark at %s\n", 
+           &_debug_str_point($v{x}, $v{y}))
+        if $self -> debug_p;
+    $self -> _element_add('Mark', %v);
+}
+
+### \Method element_add_lines\\
+
+### \Usage Pcb -> element_add_lines\\
+
+### \Description
+
+### Draws silkscreen lines using the specified line end points. Lines
+### are drawn from point to point until all the points are connected.
+
+### \BeginKVTable
+### points      &  & reference to a list containing x,y coordinates for line end points.\\
+### thickness   &  & \thicknessDEF\\
+### \EndKVTable{Keys for Method element\_add\_lines}{element-add-lines}
+
+sub element_add_lines { 
+    my $self = shift;
+    my %v = (thickness => $self -> element_get('line_thickness'),
+             $self -> scale_dim(@_));
+    my @pts = @ { $v{points} };
+    while (@pts) {
+        my ($x1, $y1) = splice @pts, 0, 2;
+        last if $#pts < 1;
+        $self -> element_add_line(x1 => $x1, y1 => $y1, 
+                                 x2 => $pts[0], y2 => $pts[1],
+                                  thickness => $v{thickness},
+                                  dim => 'mils');
+    }
+}
+
+
+### \Method element_add_rectangle\\
+
+### \Usage Pcb -> element_add_rectangle\\
+
+### \Description
+
+### Draws a silkscreen rectangle with a specified |width| and |length| at a \point.
+
+### \BeginKVTable
+### x           &  & \xDEF\\
+### y           &  & \yDEF\\
+### width       &  & rectangle width  (y direction)\\
+### length      &  & rectangle length (x direction)\\
+### thickness   &  & \thicknessDEF\\
+### \EndKVTable{Keys for Method element\_add\_rectangle}{element-add-rectangle}
+
+sub element_add_rectangle { 
+    my $self = shift;
+    my %v = (x => 0,
+             y => 0,
+             thickness => $self -> element_get('line_thickness'),
+             $self -> scale_dim(@_));
+
+    # x1,y1 lower left
+    # x2,y2 upper right
+
+    my $x1 = $v{x} - $v{length} / 2; 
+    my $x2 = $v{x} + $v{length} / 2;
+    my $y1 = $v{y} + $v{width} / 2;
+    my $y2 = $v{y} - $v{width} / 2;
+    $self -> element_add_lines(points => [$x1, $y1, $x1, $y2, $x2, $y2, $x2, $y1, $x1, $y1],
+                               %v,
+                               dim => 'mils');
+}
+
+
+### \Method element_set_text_xy\\
+
+### \Usage Pcb -> element_set_text_xy\\
+
+### \Description
+
+### Sets the position of the reference designator text. 
+
+### \BeginKVTable
+###  x & & \xDEF \\
+###  y & & \yDEF \\
+###  font\_size & & \\
+### \EndKVTable{Keys for Method element\_add\_mark}{element-add-mark}
+
+sub element_set_text_xy ($%) { 
+    my $self = shift;
+    my %v = (font_size => $self -> element_get('font_size'),
+             $self -> scale_dim(@_));
+    printf("   (element_set_text_xy) text at %s\n", 
+           &_debug_str_point($v{x}, $v{y} - $v{font_size}))
+        if $self -> debug_p;
+    $self -> element_set(text_x => $v{x},
+                         text_y => $v{y} - $v{font_size});
+}
+
+### \Method element_set\\
+
+### \Usage Pcb -> element_set\\
+
+### \Description
+
+### Sets values in the element hash table. This should be the only
+### method used to set values in the element hash. \<parameter list>
+### contains key-value pairs.
+
+sub element_set ($@) { 
+    my ($self, @key_value_pairs) = @_;
+    while (@key_value_pairs) {
+        my ($k, $v) = splice @key_value_pairs, 0, 2;
+        next if $k =~ /^_/; # do not set private variables
+        $self->{element}{$k} = $v;
+    }
+}
+
+### \Method element_get\\
+
+### \Usage Pcb -> element_get\\
+
+### \Description
+
+### Returns a value, from the element hash, for each key specified in
+### \<parameter list>. If the value is undefined in the element hash
+### then a value from the Pcb object hash is returned. A value of
+### |undef| is returned if neither hash contains a defined value for
+### the key.\par
+
+### \medskip\noindent This should be the only method used to retrieve
+### values from the element hash. \<parameter list> contains a list of
+### keys.\par
+
+### \medskip\noindent 
+
+sub element_get ($@) { 
+    my ($self, @keys) = @_;
+    my @retvals;
+    foreach my $key (@keys) {
+        my $value = $self->{element}{$key};
+        $value = $self -> get($key) unless defined $value;
+        push @retvals, $value;
+    }
+    return @retvals    if wantarray();
+    return $retvals[0] if defined wantarray();
+    return;
+}
+
+
+### \Method get\\
+
+### \Usage Pcb -> get\\
+
+### \Description
+
+### Retrieves values from the PCB object hash.  This should be the
+### only method used to retrieve values from the PCB object hash.
+### \<parameter list> contains a list of keys.
+
+sub get ($@) { 
+    my ($self, @keys) = @_;
+    my @retvals = map { $self->{$_} } @keys;
+    return @retvals    if wantarray();
+    return $retvals[0] if defined wantarray();
+    return;
+}
+
+sub debug_p { shift() -> get('debug') }
+
+
+# Since these debug routines are only meant to be called from within
+# the Pcb package distance is assumed to be mils.
+
+sub _debug_str_dim ($) { 
+    my $dim = shift;
+    return 'undef' unless defined $dim;
+    sprintf("%.2f (%.2f)", $dim, &scaled_value($dim, 'mils', 'mm'));
+}
+
+sub _debug_str_point ($$$) { 
+    my ($x, $y) = @_;
+    return sprintf("x=%s, y=%s", (map { &_debug_str_dim($_) } $x, $y));
+}
+
+
+### \Method element_dump\\
+
+### \Usage Pcb -> element_dump\\
+
+### \Description
+
+### A debugging procedure that Prints out the element command drawing
+### commands to STDOUT. 
+
+sub element_dump { 
+    my ($self) = @_;
+    my $ref = $self->{element};
+    my @fields = qw(flags description layout_name value text_x text_y direction scale text_flags);
+    foreach (@fields) {
+        printf("field %s = %s\n", $_, $ref->{$_});
+    }
+    printf("Element(0x%x \"%s\" \"%s\" \"%s\" %i %i %i %i 0x%x)\n", map {$ref->{$_}} @fields);
+    printf("(\n");
+    foreach (@ { $ref->{_elements} }) {
+        printf("   %s\n", &element_str(@$_));
+    }
+    printf(")\n");
+}
+
+
+
+my %Element_fields;
+my %Fields;
+
+BEGIN 
+{
+
+    %Element_fields = ( Element     => [qw(flags description layout_name value mark_x mark_y
+                                           text_x text_y direction scale text_flags)],
+                        ElementLine => [qw(x1 y1 x2 y2 thickness)],
+                        ElementArc  => [qw(x y width height start_angle delta_angle thickness)],
+                        Pin         => [qw(x y thickness clearance mask drill_hole name pin_number flags)],
+                        Pad         => [qw(x1 y1 x2 y2 thickness clearance mask name pin_number flags)]);
+
+    %Fields = ((map { $_ => { dim => 0, format => '0x0%x'} }
+                    qw(flags text_flags)),
+               (map { $_ => { dim => 1, format => '%i'} } 
+                    qw(text_x text_y
+                       mark_x mark_y
+                       clearance mask
+                       line_thickness arc_thickness
+                       x1 y1 x2 y2 
+                       thickness width 
+                       height length x y drill_hole
+                       xoffset yoffset
+                      points
+                       )),
+                (map { $_ => { dim => 0, format => '%i' }  } 
+                     qw(start_angle delta_angle direction scale)),
+                (map { $_ => { dim => 0, format => '"%s"' } }
+                     qw(description layout_name value name pin_number)));
+
+}
+
+sub dim_field_p ($) { 
+    my $field_name = shift;
+    return $Fields{$field_name}{dim} if exists $Fields{$field_name}{dim};
+    return 0;
+}
+
+sub element_p     { defined $Element_fields{ shift() } }
+
+sub get_field_format {
+    my $name = shift;
+    join(' ', 
+         map { defined $Fields{$_}{format} ? $Fields{$_}{format} : "***$_***" } 
+         &element_get_field_names($name));
+}
+
+sub element_get_names  { 
+    return keys %Element_fields;
+}
+
+sub element_get_field_names ($) { 
+    my ($name) = @_;
+    return () unless defined $Element_fields{$name};
+    return @ { $Element_fields{$name} };
+}
+
+sub element_str { 
+    my $element_name = shift;
+    my %v = (scale_factor => 100,
+            @_);
+    my $str;
+    croak "(Pcb) (element_str) Unknown element type '$element_name'", return('') 
+        unless &element_p($element_name);
+    my @arg;
+
+    foreach my $fn (&element_get_field_names($element_name)) {
+        croak "(Pcb) (element_str) Missing field value for field $fn, element $element_name"
+            unless defined $v{$fn};
+
+        $v{$fn} *= $v{scale_factor} if &dim_field_p($fn);
+
+        push @arg, $v{$fn};
+    }
+    $str = sprintf("%s[" . &get_field_format($element_name) . "]", $element_name, @arg);
+    return $str;
+}
+
+# Scales dimension field values to mils. Field values that are not
+# dimensions are left unchanged.  Field names and values are returned
+# as a list of key-value pairs.
+
+sub _scale_dim { 
+    my %args = (dim => 'mils', @_);
+    my @retval;
+    foreach my $key (keys %args) {
+       push @retval, $key;
+        push(@retval, $args{$key}), next unless &dim_field_p($key);
+       if (ref($args{$key}) eq '') {
+           push(@retval, &scaled_value($args{$key}, $args{dim}, 'mils'));
+       } elsif (ref($args{$key}) eq 'ARRAY') {
+           push(@retval, [ map { &scaled_value($_, $args{dim}, 'mils') } @ { $args{$key} } ]);
+       } else {
+           printf("(Pcb_9) (_scale_dim) incorrect reference type %s for arg %s\n", 
+                  ref($args{$key}), 
+                  $key);
+           croak;
+       }
+    }
+    return (@retval);
+}
+
+sub scale_dim ($@) { 
+    my ($self, @args) = @_;
+    &_scale_dim(dim => $self -> element_get('dim'),
+                @args);
+}
+
+sub _scale_factor ($) { 
+    my ($dim) = @_;
+    return undef unless defined $dim;
+    return 1    if $dim =~ /^\s*mils?\s*$/;
+    return 0.01 if $dim =~ /^\s*mils?100\s*$/;
+    return 1000/25.4 if $dim =~ /^\s*mms?\s*$/;
+    return undef;
+}
+
+sub scaled_value ($$$) { 
+    my $value = shift;
+    my $from_units = shift || 'mils';
+    my $to_units   = shift || 'mils';
+
+    $from_units = $1 if $value =~ s/(\D+)$//;
+
+    return undef unless defined $value;
+    return undef unless $value =~ /^[-+.0-9eE]+$/;
+    return $value * &_scale_factor($from_units) / &_scale_factor($to_units);
+}
+
+# adds element definitions
+
+sub _element_add { 
+    my $self = shift;
+    push @{ $self->{element}{_elements}}, [@_];
+    return unless $self -> debug_p() > 1;
+    printf("      (_element_add) %s\n", shift);
+    while (@_) {
+        my ($k, $v) = splice @_, 0, 2;
+        printf("      %s = %s\n", map { defined $_ ? $_ : 'undef' } $k, $v);
+    }
+}
+
+###\clearpage
+###\ifpdfscreen%
+###\phantomsection%
+###\addcontentsline{toc}{section}{References}%
+###\fi%
+###\nocite{footprint}
+###\nocite{Pcb}
+#\bibliographystyle{apacite}
+###\bibliography{/local/lan/texmf/bibdb/bibdb}
+###\newpage
+
+1;
+
+# Style (adapted from the Perl Cookbook, First Edition, Recipe 12.4)
+
+# 1. Names of functions and local variables are all lowercase.
+# 2. The module's persistent variables (either file lexicals
+#    or package globals) are capitalized.
+# 3. Identifiers with multiple words have each of these
+#    separated by an underscore for readability.
+# 4. Constants are all uppercase.
+# 5. If the arrow operator (->) is followed by either a
+#    method name or a variable containing a method name then
+#    there is a space before and after the operator.
+# 6. Function names, variable names, hash keys that are meant
+#    to be used only within the current package have an
+#    underscore prefix.
+
+
+__END__
+[test program]
+#!/usr/bin/perl
+
+# this is a test program for the various subroutines in the Pcb
+# library. It is only meant to test individual routines not create a
+# usable component. See the www.luciani.org for the working examples.
+
+use strict;
+use warnings;
+
+use Pcb_9;
+
+my $Pcb = Pcb_9 -> new;
+
+$Pcb -> element_begin(description => 'SMD CAP 100 x 200mils');
+
+$Pcb -> element_add_rectangle(width => 100,
+                              length => 200);
+
+$Pcb -> element_dump;
+$Pcb -> element_output;
+
+
+$Pcb -> element_begin(description => 'SMD CAP 1mm x 2mils');
+
+$Pcb -> element_add_rectangle(width => '1mm',
+                              length => 2);
+
+$Pcb -> element_dump;
+$Pcb -> element_output;
+
+
+##### No-Fee Software License Version 0.2
+
+#### Intent
+
+### The intent of this license is to allow for distribution of this
+### software without fee. Usage of this software other than
+### distribution, is unrestricted.
+
+#### License
+
+### Permission is granted to make and distribute verbatim copies of
+### this software provided that (1) no fee is charged and (2) the
+### copyright notice and license statement are preserved on all copies.
+
+### Permission is granted to make and distribute modified versions of
+### this software provided that the entire resulting derived work is
+### distributed (1) without fee and (2) with a license identical to
+### this one.
+
+### This software is provided by the author "AS IS" and any express or
+### implied warranties, including, but not limited to, the implied
+### warranties of merchantability and fitness for a particular purpose
+### are disclaimed. In no event shall the author be liable for any
+### direct, indirect, incidental, special, exemplary, or consequential
+### damages (including, but not limited to, procurement of substitute
+### goods or services; loss of use, data, or profits; or business
+### interruption) however caused and on any theory of liability,
+### whether in contract, strict liability, or tort (including
+### negligence or otherwise) arising in any way out of the use of this
+### software, even if advised of the possibility of such damage.
+
diff --git a/sch-pcb/fp/VQFN-50P-400W-400L-24N-245WT-245LT__TI_RGE_Package.fp b/sch-pcb/fp/VQFN-50P-400W-400L-24N-245WT-245LT__TI_RGE_Package.fp
new file mode 100644 (file)
index 0000000..2c29fa4
--- /dev/null
@@ -0,0 +1,33 @@
+Element[0x0 "VQFN-TI-RGE-24" "" "" 0 0 -12106 -17106 0 100 0x0]
+(
+   Pad[-8897 -4921 -6653 -4921 1102 2000 3102 "" "1" 0x0100]
+   Pad[-8897 -2952 -6653 -2952 1102 2000 3102 "" "2" 0x0100]
+   Pad[-8897 -984 -6653 -984 1102 2000 3102 "" "3" 0x0100]
+   Pad[-8897 984 -6653 984 1102 2000 3102 "" "4" 0x0100]
+   Pad[-8897 2952 -6653 2952 1102 2000 3102 "" "5" 0x0100]
+   Pad[-8897 4921 -6653 4921 1102 2000 3102 "" "6" 0x0100]
+   Pad[-4921 6653 -4921 8897 1102 2000 3102 "" "7" 0x0100]
+   Pad[-2952 6653 -2952 8897 1102 2000 3102 "" "8" 0x0100]
+   Pad[-984 6653 -984 8897 1102 2000 3102 "" "9" 0x0100]
+   Pad[984 6653 984 8897 1102 2000 3102 "" "10" 0x0100]
+   Pad[2952 6653 2952 8897 1102 2000 3102 "" "11" 0x0100]
+   Pad[4921 6653 4921 8897 1102 2000 3102 "" "12" 0x0100]
+   Pad[6653 4921 8897 4921 1102 2000 3102 "" "13" 0x0100]
+   Pad[6653 2952 8897 2952 1102 2000 3102 "" "14" 0x0100]
+   Pad[6653 984 8897 984 1102 2000 3102 "" "15" 0x0100]
+   Pad[6653 -984 8897 -984 1102 2000 3102 "" "16" 0x0100]
+   Pad[6653 -2952 8897 -2952 1102 2000 3102 "" "17" 0x0100]
+   Pad[6653 -4921 8897 -4921 1102 2000 3102 "" "18" 0x0100]
+   Pad[4921 -8897 4921 -6653 1102 2000 3102 "" "19" 0x0100]
+   Pad[2952 -8897 2952 -6653 1102 2000 3102 "" "20" 0x0100]
+   Pad[984 -8897 984 -6653 1102 2000 3102 "" "21" 0x0100]
+   Pad[-984 -8897 -984 -6653 1102 2000 3102 "" "22" 0x0100]
+   Pad[-2952 -8897 -2952 -6653 1102 2000 3102 "" "23" 0x0100]
+   Pad[-4921 -8897 -4921 -6653 1102 2000 3102 "" "24" 0x0100]
+   Pad[0 0 0 0 9645 2000 11645 "" "25" 0x0100]
+   ElementArc[-9169 -9169 551 551 0 360 1000]
+   ElementLine[-10137 10137 -10137 -10137 1000]
+   ElementLine[-10137 -10137 10137 -10137 1000]
+   ElementLine[10137 -10137 10137 10137 1000]
+   ElementLine[10137 10137 -10137 10137 1000]
+)
diff --git a/sch-pcb/fp/pcb-example-hdr1 b/sch-pcb/fp/pcb-example-hdr1
new file mode 100755 (executable)
index 0000000..b7b9755
--- /dev/null
@@ -0,0 +1,149 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2005 John C. Luciani Jr.
+
+# This program may be distributed or modified under the terms of
+# version 0.2 of the No-Fee Software License published by
+# John C. Luciani Jr.
+
+# Creates the PCB elements for Molex 8624 header connectors
+
+use strict;
+use warnings;
+
+use Pcb_8;
+
+my $Pcb = Pcb_8 -> new(debug => 1); 
+
+my @Fields = qw(circuits body_length pin_row_length);
+
+my @Def; # definitions that are common to all components
+
+while (<DATA>) {
+    s/\#.*//; # Remove comments
+    s/^\s*//; # Remove leading spaces
+    s/\s*$//; # Revove trailing spaces
+    next unless length; # Skip empty lines
+
+    # Lines that contain an '=' are global definitions.
+
+    push(@Def, $1, $2), next if /(\S+)\s*=\s*(\S.*)/;
+
+    my @values = split /\s*\|\s*/;
+
+    # hash for each footprint
+
+    my %f = ( @Def,
+             map { $_ => shift(@values) } @Fields);
+
+    $Pcb -> element_begin(description => 'TH',
+                         output_file => 
+                             "tmp/" . &package_name($f{circuits}, $f{pin_rows}),
+                         dim   => 'mils',
+                         pin_one_square => 1);
+
+    my $pin_num = 1;
+    my $pins_per_row = $f{circuits} / 2;
+
+    # lower left corner is pin one
+
+    my $x = -$f{pin_spacing} * ($pins_per_row - 1) / 2;
+    my $y =  $f{row_spacing} / 2;
+
+    # These header connectors consist of two rows of pins.  With pin
+    # one in the lower left corner we will place pins from left to
+    # right until half the pins are placed. At the halfway point we
+    # will shift to the top row and place pins from right to left.
+
+    while ($pin_num <= $f{circuits}) {
+       $Pcb -> element_add_pin(x => $x, y => $y,
+                               thickness  => 66,
+                               drill_hole => 46,
+                               mask       => 10,
+                               clearance  => 10,
+                               pin_number => $pin_num);
+
+       # If this is the last pin in the row then
+       # update the y value otherwise update the x 
+       # value. If we are past the halfway point move
+       # left (-) instead of right (+).
+
+       $y *= -1;
+       $x += $f{pin_spacing} if $y > 0;
+       $pin_num++;
+    }
+
+    $Pcb -> element_add_rectangle(width => $f{body_width},
+                                 length=> $f{body_length},
+                                 x => 0,
+                                 y => 0);
+
+
+    $Pcb -> element_set_text_xy(x => -$f{body_length}/2,
+                               y => -$f{body_width}/2 - 20);
+
+
+    $Pcb -> element_output();
+}
+
+sub package_name ($$) { 
+    my ($circuits, $rows) = @_;
+    sprintf("CON_HDR-254P-%iC-%iR-%iN__Molex_8624-Series", 
+           $circuits/$rows, 
+           $rows, 
+           $circuits);
+}
+
+__DATA__
+
+body_width = 200
+pin_spacing = 100
+row_spacing = 100
+pin_diameter = 35
+pin_rows = 2
+
+# circuits | body_length | pin_row_length
+
+4  | 190 | 100 
+6  | 290 | 200 
+8  | 390 | 300 
+10 | 490 | 400 
+12 | 590 | 500 
+14 | 690 | 600 
+16 | 790 | 700 
+18 | 890 | 800 
+20 | 990 | 900 
+22 | 1090 | 1000 
+24 | 1190| 1100 
+26 | 1290| 1200 
+28 | 1390| 1300
+
+30 | 1490 | 1400 
+32 | 1590 | 1500 
+34 | 1690 | 1600 
+36 | 1790 | 1700 
+38 | 1890 | 1800 
+40 | 1990 | 1900
+42 | 2090 | 2000
+44 | 2190 | 2100 
+46 | 2290 | 2200
+48 | 2390 | 2300 
+50 | 2490 | 2400 
+52 | 2590 | 2500 
+54 | 2690 | 2600
+
+56 | 2790 | 2700 
+58 | 2890 | 2800 
+60 | 2990 | 2900 
+62 | 3090 | 3000 
+64 | 3190 | 3100 
+66 | 3290 | 3200 
+68 | 3390 | 3300 
+70 | 3490 | 3400 
+72 | 3590 | 3500 
+74 | 3690 | 3600 
+76 | 3790 | 3700 
+78 | 3890 | 3800 
+80 | 3990 | 3900
+
+
diff --git a/sch-pcb/fp/pcb-example-hdr2 b/sch-pcb/fp/pcb-example-hdr2
new file mode 100755 (executable)
index 0000000..4b7ad20
--- /dev/null
@@ -0,0 +1,185 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2005 John C. Luciani Jr.
+
+# This program may be distributed or modified under the terms of
+# version 0.2 of the No-Fee Software License published by
+# John C. Luciani Jr.
+
+# Creates the PCB elements for Molex 8624 header connectors
+
+use strict;
+use warnings;
+
+use Pcb_8;
+
+my $Pcb = Pcb_8 -> new(debug => 0);
+
+my @Fields = qw(circuits body_length pin_row_length);
+
+my @Def; # definitions that are common to all components
+
+while (<DATA>) {
+    s/\#.*//; # Remove comments
+    s/^\s*//; # Remove leading spaces
+    s/\s*$//; # Revove trailing spaces
+    next unless length; # Skip empty lines
+
+    # Lines that contain an '=' are global definitions.
+
+    push(@Def, $1, $2), next if /(\S+)\s*=\s*(\S.*)/;
+
+    my @values = split /\s*\|\s*/;
+
+    # hash for each footprint
+
+    my %f = ( @Def,
+             map { $_ => shift(@values) } @Fields);
+
+    $Pcb -> element_begin(description => 'TH',
+                         output_file => 
+                            "tmp/" . &package_name($f{circuits}, $f{pin_rows}),
+                         dim   => 'mils',
+                         pin_one_square => 1);
+
+    my $pin_num = 1;
+    my $pins_per_row = $f{circuits} / 2;
+
+    # lower left corner is pin one
+
+    my $x0 = -$f{pin_spacing} * ($pins_per_row - 1) / 2;
+    my $y0 =  $f{row_spacing} / 2;
+
+    my $x = $x0;
+    my $y = $y0;
+
+    # These header connectors consist of two rows of pins.  With pin
+    # one in the lower left corner we will place pins from left to
+    # right until half the pins are placed. At the halfway point we
+    # will shift to the top row and place pins from right to left.
+
+    while ($pin_num <= $f{circuits}) {
+       $Pcb -> element_add_pin(x => $x, y => $y,
+                               thickness  => $f{pad_thickness},
+                               drill_hole => $f{drill_hole},
+                               mask       => 10,
+                               clearance  => 10,
+                               pin_number => $pin_num);
+
+       # Header connectors usually have pins numbered from left to
+       # right with odd numbers on the bottom and even numbers on the
+       # top. Since this example program could be used for connectors
+       # other than headers three pin-numbering options are provided.
+
+       # header - two rows of pins. numbers increase from left to right.
+       #          odd numbered pins on the bottom, even on the top.
+
+        # dip    - two rows of pins. starting in the lower left corner
+        #          numbers increase left to right along the bottom row
+       #          and right to left along the top row.
+
+       # power  - two rows of pins. numbers increase from left to right
+        #          starting on the bottom row and then continue left to right
+        #          along the top row.
+
+       if ($f{pin_numbering_scheme} eq 'header') {
+           $y *= -1;
+           $x += $f{pin_spacing} if $y > 0;
+       } elsif ($f{pin_numbering_scheme} eq 'dip') {
+           if ($pin_num == $pins_per_row) {
+               $y -= $f{row_spacing};
+           } else {
+               $x += $pin_num > $pins_per_row 
+                   ? -$f{pin_spacing}
+                   : $f{pin_spacing};
+           }
+       } elsif ($f{pin_numbering_scheme} eq 'power') {
+           if ($pin_num == $pins_per_row) {
+               $y -= $f{row_spacing};
+               $x = $x0;
+           } else {
+               $x += $f{pin_spacing}
+           }
+       } else {
+           die "unknown pin numbering scheme |$f{pin_numbering_scheme}|";
+       }
+       $pin_num++;
+    }
+
+    $Pcb -> element_add_rectangle(width => $f{body_width},
+                                 length=> $f{body_length},
+                                 x => 0,
+                                 y => 0);
+
+
+    $Pcb -> element_set_text_xy(x => -$f{body_length}/2,
+                               y => -$f{body_width}/2 - 20);
+
+
+    $Pcb -> element_output();
+}
+
+sub package_name ($$) { 
+    my ($circuits, $rows) = @_;
+    sprintf("CON_HDR-254P-%iC-%iR-%iN__Molex_8624-Series", 
+           $circuits/$rows, 
+           $rows, 
+           $circuits);
+}
+
+__DATA__
+
+pad_thickness = 66
+drill_hole = 46
+pin_numbering_scheme = header
+body_width = 200
+pin_spacing = 100
+row_spacing = 100
+pin_diameter = 35
+pin_rows = 2
+
+# circuits | body_length | pin_row_length
+
+4  | 190 | 100 
+6  | 290 | 200 
+8  | 390 | 300 
+10 | 490 | 400 
+12 | 590 | 500 
+14 | 690 | 600 
+16 | 790 | 700 
+18 | 890 | 800 
+20 | 990 | 900 
+22 | 1090 | 1000 
+24 | 1190| 1100 
+26 | 1290| 1200 
+28 | 1390| 1300
+
+30 | 1490 | 1400 
+32 | 1590 | 1500 
+34 | 1690 | 1600 
+36 | 1790 | 1700 
+38 | 1890 | 1800 
+40 | 1990 | 1900
+42 | 2090 | 2000
+44 | 2190 | 2100 
+46 | 2290 | 2200
+48 | 2390 | 2300 
+50 | 2490 | 2400 
+52 | 2590 | 2500 
+54 | 2690 | 2600
+
+56 | 2790 | 2700 
+58 | 2890 | 2800 
+60 | 2990 | 2900 
+62 | 3090 | 3000 
+64 | 3190 | 3100 
+66 | 3290 | 3200 
+68 | 3390 | 3300 
+70 | 3490 | 3400 
+72 | 3590 | 3500 
+74 | 3690 | 3600 
+76 | 3790 | 3700 
+78 | 3890 | 3800 
+80 | 3990 | 3900
+
+
diff --git a/sch-pcb/fp/pcb-example-res b/sch-pcb/fp/pcb-example-res
new file mode 100755 (executable)
index 0000000..88f5faf
--- /dev/null
@@ -0,0 +1,60 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2005 John C. Luciani Jr.
+
+# This program may be distributed or modified under the terms of
+# version 0.2 of the No-Fee Software License published by
+# John C. Luciani Jr.
+
+# Creates a 1/4 Watt resistor
+
+use strict;
+use warnings;
+
+use Pcb_8;
+
+my $Pcb = Pcb_8 -> new(debug => 1);
+
+$Pcb -> element_begin(description => 'resistor',
+                     output_file => '025W',
+                     dim   => 'mils');
+
+# the resistor centroid is at (0,0) and the pins are placed 400 mils
+# apart
+
+my $Body_width = 70;          # y direction
+my $Body_length = 240;        # x direction
+my @Pins = (-200, 0, 200, 0); # x,y pin centers
+my $Pin_num = 1;
+
+while (@Pins) {
+    my ($x, $y) = splice @Pins, 0, 2;
+    $Pcb -> element_add_pin(x => $x, y => $y,
+                           thickness  => 55,
+                           drill_hole => 35,
+                           mask => 10,
+                           clearance => 10,
+                           pin_number => $Pin_num++);
+}
+
+$Pcb -> element_add_rectangle(width => $Body_width,
+                             length=> $Body_length,
+                             thickness => 10,
+                             x => 0,
+                             y => 0);
+
+foreach my $sign (-1, 1) {
+    $Pcb -> element_add_line(x1 => $sign * $Body_length / 2,
+                            y1 => 0,
+                            x2 => $sign * ($Body_length / 2 + 30),
+                            y2 => 0,
+                            thickness => 10);
+}
+
+
+$Pcb -> element_set_text_xy(x => -$Body_length/2,
+                           y => -$Body_width/2 - 20);
+
+
+$Pcb -> element_output();
+
diff --git a/sch-pcb/fp/pcb-example-smd b/sch-pcb/fp/pcb-example-smd
new file mode 100755 (executable)
index 0000000..ff3da13
--- /dev/null
@@ -0,0 +1,100 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2005 John C. Luciani Jr.
+
+# This program may be distributed or modified under the terms of
+# version 0.2 of the No-Fee Software License published by
+# John C. Luciani Jr.
+
+# Creates the PCB elements specified in the DATA section.  The
+# footprints are for the SMD packages 0402, 0603, 0805, 1206, 1210,
+# 2010, 2512, 0402, 0504, 0603, 0805, 1206, 1210, 1812, 1825
+
+use strict;
+use warnings;
+
+use Pcb_9;
+
+my $Pcb = Pcb_9 -> new(debug => 1);
+
+my @Fields = qw(land_pattern_length  land_row_distance 
+               land_width           land_length 
+               land_row_centers     grid);
+
+while (<DATA>) {
+    s/\#.*//; # Remove comments
+    s/^\s*//; # Remove leading spaces
+    s/\s*$//; # Revove trailing spaces
+    next unless length; # Skip empty lines
+    my ($type, @values) = split /\s*\|\s*/;
+
+    # hash for each footprint
+
+    my %f = map { $_ => shift(@values) } @Fields;
+
+    $Pcb -> element_begin(description => 'SMD',
+                         output_file => "tmp/$type",
+                         dim   => 'mm');
+
+    my $x = -$f{land_row_centers} / 2;
+    foreach my $pin_num (1..2) {
+       $Pcb -> element_add_pad_rectangle(width => $f{land_width},
+                                         length=> $f{land_length},
+                                         x => $x,
+                                         y => 0,
+                                         name => 'input',
+                                         mask => 0.254,
+                                         clearance => 0.254,
+                                         pin_number => $pin_num);
+       $x += $f{land_row_centers};
+    }
+
+    # Draw a silkscreen rectangle around the component.  A silkscreen
+    # specification that all PCB vendors should be able to meet is
+    # 10mil line width and 10mil spacing. The silkscreen line width
+    # defaults to 10mils. To achieve the proper spacing we add 
+    # 30mils (0.762mm) to the maximum extents of the copper pads 
+    # (10mils on either side of the copper and 2*5 mils for the 
+    # silkscreen line).
+
+    my $length = $f{land_pattern_length} + 0.762;
+    my $width  = $f{land_width} + 0.762;
+
+    $Pcb -> element_add_rectangle(width => $width,
+                                 length=> $length,
+                                 x => 0,
+                                 y => 0);
+
+    # Place the refdes slightly (0.5mm) above the upper left corner of
+    # the outline rectangle.
+
+    $Pcb -> element_set_text_xy(x => -$length/2,
+                               y => -$width/2 - 0.5);
+
+    $Pcb -> element_output();
+
+}
+
+
+__DATA__
+
+# type   package name
+#  Z     overall length of land pattern
+#  G     distance between land rows 
+#  X     land width 
+#  Y     land length
+#  C     center-to-center spacing between land rows
+#  Grid  number of 0.5mm by 0.5mm elements 
+
+# type     Z        G       X         Y        C     Grid
+
+ 0402 |   2.20 |   0.40 |   0.70 |   0.90 |   1.30 | 2x6
+ 0504 |   2.40 |   0.40 |   1.30 |   1.00 |   1.40 | 4x6
+ 0603 |   2.80 |   0.60 |   1.00 |   1.10 |   1.70 | 4x6
+ 0805 |   3.20 |   0.60 |   1.50 |   1.30 |   1.90 | 4x8
+ 1206 |   4.40 |   1.20 |   1.80 |   1.60 |   2.80 | 4x10
+ 1210 |   4.40 |   1.20 |   2.70 |   1.60 |   2.80 | 6x10
+ 1812 |   5.80 |   2.00 |   3.40 |   1.90 |   3.90 | 8x12
+ 1825 |   5.80 |   2.00 |   6.80 |   1.90 |   3.90 | 14x12
+ 2010 |   6.20 |   2.60 |   2.70 |   1.80 |   4.40 | 6x14
+ 2512 |   7.40 |   3.80 |   3.20 |   1.80 |   5.60 | 8x16
diff --git a/sch-pcb/fp/pcb-example-tqfn b/sch-pcb/fp/pcb-example-tqfn
new file mode 100755 (executable)
index 0000000..33fd9b2
--- /dev/null
@@ -0,0 +1,260 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2007 John C. Luciani Jr.
+
+# This program may be distributed or modified under the terms of
+# version 0.2 of the No-Fee Software License published by
+# John C. Luciani Jr.
+
+# Creates Maxim TQFN style packages.  
+
+# Data is from the Maxim 21-0140 Rev G and Maxim 21-10159 Rev A
+# specifications.
+
+# The TQFN (thin quad flat no-lead) packages have solder terminations
+# on four sides and a thermal pad in the center. The two denser
+# packages (T3255-2 and T4055-1) require smaller pads on the corner
+# terminations.
+
+use strict;
+use warnings;
+use Carp;
+
+use Pcb_9; # routines to create PCB elements (packages)
+
+my $Pcb = Pcb_9 -> new(debug => 0);
+
+# The specifications to generate these symbols is in the __DATA__
+# section of this file. Each line can be either blank, contain a global
+# definition or contain a package data record.
+
+# Global definitions are saved in @Def.
+# The field names for the package data record are in @Fields.
+
+my @Def; # Global definitions saved as key-value pairs.
+my @Fields = qw(package_code
+                pin_count     
+                pad_spacing   
+                pad_width     
+                pad_length    
+                corner_pad_length
+                thermal_pad_width
+                thermal_pad_length);
+
+# Read the __DATA__ section and output a PCB footprint everytime a
+# package data record is read. 
+
+while (<DATA>) {
+    last if /^__END__$/; 
+    s/\#.*//; # Remove comments
+    s/^\s*//; # Remove leading spaces
+    s/\s*$//; # Revove trailing spaces
+    next unless length; # Skip empty lines
+
+    # Lines that contain an '=' are global definitions.  The key (lhs)
+    # and value (rhs) are pushed onto @Def. 
+
+    push(@Def, $1, $2), next if /(\S+)\s*=\s*(\S.*)/;
+
+    # A line with non-zero length that is not a global definition is a
+    # package data record. We split the package record and create a
+    # hash %p that contains key-value pairs for all of the global
+    # definitions and the current record.
+
+    my @values = split /\s*\|\s*/; 
+    my %p = ( @Def,
+              map { $_ => shift(@values) } @Fields);
+
+    # Create a simple id using the package name, package code and pin
+    # count and then start a new element.
+
+    $p{id} = join('-', map { $p{$_} } qw(package_name package_code pin_count));
+    $Pcb -> element_begin(description => $p{id},
+                          output_file => "tmp/$p{id}",
+                          dim   => 'mm');
+    print "$p{id}\n";
+
+    # Create a few convenient specifications from data in the package
+    # data record hash. The convenetions for these packages is part
+    # centroid at (0,0) and pin one is in the lower left corner.
+
+    # Corner pads on some of the parts are shorter. This condition is
+    # handled by creating a new pad length and some pad center
+    # offsets.
+
+    $p{num_pads_per_side} = $p{pin_count} / 4; # leads on four sides
+    $p{corner_pad_length}  = $p{pad_length} if $p{corner_pad_length} eq '';
+
+    my $row_center = ($p{body_width_max} - $p{pad_length}) / 2;
+    my $row_end    = ($p{num_pads_per_side} - 1) * $p{pad_spacing} / 2;
+    my $corner_offset = ($p{pad_length} - $p{corner_pad_length}) / 2;
+
+    # @xy contains the staring locations for a row of pads.
+    # @inc contains increment values for x and y and offsets for the
+    # the corner pads. for each row of pads either x or y is incremented.
+
+    my @xy = (x => -$row_center, y => -$row_end,    
+              x => -$row_end,    y =>  $row_center, 
+              x =>  $row_center, y =>  $row_end,    
+              x =>  $row_end,    y => -$row_center);
+
+    my @inc= (yinc =>  $p{pad_spacing}, xoffset => -$corner_offset,
+              xinc =>  $p{pad_spacing}, yoffset =>  $corner_offset,
+              yinc => -$p{pad_spacing}, xoffset =>  $corner_offset,
+              xinc => -$p{pad_spacing}, yoffset => -$corner_offset);
+
+    # create the rows of pads
+    
+    &set_pin_num(1);
+
+    while (@xy) {
+        my %xy = (splice(@inc, 0, 4),
+                  map { $_ => $p{$_} } qw(pad_spacing pad_width pad_length));
+
+        &draw_row_of_pads(splice(@xy, 0, 4),
+                          %xy,
+                          pad_length => $p{corner_pad_length},
+                          num_pads => 1);
+
+        # no offsets for pads that aren't on the corners
+
+        &draw_row_of_pads(%xy,
+                          xoffset => 0,
+                          yoffset => 0,
+                          num_pads => $p{num_pads_per_side} - 2);
+
+        &draw_row_of_pads(%xy,
+                          pad_length => $p{corner_pad_length},
+                          num_pads => 1);
+    }
+
+    # Add the thermal pad
+
+    $Pcb -> element_add_pad_rectangle(x => 0,
+                                      y => 0,
+                                      length => $p{thermal_pad_length}, 
+                                      width  => $p{thermal_pad_width},
+                                      name => '',
+                                      pin_number => $p{pin_count} + 1);
+
+    # add the pin one dot
+
+    my $dot_pos = $row_center + 0.254; #$p{pad_length} / 2;
+
+    $Pcb -> element_add_arc(x => -$dot_pos,
+                            y => -$dot_pos,
+                            width => $p{pad_width} / 2,
+                            height=> $p{pad_width} / 2,
+                            start_angle => 0,
+                            delta_angle => 360,
+                            thickness => 0.254); # 10 mil lines
+
+    # draw a silksreen rectangle around the package body.
+
+    $Pcb -> element_add_rectangle(x => 0,
+                                  y => 0,
+                                  width => $p{body_width_max} + 1,
+                                  length=> $p{body_length_max} + 1);
+
+    # Set the position of the reference designator to the upper left corner
+
+    $Pcb -> element_set_text_xy(x => -$p{body_length_max} / 2 - 1, 
+                                y => -$p{body_width_max}  / 2 - 1);
+
+    # Set the centroid mark and output the element
+
+    $Pcb -> element_output;
+
+}
+
+# $v{x}       current x location
+# $v{y}       current y location
+# $v{pin_num} current pin number
+
+my %v;   # values for draw_row_of_pads
+
+sub set_pin_num ($) { 
+    $v{pin_num} = shift;
+} 
+
+sub draw_row_of_pads { 
+    my %p = (xoffset => 0,
+             yoffset => 0,
+             @_);
+
+    foreach (qw(pin_num x y)) {
+        $v{$_} = $p{$_} if defined $p{$_};
+    }
+
+    # swap pad length and width for horizontal rows
+
+    ($p{pad_width}, $p{pad_length}) = ($p{pad_length}, $p{pad_width})
+        if defined $p{xinc};
+
+    foreach (1..$p{num_pads}) {
+        $Pcb -> element_add_pad_rectangle(x      => $v{x} + $p{xoffset},
+                                          y      => $v{y} + $p{yoffset},
+                                          width  => $p{pad_width},
+                                          length => $p{pad_length},
+                                          name   => '', 
+                                          pin_number => $v{pin_num}++);
+        $v{x} += $p{xinc} if defined $p{xinc};
+        $v{y} += $p{yinc} if defined $p{yinc};
+    }
+}
+
+
+
+
+1;
+
+
+
+__DATA__
+body_width_min  = 4.9  # E
+body_width      = 5.0  # E
+body_width_max  = 5.1  # E
+body_length_min = 4.9  # D
+body_length     = 5.0  # D
+body_length_max = 5.1  # D
+
+component_type     = ic
+package_name       = TQFN-Maxim-5x5
+
+# Final pad_length = pad_lenth + body_width_max - body_width_min
+
+# T1655-1   e (nom)  b, L, E2, D2 (max)
+# T2055-2   e (nom)  b (max) L, E2, D2 (nom)
+# T2055-5   e (nom)  b (max) L (min) E2, D2 (nom)
+
+# T2855-1   e (nom)  b (max) L (min) E2, D2 (nom)
+# T2855-2   e (nom)  b (max) L (min) E2, D2 (max)
+
+# T3255-2   e (nom)  b (max) L (max) E2, D2 (max)
+# T4055-1   e (nom)  b (min) L (nom) E2, D2 (min)
+
+
+#                 e      b      L     L1      E2     D2
+ T1655-1  | 16 | 0.8  | 0.35 | 0.5  |      | 3.2  | 3.2 
+ T2055-2  | 20 | 0.65 | 0.35 | 0.55 |      | 3.10 | 3.10
+ T2055-5  | 20 | 0.65 | 0.35 | 0.45 |      | 3.25 | 3.25
+
+ T2855-1  | 28 | 0.50 | 0.30 | 0.45 |      | 3.25 | 3.25
+ T2855-2  | 28 | 0.50 | 0.30 | 0.45 |      | 2.8  | 2.8 
+
+
+ T3255-2  | 32 | 0.50 | 0.30 | 0.5  | 0.25 | 3.2  | 3.2 
+ T4055-1  | 40 | 0.40 | 0.2  | 0.5  | 0.25 | 3.2  | 3.2 
+
+# Style (adapted from the Perl Cookbook, First Edition, Recipe 12.4)
+
+# 1. Names of functions and local variables are all lowercase.
+# 2. The program's persistent variables (either file lexicals
+#    or package globals) are capitalized.
+# 3. Identifiers with multiple words have each of these
+#    separated by an underscore to make it easier to read.
+# 4. Constants are all uppercase.
+# 5. If the arrow operator (->) is followed by either a
+#    method name or a variable containing a method name then
+#    there is a space before and after the operator.
+
diff --git a/sch-pcb/fp/ti_rge.pl b/sch-pcb/fp/ti_rge.pl
new file mode 100755 (executable)
index 0000000..321d4db
--- /dev/null
@@ -0,0 +1,262 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2007 John C. Luciani Jr.
+
+# This program may be distributed or modified under the terms of
+# version 0.2 of the No-Fee Software License published by
+# John C. Luciani Jr.
+
+# Creates Maxim TQFN style packages.  
+
+# Data is from the Maxim 21-0140 Rev G and Maxim 21-10159 Rev A
+# specifications.
+
+# The TQFN (thin quad flat no-lead) packages have solder terminations
+# on four sides and a thermal pad in the center. The two denser
+# packages (T3255-2 and T4055-1) require smaller pads on the corner
+# terminations.
+
+use strict;
+use warnings;
+use Carp;
+
+use Pcb_9; # routines to create PCB elements (packages)
+
+my $Pcb = Pcb_9 -> new(debug => 0);
+
+# The specifications to generate these symbols is in the __DATA__
+# section of this file. Each line can be either blank, contain a global
+# definition or contain a package data record.
+
+# Global definitions are saved in @Def.
+# The field names for the package data record are in @Fields.
+
+my @Def; # Global definitions saved as key-value pairs.
+my @Fields = qw(package_code
+                pin_count     
+                pad_spacing   
+                pad_width     
+                pad_length    
+                corner_pad_length
+                thermal_pad_width
+                thermal_pad_length);
+
+# Read the __DATA__ section and output a PCB footprint everytime a
+# package data record is read. 
+
+while (<DATA>) {
+    last if /^__END__$/; 
+    s/\#.*//; # Remove comments
+    s/^\s*//; # Remove leading spaces
+    s/\s*$//; # Revove trailing spaces
+    next unless length; # Skip empty lines
+
+    # Lines that contain an '=' are global definitions.  The key (lhs)
+    # and value (rhs) are pushed onto @Def. 
+
+    push(@Def, $1, $2), next if /(\S+)\s*=\s*(\S.*)/;
+
+    # A line with non-zero length that is not a global definition is a
+    # package data record. We split the package record and create a
+    # hash %p that contains key-value pairs for all of the global
+    # definitions and the current record.
+
+    my @values = split /\s*\|\s*/; 
+    my %p = ( @Def,
+              map { $_ => shift(@values) } @Fields);
+
+    # Create a simple id using the package name, package code and pin
+    # count and then start a new element.
+
+    $p{id} = join('-', map { $p{$_} } qw(package_name package_code pin_count));
+    $Pcb -> element_begin(description => $p{id},
+                          output_file => "tmp/$p{id}",
+                          dim   => 'mm');
+    print "$p{id}\n";
+
+    # Create a few convenient specifications from data in the package
+    # data record hash. The convenetions for these packages is part
+    # centroid at (0,0) and pin one is in the lower left corner.
+
+    # Corner pads on some of the parts are shorter. This condition is
+    # handled by creating a new pad length and some pad center
+    # offsets.
+
+    $p{num_pads_per_side} = $p{pin_count} / 4; # leads on four sides
+    $p{corner_pad_length}  = $p{pad_length} if $p{corner_pad_length} eq '';
+
+    #my $row_center = ($p{body_width_max} - $p{pad_length}) / 2;
+    my $row_center = ($p{pad_inner_width} + $p{pad_length}) / 2;
+    my $row_end    = ($p{num_pads_per_side} - 1) * $p{pad_spacing} / 2;
+    my $corner_offset = ($p{pad_length} - $p{corner_pad_length}) / 2;
+
+    # @xy contains the staring locations for a row of pads.
+    # @inc contains increment values for x and y and offsets for the
+    # the corner pads. for each row of pads either x or y is incremented.
+
+    my @xy = (x => -$row_center, y => -$row_end,    
+              x => -$row_end,    y =>  $row_center, 
+              x =>  $row_center, y =>  $row_end,    
+              x =>  $row_end,    y => -$row_center);
+
+    my @inc= (yinc =>  $p{pad_spacing}, xoffset => -$corner_offset,
+              xinc =>  $p{pad_spacing}, yoffset =>  $corner_offset,
+              yinc => -$p{pad_spacing}, xoffset =>  $corner_offset,
+              xinc => -$p{pad_spacing}, yoffset => -$corner_offset);
+
+    # create the rows of pads
+    
+    &set_pin_num(1);
+
+    while (@xy) {
+        my %xy = (splice(@inc, 0, 4),
+                  map { $_ => $p{$_} } qw(pad_spacing pad_width pad_length));
+
+        &draw_row_of_pads(splice(@xy, 0, 4),
+                          %xy,
+                          pad_length => $p{corner_pad_length},
+                          num_pads => 1);
+
+        # no offsets for pads that aren't on the corners
+
+        &draw_row_of_pads(%xy,
+                          xoffset => 0,
+                          yoffset => 0,
+                          num_pads => $p{num_pads_per_side} - 2);
+
+        &draw_row_of_pads(%xy,
+                          pad_length => $p{corner_pad_length},
+                          num_pads => 1);
+    }
+
+    # Add the thermal pad
+
+    $Pcb -> element_add_pad_rectangle(x => 0,
+                                      y => 0,
+                                      length => $p{thermal_pad_length}, 
+                                      width  => $p{thermal_pad_width},
+                                      name => '',
+                                      pin_number => $p{pin_count} + 1);
+
+    # add the pin one dot
+
+    #my $dot_pos = $row_center + 0.254; #$p{pad_length} / 2;
+    my $dot_pos = $p{body_width_max}/2 + 0.254; #$p{pad_length} / 2;
+
+    $Pcb -> element_add_arc(x => -$dot_pos,
+                            y => -$dot_pos,
+                            width => $p{pad_width} / 2,
+                            height=> $p{pad_width} / 2,
+                            start_angle => 0,
+                            delta_angle => 360,
+                            thickness => 0.254); # 10 mil lines
+
+    # draw a silksreen rectangle around the package body.
+
+    $Pcb -> element_add_rectangle(x => 0,
+                                  y => 0,
+                                  width => $p{body_width_max} + 1,
+                                  length=> $p{body_length_max} + 1);
+
+    # Set the position of the reference designator to the upper left corner
+
+    $Pcb -> element_set_text_xy(x => -$p{body_length_max} / 2 - 1, 
+                                y => -$p{body_width_max}  / 2 - 1);
+
+    # Set the centroid mark and output the element
+
+    $Pcb -> element_output;
+
+}
+
+# $v{x}       current x location
+# $v{y}       current y location
+# $v{pin_num} current pin number
+
+my %v;   # values for draw_row_of_pads
+
+sub set_pin_num ($) { 
+    $v{pin_num} = shift;
+} 
+
+sub draw_row_of_pads { 
+    my %p = (xoffset => 0,
+             yoffset => 0,
+             @_);
+
+    foreach (qw(pin_num x y)) {
+        $v{$_} = $p{$_} if defined $p{$_};
+    }
+
+    # swap pad length and width for horizontal rows
+
+    ($p{pad_width}, $p{pad_length}) = ($p{pad_length}, $p{pad_width})
+        if defined $p{xinc};
+
+    foreach (1..$p{num_pads}) {
+        $Pcb -> element_add_pad_rectangle(x      => $v{x} + $p{xoffset},
+                                          y      => $v{y} + $p{yoffset},
+                                          width  => $p{pad_width},
+                                          length => $p{pad_length},
+                                          name   => '', 
+                                          pin_number => $v{pin_num}++);
+        $v{x} += $p{xinc} if defined $p{xinc};
+        $v{y} += $p{yinc} if defined $p{yinc};
+    }
+}
+
+
+
+
+1;
+
+
+
+__DATA__
+body_width_min  = 3.85 # E
+body_width      = 4.0  # E
+body_width_max  = 4.15 # E
+body_length_min = 3.85 # D
+body_length     = 4.0  # D
+body_length_max = 4.15 # D
+
+pad_inner_width = 3.1
+
+component_type     = ic
+package_name       = VQFN-TI
+
+# Final pad_length = pad_lenth + body_width_max - body_width_min
+
+# T1655-1   e (nom)  b, L, E2, D2 (max)
+# T2055-2   e (nom)  b (max) L, E2, D2 (nom)
+# T2055-5   e (nom)  b (max) L (min) E2, D2 (nom)
+
+# T2855-1   e (nom)  b (max) L (min) E2, D2 (nom)
+# T2855-2   e (nom)  b (max) L (min) E2, D2 (max)
+
+# T3255-2   e (nom)  b (max) L (max) E2, D2 (max)
+# T4055-1   e (nom)  b (min) L (nom) E2, D2 (min)
+
+
+#                 e      b      L     L1      E2     D2
+ RGE      | 24 | 0.50 | 0.28 | 0.85 |      | 2.45 | 2.45
+
+#T2855-1  | 28 | 0.50 | 0.30 | 0.45 |      | 3.25 | 3.25
+#T2855-2  | 28 | 0.50 | 0.30 | 0.45 |      | 2.8  | 2.8 
+
+
+#T3255-2  | 32 | 0.50 | 0.30 | 0.5  | 0.25 | 3.2  | 3.2 
+#T4055-1  | 40 | 0.40 | 0.2  | 0.5  | 0.25 | 3.2  | 3.2 
+
+# Style (adapted from the Perl Cookbook, First Edition, Recipe 12.4)
+
+# 1. Names of functions and local variables are all lowercase.
+# 2. The program's persistent variables (either file lexicals
+#    or package globals) are capitalized.
+# 3. Identifiers with multiple words have each of these
+#    separated by an underscore to make it easier to read.
+# 4. Constants are all uppercase.
+# 5. If the arrow operator (->) is followed by either a
+#    method name or a variable containing a method name then
+#    there is a space before and after the operator.
+