/  pmt10.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.1
 *  revised March 31, 2000  
 *  Added CH2 code to setup channel 2 and set triggering for CH2, -300mV.
 *  Added prompts to fine tune oscilloscope settings
 *  before taking data and writting files.
 *  The program creates two output files: 
 *    *.arc  the archived data which includes a preamble and date and time stamps
  *   *.wav  the waveform files in a format suitable for gnuplot.  [VS]

 *  created  March 27, 2000
 *  V. Sandberg, P-25, LANL
 *
 * Compile on a WIndows-NT machine with Borlands 32-bit compiler
 * with the command
 *          "bcc32 -w32 pmt10.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_arc;          /* output file handle */
	FILE *outfile_wav;          /* output file handle */
    int i;                  /* loop index */
	int nr_pt;
	char c;
	char *ptr;
 	char cmd[ARRAYSIZE];
	char PMTserial[129];
	char PMTserial2[129];

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

    int n;

/*
 * ========================================================================
 *
 * 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.\n");
  printf("   Output files will 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.\n");
  printf("  Enter 1000 for a typical record.\n\n");
  scanf ("%d", &pulses);
  if ( pulses == 0)
    { 
    pulses = 1;
    }
  printf("     %d pulses will be recorded and processed\n",pulses);
  printf("\n    PMT Serial Number ? ");
  scanf("%s",PMTserial);
  printf("\n\n    Data Record being created for PMT serial # %s\n\n", PMTserial);

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

printf ("\n    Initializing and setting up oscilloscope.  Please be patient.\n\n");
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 ch2\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-1\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 10\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("9a\n");

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

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

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

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

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

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

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

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

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

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

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

    ibwrt (Dev, "select:ch2 on\n", 14L);
    if (ibsta & ERR)
    {
       GPIBCleanup(Dev, "Unable to set select:ch2 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;
    }

/******************************************************/
/**Query user if oscilloscope configuration is correct**/

    for ( ; ; )
    {
	  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;
	  }

      printf("\n  Are the current settings acceptable? [y/n]\n");
      if ('y' == getchar() )
      {
        break;
      }
    }

/*****************************************************/
/******End of Osciloscope Configuration and Setup******/
/******************************************************/

/*
 * Open the output files.
 */

    strcpy (PMTserial2, PMTserial);

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

	strcat(PMTserial2, ".wav");
	if (( outfile_wav = fopen( PMTserial2, "wb" )) == NULL)
	{
		fprintf(stderr, "can't open output file \n");
		exit(1);
	}

/*  Get preamble describing the oscilloscope's settings, data, and time  */
/*  Write as a header to the *.arc file  */

	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_arc, "%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_arc, "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_arc, "Time= %s\n", ValueStr);

/*****************************************************/
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_arc, "%d\n", wfm[i]);
	fprintf(outfile_wav, "%d\n", wfm[i]);
	}

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

fclose(outfile_arc);
fclose(outfile_wav);
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);
    }
}