/* getp3rec -- Read a P-3 record from standard input that has been
 * written to disk using rtape with the record headers enabled.
 * Return the record size in shorts.
 *
 *
 * -------------------------------------------------------------------
 * modifications leading to getp3rec.c.r1.v0 were not documented,
 * but the had to do with the compatibility of different versions
 * of the header data -- see MOD-December-5-2003 next.
 * -------------------------------------------------------------------
 *
 * MOD-December-5-2003  ---------------------------------------------
 * This modifications is made so this function can work with data 
 * files from EPIC as well as from TogaCoare. TogaCoare files 
 * have header verision equal to 1, while EPIC data have version 2.
 * This was the reason for the modification of this file made during
 * the field campaing of EPIC.
 *
 * After examination of the differences between the EPIC version 
 * (getp3rec.c.r2.v0) and the TogaCoare version (getp3rec.c.r1.v0)
 *
 * It seems to me that this file can be used for both data files.
 * At most, the only addition that is needed is a safegard against
 * the lack of data to define ta_wlenght,ta_prf, and nyv0.
 * (buff: 471, and 473)
 *
 * I'm testing if the safegard is really needed -- it doesnot seems so.
 * -------------------------------------------------------------------
 */
#include <stdio.h>
#include "cdfhdr.h"

#define MASK8 0377               /* mask for lowest byte */
#define BINANG 182.044           /* 2^15/180 */
#define RAYHEAD 22               /* size of ray header */
#define DHEAD 5                  /* size of data block header */

short getshort();

long getp3rec(max,buff)
long max;                        /* maximum number of shorts allowed */
short *buff;                     /* pointer to buffer */
{
  char header[9];
  long prop,actual;

/* read the header and decode it */
  if ((actual = fread(header,sizeof(char),8,stdin)) != 8) {
    if (actual == 0) {
      fprintf(stderr,"getp3proc: end of file on header read\n");
      return(-1);   /* end of file */
    }
    else {
      fprintf(stderr,"getp3rec: mangled block header -- ignored\n");
      return(0);                /* mangled block */
    }
  }
  header[8] = '\0';
  sscanf(header,"%d",&prop);

/* if record header indicates zero, return zero */
  if (prop == 0) return(0);

/* convert prop to number of shorts */
  prop /= 2;
  if (prop < 1 || prop > max) {
    fprintf(stderr,"getp3rec: record size %d out of requested limits\n",prop);
    exit(1);
  }

/* read the buffer and return size */
  if ((actual = fread(buff,sizeof(short),prop,stdin)) != prop) {
    if (actual == 0) {
      fprintf(stderr,"getp3rec: end of file on block read\n");
      return(-1);      /* end of file */
    }
    else {
      fprintf(stderr,"getp3rec: mangled block -- ignored\n");
      return(0);
    }
  }
  return(actual);
}

/* p3header -- Interpret P-3 header, returning useful information */
p3header(buff,len,year,mon,day,hour,min,sec,
     ac_id,flt_id,d_head_size,r_head_size,tzone,proj_id,
     lf_data_mode,lf_vargates,lf_num_in,lf_num_out,lf_firstgate,lf_gatestep,
     ta_data_mode,ta_vargates,ta_num_in,ta_num_out,ta_firstgate,ta_gatestep,nyv)

