/*  pmt9.c
 *  MiniBooNE (and maybe BooNE) test stand code 
 *  The code that runs the PMT test stand for testing the miniBooNE 
 *  photomultiplier tubes.  This program configures the Tek 620B 
 *  Digital Oscilloscope, and records 1000 anode waveforms.  The
 *  waveforms are written to a file named after the pmt under test's
 *  serial number, e.g., A124.dat.  Other code reads this *.dat file 
 *  to produce the ourput charge and time histograms and any other 
 *  test results.
 *
 *  v1.0
 *  March 27, 2000
 *  V. Sandberg, P-25, LANL
 *
 * Compile on a WIndows-NT machine with Borlands 32-bit compiler
 * with the command
 *          "bcc32 -w32 pmt9.c BorlandC_gpib-32.obj"
 * This will compile the code and link it with the National Instruments
 * GPIB driver library to produce a stand alone executable.
 *
 */

 
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>

#include <string.h>

#include <windows.h>
#include "decl-32.h"

#define ARRAYSIZE          2048     // Size of read buffer

#define BDINDEX               0     // Board Index
#define PRIMARY_ADDR_OF_SCOPE 6     // Primary address of device
#define NO_SECONDARY_ADDR     0     // Secondary address of device
#define TIMEOUT               T10s  // Timeout value = 10 seconds
#define EOTMODE               1     // Enable the END message
#define EOSMODE               0     // Disable the EOS mode

#define THRESHOLD             0.005
#define YSCALE                200.0E-06

int  Dev;
char ValueStr[ARRAYSIZE + 1];
char ErrorMnemonic[21][5] = {"EDVR", "ECIC", "ENOL", "EADR", "EARG",
                             "ESAC", "EABO", "ENEB", "EDMA", "",
                             "EOIP", "ECAP", "EFSO", "", "EBUS",
                             "ESTB", "ESRQ", "", "", "", "ETAB"};

void GPIBCleanup(int Dev, char* ErrorMsg);

int main()
{
	int rslt;               /* error return variable */
	char wfm[1040];         /* array for raw scope output */
	FILE *outfile;          /* output file handle */
	int i;                  /* loop index */
	int nr_pt;
	char c;
	char *ptr;
 	char cmd[ARRAYSIZE];
	char PMTserial[129];

	int mainloop;
	int pulses;         /* number of pmt pulses */

    int n;
    int icharge, itime;
    int hist_q[502], hist_t[502];
/*    int hist_qt[502][502];  */

 long int  y[502], 
           yoff,
           ycharge,
           charge;

  float v, ayoff, threshold, yscale;

  threshold = THRESHOLD;
  yscale = YSCALE;

/*
 *=========================================================================
 * 
 *  Clear histograms  hist_q[], hist_t[], and hist_qt[][] 
 * 
 *=========================================================================
 */

 for ( i=0; i < 502; i++)
   {
     hist_q[i] = 0;
     hist_t[i] = 0;
/*     for (n=0; n < 502; n++)
       {
         hist_qt[i][n[] = 0;
       }   */
   }

/*
 * ========================================================================
 *
 * Welcome and parameter queries to user. 
 *
 * ========================================================================
 */

  printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
  printf ("\n      Welcome to the miniBooNE/BooNE Photomultiplier Tube Test Stand\n\n\n\n");
  printf ("Please be sure all instruments are powered up and on line before continuing.\n");
  printf("Please check the time and date on the TDS620B Oscilloscope.  Output files will\n");
  printf("be labeled and identified by the date and time written.\n\n");
  printf("Press <Enter> to continue.\n");
  printf("\n\n\n\n\n\n");
  getchar(); 
  printf("Please enter the number of pulse records to collect.\n\n");
  printf("This should be an integer between 1 and 1000.  Enter 1000 for a typical record.\n");
  scanf ("%d", &pulses);
  if ( pulses == 0)
    { 
    pulses = 1;
    }
  printf(" %d pulses will be recorded and processed\n",pulses);
  printf("\nPMT Serial Number ? ");
  scanf("%s",PMTserial);
  printf("\n\nData Record being created for PMT serial # %s\n\n", PMTserial);

/*
 * ========================================================================
 *
 * INITIALIZATION SECTION  Set up GPIB communications and configure oscilloscope.
 *
 * ========================================================================
 */

printf("Opening handle to device. \n");
    Dev = ibdev(BDINDEX, PRIMARY_ADDR_OF_SCOPE, NO_SECONDARY_ADDR,
                TIMEOUT, EOTMODE, EOSMODE);
    if (ibsta & ERR)
    {
       printf("Unable to open device\nibsta = 0x%x iberr = %d\n",
               ibsta, iberr);
       return 1;
    }
printf("Clearing device with ibclr\n");
    ibclr (Dev);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to clear device");
       return 1;
    }
