// This code is used to record 40 bit time, i.e. reading 5 time bytes from
// the arduino nano.
//#include <X11/Xlib.h>
#include <assert.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <sys/io.h>
#include <unistd.h>
// #include <asm/msr.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
//  #include <asm/page.h>
#include <sys/time.h>
#include <time.h>
#include <termios.h>
#include <sys/signal.h>
#include <sys/types.h>

#define BAUDRATE B115200
#define MODEMDEVICE "/dev/ttyUSB0"
#define _POSIX_SOURCE 1 /* POSIX compliant source */
#define FALSE 0
#define TRUE 1

volatile int STOP=FALSE;

int wait_flag=TRUE;                    /* TRUE while no signal received */


int xi,y;
int ppc_fix;
int ii,i, j, jj, xn, yyn, icolor;
int xx1, xx2, yy1, yy2;
//  Global
int running, run, runc, graphdriver, graphmode, graphing;
int nx,ny, ncheck;
long int count;
float con1, con2, sumtime, v1c, v2c, xa, denom, circum;
float a, sumxx, b, sumxy, sumx, sumy, del, delx, dely;
float maxx, maxy, maxxx, maxxy, scalet, scalev;
char cho, filename[20], buffer[80], dum[80];
double fac, cpu, fr, frc,facpic,tottime,period[3600];
double x, time1, time2, timepen[3600], v2[3600],vel[3600], rvel[3600], toffset;
double astar[3600];
int ntot, ncal, s1, s2;
float ss1, inter, slop, deltime;
unsigned long by1, by2, by3, by4;
unsigned long firstcount, secondcount,countdiff;
unsigned long dum1, dum2, dum3, dum4;
FILE *inf,*outf,*outf1, *outf2, *outf3;
char fileout[20];
int fd,c, res, icount;
struct termios oldtio,newtio;
struct sigaction saio;           /* definition of signal action */
unsigned char buf[10000];

void menu();
void calbrat();
void setpoints();
void takedat();  //244
void datview();  //157
void writeout();
void signal_handler_IO (int status);   /* definition of signal handler */

int main()
{
  printf("\n\n\n  Time and Velocity program for Pendulum Data\n\n\n");
// Get the cpu frequency
  char filename[]="/proc/cpuinfo";
  inf=fopen("/dev/ttyUSB0","r");
//  while(fr<100.0)
//   {
//     fscanf(inf,"%s", dum);
//     fr=atof(dum);
//     if(fr>10) frc=fr;
 //    printf("%s    %f\n",dum, fr);
//   }

 cpu=frc*1000000.0;
  by1=256;
  by2=256*256;
  by3=by1*by2;
  by4=by2*by2;
// cpu=1600000000.0;
// printf("The cpu clock frequency is  %f Hz\n\n",cpu);
 printf("menu:\n\n");
    ntot=3;
    for (i=0;i<100;i++)
     {
      timepen[i]=(i-1)*1.0;
      vel[i]=(i-1)*1.0;
      rvel[i]=vel[i];       
     }
    iopl(3);
    circum=2.7;
    fac=4294967296.0;
    facpic=0.0000000625;
    menu();
   running=1;
 do
 {
 
   {
     printf("input an option (then hit return): \n");
     scanf("%c", &cho);
     switch(cho)
     {
      case 'n' : setpoints();    //setpoints
                 menu();
                 break;
      case 'd' : takedat();     //takedata
                 break;
      case 'z' : calbrat();    //calibrate the thickness
                 break;
      case 'v' : datview();    //datview
                 menu;
                 break;
      case 'm' : menu();
                 break;
      case 'w' : writeout();
                 break;
      case 'q' : running = 2;
      default :  menu();
                 break;
     }


   }
 }while (running==1);
 return(0);
}

void menu()
{
 printf(" total blockings = %d \n", ntot);
 printf(" effective thickness = %f [cm] \n", circum);
 printf(" press n to set the number of data points\n");
 printf(" press d to take data\n");
 printf(" press z to change the blocking thickness\n");
 printf(" press v to view data\n");
 printf(" press m to see the menu\n");
 printf(" press w to save data\n");
 printf(" press Q to exit the program\n\n\n");
}

void calbrat()
{
 printf("Input the effective thickness of the blocking \n");
 scanf("%f",&circum);
 return;
}

void testgate()
 {
 printf(" \n The test is over\n");
 printf("Press t to test again or m to menu\n\n");
 }

void setpoints()
{
  printf("Input the total # of times you want the photogate to be blocked\n");
  scanf("%d",&s1);
  ntot=s1;
  if (s1<1) ntot=1;
  if (s1>30) ntot=30;
  return;
}

void datview()
 {
 printf("Data Points    Time(sec)         Velocity(cm/sec) \n");
 for (i=1; i<=ntot; i++)
  {
  printf("     %d         %f            %f \n",i, timepen[i], rvel[i]);
  }
 }

