/*
 * scan_new.c - scan HTR data in source test format
 *  block size hard-wired at 0xfb (or change below)
 *
 *  understands counter mode and walkin' ones mode
 * 
 * Mods:
 * 25 Oct 01, esh - created
 *   make counter mode continuous across block boundaries
 */

#include <stdio.h>

/* argument switches */
static int jims_mode = 1;		/* source test file format */
static int debug = 0;			/* debugging output */
static int source_mode = 0;		/* source test mode on HTR */
static int counter_mode = 1;		/* 1=counter 0=walking ones */

#define IGNORE_LRB_ERRORS 8	/* ignore these LRB trailer errors */

#define BLOCK_BOUNDARY 7	/* number of (16-bit) data words skipped
				   at block boundary (includes 1 idle word) */
#define RAW_DATA_SIZE (0x38000>>2)	/* 87% overflow point in LRB buffer */

/* other globals */
static int block_size = 0xfb;	/* hardwired in HTR */
static long file_offs = 0;
static char errmsg[256];
static int block_start = 1;
static int block_count = 0;
static int nerr = 0;
static int synched = 0;		/* syncronized with stream or not? */


#define mangle(x) (((x)&0xcfff)|(((x)>>7)&0x60)) /* convert fee->daq */
#define SRC_MASK 0xcfff		/* bits to pay attention to */

void process( unsigned int dw);
void emit_data( unsigned short d);
void do_error( char *msg);

main( argc, argv)
     int argc;
     char *argv[];
{
  FILE *fp;
  char input_file[256];
  unsigned int hs, dsize, dw;
  int i;

  if( argc > 1) {
    for( i=1; i<argc; i++) {
      if( *argv[i] == '-') {
	switch( toupper( argv[i][1])) {

	case 'R':
	  jims_mode = 0;
	  break;

	case 'W':
	  counter_mode = 0;
	  break;

	case 'D':
	  ++debug;
	  break;

	case 'S':
	  source_mode = 1;
	  break;

	case 'F':		// input file
	  if( i == argc) {
	    fprintf( stderr, "need file name after -f\n");
	    return 1;
	  }
	  ++i;
	  strcpy( input_file, argv[i]);
	  break;

	default:
	  printf("usage:  scan_new [-f file]\n");
	  printf("                 [-r]  raw data mode\n");
	  printf("                 [-d]  increase debug mode\n");
	  printf("                 [-w]  check for walking ones\n");
	  printf("                 [-s]  source mode data mangling\n");
	  exit( 1);
	}
      }
    }
  }

  if( source_mode & !counter_mode) {
    printf("I don't know how to do walking ones in source mode\n");
    exit(1);
  }

  if( (fp = fopen( input_file, "r")) == NULL) {
    printf("Cant' open %s for input\n", input_file);
    exit( 1);
  }

  /* if in Jim's mode get data size */
  if( jims_mode) {
    fread( &hs, sizeof(dsize), 1, fp);/* skip first 2 words */
    if( debug>1 ) printf( "  Header size:  0x%08x\n", hs);

    while( hs--) {
      fread( &dsize, sizeof(dsize), 1, fp);
      if( debug>1) printf( "Header word  :  0x%08x\n", dsize);
    }
    printf("Data section size:  0x%08x DWORDS (0x%08x words)\n",
	   dsize, dsize*2);
  } else
    dsize = RAW_DATA_SIZE;
  

  while( fread( &dw, sizeof(dw), 1, fp) == 1) {
    process( dw);
    ++file_offs;
    if( file_offs >= dsize) {
      break;			/* stop at end of data section */
      printf("End of data section\n");
    }
  }

  printf( "* EOF *\n");
  printf( "%d blocks processed\n%d errors seen\n", block_count, nerr);
}

enum states { Start, BlockNo, Data, Trailer, Error };

#define maybe_header(d) ((d&0xffffff00)==0)