short *buff;                       /* buffer for data extraction */
long len;                          /* size of buffer in shorts */
short *year,*mon,*day,*hour,*min,*sec;   /* time of header */
short *ac_id;                      /* aircraft id -- 42 or 43 */
char *flt_id;                      /* flight id -- 8 bytes */
short *d_head_size,*r_head_size;   /* data and ray header size */
short *tzone;                      /* minutes from GMT of time zone (+west) */
char *proj_id;                     /* project id -- 16 bytes */
short *lf_data_mode,*lf_vargates,*lf_num_in,*lf_num_out;
float *lf_firstgate,*lf_gatestep;  /* lower fuselage radar parameters */
short *ta_data_mode,*ta_vargates,*ta_num_in,*ta_num_out;
float *ta_firstgate,*ta_gatestep,*nyv;  /* tail radar parameters */
{
  int vnum;
  float ta_wlenght,ta_prf,nyv0;
  int bin_8,bin_9,aux8,aux9;

/* MOD-December-5-2003 */
/* first get version number */
  vnum = getshort(buff,3);
  
  if ( vnum > 2 ) {
     fprintf(stderr,"p3header: version number %d not supported\n",vnum);
     exit(1);
  }

/* get the time */
  *year = getshort(buff,5);
  *mon = getshort(buff,6);
  *day = getshort(buff,7);
  *hour = getshort(buff,8);
  *min = getshort(buff,9);
  *sec = getshort(buff,10);

/* get identifiers */
  *ac_id = getshort(buff,38);
  getstring(buff,39,8,flt_id);
  getstring(buff,80,16,proj_id);

/* get the data and ray header size */
  *d_head_size = getshort(buff,43);
  *r_head_size = getshort(buff,44);

/* lower fuselage radar */
  *lf_data_mode = getshort(buff,114);
  *lf_vargates = getshort(buff,141);
  *lf_num_in = getshort(buff,143);
  *lf_num_out = getshort(buff,148);
  *lf_firstgate = 1000.*getshort(buff,140) + 10.*getshort(buff,145);
  *lf_gatestep = (float)getshort(buff,142);

/* tail radar */

  *ta_data_mode = getshort(buff,414);
  *ta_vargates = getshort(buff,441);
  *ta_num_in = getshort(buff,443);
  *ta_num_out = getshort(buff,448);
  *ta_firstgate = 1000.*getshort(buff,440) + 10.*getshort(buff,445);
  *ta_gatestep = (float)getshort(buff,442);

/* MOD-December-5-2003 */
  /* if ( vnum == 2 ) { */
          /*I should test if this safegard is reallly necesary.*/

  ta_wlenght = (float)getshort(buff,471); /*in 1/100 of cm*/
  ta_prf = (float)getshort(buff,473); /*in Hz*/
  nyv0 = (ta_wlenght * ta_prf) / 40000.0;

  /* Pulse repetition Mode for Tail Radar is set in word 401
   * bit 8 = 0 ; bit 9 = 0 => Single PRF;      =>  nyq0 
   * bit 8 = 1 ; bit 9 = 0 => dual   PRF 2/3;  => 2*nyq0  
   * bit 8 = 0 ; bit 9 = 1 => dual   PRF 3/4;  => 3*nyq0 */
  aux8 = aux9 =(unsigned)getshort(buff,401); 
  bin_8 = (aux8 >> 8 ) & ~(~0 << 1);
  bin_9 = (aux9 >> 9 ) & ~(~0 << 1);

  /*short cut to get 1,2, or 3 according to */
  *nyv = ((float)bin_8 + 2.0 * (float)bin_9 + 1.0) * nyv0;

  /* } else { *nyv = 12.89 ; } */
  /* NYQUIST from Dave Jorgensen  this is the 
     fallbak onto the behavior of getp3rec.c.r1.v0 */

}

/* p3dhead -- Extract the data header from a P-3 data block */
p3dhead(buff,length,bpointer,sweep,record,radar)
short *buff;                  /* the input buffer */
long length;                  /* length of buffer */
long *bpointer;               /* data buffer pointer */
short *sweep;                 /* sweep number */
short *record;                /* record (ray) number in this sweep */
short *radar;                 /* radar -- 1 = LF, 2 = TA */
{
  *sweep = getshort(buff,2);
  *record = getshort(buff,3);
  *radar = getshort(buff,4) >> 8;
  *bpointer = DHEAD;
}

/* p3rhead -- Extract ray header from a P-3 data block */
p3rhead(buff,length,bpointer,raybytes,refl,vel,width,ryear,rmon,rday,
     rhour,rmin,rsec,rmsec,lon,lat,alt,ua,va,wa,u,v,w,raz,rel,pitch,roll,
     drift,heading)
short *buff;                  /* the input buffer */
long length;                  /* length of buffer */
long *bpointer;               /* data buffer pointer */
short *raybytes;              /* number of bytes in ray */
short *refl,*vel,*width;      /* flags for existence of various fields */
short *ryear,*rmon,*rday,*rhour,*rmin,*rsec,*rmsec;   /* ray time */
float *lon,*lat,*alt;         /* longitude, latitude, altitude,
                                 degrees, degrees, km */
