# stdf4_to_xtdf1.pl
# Copyright (C) 2005 Michael Hackerott. All Rights Reserved
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of either the GNU General Public License or the Artistic
# License as specified in the Perl README file.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER
# OR CONTRIBUTORS 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.
#
# This module is documented using POD in-line with the perl code and
# is extracted using the pod2html utility:
#
# pod2html --infile=stdf4_to_xtdf1.pl --outfile=stdf4_to_xtdf1.html
=pod
=head1 NAME
stdf4_to_xtdf1.pl - Converts an STDF version 4 file to an XTDF version 1
file
=head1 SYNTAX
perl stdf4_to_xtdf1.pl [OPTIONS] ARGUMENTS
OPTIONS
-a, --about
Displays information about this program.
-d, --debug
Enables debug mode which outputs debug information to
standard output.
-h, --help
Displays help for this program.
ARGUMENTS
StdfFileSpec
The input STDF file specification.
RETURNS
The program returns a value of unix true (0) if no errors
occur; otherwise, a value of unix false (1) is returned.
STANDARD INPUT
Standard input is ignored.
STANDARD OUTPUT
All output is sent to standard output.
STANDARD ERROR
If an error occurs then a message is output to standard error.
=head1 SYNOPSIS
perl stdf4_to_xtdf1.pl -a
perl stdf4_to_xtdf1.pl --about
Displays information about the program.
perl stdf4_to_xtdf1.pl -h
perl stdf4_to_xtdf1.pl --help
Displays the help for the program.
perl stdf4_to_xtdf1.pl StdfFileSpec
Surveys the STDF file specified by StdfFileSpec and outputs
the survey results to standard output.
perl stdf4_to_xtdf1.pl -d StdfFileSpec
perl stdf4_to_xtdf1.pl --debug StdfFileSpec
Surveys the STDF file specified by StdfFileSpec and outputs
the survey results and debug information to standard output.
NOTE: Use command line redirection to capture standard
output to a file.
=head1 DESCRIPTION
This program converts an STDF version 4 file to an XTDF version 1 file.
An XTDF file is an XML version of a binary STDF file. The STDF field
names and data types are emulated using XML as closely as possible to
preserve the STDF file structure and content.
Advantages of XTDF compared to STDF:
+ Compatible with standard XML utilities.
+ Easy to enhance and extend contents.
+ Platform independent ASCII.
+ Easy to read.
+ Easy to edit.
Disadvatages of XTDF compared to STDF:
- Larger file size.
The official ASCII format for a binary STDF file is the ASCII Test
Data Format (ATDF) defined by Teradyne.
Advantages of XTDF compared to ATDF:
+ Preserves all STDF content (enables loss less conversion back to STDF).
+ Compatible with standard XML utilities.
+ Same syntax as STDF (ATDF has different syntax than STDF).
+ Easy to enhance and extend the syntax.
Disadvatages of XTDF compared to ATDF:
- Larger file size.
=head2 Default Output
The default output consists of the XTDF tags and data.
11:20:07 06-DEC-2005
FT_J750_112KB.stdf
113756
2
4
17:12:18 02-NOV-2005
17:12:18 02-NOV-2005
0
P
Y
65535
TJMEA0360Y00
MC9S08GT60CFD
J750-08
J750
Final_Test_44qfp
9S08GB60_J05
HR268
IG-XL
3.40.09
FCN
-40
MC9S08GT60CFD
TJN
L31R
20
MC9S08GT60CFD_FCN
9999
...
18:12:44 02-NOV-2005
0
=head2 Additional Debug Output
If the debug mode is enabled then debug information is output in
addition to the default XTDF output. (NOTE: debug mode increases the
runtime time and amount of output by approximately 15 to 25 times!)
%gOptions = ('debug' => 1);
$gStdfFile{'SPEC'} = '..\\data\\inp\\STDF\\FT_J750_112KB.stdf';
$gStdfFile{'PATH'} = '..\\data\\inp\\STDF';
$gStdfFile{'NAME'} = 'FT_J750_112KB.stdf';
$gStdfFile{'SIZE'} = 113756;
11:39:05 06-DEC-2005
FT_J750_112KB.stdf
113756
$gStdfFile{'ABO'} = 0;
$gStdfRec{'LENBIN'} =
0000 00000010 02 2 ¤
0001 00000000 00 0 ¤
$stdfRecordRead::status = 2;
$gStdfRec{'LENHEX'} = '0200';
$gStdfFile{'ENDIAN'} = 1;
$stdfRecordRead::lenhex = '0002';
$gStdfRec{'LENDEC'} = '2';
$gStdfRec{'TYPBIN'} =
0000 00000000 00 0 ¤
$gStdfRec{'TYPHEX'} = '0';
$gStdfRec{'TYPDEC'} = 0;
$gStdfRec{'SUBBIN'} =
0000 00001010 0A 10 ¤
$gStdfRec{'SUBHEX'} = '0';
$gStdfRec{'SUBDEC'} = 10;
$gStdfRecName = 'FAR';
$gStdfRec{'DATBIN'} =
0000 00000010 02 2 ¤
0001 00000100 04 4 ¤
$gStdfRec{'DATHEX'} = '0204';
$gStdfRec{'DATTXT'} = '°°';
$gStdfFld{'LEN'} = 1
$gStdfRec{'ABO'} = 0
$gStdfFld{'BIN'} =
$gStdfFld{'HEX'} = 02
$gStdfFld{'DAT'} = 2
$gStdfFld{'LEN'} = 1
$gStdfRec{'ABO'} = 1
$gStdfFld{'BIN'} =
$gStdfFld{'HEX'} = 04
$gStdfFld{'DAT'} = 4
2
4
$gStdfFile{'ABO'} = 6;
$gStdfRec{'LENBIN'} =
0000 10101010 AA 170 ¤
0001 00000000 00 0 ¤
$stdfRecordRead::status = 2;
$gStdfRec{'LENHEX'} = 'AA00';
$stdfRecordRead::lenhex = '00AA';
$gStdfRec{'LENDEC'} = '170';
$gStdfRec{'TYPBIN'} =
0000 00000001 01 1 ¤
$gStdfRec{'TYPHEX'} = '0';
$gStdfRec{'TYPDEC'} = 1;
$gStdfRec{'SUBBIN'} =
0000 00001010 0A 10 ¤
$gStdfRec{'SUBHEX'} = '0';
$gStdfRec{'SUBDEC'} = 10;
$gStdfRecName = 'MIR';
...
$gStdfFld{'LEN'} = 4
$gStdfRec{'ABO'} = 0
$gStdfFld{'BIN'} = œiC
$gStdfFld{'HEX'} = 9C016943
$gStdfFld{'DAT'} = 1130955164
$gStdfFld{'LEN'} = 1
$gStdfRec{'ABO'} = 4
$gStdfFld{'BIN'} =
$gStdfFld{'HEX'} =
$gStdfFld{'DAT'} =
18:12:44 02-NOV-2005
0
=cut
BEGIN
{
unshift(
@INC,
'lib',
'../lib'
);
};
use TDF;
use File::Basename;
use strict;
######################################################################
# PROGRAM CONSTANT DECLARATIONS
######################################################################
# set the program name
my $PROGRAM = 'stdf4_to_xtdf1.pl';
# set the version number
my $VERSION = '1.0.0';
use constant TRUE => 1;
use constant FALSE => 0;
use constant EOL => "\n";
use constant Q1 => "\'";
use constant Q2 => "\"";
use constant SPC => "\ ";
use constant TAB => "\t";
use constant ENDIAN_LITTLE => 0;
use constant ENDIAN_BIG => 1;
my %STDF_TO_ATDF_RECORD_SUBREF = (
'ATR' => \&ATR,
'BPS' => \&BPS,
'DTR' => \&DTR,
'EPS' => \&EPS,
'FAR' => \&FAR,
'FTR' => \&FTR,
'GDR' => \&GDR,
'HBR' => \&HBR,
'MIR' => \&MIR,
'MPR' => \&MPR,
'MRR' => \&MRR,
'PCR' => \&PCR,
'PGR' => \&PGR,
'PIR' => \&PIR,
'PLR' => \&PLR,
'PMR' => \&PMR,
'PRR' => \&PRR,
'PTR' => \&PTR,
'RDR' => \&RDR,
'SBR' => \&SBR,
'SDR' => \&SDR,
'TSR' => \&TSR,
'WCR' => \&WCR,
'WIR' => \&WIR,
'WRR' => \&WRR,
);
######################################################################
# PROGRAM VARIABLE DECLARATIONS
######################################################################
my @gTimer = (time());
my %gEndian = (
'STDF' => undef,
'XTDF' => endianRuntime(),
);
my %gOptions = (
'debug' => FALSE
);
# STDF File Data
my %gStdfFile = (
'ABO' => 0,
'RECNUM' => 0,
'PATH' => 0,
'NAME' => 0,
'SPEC' => 0,
);
# STDF Record Data
my %gStdfRec = (
'ABO' => undef,
'NAME' => undef,
);
# STDF Field Data
my %gStdfFld = (
'LEN' => undef,
'BIN' => undef,
'HEX' => undef,
'DEC' => undef,
'DAT' => undef,
);
my @gXML = ();
######################################################################
# MODULE MACRO DECLARATIONS
######################################################################
sub q1 {return(Q1.join(SPC, @_).Q1)};
sub q2 {return(Q2.join(SPC, @_).Q2)};
######################################################################
# MAIN
######################################################################
# enable autoflush
$| = TRUE;
# process the unix command line options
while ($ARGV[0] =~ m/^\-/)
{
my $option = shift(@ARGV);
if ($option =~ m/^\-(a|\-about)/)
{
about();
}
elsif ($option =~ m/^\-(d|\-debug)/)
{
$gOptions{'debug'} = TRUE;
}
elsif ($option =~ m/^\-(h|\-help)/)
{
help();
}
elsif ($option =~ m/^\-(l|\-log)/)
{
$gOptions{'log'} = TRUE;
};
};
dbugData([\%gOptions], ['*gOptions']);
# get the ATDF file specification
$gStdfFile{'SPEC'} = shift(@ARGV);
if ($gStdfFile{'SPEC'} eq '')
{
fatal('STDF file specification is not defined!');
}
elsif (! -f $gStdfFile{'SPEC'})
{
fatal(
'STDF file does not exist:',
$gStdfFile{'SPEC'}
);
};
dbugData([$gStdfFile{'SPEC'}], ["*gStdfFile{'SPEC'}"]);
$gStdfFile{'PATH'} = dirname($gStdfFile{'SPEC'});
dbugData([$gStdfFile{'PATH'}], ["*gStdfFile{'PATH'}"]);
$gStdfFile{'NAME'} = basename($gStdfFile{'SPEC'});
dbugData([$gStdfFile{'NAME'}], ["*gStdfFile{'NAME'}"]);
$gStdfFile{'SIZE'} = (-s $gStdfFile{'SPEC'});
dbugData([$gStdfFile{'SIZE'}], ["*gStdfFile{'SIZE'}"]);
# open the STDF file for read as binary
if (! open(FILE_STDF, '<'.$gStdfFile{'SPEC'}))
{
fatal(
'Failed to open for read STDF file:',
$gStdfFile{'SPEC'}
);
};
binmode(FILE_STDF);
@gXML = (
"",
xmlComment($PROGRAM, 'V'.$VERSION),
xmlComment('Copyright (C) 2005 Michael Hackerott'),
xmlComment('All Rights Reserved'),
xmlTagBgn('XTDF'),
xmlTag('CREATED', {}, secondsToDateTime($gTimer[0])),
xmlTag('FILENAME', {'TYPE' => 'INPUT'}, $gStdfFile{'NAME'}),
xmlTag(
'FILESIZE',
{'TYPE' => 'INPUT', 'UNIT' => 'BYTES'},
$gStdfFile{'SIZE'}
),
xmlTagBgn('STDF')
);
xtdfPrintList(@gXML);
#
# READ THE FIRST RECORD IN THE STDF FILE AND TEST TO
# VALIDATE THAT IT IS AN FAR RECORD
#
# read the first STDF record
stdfRecordRead();
# process the first STDF record
xtdfPrintLine(xmlTagBgn($gStdfRec{'NAME'}));
FAR();
xtdfPrintLine(xmlTagEnd($gStdfRec{'NAME'}));
#
# PROCESS THE REST OF THE STDF FILE RECORDS
#
# read the STDF file
while (! eof(FILE_STDF))
{
# read the next STDF record
stdfRecordRead();
# test the STDF record name
if ($gStdfRec{'NAME'} ne '')
{
# convert the STDF record data fields to ATDF
xtdfPrintLine(xmlTagBgn($gStdfRec{'NAME'}));
$STDF_TO_ATDF_RECORD_SUBREF{$gStdfRec{'NAME'}}->();
xtdfPrintLine(xmlTagEnd($gStdfRec{'NAME'}));
};
};
# close the STDF file
close(FILE_STDF);
push(@gTimer, time());
# calculate the elapsed seconds
$gTimer[2] = $gTimer[1] - $gTimer[1];
@gXML = (
xmlTagEnd('STDF'),
xmlTag(
'ELAPSED',
{'UNIT' => 'SECONDS'},
$gTimer[2]
),
xmlTagEnd('XTDF')
);
xtdfPrintList(@gXML);
# exit to unix without error
exit(0);
######################################################################
# SUBROUTINES
######################################################################
# about()
sub about
{
TDF::about($PROGRAM, $VERSION)
};
# $status = dbugEnabled()
sub dbugEnabled
{
return($gOptions{'debug'});
};
# dbugData(dbugData(\@varRefs, \@varNames))
sub dbugData
{
dbugEnabled() && TDF::dbugData(@_);
};
# dbugDataBin($datnam, $bindat)
sub dbugDataBin
{
dbugEnabled() && TDF::dbugDataBin(@_);
};
# dbugDataPurdy(\@varRefs, \@varNames)
sub dbugDataPurdy
{
dbugEnabled() && TDF::dbugDataPurdy(@_);
};
# dbugSub($subname, @_)
sub dbugSub
{
dbugEnabled() && TDF::dbugSub(@_);
};
# dbugText(@text)
sub dbugText
{
dbugEnabled() && TDF::dbugText(@_);
};
# help()
sub help
{
print <<"END_HELP";
SEE ALSO
The program documentation for additional information.
END_HELP
# exit to unix without error
exit(0);
};
# endianReverse(\$bytes)
sub endianReverse
{
my $rsBytes = shift();
if ((length(${$rsBytes}) > 1) && ($gEndian{'STDF'} != $gEndian{'XTDF'}))
{
${$rsBytes} = join('', reverse(split(//, ${$rsBytes})));
};
};
# $endianCode = endianRuntime()
sub endianRuntime
{
my $testBytes = join(' ',
map { sprintf "%#02x", $_ } unpack("C*", pack("L", 0x12345678))
);
if ($testBytes eq '0x12 0x34 0x56 0x78')
{
return(1); # BIG
};
return(0); # LITTLE
};
# $status = scrubNonPrintChars(\$text)
#
# WARNING: this subroutine modifies the text value in place replacing
# the original contents with the scrubbed contents!
sub scrubNonPrintChars
{
# get subroutine argument(s)
my $rsText = shift();
# define local variables
my $i = undef; # current record index
my $n = undef; # number of records in the list
my $statusBS = FALSE; # backspace status: default is not scrubbed
my $statusNP = FALSE; # non-print status: default is not scrubbed
# convert the text string to a list of characters
my @text = split(//, ${$rsText});
# get the index of the last element in the list
$n = $#text;
# scrub each record in the list
for $i (0 .. $n)
{
# process the special case 'backspace' character where
# not only the non-printing backspace character must be
# deleted but also the character preceeding the backspace
# character.
while ($text[$i] =~ s/(.\x08){1}/\xB0/) {$statusBS = 1;};
# test if the scalar contains: NUL, SOH, STX,
# ETX, EOT, ENQ, ACK, BEL, BS, VT, FF, SO, SI, DLE, DC1, DC2, DC3
# DC4, NAK, SYN, ETB, CAN, EM, SUB, ESC, FS, GS, RS, US, or any
# ASCII character in the range of hex 7F to FF and delete them.
#$statusNP = ($text[$i] =~ s/[\x00-\x07\x0B-\x0C\x0E-\x1F\x7F-\xFF]/\xB0/g);
$statusNP = ($text[$i] =~ s/[\x00-\x20\x7F-\xFF]/\xB0/g);
};
# set the text to the scrubbed value
${$rsText} = join('', @text);
# return scrub status
return($statusBS || $statusNP);
};
# stdfParseFldB1()
sub stdfParseFldB1
{
stdfRecToFld(1, 'B*');
return($gStdfFld{'DAT'});
};
# stdfParseFldBn()
sub stdfParseFldBn
{
stdfRecToFld(stdfParseFldU1(), 'B*');
return($gStdfFld{'DAT'});
};
# stdfParseFldC1()
sub stdfParseFldC1
{
stdfRecToFld(1, 'A*');
return($gStdfFld{'DAT'});
};
# stdfParseFldCn()
sub stdfParseFldCn
{
stdfRecToFld(stdfParseFldU1(), 'A*');
return($gStdfFld{'DAT'});
};
# stdfParseFldDn()
sub stdfParseFldDn
{
my $bitCnt = stdfParseFldU2();
dbugData([$bitCnt], ['*stdfParseFldDn::bitCnt']);
my $bytCnt = int($bitCnt / 8) + ($bitCnt % 8);
dbugData([$bytCnt], ['*stdfParseFldDn::bytCnt']);
stdfRecToFld($bytCnt, 'B*');
return($gStdfFld{'DAT'});
};
# stdfParseFldI1()
sub stdfParseFldI1
{
stdfRecToFld(1, 'C');
return($gStdfFld{'DAT'});
};
# stdfParseFldI2()
sub stdfParseFldI2
{
stdfRecToFld(2, 's*');
return($gStdfFld{'DAT'});
};
# stdfParseFldI4()
sub stdfParseFldI4
{
stdfRecToFld(4, 'i*');
return($gStdfFld{'DAT'});
};
# stdfParseFldN1()
sub stdfParseFldN1
{
stdfRecToFld(1, 'H*');
return('0x'.uc($gStdfFld{'DAT'}));
};
# stdfParseFldR4()
sub stdfParseFldR4
{
stdfRecToFld(4, 'f*');
return($gStdfFld{'DAT'});
};
# stdfParseFldU1()
sub stdfParseFldU1
{
stdfRecToFld(1, 'C');
return($gStdfFld{'DAT'});
};
# stdfParseFldU2()
sub stdfParseFldU2
{
stdfRecToFld(2, 'S*');
return($gStdfFld{'DAT'});
};
# stdfParseFldU4()
sub stdfParseFldU4
{
stdfRecToFld(4, 'L*');
return($gStdfFld{'DAT'});
};
# stdfParseFldVn($fldCnt)
sub stdfParseFldVn
{
my $fldCnt = shift();
my $fldNum = undef;
for $fldNum (1 .. $fldCnt)
{
my $typCod = stdfParseFldU1();
if ($typCod == 0) # B0
{
}
elsif ($typCod == 1) # U1
{
}
elsif ($typCod == 2) # U2
{
}
elsif ($typCod == 3) # U4
{
}
elsif ($typCod == 4) # I1
{
}
elsif ($typCod == 5) # I2
{
}
elsif ($typCod == 6) # I4
{
}
elsif ($typCod == 7) # R4
{
}
elsif ($typCod == 8) # R8
{
}
elsif ($typCod == 10) # Cn
{
}
elsif ($typCod == 11) # Bn
{
}
elsif ($typCod == 12) # Dn
{
}
elsif ($typCod == 13) # N1
{
};
};
};
# stdfRecToFld($fldLenInBytes)
sub stdfRecToFld
{
%gStdfFld = (
'LEN' => shift(),
'TMP' => shift(),
'BIN' => undef,
'HEX' => undef,
'DAT' => undef,
);
if ($gStdfRec{'ABO'} <= $gStdfRec{'LENDEC'})
{
dbugText("\$gStdfFld{'LEN'}", '=', $gStdfFld{'LEN'});
dbugText("\$gStdfRec{'ABO'}", '=', $gStdfRec{'ABO'});
$gStdfFld{'BIN'} = substr(
$gStdfRec{'DATBIN'},
$gStdfRec{'ABO'},
$gStdfFld{'LEN'},
);
dbugText("\$gStdfFld{'BIN'}", '=', $gStdfFld{'BIN'});
endianReverse(\$gStdfFld{'BIN'});
$gStdfFld{'HEX'} = uc(unpack(
'H*',
$gStdfFld{'BIN'}
));
dbugText("\$gStdfFld{'HEX'}", '=', $gStdfFld{'HEX'});
$gStdfFld{'DAT'} = unpack($gStdfFld{'TMP'}, $gStdfFld{'BIN'});
dbugText("\$gStdfFld{'DAT'}", '=', $gStdfFld{'DAT'});
};
$gStdfRec{'ABO'} += $gStdfFld{'LEN'};
};
# stdfRecordRead()
sub stdfRecordRead
{
# declare local variables
%gStdfRec = (
'ABO' => 0,
);
# get the STDF file byte offset
$gStdfFile{'ABO'} = tell(FILE_STDF);
dbugData([$gStdfFile{'ABO'}], ["*gStdfFile{'ABO'}"]);
# read REC_LEN U*2
my $status = read(FILE_STDF, $gStdfRec{'LENBIN'}, 2);
dbugDataBin("\$gStdfRec{'LENBIN'}", $gStdfRec{'LENBIN'});
dbugData([$status], ['*stdfRecordRead::status']);
# unpack REC_LEN U*2 as hex
$gStdfRec{'LENHEX'} = uc(unpack('H4', $gStdfRec{'LENBIN'}));
dbugData([$gStdfRec{'LENHEX'}], ["\$gStdfRec{'LENHEX'}"]);
# test for first record in file
if ($gStdfFile{'ABO'} == 0)
{
# determine endian
$gStdfFile{'ENDIAN'} = 0; # LITTLE
if ($gStdfRec{'LENHEX'} eq '0200')
{
$gStdfFile{'ENDIAN'} = 1; # BIG
};
dbugData([$gStdfFile{'ENDIAN'}], ["\$gStdfFile{'ENDIAN'}"]);
};
# unpack REC_LEN U*1 as dec
my $lenhex = $gStdfRec{'LENHEX'};
if ($gStdfFile{'ENDIAN'} == 1) # BIG ENDIAN
{
$lenhex = substr($lenhex, 2, 2).substr($lenhex, 0, 2);
};
dbugData([$lenhex], ['$stdfRecordRead::lenhex']);
$gStdfRec{'LENDEC'} = hex('0x'.$lenhex);
dbugData([$gStdfRec{'LENDEC'}], ["\$gStdfRec{'LENDEC'}"]);
# read REC_TYP U*1
read(FILE_STDF, $gStdfRec{'TYPBIN'}, 1);
dbugDataBin("\$gStdfRec{'TYPBIN'}", $gStdfRec{'TYPBIN'});
# unpack REC_TYP U*1 as hex
$gStdfRec{'TYPHEX'} = uc(unpack('H1', $gStdfRec{'TYPBIN'}));
dbugData([$gStdfRec{'TYPHEX'}], ["\$gStdfRec{'TYPHEX'}"]);
# unpack REC_TYP U*1 as dec
$gStdfRec{'TYPDEC'} = unpack('C1', $gStdfRec{'TYPBIN'});
dbugData([$gStdfRec{'TYPDEC'}], ["\$gStdfRec{'TYPDEC'}"]);
# read REC_SUB U*1
read(FILE_STDF, $gStdfRec{'SUBBIN'}, 1);
dbugDataBin("\$gStdfRec{'SUBBIN'}", $gStdfRec{'SUBBIN'});
# unpack REC_SUB U*1 as hex
$gStdfRec{'SUBHEX'} = uc(unpack('H1', $gStdfRec{'SUBBIN'}));
dbugData([$gStdfRec{'SUBHEX'}], ["\$gStdfRec{'SUBHEX'}"]);
# unpack REC_SUB U*1 as dec
$gStdfRec{'SUBDEC'} = unpack('C1', $gStdfRec{'SUBBIN'});
dbugData([$gStdfRec{'SUBDEC'}], ["\$gStdfRec{'SUBDEC'}"]);
# set the STDF record name
$gStdfRec{'NAME'} = stdfRecordTypeCodesToName(
$gStdfRec{'TYPDEC'},
$gStdfRec{'SUBDEC'}
);
dbugData([$gStdfRec{'NAME'}], ['*gStdfRecName']);
# test the STDF record name
if ($gStdfRec{'NAME'} eq '')
{
fatal(
'Unknown header',
'record type', $gStdfRec{'TYPDEC'},
'and/or',
'record sub-type', $gStdfRec{'SUBDEC'},
'at byte offset', $gStdfFile{'ABO'},
'in STDF file', $gStdfFile{'SPEC'}
);
};
# read the STDF record data
read(FILE_STDF, $gStdfRec{'DATBIN'}, $gStdfRec{'LENDEC'});
dbugDataBin("\$gStdfRec{'DATBIN'}", $gStdfRec{'DATBIN'});
# unpack STDF record data as hex
$gStdfRec{'DATHEX'} = uc(unpack('H*', $gStdfRec{'DATBIN'}));
dbugData([$gStdfRec{'DATHEX'}], ["\$gStdfRec{'DATHEX'}"]);
# unpack STDF record data as hex
$gStdfRec{'DATTXT'} = unpack('A*', $gStdfRec{'DATBIN'});
scrubNonPrintChars(\$gStdfRec{'DATTXT'});
dbugData([$gStdfRec{'DATTXT'}], ["\$gStdfRec{'DATTXT'}"]);
# count the read records
$gStdfFile{'RECNUM'} += 1;
};
# xmlComment(@text)
sub xmlComment
{
return(join(SPC, ''));
};
# xmlList(@list)
sub xmlList
{
return(join(',', @_));
};
# xmlTag($name[, \%attributes[, $value]])
sub xmlTag
{
my $name = shift();
my $rhAttributes = shift();
my $value = shift();
my $tagBgn = xmlTagBgn($name, $rhAttributes);
my $tagEnd = xmlTagEnd($name);
return($tagBgn.$value.$tagEnd);
};
# xmlTagBgn($name[, \%attributes])
sub xmlTagBgn
{
my $name = shift();
my $rhAttributes = shift();
my $tag = join(SPC,
$name,
map(
$_.'='.q2($rhAttributes->{$_}),
sort(keys(%{$rhAttributes}))
)
);
return('<'.$tag.'>');
};
# xmlTagEnd($name)
sub xmlTagEnd
{
my $name = shift();
my $tag = $name;
return(''.$name.'>');
};
# xtdfPrintLine(@xtdf)
sub xtdfPrintLine
{
print(join(SPC, @_).EOL);
};
# xtdfPrintList(@xtdf)
sub xtdfPrintList
{
print(join(EOL, @_).EOL);
};
#=====================================================================
# STDF TO ATDF RECORD SUBROUTINES
#=====================================================================
# ATR()
sub ATR
{
my @xtdfFlds = (
xmlTag('MOD_TIM', {}, stdfParseFldU4()),
xmlTag('CMD_LINE', {}, stdfParseFldCn()),
);
xtdfPrintList(@xtdfFlds);
};
# BPS()
sub BPS
{
my @xtdfFlds = (
xmlTag('SEQ_NAME', {}, stdfParseFldCn()),
);
xtdfPrintList(@xtdfFlds);
};
# DTR()
sub DTR
{
my @xtdfFlds = (
xmlTag('TEXT_DAT', {}, stdfParseFldCn()),
);
xtdfPrintList(@xtdfFlds);
};
# EPS()
sub EPS
{
};
# FAR()
sub FAR
{
my @xtdfFlds = (
xmlTag('CPU_TYPE', {}, stdfParseFldU1()),
xmlTag('STDF_VER', {}, stdfParseFldU1()),
);
xtdfPrintList(@xtdfFlds);
};
# FTR()
sub FTR
{
my @xtdfFlds = (
xmlTag('TEST_NUM', {}, stdfParseFldU4()),
xmlTag('HEAD_NUM', {}, stdfParseFldU1()),
xmlTag('SITE_NUM', {}, stdfParseFldU1()),
xmlTag('TEST_FLG', {}, stdfParseFldB1()),
xmlTag('OPT_FLG', {}, stdfParseFldB1()),
xmlTag('CYCL_CNT', {}, stdfParseFldU4()),
xmlTag('REL_VADR', {}, stdfParseFldU4()),
xmlTag('REPT_CNT', {}, stdfParseFldU4()),
xmlTag('NUM_FAIL', {}, stdfParseFldU4()),
xmlTag('XFAIL_AD', {}, stdfParseFldI4()),
xmlTag('YFAIL_AD', {}, stdfParseFldI4()),
xmlTag('VECT_OFF', {}, stdfParseFldI2()),
);
my $i = undef;
# RTN_ICNT
my $j = stdfParseFldU2();
# PGM_ICNT
my $k = stdfParseFldU2();
my @RTN_INDX = ();
my @RTN_STAT = ();
if ($j > 0)
{
# RTN_INDX
for $i (1 .. $j)
{
push(@RTN_INDX, stdfParseFldU2());
};
# RTN_STAT
for $i (1 .. $j)
{
push(@RTN_STAT, stdfParseFldN1());
};
};
my @PGM_INDX = ();
my @PGM_STAT = ();
if ($k > 0)
{
# PGM_INDX
for $i (1 .. $k)
{
push(@PGM_INDX, stdfParseFldU2());
};
# PGM_STAT
for $i (1 .. $k)
{
push(@PGM_STAT, stdfParseFldN1());
};
};
push(@xtdfFlds,
xmlTag('RTN_ICNT', {}, $j),
xmlTag('PGM_ICNT', {}, $k),
xmlTag('RTN_INDX', {}, xmlList(@RTN_INDX)),
xmlTag('RTN_STAT', {}, xmlList(@RTN_STAT)),
xmlTag('PGM_INDX', {}, xmlList(@PGM_INDX)),
xmlTag('PGM_STAT', {}, xmlList(@PGM_STAT)),
xmlTag('FAIL_PIN', {}, stdfParseFldDn()),
xmlTag('VECT_NAM', {}, stdfParseFldCn()),
xmlTag('TIME_SET', {}, stdfParseFldCn()),
xmlTag('OP_CODE', {}, stdfParseFldCn()),
xmlTag('TEST_TXT', {}, stdfParseFldCn()),
xmlTag('ALARM_ID', {}, stdfParseFldCn()),
xmlTag('PROG_TXT', {}, stdfParseFldCn()),
xmlTag('RSLT_TXT', {}, stdfParseFldCn()),
xmlTag('PATG_NUM', {}, stdfParseFldU1()),
xmlTag('SPIN_MAP', {}, stdfParseFldDn()),
);
xtdfPrintList(@xtdfFlds);
};
# GDR()
sub GDR
{
my @xtdfFlds = (
xmlTag('FLD_CNT', {}, stdfParseFldU2()),
xmlTag('GEN_DATA', {}, stdfParseFldVn()),
);
xtdfPrintList(@xtdfFlds);
};
# HBR()
sub HBR
{
my @xtdfFlds = (
xmlTag('HEAD_NUM', {}, stdfParseFldU1()),
xmlTag('SITE_NUM', {}, stdfParseFldU1()),
xmlTag('HBIN_NUM', {}, stdfParseFldU2()),
xmlTag('HBIN_CNT', {}, stdfParseFldU4()),
xmlTag('HBIN_PF', {}, stdfParseFldC1()),
xmlTag('HBIN_NAM', {}, stdfParseFldCn()),
);
xtdfPrintList(@xtdfFlds);
};
# MIR()
sub MIR
{
my @xtdfFlds = (
xmlTag('SETUP_T', {}, secondsToDateTime(stdfParseFldU4())),
xmlTag('START_T', {}, secondsToDateTime(stdfParseFldU4())),
xmlTag('STAT_NUM', {}, stdfParseFldU1()),
xmlTag('MODE_COD', {}, stdfParseFldC1()),
xmlTag('RTST_COD', {}, stdfParseFldC1()),
xmlTag('PROD_COD', {}, stdfParseFldC1()),
xmlTag('BURN_TIM', {}, stdfParseFldU2()),
xmlTag('CMOD_COD', {}, stdfParseFldC1()),
xmlTag('LOT_ID', {}, stdfParseFldCn()),
xmlTag('PART_TYP', {}, stdfParseFldCn()),
xmlTag('NODE_NAM', {}, stdfParseFldCn()),
xmlTag('TSTR_TYP', {}, stdfParseFldCn()),
xmlTag('JOB_NAM', {}, stdfParseFldCn()),
xmlTag('JOB_REV', {}, stdfParseFldCn()),
xmlTag('SBLOT_ID', {}, stdfParseFldCn()),
xmlTag('OPER_NAM', {}, stdfParseFldCn()),
xmlTag('EXEC_TYP', {}, stdfParseFldCn()),
xmlTag('EXEC_VER', {}, stdfParseFldCn()),
xmlTag('TEST_COD', {}, stdfParseFldCn()),
xmlTag('TST_TEMP', {}, stdfParseFldCn()),
xmlTag('USER_TXT', {}, stdfParseFldCn()),
xmlTag('AUX_FILE', {}, stdfParseFldCn()),
xmlTag('PKG_TYP', {}, stdfParseFldCn()),
xmlTag('FAMLY_ID', {}, stdfParseFldCn()),
xmlTag('DATE_COD', {}, stdfParseFldCn()),
xmlTag('FACIL_ID', {}, stdfParseFldCn()),
xmlTag('FLOOR_ID', {}, stdfParseFldCn()),
xmlTag('PROC_ID', {}, stdfParseFldCn()),
xmlTag('OPER_FRQ', {}, stdfParseFldCn()),
xmlTag('SPEC_NAM', {}, stdfParseFldCn()),
xmlTag('SPEC_VER', {}, stdfParseFldCn()),
xmlTag('FLOW_ID', {}, stdfParseFldCn()),
xmlTag('SETUP_ID', {}, stdfParseFldCn()),
xmlTag('DSGN_REV', {}, stdfParseFldCn()),
xmlTag('ENG_ID', {}, stdfParseFldCn()),
xmlTag('ROM_COD', {}, stdfParseFldCn()),
xmlTag('SERL_NUM', {}, stdfParseFldCn()),
xmlTag('SUPR_NAM', {}, stdfParseFldCn()),
);
xtdfPrintList(@xtdfFlds);
};
# MPR()
sub MPR
{
my @xtdfFlds = (
xmlTag('TEST_NUM', {}, stdfParseFldU4()),
xmlTag('HEAD_NUM', {}, stdfParseFldU1()),
xmlTag('SITE_NUM', {}, stdfParseFldU1()),
xmlTag('TEST_FLG', {}, stdfParseFldB1()),
xmlTag('PARM_FLG', {}, stdfParseFldB1()),
);
my $i = undef;
# RTN_ICNT
my $j = stdfParseFldU2();
# RSLT_CNT
my $k = stdfParseFldU2();
my @RTN_STAT = ();
if ($j > 0)
{
# RTN_STAT
for $i (1 .. $j)
{
push(@RTN_STAT, stdfParseFldN1());
};
};
my @RTN_RSLT = ();
if ($k > 0)
{
# RTN_RSLT
for $i (1 .. $k)
{
push(@RTN_RSLT, stdfParseFldR4());
};
};
push(@xtdfFlds,
xmlTag('RTN_ICNT', {}, $j),
xmlTag('RSLT_CNT', {}, $k),
xmlTag('RTN_STAT', {}, xmlList(@RTN_STAT)),
xmlTag('RTN_RSLT', {}, xmlList(@RTN_RSLT)),
xmlTag('TEST_TXT', {}, stdfParseFldCn()),
xmlTag('ALARM_ID', {}, stdfParseFldCn()),
xmlTag('OPT_FLG', {}, stdfParseFldB1()),
xmlTag('RES_SCAL', {}, stdfParseFldI1()),
xmlTag('LLM_SCAL', {}, stdfParseFldI1()),
xmlTag('HLM_SCAL', {}, stdfParseFldI1()),
xmlTag('LO_LIMIT', {}, stdfParseFldR4()),
xmlTag('HI_LIMIT', {}, stdfParseFldR4()),
xmlTag('START_IN', {}, stdfParseFldR4()),
xmlTag('INCR_IN', {}, stdfParseFldR4()),
);
# RTN_INDX
my @RTN_INDX = ();
if ($j > 0)
{
for $i (1 .. $j)
{
push(@RTN_INDX, stdfParseFldU2());
};
};
push(@xtdfFlds,
xmlTag('RTN_INDX', {}, xmlList(@RTN_INDX)),
xmlTag('UNITS', {}, stdfParseFldCn()),
xmlTag('UNITS_IN', {}, stdfParseFldCn()),
xmlTag('C_RESFMT', {}, stdfParseFldCn()),
xmlTag('C_LLMFMT', {}, stdfParseFldCn()),
xmlTag('C_HLMFMT', {}, stdfParseFldCn()),
xmlTag('LO_SPEC', {}, stdfParseFldR4()),
xmlTag('HI_SPEC', {}, stdfParseFldR4()),
);
xtdfPrintList(@xtdfFlds);
};
# MRR()
sub MRR
{
my @xtdfFlds = (
xmlTag('FINISH_T', {}, secondsToDateTime(stdfParseFldU4())),
xmlTag('DISP_COD', {}, stdfParseFldC1()),
xmlTag('USR_DESC', {}, stdfParseFldCn()),
xmlTag('EXC_DESC', {}, stdfParseFldCn()),
);
xtdfPrintList(@xtdfFlds);
};
# PCR()
sub PCR
{
my @xtdfFlds = (
xmlTag('HEAD_NUM', {}, stdfParseFldU1()),
xmlTag('SITE_NUM', {}, stdfParseFldU1()),
xmlTag('PART_CNT', {}, stdfParseFldU4()),
xmlTag('RTST_CNT', {}, stdfParseFldU4()),
xmlTag('ABRT_CNT', {}, stdfParseFldU4()),
xmlTag('GOOD_CNT', {}, stdfParseFldU4()),
xmlTag('FUNC_CNT', {}, stdfParseFldU4()),
);
xtdfPrintList(@xtdfFlds);
};
# PGR()
sub PGR
{
my @xtdfFlds = (
xmlTag('GRP_INDX', {}, stdfParseFldU2()),
xmlTag('GRP_NAM', {}, stdfParseFldCn()),
);
my $i = undef;
# INDX_CNT
my $k = stdfParseFldU2();
my @PMR_INDX = ();
if ($k > 0)
{
# PMR_INDX
for $i (1 .. $k)
{
push(@PMR_INDX, stdfParseFldU2());
};
};
push(@xtdfFlds,
xmlTag('INDX_CNT', {}, $k),
xmlTag('PMR_INDX', {}, xmlList(@PMR_INDX)),
);
xtdfPrintList(@xtdfFlds);
};
# PIR()
sub PIR
{
my @xtdfFlds = (
xmlTag('HEAD_NUM', {}, stdfParseFldU1()),
xmlTag('SITE_NUM', {}, stdfParseFldU1()),
);
xtdfPrintList(@xtdfFlds);
};
# PLR()
sub PLR
{
my $i = undef;
# GRP_CNT
my $k = stdfParseFldU2();
my @GRP_INDX = ();
my @GRP_MODE = ();
my @GRP_RADX = ();
my @PGM_CHAR = ();
my @RTN_CHAR = ();
my @PGM_CHAL = ();
my @RTN_CHAL = ();
if ($k > 0)
{
# GRP_INDX
for $i (1 .. $k)
{
push(@GRP_INDX, stdfParseFldU2());
};
# GRP_MODE
for $i (1 .. $k)
{
push(@GRP_MODE, stdfParseFldU2());
};
# GRP_RADX
for $i (1 .. $k)
{
push(@GRP_RADX, stdfParseFldU1());
};
# PGM_CHAR
for $i (1 .. $k)
{
push(@PGM_CHAR, stdfParseFldCn());
};
# RTN_CHAR
for $i (1 .. $k)
{
push(@RTN_CHAR, stdfParseFldCn());
};
# PGM_CHAL
for $i (1 .. $k)
{
push(@PGM_CHAL, stdfParseFldCn());
};
# RTN_CHAL
for $i (1 .. $k)
{
push(@RTN_CHAL, stdfParseFldCn());
};
};
my @xtdfFlds = (
xmlTag('GRP_CNT', {}, $k),
xmlTag('GRP_INDX', {}, xmlList(@GRP_INDX)),
xmlTag('GRP_MODE', {}, xmlList(@GRP_MODE)),
xmlTag('GRP_RADX', {}, xmlList(@GRP_RADX)),
xmlTag('PGM_CHAR', {}, xmlList(@PGM_CHAR)),
xmlTag('RTN_CHAR', {}, xmlList(@RTN_CHAR)),
xmlTag('PGM_CHAL', {}, xmlList(@PGM_CHAL)),
xmlTag('RTN_CHAL', {}, xmlList(@RTN_CHAL)),
);
xtdfPrintList(@xtdfFlds);
};
# PMR()
sub PMR
{
my @xtdfFlds = (
xmlTag('PMR_INDX', {}, stdfParseFldU2()),
xmlTag('CHAN_TYP', {}, stdfParseFldU2()),
xmlTag('CHAN_NAM', {}, stdfParseFldCn()),
xmlTag('PHY_NAM', {}, stdfParseFldCn()),
xmlTag('LOG_NAM', {}, stdfParseFldCn()),
xmlTag('HEAD_NUM', {}, stdfParseFldU1()),
xmlTag('SITE_NUM', {}, stdfParseFldU1()),
);
xtdfPrintList(@xtdfFlds);
};
# PRR()
sub PRR
{
my @xtdfFlds = (
xmlTag('HEAD_NUM', {}, stdfParseFldU1()),
xmlTag('SITE_NUM', {}, stdfParseFldU1()),
xmlTag('PART_FLG', {}, stdfParseFldB1()),
xmlTag('NUM_TEST', {}, stdfParseFldU2()),
xmlTag('HARD_BIN', {}, stdfParseFldU2()),
xmlTag('SOFT_BIN', {}, stdfParseFldU2()),
xmlTag('X_COORD', {}, stdfParseFldI2()),
xmlTag('Y_COORD', {}, stdfParseFldI2()),
xmlTag('TEST_T', {}, stdfParseFldU4()),
xmlTag('PART_ID', {}, stdfParseFldCn()),
xmlTag('PART_TXT', {}, stdfParseFldCn()),
xmlTag('PART_FIX', {}, stdfParseFldBn()),
);
xtdfPrintList(@xtdfFlds);
};
# PTR()
sub PTR
{
my @xtdfFlds = (
xmlTag('TEST_NUM', {}, stdfParseFldU4()),
xmlTag('HEAD_NUM', {}, stdfParseFldU1()),
xmlTag('SITE_NUM', {}, stdfParseFldU1()),
xmlTag('TEST_FLG', {}, stdfParseFldB1()),
xmlTag('PARM_FLG', {}, stdfParseFldB1()),
xmlTag('RESULT', {}, stdfParseFldR4()),
xmlTag('TEST_TXT', {}, stdfParseFldCn()),
xmlTag('ALARM_ID', {}, stdfParseFldCn()),
xmlTag('OPT_FLG', {}, stdfParseFldB1()),
xmlTag('RES_SCAL', {}, stdfParseFldI1()),
xmlTag('LLM_SCAL', {}, stdfParseFldI1()),
xmlTag('HLM_SCAL', {}, stdfParseFldI1()),
xmlTag('LO_LIMIT', {}, stdfParseFldR4()),
xmlTag('HI_LIMIT', {}, stdfParseFldR4()),
xmlTag('UNITS', {}, stdfParseFldCn()),
xmlTag('C_RESFMT', {}, stdfParseFldCn()),
xmlTag('C_LLMFMT', {}, stdfParseFldCn()),
xmlTag('C_HLMFMT', {}, stdfParseFldCn()),
xmlTag('LO_SPEC', {}, stdfParseFldR4()),
xmlTag('HI_SPEC', {}, stdfParseFldR4()),
);
xtdfPrintList(@xtdfFlds);
};
# RDR()
sub RDR
{
my $i = undef;
# NUM_BINS
my $k = stdfParseFldU2();
my @RTST_BIN = ();
if ($k > 0)
{
# GRP_INDX
for $i (1 .. $k)
{
push(@RTST_BIN, stdfParseFldU2());
};
};
my @xtdfFlds = (
xmlTag('NUM_BINS', {}, $k),
xmlTag('RTST_BIN', {}, xmlList(@RTST_BIN)),
);
xtdfPrintList(@xtdfFlds);
};
# SBR()
sub SBR
{
my @xtdfFlds = (
xmlTag('HEAD_NUM', {}, stdfParseFldU1()),
xmlTag('SITE_NUM', {}, stdfParseFldU1()),
xmlTag('SBIN_NUM', {}, stdfParseFldU2()),
xmlTag('SBIN_CNT', {}, stdfParseFldU4()),
xmlTag('SBIN_PF', {}, stdfParseFldC1()),
xmlTag('SBIN_NAM', {}, stdfParseFldCn()),
);
xtdfPrintList(@xtdfFlds);
};
# SDR()
sub SDR
{
my @xtdfFlds = (
xmlTag('HEAD_NUM', {}, stdfParseFldU1()),
xmlTag('SITE_GRP', {}, stdfParseFldU1()),
);
my $i = undef;
# SITE_CNT
my $k = stdfParseFldU1();
my @SITE_NUM = ();
if ($k > 0)
{
# SITE_NUM
for $i (1 .. $k)
{
push(@SITE_NUM, stdfParseFldU1());
};
};
push(@xtdfFlds,
xmlTag('SITE_CNT', {}, $k),
xmlTag('SITE_NUM', {}, xmlList(@SITE_NUM)),
xmlTag('HAND_TYP', {}, stdfParseFldCn()),
xmlTag('HAND_ID', {}, stdfParseFldCn()),
xmlTag('CARD_TYP', {}, stdfParseFldCn()),
xmlTag('CARD_ID', {}, stdfParseFldCn()),
xmlTag('LOAD_TYP', {}, stdfParseFldCn()),
xmlTag('LOAD_ID', {}, stdfParseFldCn()),
xmlTag('DIB_TYP', {}, stdfParseFldCn()),
xmlTag('DIB_ID', {}, stdfParseFldCn()),
xmlTag('CABL_TYP', {}, stdfParseFldCn()),
xmlTag('CABL_ID', {}, stdfParseFldCn()),
xmlTag('CONT_TYP', {}, stdfParseFldCn()),
xmlTag('CONT_ID', {}, stdfParseFldCn()),
xmlTag('LASR_TYP', {}, stdfParseFldCn()),
xmlTag('LASR_ID', {}, stdfParseFldCn()),
xmlTag('EXTR_TYP', {}, stdfParseFldCn()),
xmlTag('EXTR_ID', {}, stdfParseFldCn()),
);
xtdfPrintList(@xtdfFlds);
};
# TSR()
sub TSR
{
my @xtdfFlds = (
xmlTag('HEAD_NUM', {}, stdfParseFldU1()),
xmlTag('SITE_NUM', {}, stdfParseFldU1()),
xmlTag('TEST_TYP', {}, stdfParseFldC1()),
xmlTag('TEST_NUM', {}, stdfParseFldU4()),
xmlTag('EXEC_CNT', {}, stdfParseFldU4()),
xmlTag('FAIL_CNT', {}, stdfParseFldU4()),
xmlTag('ALRM_CNT', {}, stdfParseFldU4()),
xmlTag('TEST_NAM', {}, stdfParseFldCn()),
xmlTag('SEQ_NAME', {}, stdfParseFldCn()),
xmlTag('TEST_LBL', {}, stdfParseFldCn()),
xmlTag('OPT_FLG', {}, stdfParseFldB1()),
xmlTag('TEST_TIM', {}, stdfParseFldR4()),
xmlTag('TEST_MIN', {}, stdfParseFldR4()),
xmlTag('TEST_MAX', {}, stdfParseFldR4()),
xmlTag('TST_SUMS', {}, stdfParseFldR4()),
xmlTag('TST_SQRS', {}, stdfParseFldR4()),
);
xtdfPrintList(@xtdfFlds);
};
# WCR()
sub WCR
{
my @xtdfFlds = (
xmlTag('WAFR_SIZ', {}, stdfParseFldR4()),
xmlTag('DIE_HT', {}, stdfParseFldR4()),
xmlTag('DIE_WID', {}, stdfParseFldR4()),
xmlTag('WF_UNITS', {}, stdfParseFldU1()),
xmlTag('WF_FLAT', {}, stdfParseFldC1()),
xmlTag('CENTER_X', {}, stdfParseFldI2()),
xmlTag('CENTER_Y', {}, stdfParseFldI2()),
xmlTag('POS_X', {}, stdfParseFldC1()),
xmlTag('POS_Y', {}, stdfParseFldC1()),
);
xtdfPrintList(@xtdfFlds);
};
# WIR()
sub WIR
{
my @xtdfFlds = (
xmlTag('HEAD_NUM', {}, stdfParseFldU1()),
xmlTag('SITE_GRP', {}, stdfParseFldU1()),
xmlTag('START_T', {}, secondsToDateTime(stdfParseFldU4())),
xmlTag('WAFER_ID', {}, stdfParseFldCn()),
);
xtdfPrintList(@xtdfFlds);
};
# WRR()
sub WRR
{
my @xtdfFlds = (
xmlTag('HEAD_NUM', {}, stdfParseFldU1()),
xmlTag('SITE_GRP', {}, stdfParseFldU1()),
xmlTag('FINISH_T', {}, secondsToDateTime(stdfParseFldU4())),
xmlTag('PART_CNT', {}, stdfParseFldU4()),
xmlTag('RTST_CNT', {}, stdfParseFldU4()),
xmlTag('ABRT_CNT', {}, stdfParseFldU4()),
xmlTag('GOOD_CNT', {}, stdfParseFldU4()),
xmlTag('FUNC_CNT', {}, stdfParseFldU4()),
xmlTag('WAFER_ID', {}, stdfParseFldCn()),
xmlTag('FABWF_ID', {}, stdfParseFldCn()),
xmlTag('FRAME_ID', {}, stdfParseFldCn()),
xmlTag('MASK_ID', {}, stdfParseFldCn()),
xmlTag('USR_DESC', {}, stdfParseFldCn()),
xmlTag('EXC_DESC', {}, stdfParseFldCn()),
);
xtdfPrintList(@xtdfFlds);
};
######################################################################
=pod
=head1 REQUIRES
E Perl 5.6 or newer.
E Perl core module strict.
E Perl custom module TDF.pm.
=head1 SEE ALSO
E perl core and module documentation.
E STDF Specification V4 published by Teradyne, Inc.
E ATDF Specification V2 published by Teradyne, Inc.
=head1 AUTHORS
E Michael Hackerott, michael.hackerott@mrhackerott.org
=head1 COPYRIGHT
Copyright E 2005 Michael Hackerott. All rights reserved.
This program is free software; you can redistribute it and/r modify it
under the terms of either the GNU General Public License or the Artistic
License as specified in the Perl README file.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER
OR CONTRIBUTORS 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.
=head1 ACKNOWLEDGEMENT
The Standard Test Data Format (STDF) and ASCII Test Data Format (ATDF)
specifications are the original works of Teradyne Inc.
=head1 KNOWN BUGS
E The Vn data type not implemented. Therefore, GDR records are not
implemented.
=head1 HISTORY
1.0.0 (200512031456) Michael Hackerott
E Created program.
=cut
__END__