printf("Starting initialization sequence\n");
/*****************************************************/
/*  Wait for the instrument to clear itself and be in a clean state.  */

ibwrt (Dev, "*WAI\n", 5L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set oscilloscope to a clear state");
       return 1;
    }

/*****************************************************/
printf("display:format yt\n");

    ibwrt (Dev, "display:format yt\n", 18L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set display:format yt");
       return 1;
    }

/*****************************************************/
printf("display:style vectors\n");

    ibwrt (Dev, "display:style vectors\n", 22L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set display:style vectors");
       return 1;
    }

/*****************************************************/
printf("display:filter sinx\n");

    ibwrt (Dev, "display:filter sinx\n", 20L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set display:filter sinx");
       return 1;
    }

/*****************************************************/
printf("clearmenu\n");

    ibwrt (Dev, "clearmenu\n", 10L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set clearmenu");
       return 1;
    }

/*****************************************************/
printf("acquire:mode sample\n");

    ibwrt (Dev, "acquire:mode sample\n", 20L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set acquire:mode sample");
       return 1;
    }

/*****************************************************/
printf("acquire:stopafter sequence\n");

    ibwrt (Dev, "acquire:stopafter sequence\n", 27L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set acquire:stopafter sequence");
       return 1;
    }

/*****************************************************/
printf("trigger:main:mode normal\n");

    ibwrt (Dev, "trigger:main:mode normal\n", 25L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set trigger:main:mode normal");
       return 1;
    }

/*****************************************************/
printf("trigger:main:type edge\n");

    ibwrt (Dev, "trigger:main:type edge\n", 23L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set trigger:main:type edge");
       return 1;
    }

/*****************************************************/
printf("1\n");

    ibwrt (Dev, "trigger:main:edge:source ch1\n", 29L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set trigger:main:edge:source ch1");
       return 1;
    }

/*****************************************************/
printf("2\n");

    ibwrt (Dev, "trigger:main:edge:coupling dc\n", 30L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set trigger:main:edge:coupling dc");
       return 1;
    }

/*****************************************************/
printf("3\n");

    ibwrt (Dev, "trigger:main:edge:slope fall\n", 29L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set trigger:main:edge:slope fall");
       return 1;
    }

/*****************************************************/
printf("4\n");

    ibwrt (Dev, "trigger:main:level -3.E-3\n", 26L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set trigger:main:level -3.E-3");
       return 1;
    }

/*****************************************************/
printf("5\n");

    ibwrt (Dev, "horizontal:mode main\n", 21L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set horizontal:mode main");
       return 1;
    }

/*****************************************************/
printf("6\n");

    ibwrt (Dev, "horizontal:main:scale 1E-8\n", 27L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set horizontal:main:scale 1E-8");
       return 1;
    }

/*****************************************************/
printf("7\n");

    ibwrt (Dev, "horizontal:recordlength 500\n", 28L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set horizontal:recordlength 500");
       return 1;
    }

/*****************************************************/
printf("8\n");

    ibwrt (Dev, "horizontal:trigger:position 50\n", 31L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set horizontal:trigger:position 50");
       return 1;
    }

/*****************************************************/
printf("9\n");

    ibwrt (Dev, "ch1:bandwidth full\n", 19L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set ch1:bandwidth full");
       return 1;
    }

/*****************************************************/
printf("10\n");

    ibwrt (Dev, "ch1:coupling dc\n", 16L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set ch1:coupling dc");
       return 1;
    }

/*****************************************************/
printf("11\n");

    ibwrt (Dev, "ch1:impedance fifty\n", 20L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set ch1:impedance fifty");
       return 1;
    }