/* process one 32-bit data word */
void process( unsigned int dw)
{
  static enum states current = Start;
  enum states next;
  static int first = 1;
  static unsigned last_block=0;
  static unsigned header_block=0;
  static int count = 0;

  if( debug>1)
    printf("process( 0x%08x)\n", dw);

  next = current;

  switch( current) {
  case Error:
  case Start:
    if( maybe_header(dw)) {
      if( debug>1) printf("Maybe header\n");
      header_block = dw;
      next = BlockNo;
    }
    break;

  case BlockNo:
    if( (dw & 0xff) != header_block) {
      sprintf( errmsg, "Error:  header block# 0x%02x  then  0x%08x\n",
	     header_block, dw);
      do_error( errmsg);
      next = Error;
    } else {
      if( debug) printf("Starting block\n");
      block_start = 1;
      ++block_count;
      if( (block_count % 1000) == 0)
	printf("Block %d   file offset %d bytes\n", block_count,
	       file_offs * 4);
      
      if( first) {
	first = 0;
      } else {
	++last_block;
	if( dw != last_block) {
	  sprintf( errmsg,
		   "Error:  new block# 0x%08x  previous block# 0x%08x\n",
		 dw, last_block);
	  do_error( errmsg);
	}
      }
      last_block = dw;
      next = Data;
      count = 3;
    }
    break;

  case Data:
    emit_data( dw & 0xffff);
    emit_data( (dw>>16) & 0xffff);
    ++count;
    if( debug>1) printf("  count=0x%x\n", count);
    if( count == block_size)
      next = Trailer;
    break;

  case Trailer:
    if( count != (dw & 0xffff)) {
      sprintf( errmsg, "Error:  trailer count=0x%x  actual count=0x%x\n",
	     dw & 0xffff, count);
      do_error( errmsg);
    } else {
      next = Start;
    }
    if( (dw & (0xff0000-(IGNORE_LRB_ERRORS<<16)) ) != 0) {
      sprintf( errmsg, "Trailer errors: 0x%02x\n", (dw>>16)&0xff);
      do_error( errmsg);
    }
    if( ((dw>>24) & 0xff) != header_block) {
      sprintf( errmsg, "Trailer block# 0x%02x  Header block# 0x%02x\n",
	       (dw>>24)&0xff, header_block);
      do_error( errmsg);
    }
    break;

  default:
    printf("Unknown State %d!\n", current);
    next = Start;
    break;
  }

  if( (debug>1) && current != next) printf("Going to state %d\n", next);
  current = next;
}


void emit_data( unsigned short d)
{
  static unsigned short last_d = 1;

  if( debug)
    printf("  DATA: 0x%04x\n", d);

  if( source_mode) {

    if( !synched && (d & SRC_MASK) == 0) { /* zero means zero! */
      printf("Source mode synchronized at byte 0x%08x\n", file_offs*4);
      synched = 1;
      last_d = -1;
    }

    if( synched) {
      /* we are allegedly synchronized, and last_d holds the true
	 pre-mangling counter value */
      ++last_d;
      if( block_start) {
	block_start = 0;
	last_d += BLOCK_BOUNDARY;
      }
      if( debug)
	printf("  last_d = 0x%04x  mangle = 0x%04x\n",
	       last_d, mangle(last_d));
      if( (d&SRC_MASK) != mangle(last_d) ) {
	sprintf( errmsg,
		 "Expecting (mangled) counter data 0x%04x got 0x%04x\n",
		 mangle(last_d), d & SRC_MASK);
	do_error( errmsg);
      }
    } else {
      if( block_start)
	block_start = 0;
    }

  } else {			/* not source mode */

    if( counter_mode) {
      ++last_d;
      if( block_start) {
	block_start = 0;
	last_d += BLOCK_BOUNDARY;
      }
      if( d != last_d) {
	sprintf( errmsg, "Expecting counter data 0x%04x got 0x%04x\n",
		 last_d, d);
	do_error( errmsg);
	last_d = d;
      }
    } else {
      if( last_d == 0x8000)
	last_d = 1;
      else
	last_d <<= 1;
      if( block_start) {
	block_start = 0;
	last_d = d;
      }
      if( d != last_d) {
	sprintf( errmsg, "Expecting walking data 0x%04x got 0x%04x\n",
		 last_d, d);
	do_error( errmsg);
	last_d = d;
      }
    }
  }
}



void do_error( char *msg)
{
  static long last_offs = 0;

  printf("Error %d at byte 0x%08x (0x%08x words) block %d:\n  %s",
	 nerr, file_offs*4, (file_offs-last_offs)*2, block_count, msg);
  ++nerr;
  last_offs = file_offs;
}
