#include <error.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>

#include "drivers/linux/pci17x4/pci17x4api.hpp"

int
main(int argc, char **argv)
{
  bool ul = false;
  const char *devname = (argc > 1) ? argv[1] : NULL;
  pci17x4 *adc;
  if(devname) {
    adc = pci17x4::open(devname);
  } else if((adc = pci17x4::open("/dev/pci1744e0"))) {
    devname = "/dev/pci17x4e0";
  } else if((adc = pci17x4::open("/dev/pci1714u0"))) {
    devname = "/dev/pci17x4u0";
  } else if((adc = pci17x4::open("/dev/pci1714ul0"))) {
    devname = "/dev/pci17x4ul0";
    ul = true;
  }
  if(!adc) {
    error(1, errno, "pci17x4::open() can not open device 0");
  }
  printf("sample rate = %.2fkHz\n", (0.001 * adc->sampleRate()));
  double srate = (double)(((argc > 2) && atoi(argv[2])) ? (atoi(argv[2]) * 1000) : ul ? 10000000 : 10000000);
  adc->sampleRate(srate);
  printf("sample rate = %.2fkHz\n", (0.001 * adc->sampleRate()));
  adc->configure(16777216, 4096, 1000, 1);
  printf("buffer size = %d scans\n", (int)adc->bufferScans());
  printf("buffer block size = %d scans\n", (int)adc->blockScans());
  printf("buffer blocks = %d\n", (int)adc->bufferBlocks());
  adc->start();
  printf("sample rate = %.2fkHz\n", (0.001 * adc->sampleRate()));
  struct timeval tstart, tnow;
  gettimeofday(&tstart, NULL);
  FILE *fp = fopen("/tmp/triggers.out", "w");
  uint64_t dsum = 0, dcount = 0, tcount = 0, psamp = 0, samp = 0;
  int trig = 0, noff = 0;
  for(int i = 0; i < 1000000000; i++) {
    pci17x4::datascan_t *scans = adc->readScans(16384);
    if(!scans || ((i % 99) == 7)) {
      const pci17x4_dmastatus_t &stbuf = adc->status();
      if(stbuf.error) {
        adc->stop();
        fprintf(stderr, "\n");
        error(1, 0, "ADC error (fifo=%d, tout=%d, io=%d, buf=%d)", (int)stbuf.errfifo, (int)stbuf.errtout, (int)stbuf.errio, (int)stbuf.errbuf);
      }
      int nfull = (int)adc->bufferFull();
      double pfull = 100.0 * (double)adc->bufferFull() / (double)adc->bufferScans();
      gettimeofday(&tnow, NULL);
      double tdelta = (double)(tnow.tv_sec - tstart.tv_sec) + ((double)((int)tnow.tv_usec - (int)tstart.tv_usec) * 0.000001);
      double srate = tdelta ? ((nfull + (16384.0 * (double)(i))) / tdelta) : 0.0;
      printf("\rbuffers = %d, full = %d (%.2f%%), rate = %.2fHz        \r", i, nfull, pfull, srate);
      fflush(stdout);
    }
    if(scans) {
      if(fp) {
        for(int n = 0; n < 16384; n++, samp++) {
          int ntrig = (scans[n][0] | scans[n][1] | scans[n][2] | scans[n][3]) & 0x8000;
	  if(ntrig) {
	    if(!trig && (noff < 1024)) {
	      ntrig = 0;
	    }
	    noff = 0;
	  } else {
	    noff++;
	  }
          if(ntrig && !trig) {
            tcount++;
            if(psamp) {
              int delta = (int)(samp - psamp);
              if(dcount < 100) {
                dsum += delta;
                dcount++;
              } else {
                int davg = (int)(dsum / dcount);
                if((delta >= (davg * 0.95)) && (delta <= (davg * 1.05))) {
                  dsum += delta;
                  dcount++;
                  if((tcount % 1000) == 0) {
                    fprintf(fp, "At %lld, average trigger interval = %d samples, triggers seen = %lld\n", (long long)samp, davg, (long long)tcount);
                    fflush(fp);
                  }
                } else {
                  fprintf(fp, "At %lld, inconsistent trigger: current interval = %d samples, average = %d, noff=%d\n", (long long)samp, delta, davg, noff);
                  fflush(fp);
                }
              }
            }
            psamp = samp;
          }
          trig = ntrig;
        }
      }
      adc->freeScans(scans, 16384);
    } else {
      i--;
    }
  }
  // printf("\nsample rate = %.2fkHz\n", (0.001 * adc->sampleRate()));
  adc->stop();
  printf("sample rate = %.2fkHz\n", (0.001 * adc->sampleRate()));
  exit(0);
}
