PCB Footprint Scripting Library
I have written a Guile Scheme library to help create gschem footprints using Guile as a scripting language. It depends on the
general Guile Scheme library I have written.
You can
browse the sources here, specifically the files that start with the word
pads
.
You can download the source code from the
table of attachments below.
At the moment it remains undocumented.
Table of Contents
Installation
To install the Guile modules:
- Download the source code from the table of attachments below.
- Untar the distribution file; e.g.:
-
tar -xzf octw-guile-geda-modules-1.0.tar.gz
- Edit the Makefile:
- Change the
INSTALL_DIR
to point to the directory in which you would like to install the modules.
- Run
make
to install the modules.
Example Uses
Just to give you a flavor of what the library does I'll give a few examples.
Snippet From the QFP Script
Here is a snippet from the Guile script I use to generate "Quad Flat Package" footprints:
;; Extract parameter values.
(let-nth ((description (nth parameters))
(lead-count (string->number (nth parameters)))
(lead-width (evaled-string->cmil options (nth parameters)))
(lead-length (evaled-string->cmil options (nth parameters)))
(lead-offset (evaled-string->cmil options (nth parameters)))
(component-width (evaled-string->cmil options (nth parameters)))
(body-width (evaled-string->cmil options (nth parameters))))
;; Calculate derived values. Assumes each side has the same number
;; of leads.
(let ((x-offset (- (/ component-width 2) (/ lead-length 2)))
(side-lead-count (/ lead-count 4)))
;; Build the pads and the silk outline.
(let ((pads (compose-chain (r)
;; Create one pad the dimensions of the lead, centered
;; on the origin and aligned along the x-axis.
(make-pad-x lead-length lead-width
#:mask-extent *mask-extent*
#:clearance-extent *clearance-extent*)
;; Grow its length and width for soldering.
(grow r extra-length extra-width)
;; Move the pad to the left side of the component.
(move-along-x r (- x-offset))
;; Generate the entire left row using the lead
;; offset for spacing in the y direction, and using
;; the original pad as the template for the new row
;; pads.
(row r side-lead-count 0 lead-offset)
;; Use the entire left row and rotated versions of
;; it to create the three remaining rows.
(combine r
(rotate r 90)
(rotate r 180)
(rotate r 270))
;; Number the pads.
(enumerate* r 1)))
(silk (make-notched-outline-ul body-width
body-width
notch-length
*silk-thickness*)))
;; Create the footprint by combining the pads and the silk.
(let ((elem (make <element>
#:description description
#:name "U?"
#:contents (combine pads silk))))
;; Output the footprint.
(output elem #t)))))
Building on Primitives
Here's an example of how you can build on the more primitive library functions and macros to generate higher level footprint components. These two functions generate a silk symbol for a slotted screw and a Phillips screw:
(define (slotted-screw diameter angle thickness)
;; Create a circle of the given diameter and a slot.
(let ((circle (make-element-circle (/ diameter 2) thickness))
(slot (make-element-line diameter thickness
(angle->unit-vector angle))))
;; Combine the circle and the slot.
(combine circle slot)))
(define (phillips-screw diameter angle thickness)
;; Create a circle of the given diameter and a single line of the
;; cross.
(let ((circle (make-element-circle (/ diameter 2) thickness))
(partial-cross (make-element-line (* 0.7 diameter) thickness
(angle->unit-vector angle))))
;; Complete the cross by combining the partial cross and the
;; partial cross rotated through 90 degrees to complete the cross.
(let ((cross (combine partial-cross (rotate partial-cross 90))))
;; Combine the circle and the cross.
(combine circle cross)))
Further, these can be written a tad more succinctly like so:
(define (slotted-screw diameter angle thickness)
(combine (make-element-circle (/ diameter 2) thickness)
(make-element-line diameter thickness
(angle->unit-vector angle))))
(define (phillips-screw diameter angle thickness)
(compose-chain (c)
(make-element-line (* 0.7 diameter) thickness
(angle->unit-vector angle))
(combine c (rotate c 90)
(make-element-circle (/ diameter 2) thickness))))
Complete Radial Capacitors Script
The following is a complete example script I use to generate arbitrary footprints for radial capacitors, both polarized and unpolarized. First the main script itself:
#! /usr/bin/guile \
--debug -e main -s
!#
;;;
;;; radial-caps
;;;
;;; Copyright 2007 Dean Ferreyra, All rights reserved
;;;
;;; $Id: GEDAFootprintScriptLibrary.txt,v 1.11 2008/09/12 20:09:41 DeanFerreyra Exp $
;;; Dean Ferreyra
;;;
;;; Radial capacitors
;;;
(use-syntax (ice-9 syncase))
(use-modules (oop goops))
(use-modules (ice-9 getopt-long))
(use-modules (octw conditional)
(octw anaphoric)
(octw helper)
(octw pads)
(octw pads-scripting))
;;; Load some default constants
(load "defaults.scm")
(define (usage)
(format #t "usage: radial-caps.pads [options] <name> <description>~%")
(format #t " <pin-pitch>~%")
(format #t " <pin-diameter>~%")
(format #t " <cap-diameter>~%")
(format #t " -m, --mm distances in millimeters~%")
(format #t " -i, --in distances in inches~%")
(format #t " -c, --cmil distances in centimils~%")
(format #t " -d, --drill=PERCENT drill hole growth as a percentage of~%")
(format #t " pin diameter (defaults to ~A%)~%"
(* 100 *drill-growth-percentage*))
(format #t " -a, --copper=PERCENT copper annulus as a percentage of~%")
(format #t " drill hole diameter (defaults to ~A%)~%"
(* 100 *copper-growth-percentage*))
(format #t " -p, --polar=NUMBER polarized capacitor with square pin for pin NUMBER ~%")
(format #t " -h, --help this usage message~%")
(exit 1))
(define option-spec
`(,@(distance-units-option-spec)
(drill (single-char #\d) (value #t))
(copper (single-char #\a) (value #t))
(polar (single-char #\p) (value #t))
(help (single-char #\h))))
(define (main args)
(let* ((options (getopt-long (command-line) option-spec))
(parameters (option-ref options '() '())))
(when (option-ref options 'help #f)
(usage))
(unless (= (length parameters) 5)
(usage))
(defaults-set-evaled-options! options)
(let-nth ((name (nth parameters))
(description (nth parameters))
(pin-pitch (evaled-string->cmil options (nth parameters)))
(pin-diameter (evaled-string->cmil options (nth parameters)))
(cap-diameter (evaled-string->cmil options (nth parameters))))
(unless (and (number? pin-pitch)
(number? pin-diameter)
(number? cap-diameter))
(usage))
(let* ((drill (* pin-diameter (+ 1 *drill-growth-percentage*)))
(copper (copper-diameter drill)))
(let ((polar-pin (aand (option-ref options 'polar #f)
(string->number it))))
(let ((pins (compose-chain (p)
(make <pin>
#:thickness copper
#:clearance-extent *clearance-extent*
#:mask-extent *mask-extent*
#:drill drill)
(row p 2 pin-pitch 0)
(enumerate* p 1)
(or (and polar-pin
(shape-square p (- polar-pin 1)))
p)))
(silk (combine
(make-element-circle (/ cap-diameter 2)
*silk-thickness*))))
(let ((elem (make <element>
#:description description
#:name name
#:contents (combine pins silk))))
(output elem #t))))))))
and here is the
defaults.scm
file that provides some default values and specific helper functions that all my scripts load:
;;;
;;; defaults
;;;
;;; Copyright 2007 Dean Ferreyra, All rights reserved
;;;
;;; $Id: GEDAFootprintScriptLibrary.txt,v 1.11 2008/09/12 20:09:41 DeanFerreyra Exp $
;;; Dean Ferreyra
;;;
;;; Default values for common constants modifiable within other pads files.
;;;
;;; All distances in centimils
(define *mask-extent* 1200)
(define *clearance-extent* 1500)
(define *silk-thickness* 1000)
(define *drill-growth-percentage* (percent 15))
(define *copper-growth-percentage* (percent 100))
(define *copper-annulus-min* (mils->centimils 12))
(define (defaults-set-evaled-options! options)
(set-evaled-option! *drill-growth-percentage* options 'drill
percent)
(set-evaled-option! *copper-growth-percentage* options 'copper
percent))
(define (copper-diameter drill)
(let ((copper (* drill (+ 1 *copper-growth-percentage*)))
(min-copper (+ (* 2 *copper-annulus-min*) drill)))
(max copper min-copper)))
Here is an example using the script from the bash command line, though typically the scripts are run from Make:
$ ./radial-caps.pads --mm 'C?' --polar "CAPACITOR" 1 4.7 0.5 10 > CAP-10.0-4.7-P.fp
Here is the resulting footprint:
Element["" "CAPACITOR" "C?" "" 0 0 0 0 0 100 ""] (
Pin[-9252 0 4664 1500 7064 2264 "1" "1" "square"]
Pin[9252 0 4664 1500 7064 2264 "2" "2" ""]
ElementArc[0 0 19685 19685 0 360 1000]
)