/* program to generate data for the source test and write it to disk 
J. Rohlf, August 31, 2001
3 Oct. 2001, add pesestal shift to channel 6
*/

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


#define MAXLINE 1000 /* maximum input line size*/

int getline(char line[], int maxline);

#define MAXDAT 0xFB /* data block size, 32 bit words*/
//#define RAND_MAX 1000000 /* max random number*/

int make_data(unsigned long int data[], int maxdat, unsigned long int block_no);
long int random(void);

main()
{
  int len; /* current line length*/
  char line[MAXLINE]; /* current input line */

  unsigned long int data[MAXDAT];
  unsigned long int block_no;
  int words;
  FILE *fp;
  int rc, irun[1], word_32[1];
  int c, d, i;
  time_t curtime;
  struct tm *loctime;
  int blocks_to_write;
  int block_length[0];
  int trailer_length;
  int trailer_pos;

 /* get the last run number from file and increment*/
  fp = fopen( "run_no.dat", "r+");
  rc = fread(irun, 4, 1, fp);
  printf("old run number = %8i " ,irun[0]);
  printf("\n");

  rewind(fp);
  irun[0]=irun[0]+1;
  rc = fwrite(irun, 4, 1, fp);
  printf("new run number = %8i " ,irun[0]);
  printf("\n");

  fclose(fp);

/* open data file and write run number and word count (32 bit words) */
// write 100 blocks of length maxdat
  blocks_to_write = 100;
  //open with read/write so we can write the trailer variable word count
  fp = fopen( "dump.dat", "w+");
  block_length[0] = 2;
  rc = fwrite(block_length, 4, 1, fp);
  rc = fwrite(irun, 4, 1, fp);
  word_32[0] = MAXDAT * blocks_to_write;
  rc = fwrite(word_32, 4, 1, fp);


  //   printf("%d %d\n", MAXDAT, RAND_MAX);
  block_no = 0;
  for (i = 0; i < blocks_to_write; i++) {
     words = make_data(data, MAXDAT, block_no);
     rc = fwrite(data, 4, MAXDAT, fp);
     block_no = block_no + 1;
  }
  
  //    for (i = 0; i <= 1000; i++)
  //      printf("%d\n",data[i]);

  //add trailer
  //hold a place for the trailer word count
     trailer_pos = ftell(fp);
  irun[0] = 0;
     rc = fwrite(irun, 4, 1, fp);

  // print out start of trailer
    rc = fputs("\nFermilab Source Test, Data Trailer\n", fp);
    fputs("\nFermilab Source Test, Data Trailer\n", stdout);

/* Get the current time. */
  curtime = time (NULL);

/* Convert it to local time representation. */
  loctime = localtime (&curtime);

/* Print out the date and time in the standard format. */
  fputs (asctime (loctime), stdout);
  fputs (asctime (loctime), fp);
    fputs("(East Coast Time)\n", stdout);
    fputs("(East Coast Time)\n", fp);


  // this section to accept user input...
  // end with C-d


    fputs("Enter user comments here:\n", stdout);
    fputs("User comments:\n", fp);
    fputs("(when done type control-d)\n", stdout);


 while ((len = getline(line, MAXLINE)) > 0)

   if(len > 0) {
 rc = fputs( line,fp);
  }

 //go back and count trailer words
 fseek(fp, trailer_pos, 0);
 c = 0;
 while(1){
   rc = fread(irun, 4, 1, fp);
   if(rc == 1) c++;
   if(rc !=1) break;
 }
 fseek(fp, trailer_pos, 0);
  irun[0] = c;
     rc = fwrite(irun, 4, 1, fp);


  fclose(fp);


  return 0;
}


/* Simulate data for source test as transmitted from the DCC to the CPU
 */
