/*******************************v1.3********************************

Functions to read AC physics data (ACphysics) and AC calibration
data (ACcalib).
Author: Petter Hofverberg, petter@particle.kth.se

0410 v1.0 alive
0412 v1.1 fixed problem with found, and changed headers
0502 v1.2 added a crc check
0502 v1.3 increased buffer size

Errors: (returned to the main program as the variable "err")
err=
0xFF - data (physics or calibration) from both cards found
0xF0 - only data from main card found
0x0F - only data from extra card found
0x00 - no data found

CRCcheck:  1 - OK, 0 - error
******************************************************************/

#include <stdio.h>
#include <string.h>
 
#include "AC.h"
#define TRUE 1
#define FALSE 0

int i,j,found;
unsigned short buffer[8300];
unsigned short tmp1,tmp2,check;
unsigned char err;

struct physicsstruct physicsdata[2];
struct physicsstruct *physicspointer;

struct calibstruct calibdata;
struct calibstruct *calibpointer;


//CRC check function
short crc(short old,short new)
{
  union crc_data {
    short word;
    struct bit_field {
      unsigned b0:1;
      unsigned b1:1;
      unsigned b2:1;
      unsigned b3:1;
      unsigned b4:1;
      unsigned b5:1;
      unsigned b6:1;
      unsigned b7:1;
      unsigned b8:1;
      unsigned b9:1;
      unsigned b10:1;
      unsigned b11:1;
      unsigned b12:1;
      unsigned b13:1;
      unsigned b14:1;
      unsigned b15:1;
    } bit;
  } c,d,r;

  c.word = old;
  d.word = new;
  r.word = 0;

  r.bit.b0 = c.bit.b0 ^ c.bit.b4 ^ c.bit.b8 ^ c.bit.b11 ^ c.bit.b12 ^
             d.bit.b0 ^ d.bit.b4 ^ d.bit.b8 ^ d.bit.b11 ^ d.bit.b12;

  r.bit.b1 = c.bit.b1 ^ c.bit.b5 ^ c.bit.b9 ^ c.bit.b12 ^ c.bit.b13 ^
             d.bit.b1 ^ d.bit.b5 ^ d.bit.b9 ^ d.bit.b12 ^ d.bit.b13;

  r.bit.b2 = c.bit.b2 ^ c.bit.b6 ^ c.bit.b10 ^ c.bit.b13 ^ c.bit.b14 ^
             d.bit.b2 ^ d.bit.b6 ^ d.bit.b10 ^ d.bit.b13 ^ d.bit.b14;

  r.bit.b3 = c.bit.b3 ^ c.bit.b7 ^ c.bit.b11 ^ c.bit.b14 ^ c.bit.b15 ^
             d.bit.b3 ^ d.bit.b7 ^ d.bit.b11 ^ d.bit.b14 ^ d.bit.b15;

  r.bit.b4 = c.bit.b4 ^ c.bit.b8 ^ c.bit.b12 ^ c.bit.b15 ^
             d.bit.b4 ^ d.bit.b8 ^ d.bit.b12 ^ d.bit.b15;

  r.bit.b5 = c.bit.b0 ^ c.bit.b4 ^ c.bit.b5 ^ c.bit.b8 ^ c.bit.b9 ^
             c.bit.b11 ^ c.bit.b12 ^ c.bit.b13 ^
             d.bit.b0 ^ d.bit.b4 ^ d.bit.b5 ^ d.bit.b8 ^ d.bit.b9 ^
             d.bit.b11 ^ d.bit.b12 ^ d.bit.b13;

  r.bit.b6 = c.bit.b1 ^ c.bit.b5 ^ c.bit.b6 ^ c.bit.b9 ^ c.bit.b10 ^
             c.bit.b12 ^ c.bit.b13 ^ c.bit.b14 ^
             d.bit.b1 ^ d.bit.b5 ^ d.bit.b6 ^ d.bit.b9 ^ d.bit.b10 ^
             d.bit.b12 ^ d.bit.b13 ^ d.bit.b14;

  r.bit.b7 = c.bit.b2 ^ c.bit.b6 ^ c.bit.b7 ^ c.bit.b10 ^ c.bit.b11 ^
             c.bit.b13 ^ c.bit.b14 ^ c.bit.b15 ^
             d.bit.b2 ^ d.bit.b6 ^ d.bit.b7 ^ d.bit.b10 ^ d.bit.b11 ^
             d.bit.b13 ^ d.bit.b14 ^ d.bit.b15;

  r.bit.b8 = c.bit.b3 ^ c.bit.b7 ^ c.bit.b8 ^ c.bit.b11 ^ c.bit.b12 ^
             c.bit.b14 ^ c.bit.b15 ^
             d.bit.b3 ^ d.bit.b7 ^ d.bit.b8 ^ d.bit.b11 ^ d.bit.b12 ^
             d.bit.b14 ^ d.bit.b15;

  r.bit.b9 = c.bit.b4 ^ c.bit.b8 ^ c.bit.b9 ^ c.bit.b12 ^ c.bit.b13 ^
             c.bit.b15 ^
             d.bit.b4 ^ d.bit.b8 ^ d.bit.b9 ^ d.bit.b12 ^ d.bit.b13 ^
             d.bit.b15;

  r.bit.b10 = c.bit.b5 ^ c.bit.b9 ^ c.bit.b10 ^ c.bit.b13 ^ c.bit.b14 ^
              d.bit.b5 ^ d.bit.b9 ^ d.bit.b10 ^ d.bit.b13 ^ d.bit.b14;

  r.bit.b11 = c.bit.b6 ^ c.bit.b10 ^ c.bit.b11 ^ c.bit.b14 ^ c.bit.b15 ^
              d.bit.b6 ^ d.bit.b10 ^ d.bit.b11 ^ d.bit.b14 ^ d.bit.b15;

  r.bit.b12 = c.bit.b0 ^ c.bit.b4 ^ c.bit.b7 ^ c.bit.b8 ^ c.bit.b15 ^
              d.bit.b0 ^ d.bit.b4 ^ d.bit.b7 ^ d.bit.b8 ^ d.bit.b15;

  r.bit.b13 = c.bit.b1 ^ c.bit.b5 ^ c.bit.b8 ^ c.bit.b9 ^
              d.bit.b1 ^ d.bit.b5 ^ d.bit.b8 ^ d.bit.b9;

  r.bit.b14 = c.bit.b2 ^ c.bit.b6 ^ c.bit.b9 ^ c.bit.b10 ^
              d.bit.b2 ^ d.bit.b6 ^ d.bit.b9 ^ d.bit.b10;

  r.bit.b15 = c.bit.b3 ^ c.bit.b7 ^ c.bit.b10 ^ c.bit.b11 ^
              d.bit.b3 ^ d.bit.b7 ^ d.bit.b10 ^ d.bit.b11;

  return r.word;
}