void writeout()
 {
 outf1=fopen("penddata.txt","w");
 for (i=2; i<ntot; i=i+2)
  {
   period[i]=timepen[i+1]-timepen[i-1];
   fprintf(outf1,"%.8lf    %.8lf\n",period[i], rvel[i]);
  }
  fclose(outf1);
  printf("The data has been written to penddata.txt \n\n\n");
 }

void takedat()
{
 ncheck=1;

/* open the device to be non-blocking (read will return immediatly) */
        fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK );
//        if (fd <0) {perror(MODEMDEVICE); exit(-1); }

/* install the signal handler before making the device asynchronous */
        saio.sa_handler = signal_handler_IO;
        sigemptyset(&saio.sa_mask);   //saio.sa_mask = 0;
        saio.sa_flags = 0;
        saio.sa_restorer = NULL;
        sigaction(SIGIO,&saio,NULL);

        /* allow the process to receive SIGIO */
        fcntl(fd, F_SETOWN, getpid());
        /* Make the file descriptor asynchronous (the manual page says only
           O_APPEND and O_NONBLOCK, will work with F_SETFL...) */
        fcntl(fd, F_SETFL, FASYNC);

        tcgetattr(fd,&oldtio); /* save current port settings */
        /* set new port settings for canonical input processing */
        newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
        newtio.c_iflag = IGNPAR | ICRNL ;
        newtio.c_oflag = 0;
//        newtio.c_cflag &=~(PARENB | CSTOPB | CSIZE);
//        newtio.c_lflag = ~ICANON;
        newtio.c_cc[VMIN]=8*ntot;
        newtio.c_cc[VTIME]=0;
        newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG );
        tcflush(fd, TCIFLUSH);
        tcsetattr(fd,TCSANOW,&newtio);
  STOP=FALSE;
   i=0;
    ntot=0;
//   printf("%d \n",(int)time(NULL));
    firstcount=(int)time(NULL);
    countdiff=0;
//   printf("%ld \n",firstcount);
//   for(j=0;j<ntot;j++)
   while(countdiff<10) 
   {
   for (jj=0;jj<10;jj++)
    {
     buf[i]=fgetc(inf);
     i=i+1;
    }
    ntot=ntot+1;
    secondcount=(int)time(NULL);
    countdiff=secondcount-firstcount;
    printf("%d \n",ntot);
    firstcount=secondcount;
   }
//  for (i=0;i<10*ntot;i=i+5)
//    printf("%u %u %u %u %u \n",buf[i],buf[i+1],buf[i+2],buf[i+3],buf[i+4]);
  i=0;
  ii=1;
  while(ii<=ntot)
   {
   time1=buf[i]+by1*buf[i+1]+by2*buf[i+2]+by3*buf[i+3]+by4*buf[i+4];
   time2=buf[i+5]+buf[i+6]*by1+buf[i+7]*by2+buf[i+8]*by3+buf[i+9]*by4;
   timepen[ii]=(time1+time2)/2.0;
   timepen[ii]=timepen[ii]*facpic;
   deltime=time2-time1;
   vel[ii]=circum/deltime/facpic;
   ii=ii+1;
   i=i+10;
   }

  tottime=((dum3-dum1)+fac*(dum4-dum2))/cpu;
  toffset=timepen[1];
  for(ii=1;ii<=ntot;ii++)
   timepen[ii]=timepen[ii]-toffset;

  for (i=1; i<=ntot; i++)
  {
  rvel[i]=vel[i];
  }

  outf=fopen("tvout.txt","w");
  for (i=2;i<ntot;i++)
   {
    period[i]=timepen[i+1]-timepen[i-1];
    fprintf(outf,"%.8lf    %.8lf\n",period[i], rvel[i]);
    printf("   %.6lf     %.6lf \n",period[i], rvel[i]);
   }
  fclose(outf);
//  printf("Data Point         Time(sec)         Velocity(cm/sec) \n");
  for (i=1; i<=ntot; i++)
  {
  vel[i]=rvel[i]/100.0;
  v2[i]=vel[i]*vel[i];
  }
//  printf("The acceleration is %f cm/sec2 \n",xa*b);
 for(i=2;i<ntot;i++)
  {
   astar[i]=2.0*(vel[i-1]-vel[i+1])/period[i];
  }
 outf2=fopen("astardata.txt","w");
 outf3=fopen("astardatabackup.txt","w");
 for(i=2;i<ntot;i++)
 {
  printf("%.8f    %.8f \n",vel[i],astar[i]);
  fprintf(outf2,"%.8f    %.8f\n",vel[i],astar[i]);
  fprintf(outf3,"%.8f    %.8f\n",vel[i],astar[i]);
 }
 fclose(outf2);
 fclose(outf3);
  {if (runc==2) printf("Bad Data");}
  close(fd);
}

void signal_handler_IO (int status)
 {
   wait_flag = FALSE;
 }


