#!/usr/bin/env perl
#
# DS comment: yes, this is a horribly ugly and long perl script... please don't look at it :-)
# if you do: first we have some global counters and constants, and then two main functions for I/O (readLogs & writeOutput)
# - and two help functions to get the info for capacitors corrections,  
#   and a conversion between voltage and current for the OpAmp's
#
use strict;
use File::stat;
use Time::localtime;

my $debug = 1; #print flag: 0=quiet, 1=basic info, 2,3=progressively more info

# constants to switch on/off methods and checks
my $useGainRT = 0; # 1=>gainRT, otherwise gain(Odd/Even) info
my $checkVRefErr = 0; # select !=1 to skip VRefErr check
my $checkDFTErr = 1; # select !=1 to skip DFTErr check

# I/0 variables
my $chipQRdatabasefile = "/home/tpc/work/database/chipQR.txt";
my $topdir = "../logs"; # where to store summary info


my $script = $0; 
my $date_string = ctime(stat($script)->mtime);
my $outputstring ="CHK $script $date_string\n";

my ($sampadir, $station) = @ARGV; 
if (not defined $station) {
    print "Please provide sampadir and station arguments\n";
    exit;
}
print "sampadir $sampadir station $station\n"; 

my $sampastring = "sampa";
my @dirarr = split /$sampastring/, $sampadir;
my $chipnum = $dirarr[1];
if ( ($chipnum < 1) || ($chipnum > 999999) ) {
    print "invalid chipnum $chipnum derived from sampadir $sampadir argument\n";
    exit;
}
my $QRCode = `grep ^$chipnum $chipQRdatabasefile | awk '{print "SAMPA "\$NF}'`;
chomp $QRCode;
$outputstring .= "QR ${QRCode}\nChip ${chipnum}\nSta ${station}\n";

# global variables
my $nGain = 2;
my $nParity = 2;
my $nChan = 32;
my $nDCRef = 6; # 6 ref voltages 
my $nDCCurr = 5; # 5 currents

# arrays for keeping the found rms values, to-be-used in CheckRms
my @pedAnaArr; 
my @ped2AnaArr;
my @rmsAnaArr; 
my @rms2AnaArr;

# counters for all checks
my $fileCount = 0;
my $fileCheckCount = 0;
my $dcRefCount = 0; my $dcRefErrCount = 0;
my $dcCurrCount = 0; my $dcCurrErrCount = 0;
my $syncCount = 0; my $syncErrCount = 0;
my $baselineCount = 0; my $baselineErrCount = 0; 
my $stdevCount = 0; my $stdevErrCount = 0; 
my $pedAnaCount = 0; my $pedAnaErrCount = 0; 
my $rmsAnaCount = 0; my $rmsAnaErrCount = 0; 
my @gainCount; my @gainErrCount; 
$gainCount[0] = 0; $gainErrCount[0] = 0; 
$gainCount[1] = 0; $gainErrCount[1] = 0;
my $nGainVeryLow = 0; 
my $risetimeCount = 0; my $risetimeErrCount = 0; 
my $xtalkCount = 0; my $xtalkErrCount = 0; 
my $bitcheckCount = 0; my $bitcheckErrCount = 0; 
# RingOsc, i2c, Jtag, mem, DFT:
my $clockCount = 0; my $clockErrCount = 0;
my $i2cCount = 0; my $i2cErrCount = 0;
my $memCount = 0; my $memErrCount = 0;
my $dftCount = 0; my $dftErrCount = 0;
my $jtagCount = 0; my $jtagErrCount = 0;

########################################################
#flow of main program in 2 main functions (almost all action in the first one) 
readLogs();
writeOutput();
########################################################

