mirror of
git://projects.qi-hardware.com/eda-tools.git
synced 2024-11-28 18:51:53 +02:00
rescue files from svn.openmoko.org
This commit is contained in:
parent
702343cabc
commit
881bf33be0
140
old-boom/CHARACTERISTICS
Normal file
140
old-boom/CHARACTERISTICS
Normal file
@ -0,0 +1,140 @@
|
||||
*** This is an older draft of the concept - differs sometimes from the way
|
||||
things are done in gta02-core. ***
|
||||
|
||||
|
||||
BOM matching
|
||||
============
|
||||
|
||||
BOMs are matched with inventories in the following way:
|
||||
|
||||
- a .lst file with the BOM is generated by KiCad
|
||||
|
||||
- using a ruleset, component characteristics are translated to a
|
||||
canonical format and default values may be used for unspecified
|
||||
characteristics
|
||||
|
||||
- part catalogs are searched for matches with the canonical component
|
||||
descriptions. This yields a list of supplier-specific part numbers
|
||||
for each component.
|
||||
|
||||
Parts can be characterized by either specifying their properties or
|
||||
by equating them to another part. E.g., a Digi-Key part may be
|
||||
defined as an NXP part which in turn is equivalent to a TI part.
|
||||
|
||||
- this list is then matched against inventories, using a suitable
|
||||
optimization strategy (e.g., prioritize inventories and try to
|
||||
pick as many suitable components as possible higher priority ones
|
||||
before moving to lower priority ones)
|
||||
|
||||
E.g., local stock could be the first-level inventory, followed by
|
||||
more distant warehouses, followed by distributors, followed by
|
||||
manufacturers.
|
||||
|
||||
Inventories could also include pricing information.
|
||||
|
||||
- TBD: it would be good if parameters gathered in the matching process
|
||||
could be fed back into KiCad (as some sort of annotations, similar
|
||||
to the expanded view of schematic symbols), such that under-specifed
|
||||
parts yielding mismatches can be spotted by manual review.
|
||||
|
||||
|
||||
Catalog
|
||||
=======
|
||||
|
||||
A catalog contains part characteristics and the reference number(s)
|
||||
assigned to them.
|
||||
|
||||
|
||||
Basic syntax
|
||||
------------
|
||||
|
||||
Catalog entries consist of "words" in the sense that each word does
|
||||
not contain any whitespace and words are separated from each other by
|
||||
whitespace. Whitespace can be included in a word if it is enclosed in
|
||||
double quotes.
|
||||
|
||||
Each entry begins in the first column of a line. If an entry needs
|
||||
more than one line, the words on the continuation line(s) must be
|
||||
indented by whitespace.
|
||||
|
||||
Trailing whitespace is ignored, and so are comments beginning with a
|
||||
hash mark. Blank lines end any entry and are also ignored.
|
||||
|
||||
Each catalog entry begins with the part number followed by a part type
|
||||
designator.
|
||||
|
||||
Characteristics have the form <field>=<value>, where
|
||||
the fields follow the pattern outlined below. The value is some
|
||||
description of the value of that characteristic, typically a number
|
||||
and a unit (e.g., 4.7uF) or a name (e.g., X5R).
|
||||
|
||||
Numbers use a decimal point where necessary. Mantissas are normalized
|
||||
such that they fall into the range 1 <= n < 1000. E.g., instead of
|
||||
0.1uF, write 100nF. There is no space between number and unit. The
|
||||
Omega of Ohm is written as "R".
|
||||
|
||||
|
||||
Fields
|
||||
------
|
||||
|
||||
Each
|
||||
|
||||
General fields
|
||||
- - - - - - -
|
||||
|
||||
FP Footprint
|
||||
H Height (overrides any height implied by footprint)
|
||||
TOL Tolerance, with percent sign. Split tolerances are indicated as n/m%
|
||||
DSC Free-format description
|
||||
|
||||
|
||||
Resistors
|
||||
- - - - -
|
||||
|
||||
RES Part type designator
|
||||
R Resistance, with unit
|
||||
P Maximum power dissipation
|
||||
V Maximum volatage
|
||||
|
||||
|
||||
Capacitors
|
||||
- - - - -
|
||||
|
||||
CAP Part type designator
|
||||
C Capacitance, with unit
|
||||
M Material, e.g., TANT, NP0, X5R, etc.
|
||||
V Maximum voltage
|
||||
ESR ESR, with unit
|
||||
|
||||
|
||||
Inductors
|
||||
-- - - -
|
||||
|
||||
Diodes
|
||||
- - -
|
||||
|
||||
DIODE Regular diode
|
||||
STKY Schottky diode
|
||||
|
||||
Vf Maximum forward voltage
|
||||
Vr Maximum reverse voltage
|
||||
If Maximum forward current
|
||||
Ir Maximum reverse current
|
||||
C Capacitance
|
||||
|
||||
LED Ligh-emitting diode
|
||||
|
||||
COL Color, multiple colors are separated by /, e.g., blue/red
|
||||
ARRAY If multiple diodes form an array, this parameter describes
|
||||
its structure: CA = common anode, CC = common cathode,
|
||||
SEQ = tap-A-C-tap-A-C-tap sequence
|
||||
|
||||
ZENER Zener diode
|
||||
|
||||
Vz Zener voltage
|
||||
|
||||
TVS Transient voltage suppressor
|
||||
|
||||
Vac Working voltage, AC
|
||||
Vdc Working voltage, DC
|
||||
E Energy
|
19
old-boom/Makefile
Normal file
19
old-boom/Makefile
Normal file
@ -0,0 +1,19 @@
|
||||
UPLOAD=werner@sita.openmoko.org:public_html/gta02-core/
|
||||
COPY=rsync -e ssh --progress
|
||||
|
||||
.PHONY: all xpdf spotless upload
|
||||
|
||||
all:
|
||||
@echo "make what ? xpdf, upload, or spotless ?" 1>&2
|
||||
|
||||
workflow.pdf: workflow.fig
|
||||
fig2dev -L pdf $< >$@ || { rm -f $@; exit 1; }
|
||||
|
||||
xpdf: workflow.pdf
|
||||
xpdf workflow.pdf
|
||||
|
||||
upload: workflow.pdf
|
||||
$(COPY) workflow.pdf $(UPLOAD)/bom-workflow.pdf
|
||||
|
||||
spotless:
|
||||
rm -f workflow.pdf
|
337
old-boom/README
Normal file
337
old-boom/README
Normal file
@ -0,0 +1,337 @@
|
||||
The BOM processing system
|
||||
=========================
|
||||
|
||||
The BOM processing system takes a bill of material generated by
|
||||
KiCad and converts it in various steps into a "shopping list"
|
||||
that can be used to order from various providers.
|
||||
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
The following sections describe how to use the basic elements of
|
||||
the BOM processing system.
|
||||
|
||||
|
||||
A simple BOM translation
|
||||
------------------------
|
||||
|
||||
KiCad identifies components by a so-called component reference,
|
||||
e.g., R1001, U5, etc. In addition to this, each component can have
|
||||
various parameters, such as a "value", its footprint, and further
|
||||
user-defined items. These parameters can be shown in the schematics
|
||||
(e.g., the value usually is) or they can be hidden (e.g., the
|
||||
footprint).
|
||||
|
||||
At the end of the process, we want a "shopping list" that can be
|
||||
used to order items or to find them in an inventory or catalog.
|
||||
Components in the shopping list are identified by a part number.
|
||||
|
||||
...
|
||||
- BOM
|
||||
- inventory
|
||||
- ID matching
|
||||
|
||||
|
||||
Equivalences
|
||||
------------
|
||||
|
||||
A single component can be associated with multiple part numbers.
|
||||
For example, a chip its manufacturer calls "XYZ-R1" may be listed in
|
||||
a distributor's catalog with a completely different order number,
|
||||
such as "20-1234-8". The BOM processing system therefore
|
||||
distinguishes multiple so-called name spaces. A name space is
|
||||
identified by a (unique) name and a part number is generally
|
||||
qualified by the name of the name space.
|
||||
|
||||
E.g., if the manufacturer is called "ACME" and the distributor of
|
||||
electronical components calls itself "DIST-EL", the part in our
|
||||
example may have the equivalent names "ACME XYZ-R1" and "DIST-EL
|
||||
20-1234-8".
|
||||
|
||||
...
|
||||
- revise .inv
|
||||
|
||||
example.equ:
|
||||
|
||||
#INV
|
||||
DIST-EL 20-1234-8
|
||||
#EQU
|
||||
ACME XYZ-R1 DIST-EL 20-1234-8
|
||||
|
||||
|
||||
Adding stock and cost
|
||||
---------------------
|
||||
|
||||
- .inv, more fields
|
||||
- quanta
|
||||
|
||||
Substituting component names
|
||||
----------------------------
|
||||
|
||||
- intro to .sub
|
||||
- ad-hoc fixes
|
||||
|
||||
|
||||
Selecting characteristics
|
||||
-------------------------
|
||||
|
||||
- .sub
|
||||
- .chr
|
||||
- <rel><number><multiplier><unit> syntax
|
||||
...
|
||||
|
||||
|
||||
Generating characteristics
|
||||
--------------------------
|
||||
|
||||
- .gen
|
||||
|
||||
|
||||
Advanced topics
|
||||
===============
|
||||
|
||||
- generating .inv files
|
||||
- different presentations (e.g., CT, TR, ...)
|
||||
- component substitution (one-way equivalence)
|
||||
- problem reports
|
||||
- hiding known problems (while sourcing)
|
||||
|
||||
|
||||
File formats
|
||||
============
|
||||
|
||||
The BOM processing system uses a large number of different files to
|
||||
store information retrieved from the BOM, inventories, intermediate
|
||||
results, etc. The following sections describe the various formats.
|
||||
|
||||
|
||||
Part characteristics (.chr)
|
||||
---------------------------
|
||||
|
||||
A part characteristics file lists the parameters of components.
|
||||
This information is then matched with the parameters specified in
|
||||
the schematics.
|
||||
|
||||
The part characteristics file begins with a line containing only
|
||||
#CHR
|
||||
|
||||
After this, each line contains the manufacturer (namespace), the
|
||||
part number, and a list of parameter=value entries. Fields are
|
||||
separated by spaces.
|
||||
|
||||
Long lines can be wrapped by indenting the continuation lines.
|
||||
|
||||
Blank lines and comments (#) are ignored.
|
||||
|
||||
|
||||
Substitutions (.sub)
|
||||
--------------------
|
||||
|
||||
A substitutions file specifies rules for translating component
|
||||
parameters in schematics to part characteristics.
|
||||
|
||||
A substitution rule consists of zero or more conditions and zero or
|
||||
more assignments. The conditions are of the form field=pattern. The
|
||||
field can be a per-component fields KiCad provides or any parameter
|
||||
set by substitutions.
|
||||
|
||||
KiCad fields are named as follows:
|
||||
|
||||
KiCad field Field name
|
||||
----------- ----------
|
||||
Reference REF (*)
|
||||
Value VAL
|
||||
Footprint FP
|
||||
Field1 F1
|
||||
... ...
|
||||
|
||||
(*) As a shortcut, REF= can be omitted.
|
||||
|
||||
Note that fields with a user-defined name currently still only appear
|
||||
as F1, F2, etc.
|
||||
|
||||
The special field name FN can be used to look for a match in all of
|
||||
F1, F2, ... This way, it's sufficient to use a consistent syntax for
|
||||
additional parameters, without having to assign also a fixed location
|
||||
for them. If more than one field matches, the first match is taken.
|
||||
|
||||
Field names are case-insensitive.
|
||||
|
||||
The pattern is uses a notation similar to filename globbing. There
|
||||
are the following special constructs:
|
||||
|
||||
- * matches a string of any length
|
||||
- ? matches a single character
|
||||
- (...) matches the pattern between the parentheses and records the
|
||||
string matched
|
||||
- $X marks a value in nXn notation, e.g., 4u7 or 100R. Such values
|
||||
are converted to SI-like notation.
|
||||
|
||||
A rule is applied when all conditions are fulfilled. In this case,
|
||||
assignments of the form field=value are executed. Strings obtained
|
||||
in the match can be included in a value as follows:
|
||||
|
||||
- $field and ${field} are replaced by the respective field
|
||||
- $field:n and ${field:n} are replaced by the n-th (...) pattern in
|
||||
the match of the respective field
|
||||
|
||||
If a rule ends with an exclamation mark, the substitution process stops
|
||||
after the rule is applied. Otherwise, further rules are processed.
|
||||
|
||||
Examples:
|
||||
|
||||
R* val=$R -> R=$val
|
||||
|
||||
This rule translates the values of all resistors to SI notation.
|
||||
|
||||
D* FN=(*)Vdc -> T=TSV Vdc=FN:1
|
||||
|
||||
This rule sets the parameters T and Vdc for Zeners acting as TSVs.
|
||||
|
||||
If a set of rules has a common set of conditions or assignments, the
|
||||
more compact block notation can be used instead of repeating them for
|
||||
each rule:
|
||||
|
||||
common-conditions -> common-assignments {
|
||||
rule-specific-conditions -> rule-specific-assignments
|
||||
...
|
||||
}
|
||||
|
||||
Rules in a block only match if both the common and the rule-specific
|
||||
conditions are met. Then the common and the rule-specific assignments
|
||||
are performed. If a condition or an assignment appears both in the
|
||||
common and the rule-specific part, only the latter is used.
|
||||
|
||||
Long lines can be wrapped by indenting the continuation lines. Note
|
||||
that { and ! are also considered to be part of the same line as the
|
||||
rest of the rule. In particular, the following construct wouldn't
|
||||
work:
|
||||
|
||||
X=Y
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
With proper indentation, this would:
|
||||
|
||||
X=Y
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
|
||||
Characteristics generation (.gen)
|
||||
---------------------------------
|
||||
|
||||
The substitution mechanism can also be used to automatically generate
|
||||
characteristics from part numbers, e.g., for resistors or capacitors.
|
||||
|
||||
.gen files are exactly .sub files, with the exception that the only
|
||||
field used is the REF field and that it contains the part number.
|
||||
|
||||
Once the rule set has been processed, all fields (except REF) whose
|
||||
name doesn't begin with an underscore are placed in the characteristics
|
||||
entry as parameters.
|
||||
|
||||
An entry is only produced if the rule set is explicitly terminated.
|
||||
|
||||
|
||||
Parts list (.par)
|
||||
------------------
|
||||
|
||||
A parts file lists the parts that are suitable for a given BOM item.
|
||||
The file begins with a line containing only
|
||||
#PAR
|
||||
|
||||
After this, each line contains the component reference, a space, and
|
||||
then one or more namespace part-number groups, separated by spaces as
|
||||
well.
|
||||
|
||||
Blank lines and comments (#) are ignored.
|
||||
|
||||
|
||||
Order list (.ord)
|
||||
-----------------
|
||||
|
||||
An order file lists the quantities to order from inventories, along
|
||||
with the cost and the component references the item is used for. The
|
||||
file begins with a line containing only
|
||||
#ORD
|
||||
|
||||
After this, each line contains the supplier (namespace), the part
|
||||
number, the number of items to order, the currency code, the cost,
|
||||
and one or more component references.
|
||||
|
||||
Blank lines and comments (#) are ignored.
|
||||
|
||||
|
||||
Equivalence (.equ)
|
||||
------------------
|
||||
|
||||
Equivalence files establish equivalences between parts numbers in the
|
||||
same or in different name spaces. An equivalence file begins with a
|
||||
line containing only
|
||||
#EQU
|
||||
|
||||
After this, each line consists of the following four space-separated
|
||||
fields:
|
||||
|
||||
namespace-1 part-number-1 namespace-2 part-number-2
|
||||
|
||||
Blank lines and comments (#) are ignored.
|
||||
|
||||
|
||||
Inventory (.inv)
|
||||
----------------
|
||||
|
||||
Inventory files list inventory and component cost. An inventory file
|
||||
begins with a line containing only
|
||||
#INV
|
||||
|
||||
After this, each line contains the namespace and the part number,
|
||||
followed by the number of items in stock, the currency code, and one
|
||||
or more pricing entries.
|
||||
|
||||
Each pricing entry consists of two fields: the number of items in an
|
||||
order, and the per item price at that quantity. A sequence of
|
||||
increasing order sizes indicates that they are quanta. A sequence of
|
||||
decreasing order sizes indicates that smaller quanta are possible
|
||||
after a previous larger threshold has been met.
|
||||
|
||||
Example:
|
||||
|
||||
... USD 1 0.5 10 0.4 100 0.2
|
||||
|
||||
Means that an order of at least 170 units would be made either as
|
||||
2 * 100 units, costing USD 40, or as 1 * 100 + 7 * 10 units, costing
|
||||
USD 20 + USD 28 = USD 48.
|
||||
|
||||
If the entry is
|
||||
|
||||
... USD 1 0.5 10 0.4 100 0.2 1 0.2
|
||||
|
||||
Then the USD 0.2 per unit cost would apply to any any quantity of at
|
||||
least 100 units. So a 170 units order would cost USD 34.
|
||||
|
||||
Blank lines and comments (#) are ignored.
|
||||
|
||||
The number of items in stock and the pricing data can be omitted. We
|
||||
call this "virtual inventory". In this case, the numer of items in
|
||||
stock and the price default to large numbers (e.g., 999999). Virtual
|
||||
inventory is used to suppress warnings for parts that have not been
|
||||
sourced yet, but where sourcing is in progress.
|
||||
|
||||
|
||||
Description (.dsc)
|
||||
------------------
|
||||
|
||||
A description file contains plain text descriptions of parts. The file
|
||||
begins with a like containing only
|
||||
#DSC
|
||||
|
||||
Each line contains the name space, a space, the part number, another
|
||||
space, and the description. The description can contain any printable
|
||||
character and ends with a newline.
|
||||
|
||||
Blank lines and comments (#) are ignored.
|
222
old-boom/annotate
Executable file
222
old-boom/annotate
Executable file
@ -0,0 +1,222 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
require "parser.pl";
|
||||
require "misc.pl";
|
||||
|
||||
|
||||
$H = 50; # character height
|
||||
$W = $H*0.9; # character width
|
||||
$L = $H+20; # line skip
|
||||
|
||||
|
||||
sub normalize
|
||||
{
|
||||
my @t = @_;
|
||||
|
||||
# convert from (x0, y0, w, h) to (x0, y0, x1, y1)
|
||||
$t[2] += $t[0];
|
||||
$t[3] = $t[1]-$t[3];
|
||||
return ($t[0], $t[3], $t[2], $t[1]);
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# 2x2 matrix inversion
|
||||
# http://en.wikipedia.org/wiki/Invertible_matrix#Inversion_of_2.C3.972_matrices
|
||||
#
|
||||
|
||||
sub invert
|
||||
{
|
||||
my @m = @_;
|
||||
my $f = 1/($m[0]*$m[3]-$m[1]*$m[2]);
|
||||
return ($f*$m[3], -$f*$m[1], -$f*$m[2], $f*$m[0]);
|
||||
}
|
||||
|
||||
|
||||
sub block
|
||||
{
|
||||
my @t = &normalize(@_);
|
||||
push(@block, [ @t ]);
|
||||
$wnl .= "Wire Notes Line\n\t$t[0] $t[1] $t[2] $t[3]\n";
|
||||
}
|
||||
|
||||
|
||||
sub pass
|
||||
{
|
||||
my @t = &normalize(@_);
|
||||
|
||||
for (@block) {
|
||||
my @b = @{ $_ };
|
||||
next if $t[0] > $b[2];
|
||||
next if $t[2] < $b[0];
|
||||
next if $t[1] > $b[3];
|
||||
next if $t[3] < $b[1];
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
sub put
|
||||
{
|
||||
local ($x0, $y0, $ref, @s) = @_;
|
||||
|
||||
my $h = @s*$L;
|
||||
my $w = 0;
|
||||
for (@s) {
|
||||
my $t = $W*length $_;
|
||||
$w = $t if $t > $w;
|
||||
}
|
||||
my $a = 270;
|
||||
my $r = 100;
|
||||
my $x, $y;
|
||||
my $ym = $y0-$h+$H/2;
|
||||
for ($i = 0; $i != 128; $i++) {
|
||||
$x = int($x0+$r*cos($a/180*3.14159));
|
||||
$y = int($ym+$r*sin($a/180*3.14159));
|
||||
last if &pass($x, $y, $w, $h);
|
||||
$a += 22.5;
|
||||
$r += $L/8;
|
||||
}
|
||||
warn "no place found for \"$s[0]\"" if $i == 128;
|
||||
|
||||
my @m = &invert( @{ $m{$ref} });
|
||||
&block($x, $y+$H/2, $w, $h);
|
||||
my $n = 10;
|
||||
for my $s (reverse @s) {
|
||||
my $dx = $x-$x0;
|
||||
my $dy = $y-$y0;
|
||||
my $sx = $x0+$dx*$m[0]+$dy*$m[1];
|
||||
my $sy = $y0+$dx*$m[2]+$dy*$m[3];
|
||||
($hv, $hj, $vj) = ("H", "L", "C") if $m[0] == 1;
|
||||
($hv, $hj, $vj) = ("H", "R", "C") if $m[0] == -1;
|
||||
($hv, $hj, $vj) = ("V", "C", "B") if $m[1] == 1;
|
||||
($hv, $hj, $vj) = ("V", "C", "T") if $m[1] == -1;
|
||||
$s =~ s/~/-/g;
|
||||
print "F $n \"$s\" $hv $sx $sy $H 0000 $hj ${vj}NN\n";
|
||||
$y -= $L;
|
||||
$n++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub dsc_parts
|
||||
{
|
||||
local ($ref) = @_;
|
||||
my @p = @{ $parts{$ref} };
|
||||
my @f = ();
|
||||
while (@p) {
|
||||
my @id = splice(@p, 0, 2);
|
||||
my $id = "$id[0] $id[1]";
|
||||
my $dsc = &dsc_find($id);
|
||||
push(@f, &dsc) if defined $dsc;
|
||||
}
|
||||
return @f;
|
||||
}
|
||||
|
||||
|
||||
sub dsc_order
|
||||
{
|
||||
local ($ref) = @_;
|
||||
my @f = ();
|
||||
for my $id (keys %order) {
|
||||
my @p = @{ $order{$id} };
|
||||
for (splice(@p, 3)) {
|
||||
push(@f, &dsc_find($id)) if $_ eq $ref;
|
||||
}
|
||||
}
|
||||
return @f;
|
||||
}
|
||||
|
||||
|
||||
sub usage
|
||||
{
|
||||
print STDERR "usage: $0 [-s/from/to/ ...] ...\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
while ($ARGV[0] =~ /^-s/) {
|
||||
&usage unless &dsc_xlat_arg($');
|
||||
shift @ARGV;
|
||||
}
|
||||
&usage if $ARGV[0] =~ /^-./;
|
||||
|
||||
&parse;
|
||||
|
||||
|
||||
#
|
||||
# pass 1: find the orientation of all parts
|
||||
#
|
||||
|
||||
for (@eeschema) {
|
||||
$ref = $1 if /^L \S+ (\S+)/;
|
||||
undef $ref if /^\$EndComp/;
|
||||
next unless /^\s+(-?[01])\s+(-?[01])\s+(-?[01])\s+(-?[01])\s*$/;
|
||||
my @m = split(/\s+/);
|
||||
shift @m;
|
||||
$m{$ref} = [ @m ];
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# pass 2: block the spaces occupied by fields
|
||||
#
|
||||
|
||||
for (@eeschema) {
|
||||
$ref = $1 if /^L \S+ (\S+)/;
|
||||
if (/^P (\d+) (\d+)/) {
|
||||
$x0 = $1;
|
||||
$y0 = $2;
|
||||
}
|
||||
next unless /^F /;
|
||||
die "$_" unless
|
||||
/^F \d+ "([^"]*)" ([HV]) (\d+) (\d+) (\d+) +(\d+) ([LC]) (C)/;
|
||||
($s, $hv, $x, $y, $size, $flag, $hj, $vj) =
|
||||
($1, $2, $3, $4, $5, $6, $7, $8);
|
||||
$dx = $x-$x0;
|
||||
$dy = $y-$y0;
|
||||
$x = $x0+$dx*$m{$ref}[0]+$dy*$m{$ref}[1];
|
||||
$y = $y0+$dx*$m{$ref}[2]+$dy*$m{$ref}[3];
|
||||
next if $flag != 0;
|
||||
$w = $size*0.8*length $s;
|
||||
# we don't need to consider H/V
|
||||
&block($hj eq "L" ? $x : $x-$w/2, $y+$size/2, $w, $size);
|
||||
}
|
||||
|
||||
#
|
||||
# pass 3:
|
||||
#
|
||||
|
||||
for (@eeschema) {
|
||||
undef @f if /^\$Comp/;
|
||||
if (/^L \S+ (\S+)/) {
|
||||
$ref = $1;
|
||||
push(@f, &dsc_order($ref)) if %order;
|
||||
push(@f, &dsc_parts($ref)) if %parts;
|
||||
}
|
||||
if (/^P (\d+) (\d+)/) {
|
||||
$x = $1;
|
||||
$y = $2;
|
||||
}
|
||||
if (/^\s+/) {
|
||||
my %seen;
|
||||
my @u = ();
|
||||
for (@f) {
|
||||
next if $seen{$_};
|
||||
push(@u, $_);
|
||||
$seen{$_} = 1;
|
||||
}
|
||||
undef @f;
|
||||
# $m{$ref}[0] == 1 OK
|
||||
# $m{$ref}[0] == -1 OK
|
||||
# $m{$ref}[1] == 1 OK
|
||||
# $m{$ref}[1] == -1 OK (small deviations found)
|
||||
&put($x, $y, $ref, @u) if 1 || $m{$ref}[1] == -1;
|
||||
}
|
||||
if (/\$EndSCHEMATC/) {
|
||||
# uncomment for debugging
|
||||
# print $wnl;
|
||||
}
|
||||
print "$_\n";
|
||||
}
|
129
old-boom/bom2part
Executable file
129
old-boom/bom2part
Executable file
@ -0,0 +1,129 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
require "parser.pl";
|
||||
require "match.pl";
|
||||
require "misc.pl";
|
||||
|
||||
|
||||
sub issue
|
||||
{
|
||||
print shift(@_), " ", join(" ", @_, &eq(@_)), "\n";
|
||||
}
|
||||
|
||||
|
||||
sub scale
|
||||
{
|
||||
local ($v, $m) = @_;
|
||||
|
||||
return $v*1e-12 if $m eq "p";
|
||||
return $v*1e-9 if $m eq "n";
|
||||
return $v*1e-6 if $m eq "u";
|
||||
return $v*1e-3 if $m eq "m";
|
||||
return $v*1e3 if $m eq "k";
|
||||
return $v*1e6 if $m eq "M";
|
||||
return $v*1e9 if $m eq "G";
|
||||
return $v if $m eq "";
|
||||
die "unknown multiplier \"$m\"";
|
||||
}
|
||||
|
||||
|
||||
sub compat
|
||||
{
|
||||
local ($a, $b) = @_; # $a = part char., $b = component spec.
|
||||
|
||||
return 1 if $a eq $b;
|
||||
return 0 unless $a =~ /^([0-9.]+)([GMkmunp]?)/;
|
||||
my ($av, $am, $au) = ($1, $2, $');
|
||||
return 0 unless $b =~ /^(>|>=|<|<=)([0-9.]+)([GMkmunp]?)/;
|
||||
my ($rel, $bv, $bm, $bu) = ($1, $2, $3, $');
|
||||
return 0 if $au ne $bu;
|
||||
$av = &scale($av, $am);
|
||||
$bv = &scale($bv, $bm);
|
||||
return $av > $bv if $rel eq ">";
|
||||
return $av >= $bv if $rel eq ">=";
|
||||
return $av < $bv if $rel eq "<";
|
||||
return $av <= $bv if $rel eq "<=";
|
||||
die;
|
||||
}
|
||||
|
||||
|
||||
if ($ARGV[0] eq "-d") {
|
||||
$debug = 1;
|
||||
shift @ARGV;
|
||||
}
|
||||
&parse;
|
||||
|
||||
$total = 0;
|
||||
$bad = 0;
|
||||
|
||||
print "#PAR\n";
|
||||
for $ref (keys %cmp) {
|
||||
@f = @{ $cmp{$ref} };
|
||||
$total++;
|
||||
|
||||
print STDERR "REF $ref\n" if $debug;
|
||||
|
||||
# if we're lucky, we get a direct ID match
|
||||
|
||||
if (defined $id{$f[0]}) {
|
||||
print STDERR "FIRST ID\n" if $debug;
|
||||
&issue($ref, $id{$f[0]});
|
||||
next;
|
||||
}
|
||||
|
||||
# no such luck. Let's roll up our sleeves and to the substitutions.
|
||||
|
||||
undef %field;
|
||||
$field{"REF"} = $ref;
|
||||
$field{"VAL"} = $f[0];
|
||||
if ($f[1] eq "") {
|
||||
print STDERR "warning: $ref ($f[0]) has no footprint\n";
|
||||
} else {
|
||||
$field{"FP"} = $f[1];
|
||||
}
|
||||
for (my $i = 1; $i != 10; $i++) {
|
||||
$field{"F$i"} = $f[$i+1];
|
||||
}
|
||||
&apply_rules();
|
||||
|
||||
# try our luck again
|
||||
|
||||
if (defined $id{$field{"VAL"}}) {
|
||||
print STDERR "SECOND ID\n" if $debug;
|
||||
&issue($ref, $id{$field{"VAL"}});
|
||||
next;
|
||||
}
|
||||
|
||||
# still nothing. Let's match characteristics then.
|
||||
|
||||
my @p = ();
|
||||
COMP: for my $c (keys %chr) {
|
||||
print STDERR "PART $c\n" if $debug;
|
||||
for (keys %field) {
|
||||
next if $_ eq "REF" || $_ eq "VAL" || $_ =~ /^F\d$/;
|
||||
next if $field{$_} eq "";
|
||||
print STDERR " $_=",$field{$_}," " if $debug;
|
||||
if (!defined $chr{$c}{$_}) {
|
||||
print STDERR "NO FIELD\n" if $debug;
|
||||
next COMP;
|
||||
next;
|
||||
}
|
||||
if (&compat($chr{$c}{$_}, $field{$_})) {
|
||||
print STDERR "== $chr{$c}{$_}\n" if $debug;
|
||||
} else {
|
||||
print STDERR "!= $chr{$c}{$_}\n" if $debug;
|
||||
next COMP;
|
||||
}
|
||||
}
|
||||
push(@p, $c);
|
||||
}
|
||||
if (@p) {
|
||||
&issue($ref, @p);
|
||||
next;
|
||||
}
|
||||
|
||||
print STDERR "unmatched: $ref (", join(", ", @f), ")\n";
|
||||
$bad++;
|
||||
# print join("#", ($ref, @f)), " -> $id{$f[0]}\n";
|
||||
}
|
||||
print STDERR "$bad/$total unmatched\n" if $bad;
|
26
old-boom/boom
Executable file
26
old-boom/boom
Executable file
@ -0,0 +1,26 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
|
||||
sub usage
|
||||
{
|
||||
print STDERR "usage: $0 command [arg ...]\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
&usage unless @ARGV;
|
||||
|
||||
($d = $0) =~ s|/[^/]*$||;
|
||||
if ($d eq "") {
|
||||
$p = "/";
|
||||
} elsif ($d =~ /^\//) {
|
||||
$p = "$d";
|
||||
} else {
|
||||
chomp($cwd = `pwd`);
|
||||
$p = "$cwd/$d";
|
||||
}
|
||||
|
||||
$cmd = shift @ARGV;
|
||||
$cmd = "$p/$cmd" unless $cmd =~ m|/|;
|
||||
exec("perl", "-I", $p, $cmd, @ARGV);
|
||||
die "exec perl: $!";
|
64
old-boom/gen2chr
Executable file
64
old-boom/gen2chr
Executable file
@ -0,0 +1,64 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
require "parser.pl";
|
||||
require "match.pl";
|
||||
|
||||
|
||||
sub translate
|
||||
{
|
||||
local ($r) = @_;
|
||||
|
||||
undef %field;
|
||||
$field{"REF"} = $r;
|
||||
&match_set_error($r);
|
||||
if (!&apply_rules()) {
|
||||
print "$id{$r}\n" if $negate;
|
||||
return;
|
||||
}
|
||||
return if $negate;
|
||||
print $id{$r};
|
||||
for (sort keys %field) {
|
||||
next if $_ =~ /^_/;
|
||||
next if $_ eq "REF";
|
||||
print " $_=$field{$_}";
|
||||
}
|
||||
print "\n";
|
||||
}
|
||||
|
||||
|
||||
sub usage
|
||||
{
|
||||
print STDERR "usage: $0 [-d|-n] key file ...\n";
|
||||
print STDERR " $0 -q query file ...\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while ($ARGV[0] =~ /^-/) {
|
||||
if ($ARGV[0] eq "-d") {
|
||||
$debug = 1;
|
||||
} elsif ($ARGV[0] eq "-n") {
|
||||
$negate = 1;
|
||||
} elsif ($ARGV[0] eq "-q") {
|
||||
$query = 1;
|
||||
} else {
|
||||
&usage;
|
||||
}
|
||||
shift @ARGV;
|
||||
}
|
||||
|
||||
$key = shift @ARGV;
|
||||
&usage unless defined $key;
|
||||
|
||||
&parse;
|
||||
|
||||
if ($query) {
|
||||
$debug = 1;
|
||||
&translate($key);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
print "#CHR\n";
|
||||
for (keys %id) {
|
||||
next unless $id{$_} eq "$key $_";
|
||||
&translate($_);
|
||||
}
|
210
old-boom/match.pl
Executable file
210
old-boom/match.pl
Executable file
@ -0,0 +1,210 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use re 'eval';
|
||||
|
||||
|
||||
#
|
||||
# "sub" populates the following global variables:
|
||||
#
|
||||
# $end[rule-number] = 0 / 1
|
||||
# $match[rule-number]{field}[0] = original-pattern
|
||||
# $match[rule-number]{field}[1] = RE1
|
||||
# $match[rule-number]{field}[2] = RE2
|
||||
# $action[rule-number]{field} = value
|
||||
#
|
||||
# $match_stack[depth]{field}[0] = original-pattern
|
||||
# $match_stack[depth]{field}[1] = RE1
|
||||
# $match_stack[depth]{field}[2] = RE2
|
||||
# $action_stack[depth]{field} = value
|
||||
# $may_cont = 0 / 1
|
||||
# $last
|
||||
# $last_action
|
||||
#
|
||||
|
||||
#
|
||||
# $cvn_from{internal-handle} = index
|
||||
# $cvn_to{internal-handle} = index
|
||||
# $cvn_unit{internal-handle} = unit-name
|
||||
# $cvn_num = internal-handle
|
||||
# $found{field-or-subfield} = string
|
||||
|
||||
|
||||
#
|
||||
# We convert each input pattern into two regular expressions: the first matches
|
||||
# units in the nXn notation, e.g., 4u7 or 100R. The second matches them in SI
|
||||
# notation (sans space).
|
||||
#
|
||||
# When matching (sub_match), we first apply the first expression. Each time we
|
||||
# encounter a unit ($R, $F, etc.), __cvn is called. __cvn stores the index of
|
||||
# the unit in %cvn_from and %cvn_to.
|
||||
#
|
||||
# We then pick these substrings from the input string and convert the units to
|
||||
# SI notation. At the same time, we normalize the mantissa. Once done, we run
|
||||
# the second expression. This one always matches (hopefully :-)
|
||||
#
|
||||
# All (...) ranges in the original pattern have been replaced with named
|
||||
# capture buffers in the second expression, so all these subfields are now
|
||||
# gathered in the $+ array. (The same also happened in the first pass, but we
|
||||
# ignore it.)
|
||||
#
|
||||
# Finally, when expanding a value (sub_expand), we look for $field and
|
||||
# $field:index, and expand accordingly.
|
||||
#
|
||||
|
||||
|
||||
sub __cvn
|
||||
{
|
||||
local ($num) = @_;
|
||||
|
||||
$cvn_from{$num} = $-[$#-];
|
||||
$cvn_to{$num} = $+[$#+];
|
||||
}
|
||||
|
||||
|
||||
sub sub_match
|
||||
{
|
||||
local ($s, $field, $m1, $m2) = @_;
|
||||
|
||||
#
|
||||
# Perform the first match and record where we saw $<unit> patterns.
|
||||
#
|
||||
undef %cvn_from;
|
||||
undef %cvn_to;
|
||||
return undef unless $s =~ $m1;
|
||||
|
||||
#
|
||||
# Convert the unit patterns to almost-SI notation. (We don't put a space
|
||||
# after the number, but the rest is SI-compliant.)
|
||||
#
|
||||
my $off = 0;
|
||||
for (keys %cvn_from) {
|
||||
my $unit = $cvn_unit{$_};
|
||||
my $from = $cvn_from{$_}+$off;
|
||||
my $len = $cvn_to{$_}-$cvn_from{$_};
|
||||
die unless substr($s, $from, $len) =~
|
||||
/(\d+)$unit(\d*)|(\d+)([GMkmunpf])(\d*)/;
|
||||
|
||||
#
|
||||
# Normalize to \d+.\d*
|
||||
#
|
||||
my $v = "$1$3.$2$5";
|
||||
my $exp = $4 eq "" ? " " : $4;
|
||||
|
||||
#
|
||||
# Remove leading zeroes.
|
||||
#
|
||||
$v =~ s/^0*(\d+)/\1/;
|
||||
|
||||
#
|
||||
# Mantissa must be < 1000.
|
||||
# Do the math as string operation to avoid rounding errors.
|
||||
#
|
||||
while ($v =~ /(\d+)(\d{3})\./) {
|
||||
$v = "$1.$2$'";
|
||||
$exp =~ tr/GMk munpf/TGMk munp/;
|
||||
}
|
||||
|
||||
#
|
||||
# Mantissa must be >= 1.
|
||||
#
|
||||
while ($v =~ /\b0\.(\d+)/) {
|
||||
if (length $1 < 3) {
|
||||
$v = $1.("0" x (3-length $1)).".";
|
||||
} else {
|
||||
$v = substr($1, 0, 3).".".substr($1, 3);
|
||||
}
|
||||
$exp =~ tr/GMk munpf/Mk munpa/;
|
||||
}
|
||||
|
||||
#
|
||||
# Remove trailing zeroes
|
||||
#
|
||||
$v =~ s/(\.[1-9]*)0*/\1/;
|
||||
|
||||
$exp =~ s/ //;
|
||||
$v =~ s/\.$//;
|
||||
$v = $v.$exp.$unit;
|
||||
$off += length($v)-$len;
|
||||
substr($s, $from, $len, $v);
|
||||
}
|
||||
|
||||
#
|
||||
# Run the second match on the string to process any (...) patterns
|
||||
#
|
||||
$found{$field} = $s;
|
||||
die $m2 unless $s =~ $m2;
|
||||
for (keys %+) {
|
||||
$found{$_} = $+{$_};
|
||||
}
|
||||
return $s;
|
||||
}
|
||||
|
||||
|
||||
sub sub_expand
|
||||
{
|
||||
local ($s) = @_;
|
||||
|
||||
while ($s =~ /^([^\$]*)\$([A-Za-z_]\w*)(:(\d+))?|^([^\$]*)\${([A-Za-z_]\w*)(:(\d+))?}/) {
|
||||
my $name = "$2$6";
|
||||
$name .= "__$4$8" if defined($4) || defined($8);
|
||||
if (!defined $found{$name}) {
|
||||
die "don't know \"$name\"".
|
||||
(defined $__match_error ?
|
||||
" (processing \"$__match_error\")" : "");
|
||||
}
|
||||
$s = $1.$5.$found{$name}.$';
|
||||
}
|
||||
return $s;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# return 0 if all rules have been exhausted, 1 if there was an explicit halt.
|
||||
#
|
||||
|
||||
sub apply_rules
|
||||
{
|
||||
RULE: for (my $i = 0; $i <= $#match; $i++) {
|
||||
print STDERR "RULE #$i\n" if $debug;
|
||||
%found = %field;
|
||||
FIELD: for my $f (keys %{ $match[$i] }) {
|
||||
my @f = $f ne "FN" ? ($f) :
|
||||
("F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9");
|
||||
for (@f) {
|
||||
print STDERR " MATCH $_=$match[$i]{$f}[0] " if $debug;
|
||||
if (!defined $found{$_}) {
|
||||
print STDERR "NO FIELD\n" if $debug;
|
||||
next;
|
||||
}
|
||||
print STDERR "FIELD $found{$_} " if $debug;
|
||||
if (!defined &sub_match($found{$_}, $f,
|
||||
$match[$i]{$f}[1], $match[$i]{$f}[2])) {
|
||||
print STDERR "MISS\n" if $debug;
|
||||
next;
|
||||
}
|
||||
print STDERR "MATCH\n" if $debug;
|
||||
next FIELD;
|
||||
}
|
||||
next RULE;
|
||||
}
|
||||
for (keys %{ $action[$i] }) {
|
||||
my $s = &sub_expand($action[$i]{$_});
|
||||
print STDERR " SET $_=$action[$i]{$_} => $s\n" if $debug;
|
||||
$field{$_} = $s;
|
||||
}
|
||||
if ($end[$i]) {
|
||||
print STDERR " END\n" if $debug;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
sub match_set_error
|
||||
{
|
||||
$__match_error = $_[0];
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
95
old-boom/misc.pl
Executable file
95
old-boom/misc.pl
Executable file
@ -0,0 +1,95 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
|
||||
#
|
||||
# determine the equivalent parts, taking into account that %eq is transitive
|
||||
#
|
||||
|
||||
sub eq
|
||||
{
|
||||
my %seen;
|
||||
my @p = @_; # parts to consider
|
||||
my @r = (); # new equivalences we've found
|
||||
my $skip = @p;
|
||||
|
||||
while (@p) {
|
||||
my $p = shift @p;
|
||||
next if $seen{$p};
|
||||
$seen{$p} = 1;
|
||||
push(@r, $p) if $skip-- <= 0;
|
||||
push(@p, @{ $eq{$p} });
|
||||
}
|
||||
return @r;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# When looking for a description, we also consider equivalent parts.
|
||||
#
|
||||
# Furthermore, some descriptions may just be pointers to other descriptions.
|
||||
# Users can add regular expressions that are used to extract references from
|
||||
# a description, which are then looked up as well.
|
||||
#
|
||||
|
||||
sub __dsc_lookup
|
||||
{
|
||||
local ($id) = @_;
|
||||
|
||||
for ($id, &eq($id)) {
|
||||
return $dsc{$_} if defined $dsc{$_};
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
|
||||
sub dsc_find
|
||||
{
|
||||
my $id = $_[0];
|
||||
LOOKUP: while (1) {
|
||||
my $dsc = &__dsc_lookup($id);
|
||||
return undef unless defined $dsc;
|
||||
for (my $i = 0; $i <= $#xlat_from; $i++) {
|
||||
# @@@ this is UUUUHHHGLLEEEEE !!! Why can't I just expand $to[$i] ?
|
||||
next
|
||||
unless ($id = $dsc) =~ s/^.*$xlat_from[$i].*$/$xlat_to[$i] $1/;
|
||||
next LOOKUP if defined &__dsc_lookup($id);
|
||||
}
|
||||
return $dsc;
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
|
||||
sub dsc_xlat
|
||||
{
|
||||
local ($from, $to) = @_;
|
||||
push(@xlat_from, $from);
|
||||
push(@xlat_to, $to);
|
||||
}
|
||||
|
||||
|
||||
sub dsc_xlat_arg
|
||||
{
|
||||
return undef unless $_[0] =~ /^(.)([^\1]*)\1([^\1]*)\1$/;
|
||||
&dsc_xlat($2, $3);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Lexical ordering of component references
|
||||
#
|
||||
|
||||
sub cmp_cref
|
||||
{
|
||||
local ($a, $b) = @_;
|
||||
local ($as, $an, $bs, $bn);
|
||||
|
||||
return $a cmp $b unless ($as, $an) = $a =~ /^([[:alpha:]]+)(\d*)$/;
|
||||
return $a cmp $b unless ($bs, $bn) = $b =~ /^([[:alpha:]]+)(\d*)$/;
|
||||
return $as cmp $bs unless $as eq $bs;
|
||||
return $an <=> $bn
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
16
old-boom/pardup.pl
Executable file
16
old-boom/pardup.pl
Executable file
@ -0,0 +1,16 @@
|
||||
#!/usr/bin/perl
|
||||
while (<>) {
|
||||
@f = split(/\s+/);
|
||||
$ref = shift @f;
|
||||
for ($i = 0; $i != @f; $i++) {
|
||||
next unless $f[$i] eq "FIC" || $f[$i] eq "MISSING" ||
|
||||
$f[$i] eq "DIGI-KEY";
|
||||
splice(@f, $i, 2);
|
||||
$i--;
|
||||
}
|
||||
next if @f < 3;
|
||||
push(@{ $multi{join(" ", @f)} }, $ref);
|
||||
}
|
||||
for (sort keys %multi) {
|
||||
print "$_ -- ", join(" ", @{ $multi{$_} }), "\n";
|
||||
}
|
496
old-boom/parser.pl
Executable file
496
old-boom/parser.pl
Executable file
@ -0,0 +1,496 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use re 'eval';
|
||||
use IO::File;
|
||||
|
||||
|
||||
#
|
||||
# "sanitize" converts all "special" characters to underscores. This is used to
|
||||
# avoid part names that could conflict with other uses of meta-characters, such
|
||||
# as spaces or hash signs.
|
||||
#
|
||||
|
||||
sub sanitize
|
||||
{
|
||||
local (*s) = @_;
|
||||
my $ok = '[^-a-zA-Z0-9._%,:()=+\/]';
|
||||
|
||||
print STDERR "converting special character(s) in $s\n" if $s =~ /$ok/;
|
||||
$s =~ s/$ok/_/g;
|
||||
}
|
||||
|
||||
|
||||
sub skip
|
||||
{
|
||||
# do nothing
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# "bom" populates the following global variable:
|
||||
#
|
||||
# $cmp{component-reference}[0] = value
|
||||
# $cmp{component-reference}[1] = footprint
|
||||
# $cmp{component-reference}[2] = field1
|
||||
# ...
|
||||
#
|
||||
|
||||
sub bom
|
||||
{
|
||||
if (/^#End Cmp/) {
|
||||
$mode = *skip;
|
||||
return;
|
||||
}
|
||||
die unless /^\|\s+(\S+)\s+/;
|
||||
my $ref = $1;
|
||||
my @f = split(/\s*;\s*/, $');
|
||||
next if $f[0] eq "NC";
|
||||
for (@f) {
|
||||
s/\s+$//;
|
||||
&sanitize(\$_);
|
||||
}
|
||||
$cmp{$ref} = [ @f ];
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# "equ" populates the following global variables:
|
||||
#
|
||||
# $id{item-number} = "namespace item-number"
|
||||
# This is used for heuristics that look up parts commonly referred to by
|
||||
# their part number.
|
||||
#
|
||||
# $eq{"namespace0 item-number0"}[] = ("namespace1 item-number1", ...)
|
||||
# List of all parts a given part is equivalent to.
|
||||
#
|
||||
|
||||
sub equ
|
||||
{
|
||||
my @f = split(/\s+/);
|
||||
&sanitize(\$f[1]);
|
||||
&sanitize(\$f[3]);
|
||||
my $a = "$f[0] $f[1]";
|
||||
my $b = "$f[2] $f[3]";
|
||||
$id{$f[1]} = $a;
|
||||
$id{$f[3]} = $b;
|
||||
push @{ $eq{$a} }, $b;
|
||||
push @{ $eq{$b} }, $a;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# "inv" populates the following global variables:
|
||||
#
|
||||
# $id{item-number} = "namespace item-number"
|
||||
# This is used for heuristics that look up parts commonly referred to by
|
||||
# their part number.
|
||||
#
|
||||
# $inv{"namespace item-number"}[0] = items-in-stock
|
||||
# $inv{"namespace item-number"}[1] = currency
|
||||
# $inv{"namespace item-number"}[2] = order-quantity
|
||||
# $inv{"namespace item-number"}[3] = unit-price
|
||||
# [2] and [3] may repeat.
|
||||
#
|
||||
|
||||
sub inv
|
||||
{
|
||||
my @f = split(/\s+/);
|
||||
&sanitize(\$f[1]);
|
||||
my $id = "$f[0] $f[1]";
|
||||
shift @f;
|
||||
my $ref = shift @f;
|
||||
die "duplicate inventory entry for \"$id\"" if defined $inv{$id};
|
||||
$id{$ref} = $id;
|
||||
$inv{$id} = [ @f ];
|
||||
$inv{$id}[0] = 999999 unless defined $inv{$id}[0];
|
||||
$inv{$id}[1] = "N/A" unless defined $inv{$id}[1];
|
||||
$inv{$id}[2] = 1 unless defined $inv{$id}[2];
|
||||
$inv{$id}[3] = 999999 unless defined $inv{$id}[3];
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# "par" populates the following global variables:
|
||||
#
|
||||
# $parts{component-ref}[0] = namespace
|
||||
# $parts{component-ref}[1] = item-number
|
||||
# [0] and [1] may repeat
|
||||
#
|
||||
# $want{"namespace item"} = number of times we may use the part. If multiple
|
||||
# parts are eligible for a component, each of them is counted as desirable
|
||||
# for each component.
|
||||
#
|
||||
# $comps{"namespace item"}{component-ref} = 1
|
||||
# Set of components a part may be used for.
|
||||
#
|
||||
|
||||
sub par
|
||||
{
|
||||
my @f = split(/\s+/);
|
||||
my $ref = shift @f;
|
||||
$parts{$ref} = [ @f ];
|
||||
while (@f) {
|
||||
my @id = splice(@f, 0, 2);
|
||||
my $id = "$id[0] $id[1]";
|
||||
$want{$id}++;
|
||||
$comps{$id}{$ref} = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# "chr" populates the following global variable:
|
||||
#
|
||||
# $chr{"namespace item-number"}{parameter} = value
|
||||
#
|
||||
# $last is used internally for continuation lines.
|
||||
#
|
||||
|
||||
sub chr
|
||||
{
|
||||
my @f;
|
||||
if (/^\s+/) {
|
||||
@f = split(/\s+/, $');
|
||||
} else {
|
||||
@f = split(/\s+/);
|
||||
my $ref = shift @f;
|
||||
my $num = shift @f;
|
||||
$last = "$ref $num";
|
||||
}
|
||||
for (@f) {
|
||||
die "\"=\" missing in $_" unless /=/;
|
||||
$chr{$last}{uc($`)} = $';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# "sub" populates the following global variables:
|
||||
#
|
||||
# $end[rule-number] = 0 / 1
|
||||
# $match[rule-number]{field}[0] = original-pattern
|
||||
# $match[rule-number]{field}[1] = RE1
|
||||
# $match[rule-number]{field}[2] = RE2
|
||||
# $action[rule-number]{field} = value
|
||||
#
|
||||
# $match_stack[depth]{field}[0] = original-pattern
|
||||
# $match_stack[depth]{field}[1] = RE1
|
||||
# $match_stack[depth]{field}[2] = RE2
|
||||
# $action_stack[depth]{field} = value
|
||||
# $may_cont = 0 / 1
|
||||
# $last
|
||||
# $last_action
|
||||
#
|
||||
|
||||
#
|
||||
# $cvn_from{internal-handle} = index
|
||||
# $cvn_to{internal-handle} = index
|
||||
# $cvn_unit{internal-handle} = unit-name
|
||||
# $cvn_num = internal-handle
|
||||
# $found{field-or-subfield} = string
|
||||
|
||||
|
||||
sub sub_pattern
|
||||
{
|
||||
local ($field, $p) = @_;
|
||||
my $n = 0;
|
||||
$p =~ s/\./\\./g;
|
||||
$p =~ s/\+/\\+/g;
|
||||
$p =~ s/\?/./g;
|
||||
$p =~ s/\*/.*/g;
|
||||
my $tmp = "";
|
||||
while ($p =~ /^([^\(]*)\(/) {
|
||||
$n++;
|
||||
$tmp .= "$1(?'${field}__$n'";
|
||||
$p = $';
|
||||
}
|
||||
$p = "^".$tmp.$p."\$";
|
||||
my $q = $p;
|
||||
while ($p =~ /^([^\$]*)\$(.)/) {
|
||||
$p = "$1(\\d+$2\\d*|\\d+[GMkmunpf$2]\\d*)(?{ &__cvn($cvn_num); })$'";
|
||||
$cvn_unit{$cvn_num} = $2;
|
||||
die unless $q =~ /^([^\$]*)\$(.)/;
|
||||
$q = "$1(\\d+(\.\\d+)?[GMkmunpf]?$2)$'";
|
||||
$cvn_num++;
|
||||
}
|
||||
return ($p, $q);
|
||||
}
|
||||
|
||||
|
||||
sub sub_value
|
||||
{
|
||||
return $_[0];
|
||||
}
|
||||
|
||||
|
||||
sub sub
|
||||
{
|
||||
/^(\s*)/;
|
||||
my $indent = $1;
|
||||
my @f = split(/\s+/, $');
|
||||
my $f;
|
||||
my $in = 0; # indentation level
|
||||
while (length $indent) {
|
||||
my $c = substr($indent, 0, 1, "");
|
||||
if ($c eq " ") {
|
||||
$in++;
|
||||
} elsif ($c eq "\t") {
|
||||
$in = ($in+8) & ~7;
|
||||
} else {
|
||||
die;
|
||||
}
|
||||
}
|
||||
if ($may_cont && $in > $last) {
|
||||
pop(@match);
|
||||
pop(@action);
|
||||
pop(@end);
|
||||
} else {
|
||||
$match_stack[0] = undef;
|
||||
$action_stack[0] = undef;
|
||||
$last_action = 0;
|
||||
$last = $in;
|
||||
}
|
||||
if (!$last_action) {
|
||||
while (@f) {
|
||||
$f = shift @f;
|
||||
last if $f eq "->" || $f eq "{" || $f eq "}" || $f eq "!";
|
||||
if ($f =~ /=/) {
|
||||
$match_stack[0]{uc($`)} = [ $', &sub_pattern(uc($`), $') ];
|
||||
} else {
|
||||
$match_stack[0]{"REF"} = [ &sub_pattern("REF", $f) ];
|
||||
}
|
||||
}
|
||||
$last_action = 1 if $f eq "->";
|
||||
}
|
||||
if ($last_action) {
|
||||
while (@f) {
|
||||
$f = shift @f;
|
||||
last if $f eq "{" || $f eq "!";
|
||||
die unless $f =~ /=/;
|
||||
$action_stack[0]{uc($`)} = &sub_value($');
|
||||
}
|
||||
}
|
||||
$may_cont = 0;
|
||||
if ($f eq "{") {
|
||||
unshift(@match_stack, undef);
|
||||
unshift(@action_stack, undef);
|
||||
die "items following {" if @f;
|
||||
} elsif ($f eq "}") {
|
||||
shift @match_stack;
|
||||
shift @action_stack;
|
||||
die "items following }" if @f;
|
||||
} else {
|
||||
die "items following !" if @f && $f eq "!";
|
||||
push(@end, $f eq "!");
|
||||
$may_cont = $f ne "!";
|
||||
my $n = $#end;
|
||||
push(@match, undef);
|
||||
push(@action, undef);
|
||||
for my $m (reverse @match_stack) {
|
||||
for (keys %{ $m }) {
|
||||
$match[$n]{$_} = $m->{$_};
|
||||
}
|
||||
}
|
||||
for my $a (reverse @action_stack) {
|
||||
for (keys %{ $a }) {
|
||||
$action[$n]{$_} = $a->{$_};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# "ord" populates the following global variables:
|
||||
#
|
||||
# $order{"namespace item-number"}[0] = quantity to order
|
||||
# $order{"namespace item-number"}[1] = currency
|
||||
# $order{"namespace item-number"}[2] = total cost in above currency
|
||||
# $order{"namespace item-number"}[3] = component reference
|
||||
# ...
|
||||
#
|
||||
|
||||
sub ord
|
||||
{
|
||||
my @f = split(/\s+/);
|
||||
my @id = splice(@f, 0, 2);
|
||||
@{ $order{"$id[0] $id[1]"} } = @f;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# "dsc" populates the following global variable:
|
||||
#
|
||||
# $dsc{"namespace item-number"} = description
|
||||
#
|
||||
|
||||
sub dsc
|
||||
{
|
||||
my @f = split(/\s+/);
|
||||
my @id = splice(@f, 0, 2);
|
||||
$dsc{"$id[0] $id[1]"} = join(" ", @f);
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# "eeschema" populates the following global variable:
|
||||
#
|
||||
# $eeschema[] = line
|
||||
#
|
||||
|
||||
|
||||
sub eeschema
|
||||
{
|
||||
push(@eeschema, $_[0]);
|
||||
if ($_[0] =~ /^\$EndSCHEMATC/) {
|
||||
$mode = *skip;
|
||||
undef $raw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub babylonic
|
||||
{
|
||||
if ($_[0] =~ /^#/) {
|
||||
$hash++;
|
||||
if ($hash == 2) {
|
||||
$mode = *skip;
|
||||
undef $raw;
|
||||
}
|
||||
return;
|
||||
}
|
||||
&bom($_[0]) if $hash == 1;
|
||||
}
|
||||
|
||||
|
||||
sub dirname
|
||||
{
|
||||
local ($name) = @_;
|
||||
|
||||
return $name =~ m|/[^/]*$| ? $` : ".";
|
||||
}
|
||||
|
||||
|
||||
sub rel_path
|
||||
{
|
||||
local ($cwd, $path) = @_;
|
||||
|
||||
return $path =~ m|^/| ? $path : "$cwd/$path";
|
||||
}
|
||||
|
||||
|
||||
sub parse_one
|
||||
{
|
||||
local ($name) = @_;
|
||||
|
||||
my $file = new IO::File->new($name) || die "$name: $!";
|
||||
my $dir = &dirname($name);
|
||||
|
||||
while (1) {
|
||||
$_ = <$file>;
|
||||
if (!defined $_) {
|
||||
$file->close();
|
||||
return unless @inc;
|
||||
$file = pop @inc;
|
||||
$dir = pop @dir;
|
||||
next;
|
||||
}
|
||||
if (/^\s*include\s+(.*?)\s*$/) {
|
||||
push(@inc, $file);
|
||||
push(@dir, $dir);
|
||||
$name = &rel_path($dir, $1);
|
||||
$dir = &dirname($name);
|
||||
$file = new IO::File->new($name) || die "$name: $!";
|
||||
next;
|
||||
}
|
||||
chop;
|
||||
|
||||
# ----- KiCad BOM parsing. Alas, the BOM is localized, so there are almost no
|
||||
# reliable clues for the parser. Below would be good clues for the English
|
||||
# version:
|
||||
if (0 && /^#Cmp.*order = Reference/) {
|
||||
$mode = *bom;
|
||||
next;
|
||||
}
|
||||
if (0 && /^#Cmp.*order = Value/) {
|
||||
$mode = *skip;
|
||||
next;
|
||||
}
|
||||
if (0 && /^eeschema \(/) { # hack to allow loading in any order
|
||||
$mode = *skip;
|
||||
next;
|
||||
}
|
||||
# ----- now an attempt at a "generic" version:
|
||||
if (/^eeschema \(/) {
|
||||
$mode = *babylonic;
|
||||
$hash = 0;
|
||||
$raw = 1;
|
||||
next;
|
||||
}
|
||||
# -----
|
||||
if (/^EESchema Schematic/) {
|
||||
$mode = *eeschema;
|
||||
$raw = 1;
|
||||
die "only one schematic allowed" if defined @eeschema;
|
||||
&eeschema($_);
|
||||
next;
|
||||
}
|
||||
if (/^#EQU\b/) {
|
||||
$mode = *equ;
|
||||
next;
|
||||
}
|
||||
if (/^#INV\b/) {
|
||||
$mode = *inv;
|
||||
next;
|
||||
}
|
||||
if (/^#PAR\b/) {
|
||||
$mode = *par;
|
||||
next;
|
||||
}
|
||||
if (/^#CHR\b/) {
|
||||
$mode = *chr;
|
||||
undef $last;
|
||||
next;
|
||||
}
|
||||
if (/^#(SUB|GEN)\b/) {
|
||||
$mode = *sub;
|
||||
undef $last;
|
||||
undef $last_action;
|
||||
undef $may_cont;
|
||||
next;
|
||||
}
|
||||
if (/^#ORD\b/) {
|
||||
$mode = *ord;
|
||||
next;
|
||||
}
|
||||
if (/^#DSC\b/) {
|
||||
$mode = *dsc;
|
||||
next;
|
||||
}
|
||||
if (/^#END\b\(/) { # for commenting things out
|
||||
$mode = *skip;
|
||||
next;
|
||||
}
|
||||
if (!$raw) {
|
||||
s/#.*//;
|
||||
next if /^\s*$/;
|
||||
}
|
||||
&$mode($_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub parse
|
||||
{
|
||||
$mode = *skip;
|
||||
for (@ARGV) {
|
||||
&parse_one($_);
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# in case user calls directly &parse_one and not &parse
|
||||
#
|
||||
$mode = *skip;
|
||||
|
||||
return 1;
|
133
old-boom/part2order
Executable file
133
old-boom/part2order
Executable file
@ -0,0 +1,133 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
require "parser.pl";
|
||||
require "misc.pl";
|
||||
|
||||
$mult = shift(@ARGV);
|
||||
&parse;
|
||||
|
||||
|
||||
sub number
|
||||
{
|
||||
local ($id) = @_;
|
||||
|
||||
my $s = $inv{$id}[0];
|
||||
my $n = $want{$id}*$mult;
|
||||
return $n < $s ? $n : $s;
|
||||
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# The heuristics here aren't very nice. We give zero-cost stock priority over
|
||||
# any other stock, when we go by stock size up to the quantity we need. The
|
||||
# idea is to exhause local stock (zero-cost) first, then try to obtain the
|
||||
# parts with as few orders as possible.
|
||||
#
|
||||
# It would be better to have some sort of priority, so that we can express a
|
||||
# preference among stock we already own. Also, if non-zero-cost stock has widly
|
||||
# different prices, the smallest order cost may not be a good indicator of
|
||||
# which source we prefer.
|
||||
#
|
||||
# Furthermore, the algorithm doesn't consider the number of sources we use in
|
||||
# total or things like lead time, shipping cost, customs, etc.
|
||||
#
|
||||
|
||||
sub rank
|
||||
{
|
||||
local ($a, $b) = @_;
|
||||
|
||||
my $na = &number($a); # min(number wanted, available)
|
||||
my $nb = &number($b);
|
||||
my $pa = $inv{$a}[3]; # per unit price for smallest quantum
|
||||
my $pb = $inv{$b}[3];
|
||||
|
||||
#print STDERR "a=$a b=$b na=$na nb=$nb pa=$pa pb=$pb\n";
|
||||
return 1 if $na && !$pa && $pb;
|
||||
return -1 if $nb && $pa && !$pb;
|
||||
return $na <=> $nb if $na != $nb;
|
||||
return $pb <=> $pa;
|
||||
}
|
||||
|
||||
|
||||
for (keys %parts) {
|
||||
$parts++;
|
||||
}
|
||||
|
||||
print "#ORD\n";
|
||||
for (sort { &rank($b, $a) } keys %want) {
|
||||
my $n = &number($_);
|
||||
$n -= $n % $mult;
|
||||
next unless $n;
|
||||
my @f = @{ $inv{$_} };
|
||||
my $max = shift @f;
|
||||
my $currency = shift @f;
|
||||
my @qty;
|
||||
my @price;
|
||||
my %index;
|
||||
my $best_qty;
|
||||
my $best_price = undef;
|
||||
while (@f) {
|
||||
my $q = shift @f;
|
||||
my $p = shift @f;
|
||||
if (defined $index{$q}) {
|
||||
$price[$index{$q}] = $p;
|
||||
} else {
|
||||
push(@qty, $q);
|
||||
push(@price, $p);
|
||||
$index{$q} = $#qty;
|
||||
# @@@ this fails if smaller quantities following a large quantity
|
||||
# differ from the quantities preceding them. E.g., 1 10 100 25
|
||||
# wouldn't yield correct results.
|
||||
}
|
||||
for (my $i = $#qty; $i >= 0; $i--) {
|
||||
my $order = 0;
|
||||
my $price = 0;
|
||||
my $left = $n;
|
||||
for (my $j = $#qty; $j >= $i; $j--) {
|
||||
while ($left >= ($j == $i ? 1 : $qty[$j])) {
|
||||
$left -= $qty[$j];
|
||||
$order += $qty[$j];
|
||||
$price += $price[$j]*$qty[$j];
|
||||
}
|
||||
}
|
||||
next if $order > $max;
|
||||
if (!defined $best_price || $price < $best_price) {
|
||||
$best_price = $price;
|
||||
$best_qty = $order;
|
||||
}
|
||||
}
|
||||
}
|
||||
next if !defined $best_price;
|
||||
print "$_ $best_qty $currency $best_price";
|
||||
my $id = $_;
|
||||
while (keys %{ $comps{$id} }) {
|
||||
last if $best_qty < $mult;
|
||||
$best_qty -= $mult;
|
||||
my $ref = (sort { &cmp_cref($a, $b); } keys %{ $comps{$id} })[0];
|
||||
#print STDERR "$id: $ref + ", join("|", keys %{ $comps{$id} }), "\n";
|
||||
my @f = @{ $parts{$ref} };
|
||||
while (@f) {
|
||||
my @id2 = splice(@f, 0, 2);
|
||||
my $id2 = "$id2[0] $id2[1]";
|
||||
$want{$id2}--;
|
||||
delete $comps{$id2}{$ref};
|
||||
}
|
||||
print " $ref";
|
||||
}
|
||||
print "\n";
|
||||
}
|
||||
|
||||
for my $id (sort { $want{$b} <=> $want{$a} } keys %want) {
|
||||
next unless $want{$id};
|
||||
print STDERR "$id";
|
||||
for (&eq($id)) {
|
||||
# next unless $want{$_};
|
||||
die "\n$_ ($want{$_}) vs. $id want ($want{$id})"
|
||||
unless $want{$_} == $want{$id};
|
||||
print STDERR " $_";
|
||||
$want{$_} = 0;
|
||||
}
|
||||
print STDERR ": want $want{$id}\n";
|
||||
$want{$id} = 0;
|
||||
}
|
131
old-boom/prettyord
Executable file
131
old-boom/prettyord
Executable file
@ -0,0 +1,131 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
require "parser.pl";
|
||||
require "misc.pl";
|
||||
|
||||
|
||||
sub usage
|
||||
{
|
||||
print STDERR <<"END";
|
||||
usage: $0 [-c] [-f|-t] [-r] [-s/from/to/ ...] ...
|
||||
|
||||
-c generate CSV output (default: generate formatted text)
|
||||
-f generate SMT fab output (default: generate shopping list)
|
||||
-r sort by component reference (default: sort by part number)
|
||||
-s/from/to/ substitute description and treat result as reference
|
||||
-t print the total number of items and the total cost.
|
||||
-t cannot be combined with -c or -f.
|
||||
END
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$shop = 1;
|
||||
$by_pn = 1;
|
||||
while ($ARGV[0] =~ /^-./) {
|
||||
if ($ARGV[0] =~ /^-s/) {
|
||||
&usage unless &dsc_xlat_arg($');
|
||||
} elsif ($ARGV[0] eq "-c") {
|
||||
$csv = 1;
|
||||
} elsif ($ARGV[0] eq "-f") {
|
||||
$shop = 0;
|
||||
} elsif ($ARGV[0] eq "-r") {
|
||||
$by_pn = 0;
|
||||
} elsif ($ARGV[0] eq "-t") {
|
||||
$total = 1;
|
||||
} else {
|
||||
&usage;
|
||||
}
|
||||
shift @ARGV;
|
||||
}
|
||||
|
||||
&usage if $total && !$shop;
|
||||
&usage if $total && $csv;
|
||||
|
||||
&parse;
|
||||
|
||||
$out[0][0] = "Pos";
|
||||
$out[1][0] = "Qty";
|
||||
$out[2][0] = "P/N";
|
||||
$out[3][0] = "Description";
|
||||
|
||||
if ($shop) {
|
||||
$out[4][0] = "Value";
|
||||
$out[5][0] = "";
|
||||
} else {
|
||||
$out[4][0] = "Ref";
|
||||
}
|
||||
|
||||
for (sort { $by_pn ? $a cmp $b : &cmp_cref($order{$a}[3], $order{$b}[3]) }
|
||||
keys %order) {
|
||||
push(@{ $out[0] }, ++$n);
|
||||
push(@{ $out[1] }, $shop ? $order{$_}[0] : @{ $order{$_} }-3);
|
||||
@f = split(/\s+/, $_);
|
||||
push(@{ $out[2] }, $shop ? $f[1] : "$f[0] $f[1]");
|
||||
my $dsc = &dsc_find($_);
|
||||
print STDERR "$_: no description\n" unless defined $dsc;
|
||||
push(@{ $out[3] }, defined $dsc ? $dsc : "???");
|
||||
if ($shop) {
|
||||
push(@{ $out[4] }, $order{$_}[1]);
|
||||
push(@{ $out[5] }, sprintf("%.2f", $order{$_}[2]));
|
||||
$price{$order{$_}[1]} += $order{$_}[2];
|
||||
} else {
|
||||
my @r = @{ $order{$_} };
|
||||
push(@{ $out[4] }, join(", ", @r[3..$#r]));
|
||||
}
|
||||
}
|
||||
|
||||
if ($csv) {
|
||||
for ($i = 0; $i <= $#{ $out[0] }; $i++) {
|
||||
for ($j = 0; $j <= $#out; $j++) {
|
||||
print "," if $j;
|
||||
if ($i && $j < 2) {
|
||||
print $out[$j][$i];
|
||||
} else {
|
||||
my $s = $out[$j][$i];
|
||||
$s =~ s/"/''/g;
|
||||
print "\"$s\"";
|
||||
}
|
||||
}
|
||||
print "\n";
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
for (@out) {
|
||||
push(@max, 0);
|
||||
if (length $_->[0]) {
|
||||
$max[$last_pos] = $last_len if defined $last_pos;
|
||||
$last_pos = $#max;
|
||||
$last_len = length $_->[0];
|
||||
}
|
||||
}
|
||||
$i = 0;
|
||||
for (@out) {
|
||||
$first = 1;
|
||||
for (@{ $_ }) {
|
||||
next if $first-- > 0;
|
||||
$max[$i] = length $_ if length $_ > $max[$i];
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
for ($i = 0; $i <= $#{ $out[0] }; $i++) {
|
||||
$l = "";
|
||||
for ($j = 0; $j != 6; $j++) {
|
||||
my $s = $out[$j][$i];;
|
||||
$l .= $s if $j == 2 || $j == 3 || $j == 4;
|
||||
$l .= " " x ($max[$j]-length $s);
|
||||
$l .= $s if $j == 0 || $j == 1 || $j == 5;
|
||||
$l .= " " unless $j == 5;
|
||||
}
|
||||
$l =~ s/\s*$//;
|
||||
print "$l\n";
|
||||
}
|
||||
|
||||
if ($total) {
|
||||
print "$n item".($n == 1 ? "" : "s");
|
||||
for (sort keys %price) {
|
||||
print ", $_ $price{$_}";
|
||||
}
|
||||
print "\n";
|
||||
}
|
45
old-boom/testsub
Executable file
45
old-boom/testsub
Executable file
@ -0,0 +1,45 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
require "parser.pl";
|
||||
require "match.pl";
|
||||
|
||||
|
||||
sub usage
|
||||
{
|
||||
print STDERR "usage: $0 [-d] file.sub|field ...\n\n";
|
||||
print STDERR " fields: ref value [footprint user-field ...]\n";
|
||||
}
|
||||
|
||||
|
||||
for (@ARGV) {
|
||||
if ($_ eq "-d") {
|
||||
$debug = 1;
|
||||
next;
|
||||
}
|
||||
&usage if /^-/;
|
||||
if (/\.sub$/) {
|
||||
&parse_one($_);
|
||||
} else {
|
||||
push(@f, $_);
|
||||
}
|
||||
}
|
||||
|
||||
&usage unless @f >= 2;
|
||||
|
||||
$field{"REF"} = shift @f;
|
||||
$field{"VAL"} = shift @f;
|
||||
$field{"FP"} = shift @f;
|
||||
|
||||
for (my $i = 1; $i != 10; $i++) {
|
||||
$field{"F$i"} = $f[$i-1];
|
||||
}
|
||||
|
||||
&apply_rules;
|
||||
|
||||
for (sort keys %field) {
|
||||
if ($field{$_} =~ / /) {
|
||||
print "$_ = \"$field{$_}\"\n";
|
||||
} else {
|
||||
print "$_ = $field{$_}\n";
|
||||
}
|
||||
}
|
147
old-boom/workflow.fig
Normal file
147
old-boom/workflow.fig
Normal file
@ -0,0 +1,147 @@
|
||||
#FIG 3.2 Produced by xfig version 3.2.5a
|
||||
Landscape
|
||||
Center
|
||||
Metric
|
||||
A4
|
||||
100.00
|
||||
Single
|
||||
-2
|
||||
1200 2
|
||||
6 450 5850 3150 6525
|
||||
4 0 0 50 -1 14 12 0.0000 4 180 2700 450 6030 Source file (in SVN)\001
|
||||
4 0 0 50 -1 12 12 0.0000 4 150 1890 450 6255 Generated file\001
|
||||
4 0 0 50 -1 18 12 0.0000 4 210 1830 450 6480 Program (in SVN)\001
|
||||
-6
|
||||
6 450 7875 6480 9000
|
||||
4 0 0 50 -1 12 12 0.0000 4 105 540 450 8055 .csv\001
|
||||
4 0 0 50 -1 12 12 0.0000 4 150 540 450 8280 .inv\001
|
||||
4 0 0 50 -1 12 12 0.0000 4 150 540 450 8505 .equ\001
|
||||
4 0 0 50 -1 12 12 0.0000 4 150 540 450 8730 .par\001
|
||||
4 0 0 50 -1 12 12 0.0000 4 150 540 450 8955 .ord\001
|
||||
4 0 0 50 -1 1 12 0.0000 4 195 2520 1350 8280 inventory with stock and cost\001
|
||||
4 0 0 50 -1 1 12 0.0000 4 195 3045 1350 8055 GTA02 EE component stock at FIC\001
|
||||
4 0 0 50 -1 1 12 0.0000 4 195 5130 1350 8505 part number equivalences, e.g., manufacturer vs. distributor\001
|
||||
4 0 0 50 -1 1 12 0.0000 4 195 2910 1350 8730 component to part number(s) map\001
|
||||
4 0 0 50 -1 1 12 0.0000 4 195 5025 1350 8955 list of parts to order, with price and component references\001
|
||||
-6
|
||||
6 450 7425 3465 7875
|
||||
4 0 0 50 -1 12 12 0.0000 4 150 540 450 7605 .chr\001
|
||||
4 0 0 50 -1 12 12 0.0000 4 150 540 450 7830 .sub\001
|
||||
4 0 0 50 -1 1 12 0.0000 4 195 1695 1350 7605 part characteristics\001
|
||||
4 0 0 50 -1 1 12 0.0000 4 195 2085 1350 7830 parameter substitutions\001
|
||||
-6
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 4
|
||||
1 1 2.00 60.00 60.00
|
||||
7875 2700 7875 2925 6525 2925 6525 4725
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 4
|
||||
1 1 2.00 60.00 60.00
|
||||
9000 2700 9000 5850 6525 5850 6525 6075
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 4
|
||||
1 1 2.00 60.00 60.00
|
||||
3150 1350 3150 5850 6075 5850 6075 6075
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
|
||||
1 1 2.00 60.00 60.00
|
||||
6300 2700 6300 4725
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
|
||||
1 1 2.00 60.00 60.00
|
||||
6300 2025 6300 2475
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
|
||||
1 1 2.00 60.00 60.00
|
||||
6300 1350 6300 1800
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 4
|
||||
1 1 2.00 60.00 60.00
|
||||
4950 1350 4950 4275 6075 4275 6075 4725
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 3
|
||||
1 1 2.00 60.00 60.00
|
||||
3150 4500 5850 4500 5850 4725
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 4
|
||||
1 1 2.00 60.00 60.00
|
||||
8100 4275 8100 4500 6750 4500 6750 4725
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 0 0 3
|
||||
11700 1575 11700 3150 10170 3150
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
|
||||
1 1 2.00 60.00 60.00
|
||||
6300 4950 6300 5400
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
|
||||
1 1 2.00 60.00 60.00
|
||||
6300 5625 6300 6075
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
|
||||
1 1 2.00 60.00 60.00
|
||||
6300 6300 6300 6750
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
|
||||
1 1 2.00 60.00 60.00
|
||||
6300 6975 6300 7425
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
|
||||
1 1 2.00 60.00 60.00
|
||||
6525 7650 6525 8100
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
|
||||
1 1 2.00 60.00 60.00
|
||||
9000 1350 9000 1800
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 3
|
||||
1 1 2.00 60.00 60.00
|
||||
9000 1575 7875 1575 7875 1800
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 3
|
||||
1 1 2.00 60.00 60.00
|
||||
9000 1575 10125 1575 10125 1800
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
|
||||
1 1 2.00 60.00 60.00
|
||||
7875 2025 7875 2475
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
|
||||
1 1 2.00 60.00 60.00
|
||||
9000 2025 9000 2475
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
|
||||
1 1 2.00 60.00 60.00
|
||||
7875 2925 7875 3375
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 3
|
||||
1 1 2.00 60.00 60.00
|
||||
8955 3150 8325 3150 8325 3375
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
|
||||
1 1 2.00 60.00 60.00
|
||||
8100 3600 8100 4050
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
|
||||
1 1 2.00 60.00 60.00
|
||||
10125 2025 10125 2475
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 4
|
||||
1 1 2.00 60.00 60.00
|
||||
10125 2700 10125 7200 6750 7200 6750 7425
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
|
||||
1 1 2.00 60.00 60.00
|
||||
8955 4500 8100 4500
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
9045 3150 10080 3150
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 0 0 3
|
||||
11700 4050 11700 4500 10170 4500
|
||||
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||
10080 4500 9045 4500
|
||||
4 0 0 50 -1 2 16 0.0000 4 255 3345 450 675 BOM Processing - Workflow\001
|
||||
4 1 0 50 -1 12 12 0.0000 4 195 1890 6300 2655 gta02-core.lst\001
|
||||
4 1 0 50 -1 18 12 0.0000 4 165 1035 6300 1980 eeschema\001
|
||||
4 1 0 50 -1 14 12 0.0000 4 150 675 6300 1305 *.sch\001
|
||||
4 1 0 50 -1 18 12 0.0000 4 210 990 6300 4905 bom2part\001
|
||||
4 1 0 50 -1 18 12 0.0000 4 210 1110 6300 6255 part2order\001
|
||||
4 1 0 50 -1 12 12 0.0000 4 195 1890 6300 6930 gta02-core.ord\001
|
||||
4 1 0 50 -1 12 12 0.0000 4 195 1890 6300 5580 gta02-core.par\001
|
||||
4 1 0 50 -1 14 12 0.0000 4 195 1890 4950 1305 gta02-core.sub\001
|
||||
4 1 0 50 -1 14 12 0.0000 4 195 1890 3105 1305 gta02-core.inv\001
|
||||
4 1 0 50 -1 18 12 0.0000 4 210 975 6525 7605 prettyord\001
|
||||
4 1 0 50 -1 18 12 0.0000 4 165 1095 7875 1980 fic2vendor\001
|
||||
4 1 0 50 -1 18 12 0.0000 4 165 675 9000 1980 fic2inv\001
|
||||
4 1 0 50 -1 18 12 0.0000 4 210 855 8100 3555 gen2chr\001
|
||||
4 1 0 50 -1 12 12 0.0000 4 150 675 8100 4230 *.chr\001
|
||||
4 1 0 50 -1 12 12 0.0000 4 195 945 7875 2655 fic.equ\001
|
||||
4 1 0 50 -1 12 12 0.0000 4 150 945 9000 2655 fic.inv\001
|
||||
4 1 0 50 -1 18 12 0.0000 4 165 735 10125 1980 fic2dsc\001
|
||||
4 1 0 50 -1 14 12 0.0000 4 195 2700 9000 1305 inventory-fic-ee.csv\001
|
||||
4 0 0 50 -1 12 12 0.0000 4 150 540 450 7155 .lst\001
|
||||
4 0 0 50 -1 1 12 0.0000 4 195 2220 1350 7155 BOM generated by KiCad\001
|
||||
4 0 0 50 -1 12 12 0.0000 4 150 540 450 6930 .sch\001
|
||||
4 0 0 50 -1 1 12 0.0000 4 195 2010 1350 6930 schematics (for KiCad)\001
|
||||
4 0 0 50 -1 12 12 0.0000 4 150 540 450 7380 .gen\001
|
||||
4 0 0 50 -1 1 12 0.0000 4 195 2745 1350 7380 characteristics generation rules\001
|
||||
4 0 0 50 -1 12 12 0.0000 4 150 540 450 9180 .dsc\001
|
||||
4 0 0 50 -1 1 12 0.0000 4 195 2685 1350 9180 Textual component description\001
|
||||
4 1 0 50 -1 14 12 0.0000 4 180 675 11700 1305 *.gen\001
|
||||
4 1 0 50 -1 14 12 0.0000 4 150 675 11700 3780 *.chr\001
|
||||
4 1 0 50 -1 14 9 0.0000 4 135 1440 11700 4005 (acx, misc, ...)\001
|
||||
4 1 0 50 -1 14 9 0.0000 4 135 1800 11700 1530 (darfon, ralec, ...)\001
|
||||
4 1 0 50 -1 12 12 0.0000 4 150 945 10125 2655 fic.dsc\001
|
Loading…
Reference in New Issue
Block a user