//Fill physicsdata from buffer
void fillphys(int k,unsigned short *buff)
{
  for(i=0;i<2;i++) physicsdata[k].header[i]=buff[i];
  physicsdata[k].status=buff[2];
  physicsdata[k].hitmap=buff[3];
  for(i=0;i<6;i++) physicsdata[k].regist[i]=buff[4+i];
  for(i=0;i<16;i++) physicsdata[k].shift[i]=buff[10+i];
  for(i=0;i<16;i++) physicsdata[k].counters[i]=buff[26+i];
  for(i=0;i<8;i++) physicsdata[k].coinc[i]=buff[42+i];
  physicsdata[k].trigg=buff[50];
  for(i=0;i<2;i++) physicsdata[k].clock[i]=buff[51+i];
  for(i=0;i<2;i++) physicsdata[k].temp[i]=buff[53+i];
  for(i=0;i<8;i++) physicsdata[k].DAC[i]=buff[55+i];
  physicsdata[k].CRC=buff[63];
  if(check==physicsdata[k].CRC)
    physicsdata[k].CRCcheck=TRUE;
  else
    physicsdata[k].CRCcheck=FALSE;
}

//Fill calibdata from buffer
void fillcalib(unsigned short *buff)
{
  for(i=0;i<2;i++) calibdata.header[i]=buff[i];
  for(i=0;i<5;i++) calibdata.status[i]=buff[2+i];
  for(i=0;i<8;i++) calibdata.temp[i]=buff[7+i];
  for(i=0;i<8;i++) calibdata.DAC1[i]=buff[15+i];
  for(i=0;i<8;i++) calibdata.DAC2[i]=buff[23+i];
  for(i=0;i<6;i++) calibdata.regist[i]=buff[31+i];
  for(i=0;i<8;i++) calibdata.time[i]=buff[37+i];
  calibdata.n_tr=buff[45];
  for(i=0;i<16;i++) calibdata.hitmap_tr[i]=buff[46+i];
  for(i=0;i<4096;i++) calibdata.curve1[i]=buff[62+i];
  for(i=0;i<4096;i++) calibdata.curve2[i]=buff[4158+i];
  calibdata.iCRC=buff[8254];
  calibdata.tail=buff[8255];
  calibdata.CRC=buff[8256];
  if(check==calibdata.CRC)
    calibdata.CRCcheck=TRUE;
  else
    calibdata.CRCcheck=FALSE;
}