sub readLogs {
# filename info
#my $initstring = "init.log"; # we do not check anything for the init
    my $runstring = "run.log";
    my $run2string = "readnoise.log";
    my $dcstring = "dc.log";
    my $miscstring = "misc.log";
    my $misc2string = "misc2.log";
    my $jtagfilestring = "jtag.log";
    my $dftstring = "dft.log"; 
# DAQ files; different versions for different gains
    my $calibstring = "gain";
    my $noisestring = "stats";
    my $noiseAnastring = "noiseAna";
    my $reAnastring = "reAna";
    my $xtalkstring = "xtalk";
    my $risetimestring = "rise_time";
    my $bitcheckstring = "bitcheck"; 
    
    my $reAna = 0;
    my $iChan = 0;
    my $iGain = 0;
    my @gainstring;
    $gainstring[0] = "20mV";
    $gainstring[1] = "30mV";
    my $iParity = 0;
    my @paritystring;
    $paritystring[0] = "even";
    $paritystring[1] = "odd";
    my @parityVal; # look at only the half of the channels with the right modulus values
    $parityVal[0] = 0;
    $parityVal[1] = 1;
    
# cuts on values
# DC
    my @DCValstring = ( "VDDA", "VREF", "VDD", "V450", "V600", "V750",
			"FE1_CURR", "FE2_CURR", "AD_CURR", "DR_CURR", "DG_CURR");
    my @minDCRef = ( 1.238, 1.093, 1.240, 0.450, 0.600, 0.750 ); # not used
    my @maxDCRef = ( 1.260, 1.110, 1.260, 0.520, 0.660, 0.811 ); # not used
    my $minDCVRefDiff = 0.145; # for V600-V450, V750-V600
    my $maxDCVRefDiff = 0.158;

    my @minDCACurr = ( 75.000, 50.000, 3.000, 35.000, 10.000 );
    my @maxDCACurr = ( 100.000, 80.000, 14.000, 44.000, 20.000 );

# run (sync) values
    my $SyncLowstring = "SYNC Low";
    my $SyncHighstring = "SYNC High";
    my $minSync = 200;
    my $maxSync = 300;
# noise files: different cuts for different gains
    my @minPedVal;
    $minPedVal[0] = 40;
    $minPedVal[1] = 20; # not used
    my @maxPedVal;
    $maxPedVal[0] = 110;
    $maxPedVal[1] = 130; # not used
    my @minRmsVal;
    $minRmsVal[0] = 0.6;
    $minRmsVal[1] = 0.2; # not used
    my @maxRmsVal;
    $maxRmsVal[0] = 1.7;
    if ($station == 1) { # a bit worse noise than station 2?
	$maxRmsVal[0] = 1.7;
    }

    $maxRmsVal[1] = 2.5; # not used
    my $maxRmsVal31 = 2.0; # looser cut for 30 & 31 

# calib files: different cuts for different gains
    my @minGainVal;
    my @maxGainVal;
# start with gain0; different cuts depending on which method and station we have
    $minGainVal[0] = 19.0;
    $maxGainVal[0] = 23.0;
    if ($useGainRT == 1) { # for RT
	$minGainVal[0] = 19.0;
	$maxGainVal[0] = 23.0; 
    } 

# also have a check for very low/outlier values
    my $minGainVeryLow = $minGainVal[0] - 0.6;

# coarser checks for gain1
    $minGainVal[1] = 25; # for coarse check
    $maxGainVal[1] = 35; # for coarse check
    
# rise-time files: different cuts for different gains?
    my @minRiseTimeVal;
    $minRiseTimeVal[0] = 55;
    $minRiseTimeVal[1] = 50; # not used
    my @maxRiseTimeVal;
    $maxRiseTimeVal[0] = 75;
    $maxRiseTimeVal[1] = 80; # not used
    
# xtalk files: different cuts for different gains?
    my @minXtalkVal;
    $minXtalkVal[0] = -0.01;
    $minXtalkVal[1] = -0.01; # not used
    my @maxXtalkVal;
    $maxXtalkVal[0] = 0.05;
    $maxXtalkVal[1] = 0.05; # not used

# bitcheck files; test done for 20 mV files
    my $minBitcheckLimit = 1;
    my $maxBitcheckLimit = 300;

# clockSpeed
    my $clockstring = "Clock speed";
    my $minClockSpeed = 130;
    my $maxClockSpeed = 170;
# i2c_read
    my $i2cstring = "i2c_read_errors";
    my $maxi2cReadErrors = 0;
# memory
    my $memorystring = "Memory";
    my $failstring = "failed";
# JTAG
    my $jtagstring = "JTAG";
    my $jtagErrstring = "ERROR";
# DFT
    my $mismatchstring = "mismatches";
    my $maxMismatches = 2;

    if ($debug > 0) { print "Checking logs for chip ${chipnum}:\n"; }
    my $chipstring = "sampa${chipnum}";
    my $logstring = ".log";
    open(my $fh, "-|", "ls $sampadir/*${logstring}");

# variables for reading files
    my $line = "";
    my $infostring = "";
    my $splitBracket = "\\\[";
    my $splitComma = "\,";
    my $splitColon = "\:";
    my $splitSpace = " ";

    while(my $filename = <$fh>) {
	chomp($filename);
	if ($debug > 1) { print "filename $filename\n"; }
    
	if ($filename =~ /$noisestring/) {
	    if ($debug > 1) { print "\n noise file\n"; }
	    open( my $tfh, '<', $filename ) or die "Can't open $filename: $!";

#mean
	    if ($filename =~ /$gainstring[0]/) { $iGain = 0; }
	    else { $iGain = 1; }
	    my $selectNoiseAna = 0; # which reAna val will be checked and have out-of-bounds messages printed?
	    $reAna = 0; 
	    my $pedstring = "Ped$gainstring[$iGain]";
	    my $rmsstring = "Rms$gainstring[$iGain]";
	    if ($filename =~ /$reAnastring/) { 
		$reAna = 1; 
		$pedstring = "2Ped$gainstring[$iGain]";
		$rmsstring = "2Rms$gainstring[$iGain]";
	    }

	    $outputstring .= "$pedstring";
	    $line = <$tfh>;
	    chop $line; chop $line; chop $line;
	    my @arr = split /$splitBracket/, $line;
	    my @baselinearr = split /$splitComma/, $arr[1];	
	    my $nBl = 0;
	    my $sumBl = 0;
	    foreach my $bl (@baselinearr) {
		my $result = sprintf("%.1f", $bl); 
		$outputstring .= " $result";
		if ($debug > 2) { print "bl $baselineCount $bl \n"; }
		if ( ($reAna == $selectNoiseAna) && ($iGain==0) ) {
		    if ( ($bl < $minPedVal[$iGain]) || ($bl > $maxPedVal[$iGain]) ) {
			if ($debug > 0) { print "out-of-bounds bl $baselineCount : baseline $bl \n"; }
			$baselineErrCount++;
		    }
		    $sumBl += $bl;
		    $nBl++;
		    $baselineCount++;
		}
	    }
	    $outputstring .= "\n";
#stdev
	    $outputstring .= "$rmsstring";
	    $line = <$tfh>;
	    chop $line; chop $line;
	    @arr = split /$splitBracket/, $line;
	    my @stdevarr = split /$splitComma/, $arr[1];	
	    my $nStdev = 0;
	    my $sumStdev = 0;
	    foreach my $stdev (@stdevarr) {
		my $result = sprintf("%.2f", $stdev); 
		$outputstring .= " $result";
		if ($debug > 2) { print "stdev $stdevCount : $stdev \n"; }
		if ( ($reAna == $selectNoiseAna) && ($iGain==0) ) {
		    if ( ($stdev < $minRmsVal[$iGain]) || ($stdev > $maxRmsVal[$iGain]) ) {
			if ($debug > 0) { print "out-of-bounds stdev $stdevCount : stdev $stdev \n"; }
			$stdevErrCount++;
		    }
		    $stdevCount++;
		    $sumStdev += $stdev;
		    $nStdev++;
		}
	    }
	    close $tfh;
	    $outputstring .= "\n";

	    if ($debug > 0) { 
		if ($nBl > 0) {
		    my $aveBl = $sumBl / $nBl;
		    print "aveBl $aveBl\n";
		}
		if ($nStdev > 0) {
		    my $aveStdev = $sumStdev / $nStdev;
		    print "aveStdev $aveStdev\n";
		}
		print "baselineCount $baselineCount baselineErrCount $baselineErrCount\n";
		print "stdevCount $stdevCount stdevErrCount $stdevErrCount\n";
	    }
	    if ($reAna == 0) { $fileCheckCount++; }
	} # end noise file   
	elsif ($filename =~ /$noiseAnastring/) {
	    if ($debug > 1) { print "\n noiseAna file\n"; }
	    open( my $tfh, '<', $filename ) or die "Can't open $filename: $!";

	    if ($filename =~ /$gainstring[0]/) { $iGain = 0; }
	    else { $iGain = 1; }

	    $reAna = 0; 
	    my $pedstring = "PedAna$gainstring[$iGain]";
	    my $rmsstring = "RmsAna$gainstring[$iGain]";
	    if ($filename =~ /$reAnastring/) { 
		$reAna = 1; 
		$pedstring = "2PedAna$gainstring[$iGain]";
		$rmsstring = "2RmsAna$gainstring[$iGain]";
	    }

	    $line = <$tfh>; # header
	    for ($iChan = 0; $iChan<$nChan; $iChan++) {
		$line = <$tfh>;
		chomp $line;
		$line =~ s/\s+/ /g;
		$line =~ s/^\s+//;
		my @carr = split /$splitSpace/, $line;
		my $pedVal = $carr[1];
		my $rmsVal = $carr[2];
		my $resultPed = sprintf("%.1f", $pedVal); 
		$pedstring .= " $resultPed";
		my $resultRms = sprintf("%.2f", $rmsVal); 
		if ($iGain == 0) {
		    if ($reAna == 0) { 
			push(@pedAnaArr, $pedVal); 
			push(@rmsAnaArr, $rmsVal); 
		    }
		    else { 
			push(@ped2AnaArr, $pedVal); 
			push(@rms2AnaArr, $rmsVal); 
		    }
		}
		$rmsstring .= " $resultRms";
		if ($debug > 2) { print "carr0 $carr[0] carr1 $carr[1] carr2 $carr[2] carr3 $carr[3]\n"; }
	    }
	    close $tfh;
	    $outputstring .= "$pedstring\n";
	    $outputstring .= "$rmsstring\n";

	    if ($reAna == 0) { $fileCheckCount++; }
	} # end noiseAna file   
	elsif ($filename =~ /$bitcheckstring/) {
	    if ($debug > 1) { print "\n bitcheck file\n"; }
	    open( my $tfh, '<', $filename ) or die "Can't open $filename: $!";

	    if ($filename =~ /$gainstring[0]/) { $iGain = 0; }
	    else { $iGain = 1; }

	    my $minstring = "Min$gainstring[$iGain]";
	    my $maxstring = "Max$gainstring[$iGain]";

	    $line = <$tfh>; # header
	    for ($iChan = 0; $iChan<$nChan; $iChan++) {
		$line = <$tfh>;
		chomp $line;
		$line =~ s/\s+/ /g;
		$line =~ s/^\s+//;
		my @carr = split /$splitSpace/, $line;
		my $minVal = $carr[1];
		my $maxVal = $carr[2];
		$minstring .= " $minVal";
		$maxstring .= " $maxVal";

		if ($iGain == 0) {
		    if ( ($minVal > $minBitcheckLimit) || ($maxVal < $maxBitcheckLimit) ) {
			if ($debug > 0) { print "out-of-bounds minVal $minVal maxVal $maxVal \n"; }
			$bitcheckErrCount++;
		    }
		    $bitcheckCount++;
		}
	    }
	    close $tfh;
	    $outputstring .= "$minstring\n";
	    $outputstring .= "$maxstring\n";

	} # end bitcheck file   
	elsif ($filename =~ /$xtalkstring/) {
	    if ($filename =~ /$paritystring[0]/) { $iParity = 0; }
	    else { $iParity = 1; }
	    if ($filename =~ /$gainstring[0]/) { $iGain = 0; }
	    else { $iGain = 1; }
	    if ($debug > 1) { print "xtalk file parity $iParity gain $iGain\n"; }
	    $outputstring .= "X$gainstring[$iGain]$paritystring[$iParity]";
	    my $xMax = 0;

	    open( my $tfh, '<', $filename ) or die "Can't open $filename: $!";
	    $line = <$tfh>; # header
	    $line = <$tfh>; # skip pulse 0
	    $line = <$tfh>; # skip pulse 1
	    $line = <$tfh>;
	    chomp $line;
	    $line =~ s/\s+/ /g;
	    $line =~ s/^\s+//;
	    my @xarr = split /$splitSpace/, $line;
	    my $nx = 0;
	    foreach my $x (@xarr) {
		if ( ($nx>0) && ($x>$xMax) ) { $xMax = $x;} 
		if ($debug > 2) { print "nx $nx x $x \n"; }
		if ( $nx > 0 ) { # skip first field
		    if ($iGain == 0) {
			if ( ($x < $minXtalkVal[$iGain]) || ($x > $maxXtalkVal[$iGain]) ) {
			    if ($debug > 0) { print "out-of-bounds nx $x : x $x \n"; }
			    $xtalkErrCount++;
			}
			$xtalkCount++;
		    }
		}
		$nx++;
	    }	
	    close $tfh;
	    my $result = sprintf("%.1e", $xMax); 
	    $outputstring .= " $result\n";

	    if ( ($debug > 0) && ($iGain==0) ) { 
		print "xtalkCount $xtalkCount xtalkErrCount $xtalkErrCount\n";
	    }
	    $fileCheckCount++;
	} # end xtalk file   
	elsif ($filename =~ /$calibstring/) {
	    if ($filename =~ /$paritystring[0]/) { $iParity = 0; }
	    else { $iParity = 1; }
	    if ($filename =~ /$gainstring[0]/) { $iGain = 0; }
	    else { $iGain = 1; }
	    if ($debug > 1) { print "calib file parity $iParity gain $iGain\n"; }
	    $outputstring .= "Gain$gainstring[$iGain]$paritystring[$iParity]";
	    
	    open( my $tfh, '<', $filename ) or die "Can't open $filename: $!";
	    $line = <$tfh>; # header
	    my $nsumGain = 0;
	    my $sumGain = 0;
	    my $mychan = 0;
	    if ($iParity == 1) { # skip chan 0 if odd parity
		$line = <$tfh>;
		$mychan++; 
	    } 
	    for ($iChan = 0; $iChan<($nChan/2); $iChan++) {
		$line = <$tfh>;
		chomp $line;
		$line =~ s/\s+/ /g;
		$line =~ s/^\s+//;
		my @carr = split /$splitSpace/, $line;
		my $gainVal = CapCorr( $carr[1], $mychan );
		my $result = sprintf("%.2f", $gainVal); 
		$outputstring .= " $result";
		if ($debug > 2) { print "carr0 $carr[0] carr1 $carr[1] carr2 $carr[2] carr3 $carr[3]\n"; }
		if ($useGainRT != 1) { # not RT
		    if ( ($gainVal < $minGainVal[$iGain]) || ($gainVal > $maxGainVal[$iGain]) ) {
			if ($debug > 0) { print "out-of-bounds chan $mychan : gainval $gainVal \n"; }
			$gainErrCount[$iGain]++;
		    }
		    if ( ($iGain==0) && ($gainVal < $minGainVeryLow) ) {
			if ($debug > 0) { print "GainVeryLow chan $mychan : gainval $gainVal \n"; }
			$nGainVeryLow++;
		    }
		    $gainCount[$iGain]++;
		}

		$nsumGain++;
		$sumGain += $gainVal;
		$line = <$tfh>; # skip next line
		$mychan += 2;
	    }
	    close $tfh;
	    $outputstring .= "\n";

	    if ($debug > 0) { 
		if ($nsumGain > 0) {
		    my $aveGain = $sumGain / $nsumGain;
		    print "aveGain $aveGain\n";
		}
	    }
	    $fileCheckCount++;
	} # end calib file   
	elsif ($filename =~ /$risetimestring/) {
	    if ($filename =~ /$gainstring[0]/) { $iGain = 0; }
	    else { $iGain = 1; }
	    if ($debug > 1) { print "risetime file gain $iGain\n"; }
	    $outputstring .= "RT$gainstring[$iGain]";

# highest fC charge from calib.cpp: 179.9316 * 1.5 * 11.0/(11.0 + 39.0) * 1.172 = 69.59 fC
# factor from Anders from calib-file to delay-file charge: 1000/1474 => 47.212 fC here
# ADC amp should be multiplied with 2.15 to go from ADC to mV, and then we divide with charge to get gain 
	    my $amp2gain = 2.15 / 47.212; 
	    my $outputstringGain = "Gain$gainstring[$iGain]";
	    my $outputstringTS = "TS$gainstring[$iGain]";
	    
	    my $nsumRiseTime = 0;
	    my $sumRiseTime = 0;
	    open( my $tfh, '<', $filename ) or die "Can't open $filename: $!";
	    $line = <$tfh>; # header
	    for ($iChan = 0; $iChan<$nChan; $iChan++) {
		$line = <$tfh>;
		chomp $line;
		$line =~ s/\s+/ /g;
		$line =~ s/^\s+//;
		my @rarr = split /$splitSpace/, $line;
		if ($debug > 2) { print "rarr0 $rarr[0] rarr1 $rarr[1] rarr2 $rarr[2] rarr3 $rarr[3]\n"; }
		my $risetimeVal = $rarr[1];
		my $result = sprintf("%.2f", $risetimeVal); 
		$outputstring .= " $result";		

		my $ampVal = $rarr[4];
		my $tsVal = $rarr[7];
		if ($debug > 2) { print "ampVal $ampVal rarr6 $rarr[6] tsVal $tsVal\n"; }
		my $gainVal = $ampVal * $amp2gain; 
		my $resultGain = sprintf("%.2f", $gainVal); 
		my $resultTS = sprintf("%.2f", $tsVal); 
		$outputstringGain .= " $resultGain";		
		$outputstringTS .= " $resultTS";		

		if ($iGain == 0) {
		    if ( ($risetimeVal < $minRiseTimeVal[$iGain]) || ($risetimeVal > $maxRiseTimeVal[$iGain]) ) {
			if ($debug > 0) { print "out-of-bounds chan $iChan : risetimeval $risetimeVal \n"; }
			$risetimeErrCount++;
		    }
		    $risetimeCount++;
		}
		$nsumRiseTime++;
		$sumRiseTime += $risetimeVal;

		if ($useGainRT == 1) { # for RT
		    if ( ($gainVal < $minGainVal[$iGain]) || ($gainVal > $maxGainVal[$iGain]) ) {
			if ($debug > 0) { print "out-of-bounds chan $iChan : gainval $gainVal \n"; }
			$gainErrCount[$iGain]++;
		    }
		    if ( ($iGain==0) && ($gainVal < $minGainVeryLow) ) {
			if ($debug > 0) { print "GainVeryLow chan $iChan : gainval $gainVal \n"; }
			$nGainVeryLow++;
		    }
		    $gainCount[$iGain]++;
		}

	    }	
	    close $tfh;
	    $outputstring .= "\n";
	    $outputstring .= "$outputstringGain\n";
	    $outputstring .= "$outputstringTS\n";
	    
	    if ($debug > 0) { 
		if ($nsumRiseTime > 0) {
		    my $aveRiseTime = $sumRiseTime / $nsumRiseTime;
		    print "aveRiseTime $aveRiseTime\n";
		}
		if ($iGain == 0) { print "risetimeCount $risetimeCount risetimeErrCount $risetimeErrCount\n"; }
		print "iGain $iGain gainCount $gainCount[$iGain] gainErrCount $gainErrCount[$iGain]\n"; 
	    }
	    $fileCheckCount++;
	} # end risetime file   
	elsif ($filename =~ /$dcstring/) {
	    if ($debug > 1) { print "dc file\n"; }
	    open( my $tfh, '<', $filename ) or die "Can't open $filename: $!";
	    
	    my @dcArr;
	    my $iDCVal;
	    $outputstring .= "VRef";
	    while ($iDCVal<$nDCRef) {
		my $line = <$tfh>; chomp $line;
		if ($line =~ /$DCValstring[$iDCVal]/) {
		    my @darr = split /$splitColon/, $line;
		    if ($debug > 2) { print "darr0 $darr[0] darr1 $darr[1] darr2 $darr[2] darr3 $darr[3]\n"; }
		    my @darr2 = split /$splitComma/, $darr[2];
		    my $dcVal = $darr2[0] + 0;
		    my $result = sprintf("%.3f", $dcVal); 
		    $outputstring .= " $result";
		    $iDCVal++;
		    push(@dcArr, $dcVal); 
		}
	    }
	
# don't check the values themselves but just the differences between the last two pair values, index 5-4 and 4-3 (should be 0.1515 +- 0.0065)		    
	    my $nDC = scalar @dcArr;
	    if ($debug > 0) { print "nDC $nDC iDCVal $iDCVal\n"; }
	    for (my $iRef = ($nDC-3); $iRef<($nDC-1); $iRef++) {
		my $dcDiff = $dcArr[$iRef+1] - $dcArr[$iRef];
		if ( ($dcDiff < $minDCVRefDiff) || ($dcDiff > $maxDCVRefDiff) ) {
		    if ($debug > 0) { print "out-of-bounds dcRef $iRef : dcDiff $dcDiff\n"; }
		    $dcRefErrCount++; 
		}
		$dcRefCount++; 
	    }	
	    $outputstring .= "\n";

	    my $voltCurrstring = "VCurr";
	    my $ampCurrstring = "ACurr";
	    while(my $line = <$tfh>) {
		chomp $line;
		if ($line =~ /$DCValstring[$iDCVal]/) {
		    my @darr = split /$splitColon/, $line;
		    if ($debug > 2) { print "darr0 $darr[0] darr1 $darr[1] darr2 $darr[2] darr3 $darr[3]\n"; }
		    my @darr2 = split /$splitComma/, $darr[2];
		    my $dcVal = $darr2[0] + 0;
		    my $iCurr = $iDCVal - $nDCRef;
		    my $mA = Volt2Amp( $dcVal, $iCurr );
		    $voltCurrstring .= " $dcVal";
		    $ampCurrstring .= " $mA";
		    
		    if ( ($mA < $minDCACurr[$iCurr]) || ($mA > $maxDCACurr[$iCurr]) ) {
			if ($debug > 0) { print "out-of-bounds dcCurr $dcCurrCount : dcVal $dcVal mA $mA\n"; }
			$dcCurrErrCount++; 
		    }
		    $dcCurrCount++; 
		    $iDCVal++;
		}
	    }	
	    close $tfh;
	    $outputstring .= "$voltCurrstring\n";
	    $outputstring .= "$ampCurrstring\n";
	    if ($debug > 0) { 
		print "dcRefCount $dcRefCount dcRefErrCount $dcRefErrCount\n";
		print "dcCurrCount $dcCurrCount dcCurrErrCount $dcCurrErrCount\n";
	    }
	    $fileCheckCount++;
	} # end dc file   
	elsif ( ($filename =~ /$runstring/) || ($filename =~ /$run2string/) ) {
	    if ($debug > 1) { print "run file\n"; }
	    if ($filename =~ /$runstring/) {
		$outputstring .= "Sync";
		$reAna = 0;
	    }
	    else {
		$outputstring .= "2Sync";
		$reAna = 1;
	    }
	    
	    open( my $tfh, '<', $filename ) or die "Can't open $filename: $!";
	    while(my $line = <$tfh>) {
		chomp $line;
		if ( ($line =~ /$SyncLowstring/) || ($line =~ /$SyncLowstring/) ) {
		    my @sarr = split /$splitColon/, $line;
		    if ($debug > 2) { print "sarr0 $sarr[0] sarr1 $sarr[1]\n"; }
		    my $syncVal = $sarr[1] + 0;
		    $outputstring .= " $syncVal";
		    if ( ($syncVal < $minSync) || ($syncVal > $maxSync) ) {
			$syncErrCount++;
		    }
		    $syncCount++;
		}
	    }	
	    close $tfh;
	    $outputstring .= "\n";
	    
	    if ($debug > 0) { print "syncCount $syncCount syncErrCount $syncErrCount\n"; }
	    if ($reAna == 0) { $fileCheckCount++; }
	} # end run file   	
	elsif ( ($filename =~ /$miscstring/) || ($filename =~ /$misc2string/) ) {
	    if ($debug > 1) { print "misc file\n"; }
	    $reAna = 0;
	    if ($filename =~ /$misc2string/) {
		$reAna = 1;
	    }

	    open( my $tfh, '<', $filename ) or die "Can't open $filename: $!";
	    while(my $line = <$tfh>) {
		chomp $line;

		if ($line =~ /$clockstring/) {
		    $line =~ s/\s+/ /g;
		    $line =~ s/^\s+//;
		    my @carr = split /$splitSpace/, $line;
		    if ($debug > 2) { print "clock line $line\ncarr0 $carr[0] carr1 $carr[1] carr2 $carr[2]\n"; }
		    my $clockVal = $carr[5] + 0;
		    if ($reAna == 0) { $outputstring .= "RingOsc $clockVal\n"; }
		    else { $outputstring .= "2RingOsc $clockVal\n"; }
		    if ( ($clockVal < $minClockSpeed) || ($clockVal > $maxClockSpeed) ) {
			$clockErrCount++;
		    }
		    $clockCount++;
		}
		elsif ($line =~ /$i2cstring/) {
		    $line =~ s/\s+/ /g;
		    $line =~ s/^\s+//;
		    my @carr = split /$splitSpace/, $line;
		    if ($debug > 2) { print "carr0 $carr[0] carr1 $carr[1]\n"; }
		    my $i2cVal = $carr[1] + 0;
		    if ($reAna == 0) { $outputstring .= "i2cErr $i2cVal\n"; }
		    else { $outputstring .= "2i2cErr $i2cVal\n"; }
		    if ( $i2cVal > $maxi2cReadErrors ) {
			$i2cErrCount++;
		    }
		    $i2cCount++;
		}
		elsif ($line =~ /$memorystring/) {
		    $line =~ s/\s+/ /g;
		    my @marr = split /$memorystring/, $line;
		    $marr[1] =~ s/^\s+//;
		    my @carr = split /$splitSpace/, $marr[1];
		    if ($debug > 2) { print "carr0 $carr[0] carr1 $carr[1]\n"; }
		    my $memStatus = $carr[1];
		    chop $carr[4];
		    my $memVal = $carr[4] + 0;
#		    $outputstring .= "Mem $memStatus $memVal\n";
		    if ($reAna == 0) { $outputstring .= "Mem $memVal\n"; }
		    else { $outputstring .= "2Mem $memVal\n"; }
		    if ( $memStatus eq $failstring ) {
			$memErrCount++;
		    }
		    $memCount++;
		}
	    }	
	    close $tfh;

	    if ($debug > 0) { 
		print "clockCount $clockCount clockErrCount $clockErrCount\n";
		print "i2cCount $i2cCount i2cErrCount $i2cErrCount\n";
		print "memCount $memCount memErrCount $memErrCount\n";
	    }

	    if ($reAna == 0) { $fileCheckCount++; }
	} # end misc file   	
	elsif ($filename =~ /$jtagfilestring/) {
	    if ($debug > 1) { print "jtag file\n"; }

	    open( my $tfh, '<', $filename ) or die "Can't open $filename: $!";
	    while(my $line = <$tfh>) {
		chomp $line;

		if ($line =~ /$jtagstring/) {
		    if ($line =~ /$jtagErrstring/) {
			$jtagErrCount++;
		    }
		    $jtagCount++;
		}
	    }	
	    close $tfh;

	    $outputstring .= "Jtag $jtagErrCount\n";
	    
	    if ($debug > 0) { 
		print "jtagCount $jtagCount jtagErrCount $jtagErrCount\n";
	    }

	    $fileCheckCount++;
	} # end jtag file   	
	elsif ($filename =~ /$dftstring/) {
	    if ($debug > 1) { print "dft file\n"; }

	    open( my $tfh, '<', $filename ) or die "Can't open $filename: $!";
	    while(my $line = <$tfh>) {
		chomp $line;

		if ($line =~ /$mismatchstring/) {
		    $line =~ s/\s+/ /g;
		    $line =~ s/^\s+//;
		    my @carr = split /$splitSpace/, $line;
		    if ($debug > 2) { print "mismatch line $line\ncarr2 $carr[2] carr3 $carr[3]\n"; }
		    my $mismatchVal = $carr[3] + 0;
		    $outputstring .= "DFT $mismatchVal\n";
		    if ( $mismatchVal > $maxMismatches ) {
			$dftErrCount++;
		    }
		    $dftCount++;
		}

	    }	
	    close $tfh;
	    
	    $fileCheckCount++;
	} # end dft file   	

	$fileCount++;
    }

# have gone through all files; let's check the Pedestal and RMS values now
    my $nPassPed = CheckPed( $minPedVal[0], $maxPedVal[0] );
    my $nPassRms = CheckRms( $minRmsVal[0], $maxRmsVal[0], $maxRmsVal31 );
}