int make_data(unsigned long int d[], int lim, unsigned long int b)
{
  int data_a, data_b, data_c, data_d, i, imax;
  long int krandom;
  unsigned short int cap_id;
  //  printf("%d\n",RAND_MAX);
  if(lim == 0)
    return 0;
  else {
/* first 32 bit word
byte 0 =  block number
byte 1 = 0
byte 2-3 = user data
*/
    d[0] = b & 0xff;
//second word is block number
    d[1] = b;

/* next word is
bytes 0-1 = data_a and data_b, source on and off
bytes 2-3 = data_c and data_d, source on and off 
*/

//now generate two 16-bit data words and pack them
// data for source on... channel a
// set cap id
    cap_id = 3;
    for(i = 2; i < lim-1; i++) {
      cap_id = (cap_id+1) & 3;
      krandom = random();
      krandom = krandom / 2147.483647;
// printf("%d\n",krandom);
      data_a = 0;
      data_b = 0;
      if((krandom >= 0) && (krandom <= 249))
	data_b = 4;
      if((krandom >= 250) && (krandom <= 3583))
	data_b = 3;
      if((krandom >= 3584) && (krandom <= 36920))
	data_b = 2;
      if((krandom >= 36921) && (krandom <= 259165))
	data_b = 1;
      data_b = data_b + 6.2;
      krandom = random();
      krandom = krandom / 2147.483647;
      if((krandom >= 0) && (krandom <= 3))
	data_a = 4;
      if((krandom >= 4) && (krandom <= 154))
	data_a = 3;
      if((krandom >= 155) && (krandom <= 4678))
	data_a = 2;
      if((krandom >= 4570) && (krandom <= 95053))
	data_a = 1;
      data_a = data_a + data_b;
// data for source off... channel b
      krandom = random();
      krandom = krandom / 2147.483647;
      data_b = 0;
      if((krandom >= 0) && (krandom <= 249))
	data_b = 4;
      if((krandom >= 250) && (krandom <= 3583))
	data_b = 3;
      if((krandom >= 3584) && (krandom <= 36920))
	data_b = 2;
      if((krandom >= 36921) && (krandom <= 259165))
	data_b = 1;
      data_b = data_b + 6.2;
      /*if(data_b != 0)
	printf("%d\n",data_b);*/
  d[i] = data_a + (data_b << 7) + (cap_id << 14);

// data for source on... next word
      cap_id = (cap_id+1) & 3;
      krandom = random();
      krandom = krandom / 2147.483647;
      data_c = 0;
      data_d = 0;
      if((krandom >= 0) && (krandom <= 249))
	data_d = 4;
      if((krandom >= 250) && (krandom <= 3583))
	data_d = 3;
      if((krandom >= 3584) && (krandom <= 36920))
	data_d = 2;
      if((krandom >= 36921) && (krandom <= 259165))
	data_d = 1;
      data_d = data_d + 6.2;
      krandom = random();
      krandom = krandom / 2147.483647;
      if((krandom >= 0) && (krandom <= 3))
	data_c = 4;
      if((krandom >= 4) && (krandom <= 154))
	data_c = 3;
      if((krandom >= 155) && (krandom <= 4678))
	data_c = 2;
      if((krandom >= 4570) && (krandom <= 95053))
	data_c = 1;
      data_c = data_c + data_d;
// data for source off... 
      krandom = random();
      krandom = krandom / 2147.483647;
      data_d = 0;
      if((krandom >= 0) && (krandom <= 249))
	data_d = 4;
      if((krandom >= 250) && (krandom <= 3583))
	data_d = 3;
      if((krandom >= 3584) && (krandom <= 36920))
	data_d = 2;
      if((krandom >= 36921) && (krandom <= 259165))
	data_d = 1;
      data_d = data_d + 6.2;

 
      d[i] = d[i] + (data_c << 16) + (data_d << 23) + (cap_id << 30);
      //    printf("%d\n",d[i]);
    }
//one more word to write
      d[lim-1] = (lim & 0xffff) + (b << 24);
  return lim;
  }
}

/* source calibration tests
data format
16 bit words

D(15:14)	CapID_B(1:0)
D(13)		CapID error
D(12)		G-Link error
D(11:7)		Mant_B
D(6)		Exp_B(1) OR Exp_A(1)
D(5)		Exp_B(0) OR Exp_A(0)
D(4:0)		Mant_A

CapID_B(1:0) are supposed to change cyclicly: ...,00, 01, 10, 11, 00, 01,
...  When this sequence is violated then the CapID error bit is asserted.
CapID error is in the same clock slot of the word tha violated the sequence.
NB: when GLink goes from IDLE to DATA (or CONTROL) mode, the first word can
generate a spurious CapID error
*/

/* poisson distribution
exp(-a) * a**n / n!
a = 0.3
n=0   0.7408
n=1   0.2222
n=2   0.0333
n=3   0.0033
n=4   0.0003


a = 0.1
n=0   0.904837
n=1   0.090484
n=2   0.004524
n=3   0.000151
n=4   0.000004

a = 0.01
n=0   0.990050
n=1   0.009900
n=2   0.000050

*/




int getline(char s[], int lim)
{
  int c, i;

  for(i = 0; i < lim-1 && (c=getchar()) != EOF && c != '\n'; ++i)
    s[i] = c;
  if (c == '\n') {
    s[i] = c;
    ++i;
  }
  s[i] = '\0';
  return i;
}