unsigned char ACphysics(int length,unsigned char* datapointer,struct physicsstruct* physicspointer)
{

  err=0;
  found=0;
  check=0;
  int iter=2;
  for(i=0;i<8300;i++)
    buffer[i]=0;
  fillphys(0,&buffer[0]);
  fillphys(1,&buffer[0]);

  //look for top header ACAC, then unpack data to main card buffer or extra card buffer depending on the subheader
  //AC11 for main, AC22 for extra
  while(found<2 && iter<length)
    {
      tmp1 = ((*datapointer) << 8) | *(datapointer+1);
      tmp2 = ((*(datapointer+2)) << 8) | *(datapointer+3);
      if(tmp1 == 0xACAC && ((tmp2 == 0xAC11 && (err&0xF0)==0x0) || (tmp2 == 0xAC22 && (err&0x0F)==0x0)))
	{ 
	  for(i=0;i<64;i++)
	    {
	      buffer[i]=((*datapointer) << 8) | *(datapointer+1);
	      if(i<63)
		check=crc(check,buffer[i]);
	      datapointer=datapointer+2;
	    }
	  if(tmp2==0xAC11){          //main card
	    fillphys(0,&buffer[0]);
	    err |= 0xF0;
	  }
	  else{                      //extra card
	    fillphys(1,&buffer[0]);
	    err |= 0x0F;
	  } 
	  tmp1=tmp2=0x0000;
	  check=0x0;
	  found++;
	}
      else{
	datapointer++;
	iter=iter+1;}
    }
  //point struct-pointer to physicsdata
  physicspointer[0]=physicsdata[0];  //card1
  physicspointer[1]=physicsdata[1];  //card2

  return err;

}


unsigned char ACcalib(int length, unsigned char* datapointer, struct calibstruct* calibpointer)
{

  err=0;
  found=0;
  check=0;
  int iter=2;
  for(i=0;i<8300;i++)
    buffer[i]=0;
  fillcalib(&buffer[0]);

  //look for the top header 0xACCA, then the subheaders 0xAC11 and 0xAC22, and unpack the data
  //to each card depending on these.
  while(found<1 && iter<length)
    {
      tmp1 = ((*datapointer) << 8) | *(datapointer+1);
      tmp2 = ((*(datapointer+2)) << 8) | *(datapointer+3);
      
      if(tmp1 == 0xACCA && ((tmp2 == 0xAC11 && (err&0xF0)==0x0) || (tmp2 == 0xACA2 && (err&0x0F)==0x0)))
	{
	  for(i=0;i<8257;i++)
	    {
	      buffer[i]=((*datapointer) << 8) | *(datapointer+1);
	      if(i<8256) //8257
		check=crc(check,buffer[i]);
	      datapointer=datapointer+2;
	      }
	  
	  if(tmp2==0xAC11){          //main
	    fillcalib(&buffer[0]);
	    err |= 0xF0;
	  }
	  else{                      //extra
	    fillcalib(&buffer[0]);
	    err |= 0x0F; 
	    }
	  tmp1=tmp2=0x0000;
	  found++;
	}
      else{
	datapointer++;
	iter=iter+1;}
    }
  memcpy(calibpointer,&calibdata,sizeof(calibdata));
  
  return err;
}