sub writeOutput {
# cuts on counters
    my $nDAQFiles = 4; #4=noise, calib-odd, calib-even, delay-all 
    my $nAnaFiles = $nDAQFiles + 3; # also run xtalk analysis on calib files (2) + noiseAna (1)

    my $minDCRefOK = 2; # only check V750-V600 and V600-V450
    my $maxDCRefNotOK = 0;
    my $minDCCurrOK = $nDCCurr;
    my $maxDCCurrNotOK = 0;
    
    my $minSyncOK = $nGain * $nDAQFiles; 
    my $maxSyncNotOK = 0;
    my $minPedOK = $nChan;# * $nGain;
    my $maxPedNotOK = 0;
    my $minRmsOK = $nChan;# * $nGain;
    my $maxRmsNotOK = 0;
    my $minGainOK = $nChan;
    my $maxGainNotOK = 0;
    my $minGainOK30 = $nChan - 3; #bit more relaxed cuts for 30 mV than 20 mV gain
    my $maxGainNotOK30 = 3;
    my $minRiseTimeOK = $nChan;# * $nGain;
    my $maxRiseTimeNotOK = 0;
    my $minXtalkOK = $nChan;# * $nGain;
    my $maxXtalkNotOK = 0;

    my $maxBitcheckNotOK = 0;

    my $minClockOK = 1;
    my $maxClockNotOK = 0;
    my $mini2cOK = 1;
    my $maxi2cNotOK = 0;
    my $minMemOK = 1;
    my $maxMemNotOK = 0;
    my $minJtagOK = 10; 
    my $maxJtagNotOK = 0;
    my $minDFTOK = 1;
    my $maxDFTNotOK = 0;

    my $fileExpectedCount = ($nAnaFiles * $nGain) + 5; # +5 is for run.log, dc.log, misc.log, jtag.log, dft.log

    if ($debug>0) { print "found $fileCount files - checked $fileCheckCount - expected $fileExpectedCount\n"; }
    my $FileCountErr = 0;
    if ($fileCheckCount != $fileExpectedCount) { $FileCountErr = 1; }		
#test
    my $DCRefErr = 0;
    my $DCCurrErr = 0;
    my $SyncErr = 0;
    my $PedAnaErr = 0;
    my $RmsAnaErr = 0;
    my $GainErr = 0;
    my $RiseTimeErr = 0;
    my $XtalkErr = 0;
    my $BitcheckErr = 0;
    my $ClockErr = 0;
    my $i2cErr = 0;
    my $MemErr = 0;
    my $JtagErr = 0;
    my $DFTErr = 0;
#
    if ( ($dcRefCount < $minDCRefOK) || ($dcRefErrCount > $maxDCRefNotOK) ) { $DCRefErr = 1; }
    if ( ($dcCurrCount < $minDCCurrOK) || ($dcCurrErrCount > $maxDCCurrNotOK) ) { $DCCurrErr = 1; }
    if ( ($syncCount < $minSyncOK) || ($syncErrCount > $maxSyncNotOK) ) { $SyncErr = 1; }
    if ( ($pedAnaCount < $minPedOK) || ($pedAnaErrCount > $maxPedNotOK) ) { $PedAnaErr = 1; }
    if ( ($rmsAnaCount < $minRmsOK) || ($rmsAnaErrCount > $maxRmsNotOK) ) { $RmsAnaErr = 1; }
    if ( ($gainCount[0] < $minGainOK) || ($gainErrCount[0] > $maxGainNotOK) ) { $GainErr = 1; }
    if ( ($gainCount[1] < $minGainOK30) || ($gainErrCount[1] > $maxGainNotOK30) ) { $GainErr = 1; }
    if ( ($xtalkCount < $minXtalkOK) || ($xtalkErrCount > $maxXtalkNotOK) ) { $XtalkErr = 1; }
    if ( ($bitcheckErrCount > $maxBitcheckNotOK) ) { $BitcheckErr = 1; }
    if ( ($risetimeCount < $minRiseTimeOK) || ($risetimeErrCount > $maxRiseTimeNotOK) ) { $RiseTimeErr = 1; }
# we run misc (clock, i2c and mem) checks twice, and consider it enough if works at least once
    if ($clockErrCount >= $clockCount) { $ClockErr = 1; }
    if ($i2cErrCount >= $i2cCount) { $i2cErr = 1; }
    if ($memErrCount >= $memCount) { $MemErr = 1; }
    if ( ($jtagCount < $minJtagOK) || ($jtagErrCount > $maxJtagNotOK) ) { $JtagErr = 1; }
    if ( ($dftCount < $minDFTOK) || ($dftErrCount > $maxDFTNotOK) ) { $DFTErr = 1; }

    my $ErrorCode = ($FileCountErr * 1) + ($DCRefErr * 2) +  ($DCCurrErr * 4) + ($SyncErr * 8) + 
	($PedAnaErr * 0x10) + ($RmsAnaErr * 0x20) + ($GainErr * 0x40) + ($RiseTimeErr * 0x80) +
	($XtalkErr * 0x100) + ($ClockErr * 0x200) + ($i2cErr * 0x400) + ($JtagErr * 0x800) +
	($MemErr * 0x1000) + ($DFTErr * 0x2000) + ($BitcheckErr * 0x4000);
    my $nErrors = $FileCountErr + $DCRefErr +  $DCCurrErr + $SyncErr + 
	$PedAnaErr + $RmsAnaErr + $GainErr + $RiseTimeErr +
	$XtalkErr + $ClockErr + $i2cErr + $JtagErr +
	$MemErr + $DFTErr + $BitcheckErr;
    my $errhex = sprintf("0x%x", $ErrorCode);
    $outputstring .= "ErrCode $errhex\n";
    
    print "\nSummary: Chip $chipnum\n";
    print "QRCode $QRCode\n";
    print "FileCountErr $FileCountErr\n";
    print "DCRefErr $DCRefErr\n";
    print "DCCurrErr $DCCurrErr\n";
    print "SyncErr $SyncErr\n";
    print "PedAnaErr $PedAnaErr\n";
    print "RmsAnaErr $RmsAnaErr\n";
    print "GainErr $GainErr\n";
    print "RiseTimeErr $RiseTimeErr\n";
    print "XtalkErr $XtalkErr\n";
    print "BitcheckErr $BitcheckErr\n";
    print "ClockErr $ClockErr\n";
    print "i2cErr $i2cErr\n";
    print "MemErr $MemErr\n";
    print "DFTErr $DFTErr\n";
    print "JtagErr $JtagErr\n";

    print "nErrors $nErrors \n";
    print "ErrorCode $errhex \n";

# Error code logic for return code
    my $ReturnCode = 0;
#0 = Chip OK
#2 = Bad 2 => discard : DFT, Jtag, Mem, i2c + Pedestal errors
#5 = C1 => retest : voltages, currents, sync + Rms, RiseTime, Xtalk errors + nGainVeryLow>0
#6 = C2 => spares; gain not quite good enough (nGainVeryLow==0 && nGainErr>0)
    
    if ( (($checkDFTErr==1) && ($DFTErr > 0)) || ($JtagErr > 0) || ($i2cErr > 0) || ($MemErr > 0) ) { 
	$ReturnCode = 2; # Code 2 - Discard: Digital errors 
    } 
    elsif ( (($checkVRefErr==1) && ($DCRefErr > 0)) || ($DCCurrErr > 0) || ($SyncErr > 0) ) { 
	$ReturnCode = 5; # Code 5 - Retest: DC Ref voltages or current or Sync issues 
    } 
    elsif ( ($PedAnaErr > 0) )  { 
	$ReturnCode = 2; # Code 2 - Discard: Pedestal errors
    } 
    elsif ( ($RiseTimeErr > 0) || ($XtalkErr > 0) || ($RmsAnaErr > 0) || ($nGainVeryLow > 0) || ($BitcheckErr>0) )  { 
	$ReturnCode = 5; # Code 5 - Retest: analog issues
    } 
    elsif ( ($GainErr>0) )  { 
	$ReturnCode = 6; # Code 6 - Gain spares
    } 

    print "ReturnCode $ReturnCode \n";
    $outputstring .= "RCode $ReturnCode\n";

# also print all the needed result values to ascii file (blob) for database
    my $outputFilename = "${sampadir}/result${chipnum}.log";
    if (-e $outputFilename) { 
# if this file already exists, then write a new .recheck version
	$outputFilename = "${sampadir}/result${chipnum}.log.recheck";
    }
    my $outputSummaryFilename = "$topdir/summary.csv";
    
    open(OUTSUMMARY, ">>$outputSummaryFilename");
    print OUTSUMMARY "$chipnum $ReturnCode\n";
    close OUTSUMMARY;

    open(OUTP, ">$outputFilename");
    print OUTP "$outputstring";
    close OUTP;
}