float *ua,*va,*wa;            /* aircraft velocity, m/s */
float *u,*v,*w;               /* wind velocity, m/s */
float *raz,*rel;              /* raw azimuth and elevation of ray, degrees */
float *pitch,*roll,*drift,*heading;   /* aircraft orientation and drift
                                 (degrees) */
{
  short temp;
  short *bp;

/* set up a pointer to the start of the ray header */
  bp = buff + *bpointer;

/* snarf the data */
  *raybytes = getshort(bp,0);
  temp = getshort(bp,1);
  *refl = (temp >> 15) & 1;
  *vel = (temp >> 14) & 1;
  *width = (temp >> 13) & 1;
  *ryear = MASK8 & temp;
  temp = getshort(bp,2);
  *rmon = MASK8 & (temp >> 8);
  *rday = MASK8 & temp;
  *rhour = MASK8 & getshort(bp,3);
  *rmin = getshort(bp,4);
  temp = getshort(bp,5);
  *rsec = temp/100;
  *rmsec = 10*(temp - 100*(*rsec));
  *lon = ((float)getshort(bp,7))/BINANG;
  *lat = ((float)getshort(bp,6))/BINANG;
  *alt = ((float)getshort(bp,8))/1000.;
  *ua = .1*((float)getshort(bp,9));
  *va = .1*((float)getshort(bp,10));
  *wa = .1*((float)getshort(bp,11));
  *u = .1*((float)getshort(bp,12));
  *v = .1*((float)getshort(bp,13));
  *w = .1*((float)getshort(bp,14));
  *raz = ((float)getshort(bp,17))/BINANG;
  *rel = ((float)getshort(bp,16))/BINANG;
  *pitch = ((float)getshort(bp,18))/BINANG;
  *roll = ((float)getshort(bp,19))/BINANG;
  *drift = ((float)getshort(bp,20))/BINANG;
  *heading = ((float)getshort(bp,21))/BINANG;
  if (*heading < 0.) *heading += 360.;

/* increment the buffer pointer */
  *bpointer += RAYHEAD;
}

/* uncomp -- uncompress data buffer */
int uncomp(buff,length,bpointer,raybytes,outlen,outmax,ubuff)
short *buff;                       /* input buffer */
long length;                       /* length of input buffer */
long *bpointer;                    /* buffer pointer */
long raybytes;                     /* size of ray block in bytes */
long *outlen;                      /* size of unpacked data (bytes) */
long outmax;                       /* size of output buffer */
short *ubuff;                      /* unpacked buffer */
{
  short temp,temp2,run;
  long i,j,k,size;

/* compute size of data block in shorts */
  size = (raybytes + 1)/2 - RAYHEAD;

/* loop on input words */
  j = 0;
  i = *bpointer;
  while (i < *bpointer + size) {
    temp = getshort(buff,i++);

/* decode run length encoding */
/* end of ray or garbage */
    if (temp >= 0 && temp <= 2) break;

/* temp is number of short zeros */
    else if (temp > 0) {
      for (k = 0; k < 2*temp; k++) {
        if (j >= outmax) {
          fprintf(stderr,"uncomp: length %d of output buffer exceeded\n",
               outmax);
          return(1);
        }
        ubuff[j++] = 0;
      }
    }

/* temp with sign removed is number of short data points */
    else {
      temp = temp & 077777;
      for (k = 0; k < temp; k++) {
        temp2 = getshort(buff,i++);
        if (j >= outmax) {
          fprintf(stderr,"uncomp: length %d of output buffer exceeded\n",
               outmax);
          return(1);
        }
        ubuff[j++] = (temp2 >> 8) & MASK8;
        if (j >= outmax) {
          fprintf(stderr,"uncomp: length %d of output buffer exceeded\n",
               outmax);
          return(1);
        }
        ubuff[j++] = temp2 & MASK8;
      }
    }
  }

/* set output length */
  *outlen = j;

/* increment input buffer pointer */
  *bpointer += size;

/* success */
  return(0);
}

/* getshort -- get a short from the buffer */
short getshort(buff,position)
short *buff;
int position;
{
  short w;
  char *cp,*wp;

/* byte swapping if VAX-type ordering of bytes in shorts -- tested on
   a decstation 5000 */
#if VAX
  cp = (char*)(buff + position);
  wp = (char*)(&w);
  *wp = *(cp + 1);
  *(wp + 1) = *cp;
  return(w);

/* otherwise, no byte swapping */
#else
  return(buff[position]);
#endif
}

/* getstring -- get a null terminated string from the P-3 buffer */
getstring(buff,position,length,result)
short *buff;
int position,length;
char *result;
{
  int i;
  for (i = 0; i < length; i++) result[i] = *(((char*)(buff + position)) + i);
  result[length] = '\0';
}