/*****************************************************/
printf("12\n");

    ibwrt (Dev, "ch1:offset 0\n", 13L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set ch1:offset 0");
       return 1;
    }

/*****************************************************/
printf("13\n");

    ibwrt (Dev, "ch1:position 3\n", 15L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set ch1:position 3");
       return 1;
    }
 
/*****************************************************/
printf("14\n");

    ibwrt (Dev, "ch1:scale 5.E-3\n", 16L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set ch1:scale 5.E-3");
       return 1;
    }

/*****************************************************/
printf("15\n");

    ibwrt (Dev, "select:ch1 on\n", 14L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set select:ch1 on");
       return 1;
    }

/*****************************************************/
printf("16\n");

    ibwrt (Dev, "data:source ch1\n", 16L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set sdata:source ch1");
       return 1;
    }

/*****************************************************/
printf("17\n");

    ibwrt (Dev, "data:encdg ribinary\n", 20L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set data:encdg ribinary");
       return 1;
    }

 /*****************************************************/
printf("18\n");

    ibwrt (Dev, "data:width 1\n", 13L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set data:width 1");
       return 1;
    }

/*****************************************************/
printf("19\n");

    ibwrt (Dev, "data:start 1\n", 13L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set data:start 1");
       return 1;
    }

/*****************************************************/
printf("20\n");

    ibwrt (Dev, "data:stop 500\n", 14L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set data:stop 500");
       return 1;
    }

 /*****************************************************/
printf("21.\n");

    ibwrt (Dev, "header off\n", 11L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set header off");
       return 1;
    }

/******************************************************/
/*  wait for all the set up commands to finish.  */

    ibwrt (Dev, "*WAI\n", 5L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set oscilloscope to a clear state");
       return 1;
    }

/******************************************************/
/*
 * Open the output file.
 */

	strcat(PMTserial, ".dat");
	if (( outfile = fopen( PMTserial, "wb" )) == NULL)
	{
		fprintf(stderr, "can't open output file %s\n");
		exit(1);
	}

/*****************************************************/
for(mainloop = 0; mainloop < pulses; mainloop++)
  {

 /*****************************************************/

    ibwrt (Dev, "acquire:state run\n", 18L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set acquire:state run");
       return 1;
    }

    ibwrt (Dev, "*WAI\n", 5L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to acquire.");
       return 1;
    }

/*****************************************************/
/*  Get waveform  */

    ibwrt (Dev, "curve?\n", 7L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to get curve?");
       return 1;
    }

/*
 * Read in the header information. The header includes #<x><yyy>.
 */

    ibrd( Dev, &c, 1L );      /* read in the '#' symbol */
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to read the # symbol");
       return 1;
    }

    ibrd( Dev, &c, 1L );      /* read in string length of num bytes to transfer */
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to read in size of bytes <x>");
       return 1;
    }

	rslt = atoi(&c);           /* convert string to integer */
    ibrd( Dev, cmd, (long int)rslt );  /* read in string containing num bytes to transfer */
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to read in <YYY>string");
       return 1;
    }

	cmd[rslt]='\0';            /* force a null terminated string */
	rslt = atoi(cmd);          /* num bytes to transfer */

/*
 * Read the raw waveform data including the linefeed at the end.
 */
    ibrd( Dev, wfm, (long int)rslt );
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to read waveform data string");
       return 1;
    }

/* Get linefeed at the end */
    ibrd( Dev, &c, 1L );
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to read terminating <LF>");
       return 1;
    }

/*   nr_pt = 500;  */

	for(i=0;i<rslt;i++)
	{
	fprintf(outfile, "%d\n", wfm[i]);
	}

printf("PMT # %s,   processing waveform # %d of %d\n", PMTserial, mainloop, pulses);

/*  Process data for baseline adjustment and q and t determination.
    This will add data to the histogram arrays hist_q and hist_t.

   histogram.c
   reads the output file from pmtX.c  
   and computes the DC baseline,
   charge, time, and histograms the charge
   and time distributions.
   version 0.2  
   March 21, 2000 
   V. Sandberg, P-25, LANL
 */

/*
 *  Data is stored in 500 point records in array y[]. 
 *   i indexes the position within a record and runs from 1 to 500.
 */