sub CheckPed {
    my $minCut = $_[0];
    my $maxCut = $_[1];
# we will check the minimum for each channel of the two noise runs for pedAnaArr and ped2AnaArr (if existing)
# and compare to the input cut values
    my $nPass = 0;
    my $iChan = 0;

    my $nPed = scalar @pedAnaArr;
    my $nPed2 = scalar @ped2AnaArr;
    print "nPed $nPed nPed2 $nPed2\n"; 

    if ($nPed != $nChan) {
	print "unexpected nPed $nPed - returning from CheckPed \n"; 
	return 0;
    }

    if ($nPed2 == $nPed) { # ok to compare with 2nd array also
	for ($iChan = 0; $iChan<$nChan; $iChan++) {
	    my $pedValLow = $pedAnaArr[$iChan];
	    my $pedValHigh = $pedAnaArr[$iChan];
# we should keep the lowest high, and the highest low value (i.e. not absolute highest or lowest)
	    if ($pedAnaArr[$iChan] < $ped2AnaArr[$iChan]) { $pedValLow = $ped2AnaArr[$iChan]; }
	    if ($pedAnaArr[$iChan] > $ped2AnaArr[$iChan]) { $pedValHigh = $ped2AnaArr[$iChan]; }
	    if ( ($pedValLow < $minCut) || ($pedValHigh > $maxCut) ) {
		if ($debug > 0) { print "out-of-bounds ped $pedAnaCount : pedValLow $pedValLow pedValHigh $pedValHigh \n"; }
		$pedAnaErrCount++;
	    }
	    else { $nPass++; }
	    $pedAnaCount++;
	}
    }
    else { # just use value from first array
	for ($iChan = 0; $iChan<$nChan; $iChan++) {
	    my $pedVal = $pedAnaArr[$iChan];
	    if ( ($pedVal < $minCut) || ($pedVal > $maxCut) ) {
		if ($debug > 0) { print "out-of-bounds ped $pedAnaCount : pedVal $pedVal \n"; }
		$pedAnaErrCount++;
	    }
	    else { $nPass++; }
	    $pedAnaCount++;
	}
    }

    if ($debug > 0) {
	print "pedAnaCount $pedAnaCount nPass $nPass pedAnaErrCount $pedAnaErrCount\n";
    }

    return $nPass;
}

sub CheckRms {
    my $minCut = $_[0];
    my $maxCut = $_[1];
    my $maxCut31 = $_[2];
# we will check the minimum for each channel of the two noise runs for rmsAnaArr and rms2AnaArr (if existing)
# and compare to the input cut values
    my $nPass = 0;
    my $iChan = 0;

    my $nRms = scalar @rmsAnaArr;
    my $nRms2 = scalar @rms2AnaArr;
    print "nRms $nRms nRms2 $nRms2\n"; 

    if ($nRms != $nChan) {
	print "unexpected nRms $nRms - returning from CheckRms \n"; 
	return 0;
    }

    if ($nRms2 == $nRms) { # ok to compare with 2nd array also
	for ($iChan = 0; $iChan<$nChan; $iChan++) {
	    my $rmsValLow = $rmsAnaArr[$iChan];
	    my $rmsValHigh = $rmsAnaArr[$iChan];
	    my $rmsCutHigh = $maxCut;
	    if ($iChan >= 30) { # 30,31
		$rmsCutHigh = $maxCut31;
	    }
# we should keep the lowest high, and the highest low value (i.e. not absolute highest or lowest)
	    if ($rmsAnaArr[$iChan] < $rms2AnaArr[$iChan]) { $rmsValLow = $rms2AnaArr[$iChan]; }
	    if ($rmsAnaArr[$iChan] > $rms2AnaArr[$iChan]) { $rmsValHigh = $rms2AnaArr[$iChan]; }
	    if ( ($rmsValLow < $minCut) || ($rmsValHigh > $rmsCutHigh) ) {
		if ($debug > 0) { print "out-of-bounds rms $rmsAnaCount : rmsValLow $rmsValLow rmsValHigh $rmsValHigh \n"; }
		$rmsAnaErrCount++;
	    }
	    else { $nPass++; }
	    $rmsAnaCount++;
	}
    }
    else { # just use value from first array
	for ($iChan = 0; $iChan<$nChan; $iChan++) {
	    my $rmsVal = $rmsAnaArr[$iChan];
	    my $rmsCutHigh = $maxCut;
	    if ($iChan >= 30) { # 30,31
		$rmsCutHigh = $maxCut31;
	    }
	    if ( ($rmsVal < $minCut) || ($rmsVal > $rmsCutHigh) ) {
		if ($debug > 0) { print "out-of-bounds rms $rmsAnaCount : rmsVal $rmsVal \n"; }
		$rmsAnaErrCount++;
	    }
	    else { $nPass++; }
	    $rmsAnaCount++;
	}
    }

    if ($debug > 0) {
	print "rmsAnaCount $rmsAnaCount nPass $nPass rmsAnaErrCount $rmsAnaErrCount\n";
    }

    return $nPass;
}