/*  fill the data record array y[]  */
  /*  for(i=1; i<501; i++)
    {
      n = i - 1;
      y[i] = wfm[n];
    }
  */
/*  shift point value according to tek vertical offset = 75  */
   /* for (i=1; i < 501; i++)
    {
      y[i] = y[i] - 75L;
    }
   */
/*  compute the DC baseline using the first 100 data points  */
  /* yoff = 0L;
    for (i=1; i<101; i++)
    {
      yoff = yoff + y[i];
    }
    ayoff = ((float) yoff)/100.00; */
    /*  analog offset value, for use in time determination  */
   
/*  compute the charge between 200 and 500, a 300 ns wide window  */
   /*  ycharge = 0L;
    for (i=201; i<501; i++)
    {
      ycharge = ycharge + y[i];
    }
   */
/*  correct for the DC offset and flip the sign  */
    /* charge = (3L*yoff - ycharge);  
    if (charge < 0L)
    {
      charge =0L;
    }
   */
/*  Determine charge histogram bin and increment histogram  */
  /*    if ( charge > 5000L)
      {
      hist_q[501] = hist_q[501] +1;
      }
    else
      {
        icharge = ((int) charge/10);
        hist_q[icharge] = hist_q[icharge] +1;
      }
  */
/*  Determine time when pulse crosses threshold voltage  */
 /*   itime = 501;
    for (i=1;i<501;i++)
    {
      v = ((float)y[i] - ayoff) * yscale - threshold;
      if ( v < 0.0 )
        {
          itime = i;
          i = 501;
        }
    }
    hist_t[itime] = hist_t[itime] +1;
 */
/*  Collect data for the correlation in the 2-D histogram hist_qt[][]  */
/*    hist_qt[icharge][itime] = hist_qt[icharge][itime] +1;  */

  }
/*  end of mainloop  */

  /*  send out the histogram  */
/*  for ( i = 0; i < 501; i++)
    {
      printf("%d\n", hist_q[i]);
    }
*/
/*****************************************************/
/*  Get preamble describing the oscilloscope's settings  */

	ibwrt (Dev, "WFMPre?\n", 8L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to send WFMPre?");
       return 1;
    }

    ibrd (Dev, ValueStr, ARRAYSIZE);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to read format data from oscilloscope");
       return 1;
    }
    ValueStr[ibcntl - 1] = '\0';
	fprintf(outfile, "%s\n", ValueStr);

	ibwrt (Dev, "DATE?\n", 6L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to send WFMPre?");
       return 1;
    }

    ibrd (Dev, ValueStr, ARRAYSIZE);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to read format data from oscilloscope");
       return 1;
    }
    ValueStr[ibcntl - 1] = '\0';
	fprintf(outfile, "Date= %s\n", ValueStr);

	ibwrt (Dev, "TIME?\n", 6L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to send WFMPre?");
       return 1;
    }

    ibrd (Dev, ValueStr, ARRAYSIZE);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to read format data from oscilloscope");
       return 1;
    }
    ValueStr[ibcntl - 1] = '\0';
	fprintf(outfile, "Time= %s\n", ValueStr);

/*****************************************************/
/*  print histograms to outfile, printing in order
    hist_q
    hist_t
    hist_qt
 */
/* fprintf( outfile, "hist_q\n");
 for ( i = 0; i < 502; i++)
    {
      fprintf(outfile, "%d\n", hist_q[i]);
    }
 fprintf( outfile, "hist_t\n");
 for ( i = 0; i < 502; i++)
    {
      fprintf(outfile, "%d\n", hist_t[i]);
    }
*/
/* for ( i = 0; i < 501; i++)
    {
      for ( n = 0; n < 501; n++)
        {
          fprintf(outfile, "%d\n", hist_qt[i][n]);
        }
    }
*/

/******************************************************/
fclose(outfile);
printf("\n\n    Made it to the end.  Time to change to the next tube\n");
return (0);
}

/*****************************************************/

void GPIBCleanup(int Dev, char* ErrorMsg)
{
    printf("Error : %s\nibsta = 0x%x iberr = %d (%s)\n",
            ErrorMsg, ibsta, iberr, ErrorMnemonic[iberr]);
    if (Dev != -1)
    {
       printf("Cleanup: Taking device offline\n");
       ibonl (Dev, 0);
    }
}