sub Volt2Amp {
    my $volt = $_[0];
    my $id = sprintf "%.0f", $_[1];
    my $mA = 0; 
    if ( ($id >= 0) && ($id < $nDCCurr) ) {
# @marr values from ~/work/opamp/calib_sta*.log
	if ($station == 1) {
	    my @marr = ( -0.11925, -0.04784, 0.02099, -0.06971, -0.06636 ); 
	    my $m = $marr[$id]; 
	    $mA = 4 * 50.0 * ($volt - $m);
	}
	else { 
	    my @marr = ( -0.00619, -0.08952, -0.05947, -0.08405, -0.06029 ); 
	    my $m = $marr[$id]; 
	    $mA = 4 * 49.2 * ($volt - $m);
	}
    }
    
    return $mA;
}

sub CapCorr {
    my $gain = $_[0] + 0;
    my $chan = sprintf "%.0f", $_[1];

    my $corr = 1.0; 
    if ( ($chan >= 0) && ($chan < $nChan) ) {
	if ($station == 1) {
	    my @caparr = ( 
		1.01076, 1.00423, 1.01335, 1.00718, 1.00187, 1.00374, 0.999222, 0.998755, 
		0.987168, 0.998086, 1.00046, 0.986451, 1.00473, 0.998762, 1.01739, 0.986038, 
		1.00172, 0.997992, 0.995849, 0.999144, 0.991868, 0.976614, 1.00683, 0.994169, 
		0.99998, 0.981731, 1.01026, 0.997688, 1.02123, 0.99549, 1.00377, 0.996182
		); 
	    # my $scale = 20.0 / 20.269;
	    my $scale = 1.0; #DS, unscaled
	    $corr = $caparr[$chan] * $scale; 
	}
	else { # station 2, not yet calibrated
	    my @caparr = ( 
		0.99999, 1.00334, 0.991291, 1.00982, 1.00289, 1.03392, 0.984688, 1.01846, 
		1.00386, 1.01712, 1.00119, 0.986346, 0.977238, 0.996318, 1.00885, 0.976326, 
		0.979849, 1.00013, 1.0126, 0.997502, 0.969492, 1.01243, 0.989848, 1.00514, 
		1.01333, 1.0104, 0.99873, 0.996653, 0.998887, 1.01199, 0.993609, 0.990812 
		);
	    # my $scale = 20.0 / 18.991;
	    my $scale = 1.0; #DS, unscaled
	    $corr = $caparr[$chan] * $scale; 

	}
    }
    my $newgain = $gain * $corr;
    return $newgain;
}

