/* **********************************************************************
 * *                                                                    *
 * *                                                                    *
 * *                                                                    *
 * **********************************************************************
 * File: utils/tdwr/raw_create_task.c
 *
 *                     COPYRIGHT (c) 2004, 2005  BY
 *          SIGMET INCORPORATED, WESTFORD MASSACHUSETTS, U.S.A.
 * 
 * THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND  COPIED
 * ONLY  IN  ACCORDANCE WITH  THE  TERMS  OF  SUCH  LICENSE  AND WITH THE
 * INCLUSION OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE  OR  ANY OTHER
 * COPIES  THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
 * OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF  THE  SOFTWARE  IS  HEREBY
 * TRANSFERED.
 */

#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#define INCLUDE_SYSTIME_PROTOTYPES 1
#include <sys/time.h>
#include <sys/msg.h>
#include <unistd.h>

#include "sigtypes.h"
#include "dsp.h"
#include "headers.h"
#include "iris_task.h"
#include "ingest.h"
#include "product.h"
#include "sigversion.h"

#include "dsp_lib.h"
#include "misc_lib.h"
#include "user_lib.h"

#define TDWR_ALLOCATE 1

#include "tdwr_interface.h"

struct config_file
{
  int    mon_lprf_num, haz_lprf_num;
  BIN2   mele[40], hele[40];
  int    mon_scan_expected, haz_scan_expected;
};
static void ProcessConfigFile( struct config_file *pConfig_a, const char *sPath_a );
static void CloseLprfScan
( const struct product_configuration *pLpcf_a,
  struct ingest_data_header *pIdhdr_a,
  const UINT4 ptr_table_a[360], 
  const UINT1 t_data_val_a[1546*360], 
  const UINT1 z_data_val_a[1546*360], 
  const char *lingest_summary_path_a,
  int        *praw_count_a );

static void CloseVolScan
( const struct product_configuration *pVpcf_a,
  struct ingest_data_header *pIdhdr_a,
  const UINT4 ptr_table_a[360], 
  const UINT1 t_data_val_a[1546*360], 
  const UINT1 z_data_val_a[1546*360], 
  const UINT1 v_data_val_a[612*360], 
  const UINT1 w_data_val_a[612*360], 
  const UINT1 c_data_val_a[612*360], 
  const char *lingest_summary_path_a,
  int        *pRawCount_a,
  int         lCloseFlag_a );  /* Close partial volume scan */

static void sighup_handler (int signal_a);

static char   log_str[200];

int main(int argc, char **argv)
{
  union  tdwr_buf *mptr;
  struct mail_ptr mail_ptr;
  int    Ethernet_qid;
  int    dwell_index, int_vel, int_width, max_range;
  UINT1  done, previous_scan_number, scan_number, lprf_flag, scan_flag, vol_flag;
  UINT2  previous_vol_count, vol_in_progress;
  char   tmp_str[PATHNAME_SIZE];
  UINT4  ptr_table[360];
  char   vingest_summary_path[PATHNAME_SIZE], lingest_summary_path[PATHNAME_SIZE];
  char   vingest_summary_name[20], lingest_summary_name[20];
  UINT1  t_data_val[1546*360], z_data_val[1546*360], v_data_val[612*360], w_data_val[612*360], c_data_val[612*360];
  int    i, j, k, soe_time, int_azimuth, int_elevation, byte_index, raw_count;
  struct full_time_spec DataTime;
  struct ingest_data_header idhdr;
  struct ray_header ray_header;
  struct product_configuration lpcf, vpcf;
  float  elevation, azimuth, nyquist, vel, width; 
  float  vel_ratio, width_ratio, tmp_float;
  struct sigaction action;
  struct config_file Config;
  
  logging = 0;
  action.sa_handler = sighup_handler;
  sigemptyset( &action.sa_mask );
  action.sa_flags = 0;
  sigaction( SIGHUP, &action, NULL );

  sleep(5);

  /*****
    Process the configuration file
  *****/
  if (argc != 2)
    {
      printf("usage: raw_create_task <config file name>\n");
      exit(0);
    }
  ProcessConfigFile( &Config, argv[1] );

  /* Starting here catch signals */
  sig_establish( SignalHandler, "raw_create_task" );

  strcpy(tmp_str, "rm -f /usr/iris_data/volume/*");
  system(tmp_str);

  Ethernet_qid = msgget( 234, (IPC_CREAT|0777));
  global_memory_attach();

  if (Ethernet_qid==-1)
    Lprintf("Msg queue get failed!");
  else
    {
      sprintf(log_str, "Msg queue id=%d", Ethernet_qid );
      Lprintf(log_str);
    }

  /* Read dwells and discard until we get a start of volume, so we can
   * sync up with TDWR */
  done = 0;
  while (!done)
    {
      msgrcv(Ethernet_qid, &mail_ptr, 4, 0, 0);
      dwell_index = mail_ptr.index;
      mptr = dwell_p + dwell_index;
      previous_vol_count = mptr->tdwr_buf_norm.volume_scan_count;
      if (mptr->tdwr_buf_norm.sov)
	{
	  done = 1; 
	}   
      else
	{
	  dwell_table->node[dwell_index] = 0;
	}     
    } 
  
  previous_scan_number = 0;
  scan_number = 0;
  lprf_flag = 0;
  scan_flag = 0;
  vol_flag = 0;
  raw_count = 0;

  /* This is the main loop of the program.  Here we check to see if the dwell is either
     a normal dwell (2B00) or a low prf dwell (2B01).  Then based that, we process the
     dwell as below. */

  Lprintf("Start of first full volume scan.");
  while(1)
  {
    /* If this is a normal dwell */
    if (mptr->tdwr_hdr.msg_id == 0x2B00)
    {

      /* If we currently are collecting for a low prf scan, then close out that scan first */
      if (lprf_flag)
      {
	lprf_flag = 0;
	CloseLprfScan( &lpcf, &idhdr, ptr_table, t_data_val, z_data_val, 
		       lingest_summary_path, &raw_count );
      }

      /* If we get the start of a new scan, and an old scan is still open, 
	 then close out that old scan first */ 
      if (mptr->tdwr_buf_norm.soe ||
         (previous_scan_number != mptr->tdwr_buf_norm.scan_number))
      {
	if (scan_flag)
	{
	  /* close out old scan */
	  scan_flag = 0;
	  vpcf.psi.raw.isweep = scan_number;
	  CloseVolScan( &vpcf, &idhdr, ptr_table, t_data_val, z_data_val, v_data_val,
			w_data_val, c_data_val, vingest_summary_path, &raw_count, 0 );
	}
      }

      /* If we are not currently processing a scan, set flag so we can start new scan processing */ 
      if (!scan_flag)
      {
        mptr->tdwr_buf_norm.soe = 1;
      }

      /* If we are in the middle of processing a volume, and we detect a new volume has 
	 started, then set the flag to close out that old volume */
      if (vol_flag && (vol_in_progress != mptr->tdwr_buf_norm.volume_scan_count))
      {
        vol_flag = 0;
      }

      /* If we currently don't have a volume open, then open a new one */
      if (vol_flag == 0)
      {
	struct ingest_header vihdr;
	FILE   *out_file;
	struct timeval tv;

	/* open new volume */
	vol_flag = 1;
	tv.tv_sec  = mptr->tdwr_buf_norm.timestamp;
	tv.tv_usec = 0;
	TimeFullFromTimeval( &DataTime, &tv, TIME_FLG_LOCAL );
	/* tm = localtime((time_t *)&mptr->tdwr_buf_norm.timestamp); */
	lstart_name_int( vingest_summary_name, "TDR", &DataTime.Ymds );
	strcpy( vingest_summary_path, "/usr/iris_data/volume/" );
	strcat( vingest_summary_path, vingest_summary_name );

	memset( &vihdr, 0, sizeof(struct ingest_header));
	vihdr.hdr.id = ST_INGEST_HDR;
	vihdr.hdr.ivers = SVER_INGEST_HDR_P;
	vihdr.hdr.ibytes = sizeof (struct ingest_header);
	vihdr.hdr.reserved = 0;
	vihdr.hdr.iflags = 0;
 
        strcpy( vihdr.icf.sfile, vingest_summary_name); 
        vihdr.icf.idfnum = 0;
        vihdr.icf.isweeps_done = 0;
        vihdr.icf.idfsize = 0;
        vihdr.icf.ib_rayhed = 12;
        vihdr.icf.ib_task = sizeof(struct task_configuration);
        memcpy( vihdr.icf.sSitename, "tdr_rad1        ", 16);
        vihdr.icf.ilat = (BIN4)( 22.3628 * (0x20000000 / 45.0));
        vihdr.icf.ilon = (BIN4)(114.0111 * (0x20000000 / 45.0));
	strcpy((char *)&(vihdr.icf.siris_version),  IRIS_VERSION );
	vihdr.icf.ignd_hgt = 50;
	vihdr.icf.irad_hgt = 30;
        vihdr.icf.inrev = 360;
        vihdr.icf.ialtitude = 8000;

	vihdr.icf.VolumeYmds   = DataTime.Ymds;
	vihdr.icf.iMinutesWest = DataTime.iMinutesWest;
	vihdr.icf.iLocalWest   = DataTime.iLocalWest;
	memcpy( vihdr.icf.sLocalTZName, DataTime.sLocalTZName, 8 );

        vihdr.icf.isndx = 0;
        vihdr.icf.irtotl = 360;

        vihdr.tcf.hdr.id = ST_TASK_CONF;
        vihdr.tcf.hdr.ivers = SVER_TASK_CONF_P;
        vihdr.tcf.hdr.ibytes = sizeof(struct task_configuration);

	DspMaskSet( &vihdr.tcf.dsp.DataMask, DB_DBT );
	DspMaskSet( &vihdr.tcf.dsp.DataMask, DB_DBZ );
	DspMaskSet( &vihdr.tcf.dsp.DataMask, DB_VEL );
	DspMaskSet( &vihdr.tcf.dsp.DataMask, DB_WIDTH );
	DspMaskSet( &vihdr.tcf.dsp.DataMask, DB_VELC );

	/* vihdr.tcf.dsp.idata = (1 << DB_DBT) | (1 << DB_DBZ) | (1 << DB_VEL) |
	 * (1 << DB_WIDTH) | (1 << DB_VELC); */

        vihdr.tcf.dsp.itrig = 0; /* unfolding: 0=none, 1=2:3 */
        vihdr.tcf.dsp.iprf = (int)((1.0 / (518.0 / 1000000.0)) + 0.5);
        vihdr.tcf.dsp.ipw = 110; /* fixed for TDWR */

        vihdr.tcf.rng.ibin_first = 0;
        vihdr.tcf.rng.ibin_last = 600 * 150 * 100;
        vihdr.tcf.rng.ibin_in_num = 600;
        vihdr.tcf.rng.ibin_out_num = 600;
        vihdr.tcf.rng.ibin_in_step = 150 * 100;
        vihdr.tcf.rng.ibin_out_step = 150 * 100;

        vihdr.tcf.scan.iscan = 4; /* ppi full */
	vihdr.tcf.misc.ilambda = 535;
        vihdr.tcf.misc.itrunc = 2130000;

        memset(&vpcf, 0, sizeof(struct product_configuration));
	vpcf.epoch         = vihdr.icf.VolumeYmds;
	vpcf.prod_time     = vihdr.icf.VolumeYmds;

	vpcf.hdr.id = ST_PRODUCT_CONF;
	vpcf.hdr.ivers = SVER_PRODUCT_CONF_P;
	vpcf.hdr.ibytes = sizeof(struct product_configuration);
	vpcf.iptype = PROD_RAW;
	vpcf.isch = PSC_ALL;
	vpcf.irange_last_v20 = 600 * 150 * 100;
	vpcf.psi.raw.iDataMask0 = vihdr.tcf.dsp.DataMask.iWord0;
	vpcf.psi.raw.iraw_bin_last = 600 * 150 * 100;
	vpcf.psi.raw.iraw_convert = 0;
	vpcf.psi.raw.iflags = 1;
	vpcf.ixsize = vpcf.iysize = 240;
	vpcf.idata_out = 0x22;
	vpcf.idata_in = 0x02;
	vpcf.colors.istart = 500;
	vpcf.colors.istep = 100;
	vpcf.colors.icolcnt = 16;
	vpcf.colors.iset_and_scale = 0x0101;

        if (mptr->tdwr_buf_norm.scan_strategy == 1)
	{
	  memcpy(vpcf.spname, "MON_RAW     ", 12); 
	  memcpy(vpcf.stname, "TDWR_MON    ", 12); 
          memcpy(vihdr.tcf.end.stname, "TDWR_MON    ", 12);
          vihdr.tcf.scan.isweeps = Config.mon_scan_expected;
          for (k=0; k<Config.mon_scan_expected; k++) 
            vihdr.tcf.scan.u.ppi.iellst[k] = Config.mele[k];
        }
        else
	{
	  memcpy(vpcf.spname, "HAZ_RAW     ", 12); 
	  memcpy(vpcf.stname, "TDWR_HAZ    ", 12); 
          memcpy(vihdr.tcf.end.stname, "TDWR_HAZ    ", 12);
          vihdr.tcf.scan.isweeps = Config.haz_scan_expected;
          for (k=0; k<Config.haz_scan_expected; k++) 
            vihdr.tcf.scan.u.ppi.iellst[k] = Config.hele[k];
        }

	out_file = fopen(vingest_summary_path, "w+b");
	  if (!out_file)
	    {
	      sprintf( log_str, "%s %s", strerror(errno), vingest_summary_path );
	      Lprintf( log_str );
	      exit(EXIT_FAILURE);
	    }
	fwrite(&vihdr, 1, sizeof(struct ingest_header), out_file);
	fclose(out_file);
      }

      /* if this is start of a new elevation scan, then do soe processing */
      if (mptr->tdwr_buf_norm.soe)
      {
	struct timeval tv;
        scan_flag = 1;
        if (mptr->tdwr_buf_norm.scan_strategy == 1)
	{
	  scan_number = mptr->tdwr_buf_norm.scan_number;
	  if (scan_number > Config.mon_lprf_num) scan_number--;
        }
	else
	{
	  scan_number = mptr->tdwr_buf_norm.scan_number;
	  if (scan_number > Config.haz_lprf_num) scan_number--;
	}
        
        elevation = mptr->tdwr_buf_norm.current_elevation;

        if (elevation < 0.0) elevation += 360.0;
        elevation = ((elevation / 360.0) * 65535.0) + 0.5;
        int_elevation = (int)elevation;
        if (int_elevation < 0) int_elevation = 0;
        if (int_elevation > 65535) int_elevation = 65535;

        /*
          Fill the data areas with area not scanned for all 360 rays.
          And update the ptr_table to point to these blank rays.
          As we gets rays in, we will overwrite this data.
        */

        for (i=0; i<360; i++)
        {
          ptr_table[i] = 0;
        }
	/* let's alway assume largest nyquist */
	nyquist = ((300000000.0 / 5610000000.0) / 4.0) * (1.0 / (518.0 / 1000000.0));

	soe_time = mptr->tdwr_buf_norm.timestamp;
	tv.tv_sec  = soe_time;
	tv.tv_usec = 0;
	TimeFullFromTimeval( &DataTime, &tv, TIME_FLG_LOCAL );
	/* tm = localtime((time_t *)&soe_time); */

        idhdr.hdr.id = ST_INGEST_DATA;
	idhdr.hdr.ivers = SVER_INGEST_DATA_P;
	idhdr.hdr.ibytes = 76 + (360*4)+(360*612);
	idhdr.hdr.iflags = 0;
	idhdr.time    = DataTime.Ymds;
	vpcf.ing_time = DataTime.Ymds;

        idhdr.isweep = scan_number;
	idhdr.inrev = 360;
	idhdr.isndx = 0;
	idhdr.irtotl = 360;
	idhdr.iwritn = 360;
	idhdr.ibits_bin = 8;
	idhdr.iangle = int_elevation;
      } /* end SOE processing */

      /* Now, just process this dwell! */
      if (mptr->tdwr_buf_norm.dwell_id == 0)
      {
        azimuth = mptr->tdwr_buf_norm.current_azimuth - 2.0;
        if (azimuth < 0.0) azimuth += 360.0;
        int_azimuth = (int)(((azimuth / 360.0) * 65535.0) + 0.5); 
	if (int_azimuth < 0) int_azimuth = 0;
	if (int_azimuth > 65535) int_azimuth = 65535;
	ray_header.iaz_start = (BIN2)int_azimuth;

	azimuth = azimuth + 1.0;
	if (azimuth > 360.0) azimuth = azimuth - 360.0;
        int_azimuth = (int)(((azimuth / 360.0) * 65535.0) + 0.5); 
	if (int_azimuth < 0) int_azimuth = 0;
	if (int_azimuth > 65535) int_azimuth = 65535;
	ray_header.iaz_end = (BIN2)int_azimuth;
	ray_header.iel_start = int_elevation;
	ray_header.iel_end = int_elevation;
	ray_header.ibincount = 600;
        ray_header.itime = mptr->tdwr_buf_norm.timestamp - soe_time;

        int_azimuth = mptr->tdwr_buf_norm.integer_azimuth - 2;
        if (int_azimuth < 0) int_azimuth += 360;
        byte_index = int_azimuth * 612;
        ptr_table[int_azimuth] = byte_index + 1;
        memcpy(&t_data_val[byte_index], &ray_header, 12);
        memcpy(&z_data_val[byte_index], &ray_header, 12);
        memcpy(&v_data_val[byte_index], &ray_header, 12);
        memcpy(&w_data_val[byte_index], &ray_header, 12);
        memcpy(&c_data_val[byte_index], &ray_header, 12);
        byte_index += 12;

        if (mptr->tdwr_buf_norm.final_range_sample > 600)
	    mptr->tdwr_buf_norm.final_range_sample = 600;
        for (i=0; i<mptr->tdwr_buf_norm.final_range_sample; i++)
        {
	  if (mptr->tdwr_buf_norm.normal_sample[i].SNR > 1)
          { 
	    t_data_val[byte_index + i] = mptr->tdwr_buf_norm.normal_sample[i].Z + 4;
          }
          else
          {
	    t_data_val[byte_index + i] = 0;
          }

	  if (mptr->tdwr_buf_norm.normal_sample[i].conditioned_valid_flag &&
	  !mptr->tdwr_buf_norm.normal_sample[i].point_target_flag &&
	  mptr->tdwr_buf_norm.normal_sample[i].SNR > 1)
          {
	    z_data_val[byte_index + i] = mptr->tdwr_buf_norm.normal_sample[i].Z + 4;
          }
	  else
	  {
	    z_data_val[byte_index + i] = 0;
	  }

	  if (mptr->tdwr_buf_norm.normal_sample[i].velocity_valid_flag &&
	     !mptr->tdwr_buf_norm.normal_sample[i].point_target_flag)
          {
	    /* this number is between -80 and +80 */
	    vel = ((float)mptr->tdwr_buf_norm.normal_sample[i].V / 4.0) - 80.0;
	    /* this number is between -1 and +1 */
	    vel_ratio = vel / nyquist;
	    /* this number is between 0 and 2 */
	    vel_ratio += 1.0;
	    /* this number is between 0 and 256 */
	    vel_ratio *= 128.0;
	    vel_ratio += 0.5;
	    int_vel = (int)vel_ratio;
	    if (int_vel <= 0) int_vel = 1;
	    if (int_vel >= 256) int_vel = 255;
	    v_data_val[byte_index + i] = (unsigned char)int_vel;

	    width = (float)mptr->tdwr_buf_norm.normal_sample[i].W / 4.0;
	    width_ratio = width / nyquist;
	    width_ratio *= 256.0;
	    width_ratio += 0.5;
	    int_width = (int)width_ratio;
	    if (int_width <= 0) int_width = 1;
	    if (int_width >= 256) int_width = 255;
	    w_data_val[byte_index + i] = (unsigned char)int_width;

	    /* this number is between -80 and + 80 */
	    vel = (float)mptr->tdwr_buf_norm.normal_sample[i].VC / 4.0 - 80.0;
            if (vel < -75.0) vel = -75.0;
            if (vel >  75.0) vel =  75.0;
	    /* this is a number between 0 and 150 */
	    vel += 75.0;
            vel /= (150.0/256.0);
	    vel += 0.5;
	    int_vel = (int)vel;
	    if (int_vel <= 0) int_vel = 1;
	    if (int_vel >= 256) int_vel = 255;
	    c_data_val[byte_index + i] = (unsigned char)int_vel;
          }
	  else
	  {
	    v_data_val[byte_index + i] = 0;
	    w_data_val[byte_index + i] = 0;
	    c_data_val[byte_index + i] = 0;
	  }
        } /* end for all range samples */
        for (i=mptr->tdwr_buf_norm.final_range_sample; i<600; i++)
	{
	  t_data_val[byte_index + i] = 0;
	  z_data_val[byte_index + i] = 0;
	  v_data_val[byte_index + i] = 0;
	  w_data_val[byte_index + i] = 0;
	  c_data_val[byte_index + i] = 0;
	}
      } /* end if signal dwell */

      /* if this is the end of an elevation scan, do eoe processing */
      if (mptr->tdwr_buf_norm.eoe)
      {
        scan_flag = 0;
	vpcf.psi.raw.isweep = scan_number;
	CloseVolScan( &vpcf, &idhdr, ptr_table, t_data_val, z_data_val, v_data_val,
		      w_data_val, c_data_val, vingest_summary_path, &raw_count, 0 );
      }

      /* if this is the end of a volume scan, do eov processing */
      if (mptr->tdwr_buf_norm.eov)
      {
	vol_flag = 0;
      }
      vol_in_progress = mptr->tdwr_buf_norm.volume_scan_count;

    } /* end if 2B00 */

    /* If this is a low prf dwell, then process it accordingly */
    if (mptr->tdwr_hdr.msg_id == 0x2B01)
    {
      /* If a normal scan is open, then close it first */
      if (scan_flag)
      {
	/* close out old scan */
	scan_flag = 0;
	vpcf.psi.raw.isweep = scan_number;
	CloseVolScan( &vpcf, &idhdr, ptr_table, t_data_val, z_data_val, v_data_val,
		      w_data_val, c_data_val, vingest_summary_path, &raw_count, 1 );
      }

      /* If a low prf scan is not open, then set flag to open it first */
      if (!lprf_flag)
      {
        mptr->tdwr_buf_norm.soe = 1;
      }

      /* If new scan, prepare to open this new scan */
      if (mptr->tdwr_buf_norm.soe)
      {
	struct ingest_header lihdr;
	FILE   *out_file;
	struct timeval tv;
	/* If a low prf scan is already open, then close old one first */
	if (lprf_flag)
	{
	  /* close out old lprf */
	  lprf_flag = 0;
	  CloseLprfScan( &lpcf, &idhdr, ptr_table, t_data_val, z_data_val, 
			 lingest_summary_path, &raw_count );
	}

	tv.tv_sec  = mptr->tdwr_buf_lprf.timestamp;
	tv.tv_usec = 0;
	TimeFullFromTimeval( &DataTime, &tv, TIME_FLG_LOCAL );
	/* tm = localtime((time_t *)&mptr->tdwr_buf_lprf.timestamp); */
	soe_time = mptr->tdwr_buf_norm.timestamp;
	lstart_name_int( lingest_summary_name, "TDR", &DataTime.Ymds );
	strcpy( lingest_summary_path, "/usr/iris_data/volume/" );
	strcat( lingest_summary_path, lingest_summary_name );

	memset( &lihdr, 0, sizeof(struct ingest_header));
	lihdr.hdr.id = ST_INGEST_HDR;
	lihdr.hdr.ivers = SVER_INGEST_HDR_P;
	lihdr.hdr.ibytes = sizeof (struct ingest_header);
	lihdr.hdr.reserved = 0;
	lihdr.hdr.iflags = 0;
 
        strcpy( lihdr.icf.sfile, lingest_summary_name); 
        lihdr.icf.idfnum = 0;
        lihdr.icf.isweeps_done = 1;
        lihdr.icf.idfsize = 0;
        lihdr.icf.ib_rayhed = 12;
        lihdr.icf.ib_task = sizeof(struct task_configuration);
        memcpy( lihdr.icf.sSitename, "tdr_rad1        ", 16);
        lihdr.icf.ilat = (BIN4)( 22.3628 * (0x20000000 / 45.0));
        lihdr.icf.ilon = (BIN4)(114.0111 * (0x20000000 / 45.0));
	strcpy((char *)&(lihdr.icf.siris_version),  IRIS_VERSION);
	lihdr.icf.ignd_hgt = 50;
	lihdr.icf.irad_hgt = 30;
        lihdr.icf.inrev = 360;
        lihdr.icf.ialtitude = 8000;

	lihdr.icf.VolumeYmds   = DataTime.Ymds; 
	lihdr.icf.iMinutesWest = DataTime.iMinutesWest;
	lihdr.icf.iLocalWest   = DataTime.iLocalWest;
	memcpy( lihdr.icf.sLocalTZName, DataTime.sLocalTZName, 8 );

        lihdr.icf.isndx = 0;
        lihdr.icf.irtotl = 360;

        lihdr.tcf.hdr.id = ST_TASK_CONF;
        lihdr.tcf.hdr.ivers = SVER_TASK_CONF_P;
        lihdr.tcf.hdr.ibytes = sizeof(struct task_configuration);

	DspMaskSet( &lihdr.tcf.dsp.DataMask, DB_DBT );
	DspMaskSet( &lihdr.tcf.dsp.DataMask, DB_DBZ );

        lihdr.tcf.dsp.itrig = 0; /* unfolding: 0=none, 1=2:3 */
        lihdr.tcf.dsp.iprf = (int)((1.0 / 
          (mptr->tdwr_buf_lprf.pri / 1000000.0)) + 0.5);
        lihdr.tcf.dsp.ipw = 110; /* fixed for TDWR */

        lihdr.tcf.rng.ibin_first = 0;
        lihdr.tcf.rng.ibin_last = ((900 * 150) + (1084 * 300)) * 100;
        lihdr.tcf.rng.ibin_in_num = 450+1084;
        lihdr.tcf.rng.ibin_out_num = 450+1084;
        lihdr.tcf.rng.ibin_in_step = 300 * 100;
        lihdr.tcf.rng.ibin_out_step = 300 * 100;

        lihdr.tcf.scan.iscan = 4; /* ppi full */
        lihdr.tcf.scan.isweeps = 1;
	tmp_float = mptr->tdwr_buf_lprf.current_elevation;
        if (tmp_float < 0.0) tmp_float += 360.0;
        tmp_float = ((tmp_float / 360.0) * 65535.0) + 0.5;
        lihdr.tcf.scan.u.ppi.iellst[0] = (BIN2)tmp_float;
	lihdr.tcf.misc.ilambda = 535;
        lihdr.tcf.misc.itrunc = 2130000;

        memset(&lpcf, 0, sizeof(struct product_configuration));
	lpcf.ing_time = lihdr.icf.VolumeYmds;
	lpcf.epoch    = lihdr.icf.VolumeYmds;

	lpcf.hdr.id = ST_PRODUCT_CONF;
	lpcf.hdr.ivers = SVER_PRODUCT_CONF_P;
	lpcf.hdr.ibytes = sizeof(struct product_configuration);
	lpcf.iptype = PROD_RAW;
	lpcf.isch = PSC_ALL;
	lpcf.irange_last_v20 = ((900 * 150) + (1084 * 300)) * 100;
	lpcf.psi.raw.iDataMask0 = lihdr.tcf.dsp.DataMask.iWord0;
	lpcf.psi.raw.iraw_bin_last = 450+1084;
	lpcf.psi.raw.iraw_convert = 0;
	lpcf.psi.raw.iflags = 1;
	lpcf.psi.raw.isweep = 1;
	lpcf.ixsize = vpcf.iysize = 240;
	lpcf.idata_out = 0x22;
	lpcf.idata_in = 0x02;
	lpcf.colors.istart = 500;
	lpcf.colors.istep = 100;
	lpcf.colors.icolcnt = 16;
	lpcf.colors.iset_and_scale = 0x0101;
	memcpy(lpcf.spname, "SURVEILLANCE", 12); 

        memcpy(lihdr.tcf.end.stname, "SURVEILLANCE", 12);

	out_file = fopen(lingest_summary_path, "w+b");
	if (!out_file)
	  {
	    sprintf( log_str, "%s %s", strerror(errno), lingest_summary_path );
	    Lprintf( log_str );
	    exit(EXIT_FAILURE);
	  }
	fwrite(&lihdr, 1, sizeof(struct ingest_header), out_file);
	fclose(out_file);

        elevation = mptr->tdwr_buf_lprf.current_elevation;
        if (elevation < 0.0) elevation += 360.0;
        elevation = ((elevation / 360.0) * 65535.0) + 0.5;
        int_elevation = (int)elevation;
        if (int_elevation < 0) int_elevation = 0;
        if (int_elevation > 65535) int_elevation = 65535;

        /*
          Fill the data areas with area not scanned for all 360 rays.
          And update the ptr_table to point to these blank rays.
          As we gets rays in, we will overwrite this data.
        */

        for (i=0; i<360; i++)
        {
          ptr_table[i] = 0;
        }
	/* let's alway assume largest nyquist */

        idhdr.hdr.id = ST_INGEST_DATA;
	idhdr.hdr.ivers = SVER_INGEST_DATA_P;
	idhdr.hdr.ibytes = 76 + (360*4) + (360*1546);
	idhdr.hdr.iflags = 0;
	idhdr.time = DataTime.Ymds;

        idhdr.isweep = 1;
	idhdr.inrev = 360;
	idhdr.isndx = 0;
	idhdr.irtotl = 360;
	idhdr.iwritn = 360;
	idhdr.ibits_bin = 8;
	idhdr.idata = 2;
	idhdr.iangle = int_elevation;
	lprf_flag = 1;
      } /* end SOE processing */

      if (mptr->tdwr_buf_lprf.dwell_id == 0)
      {
        azimuth = mptr->tdwr_buf_lprf.current_azimuth - 2.0;
        if (azimuth < 0.0) azimuth += 360.0;
        int_azimuth = (int)(((azimuth / 360.0) * 65535.0) + 0.5); 
	if (int_azimuth < 0) int_azimuth = 0;
	if (int_azimuth > 65535) int_azimuth = 65535;
	ray_header.iaz_start = (BIN2)int_azimuth;

	azimuth = azimuth + 1.0;
	if (azimuth > 360.0) azimuth = azimuth - 360.0;
        int_azimuth = (int)(((azimuth / 360.0) * 65535.0) + 0.5); 
	if (int_azimuth < 0) int_azimuth = 0;
	if (int_azimuth > 65535) int_azimuth = 65535;
	ray_header.iaz_end = (BIN2)int_azimuth;
	ray_header.iel_start = int_elevation;
	ray_header.iel_end = int_elevation;
	ray_header.ibincount = 1534;
        ray_header.itime = mptr->tdwr_buf_lprf.timestamp - soe_time;

        int_azimuth = mptr->tdwr_buf_lprf.integer_azimuth - 2;
        if (int_azimuth < 0) int_azimuth += 360;
        byte_index = int_azimuth * 1546;
        ptr_table[int_azimuth] = byte_index + 1;
        memcpy(&t_data_val[byte_index], &ray_header, 12);
        memcpy(&z_data_val[byte_index], &ray_header, 12);
        byte_index += 12;

        /* The first 900 input samples are spaced 150M each.  Combine every
           two of these into one output sample.
        */
	j = 0;
	if (mptr->tdwr_buf_lprf.final_range_sample >= 900) max_range = 900;
	else max_range = mptr->tdwr_buf_lprf.final_range_sample;
        for (i=0; i<max_range; i+=2)
        {
          if (mptr->tdwr_buf_lprf.lprf_sample[i].valid_flag && mptr->tdwr_buf_lprf.SNR[i] > 1 &&
	      mptr->tdwr_buf_lprf.lprf_sample[i+1].valid_flag && mptr->tdwr_buf_lprf.SNR[i+1] > 1)
          {
	    t_data_val[byte_index + j] = ((mptr->tdwr_buf_lprf.Z[i] + 4) +
	      (mptr->tdwr_buf_lprf.Z[i+1] + 4)) / 2;
          }
	  else if (mptr->tdwr_buf_lprf.lprf_sample[i].valid_flag && mptr->tdwr_buf_lprf.SNR[i] > 1)
          {
	    t_data_val[byte_index + j] = mptr->tdwr_buf_lprf.Z[i] + 4;
          }
	  else if (mptr->tdwr_buf_lprf.lprf_sample[i+1].valid_flag && mptr->tdwr_buf_lprf.SNR[i+1] > 1)
          {
	    t_data_val[byte_index + j] = mptr->tdwr_buf_lprf.Z[i+1] + 4;
          }
	  else
	  {
	    t_data_val[byte_index + j] = 0;
	  }

          if (mptr->tdwr_buf_lprf.lprf_sample[i].valid_flag &&
	     !mptr->tdwr_buf_lprf.lprf_sample[i].point_target_flag &&
	      mptr->tdwr_buf_lprf.SNR[i] > 1 &&
	      mptr->tdwr_buf_lprf.lprf_sample[i+1].valid_flag &&
	     !mptr->tdwr_buf_lprf.lprf_sample[i+1].point_target_flag &&
	      mptr->tdwr_buf_lprf.SNR[i+1] > 1)
          {
	    z_data_val[byte_index + j] = ((mptr->tdwr_buf_lprf.Z[i] + 4) +
	      (mptr->tdwr_buf_lprf.Z[i+1] + 4)) / 2;
          }
	  else if (mptr->tdwr_buf_lprf.lprf_sample[i].valid_flag &&
	          !mptr->tdwr_buf_lprf.lprf_sample[i].point_target_flag &&
	           mptr->tdwr_buf_lprf.SNR[i] > 1)
          {
	    z_data_val[byte_index + j] = mptr->tdwr_buf_lprf.Z[i] + 4;
          }
	  else if (mptr->tdwr_buf_lprf.lprf_sample[i+1].valid_flag &&
	          !mptr->tdwr_buf_lprf.lprf_sample[i+1].point_target_flag &&
	           mptr->tdwr_buf_lprf.SNR[i+1] > 1)
          {
	    z_data_val[byte_index + j] = mptr->tdwr_buf_lprf.Z[i+1] + 4;
          }
	  else
	  {
	    z_data_val[byte_index + j] = 0;
	  }
	  j++;
        }

        if (mptr->tdwr_buf_lprf.final_range_sample > 1984)
	    mptr->tdwr_buf_lprf.final_range_sample = 1984;

	for (i=900; i<mptr->tdwr_buf_lprf.final_range_sample; i++)
	{
	  if (mptr->tdwr_buf_lprf.lprf_sample[i].valid_flag)
          {
	    t_data_val[byte_index + j] = mptr->tdwr_buf_lprf.Z[i] + 4;
          } 
	  else
	  {
	    t_data_val[byte_index + j] = 0;
	  }

	  if (mptr->tdwr_buf_lprf.lprf_sample[i].valid_flag &&
	     !mptr->tdwr_buf_lprf.lprf_sample[i].point_target_flag)
          {
	    z_data_val[byte_index + j] = mptr->tdwr_buf_lprf.Z[i] + 4;
          }
	  else
	  {
	    z_data_val[byte_index + j] = 0;
	  }
	  j++;
        }
	for (i=mptr->tdwr_buf_lprf.final_range_sample; i<1984; i++)
	{
	  t_data_val[byte_index + j] = 0;
	  z_data_val[byte_index + j] = 0;
	  j++;
        }
      } /* end if signal dwell */


      /* if this is the end of a lprf scan, do eov processing */
      if (mptr->tdwr_buf_lprf.eoe)
      {
        /* close out lprf */
        lprf_flag = 0;
	CloseLprfScan( &lpcf, &idhdr, ptr_table, t_data_val, z_data_val, 
		       lingest_summary_path, &raw_count );
      }

      /* if this is the end of a volume scan, do eov processing */
      if (mptr->tdwr_buf_lprf.eov)
      {
	vol_flag = 0;
      }

    } /* end if lprf dwell 2B01 */


    /* Read another dwell - if necessary, continue reading until get an sov */
    do 
    {
      dwell_table->node[dwell_index] = 0;

      msgrcv(Ethernet_qid, &mail_ptr, 4, 0, 0);
      dwell_index = mail_ptr.index;
      mptr = dwell_p+dwell_index;

      if ( (mptr->tdwr_buf_norm.volume_scan_count != previous_vol_count) ||
	    mptr->tdwr_buf_norm.sov )
      {
	sprintf( log_str, "Skipping msg %d, volume %d.", 
		 dwell_index, mptr->tdwr_buf_norm.volume_scan_count);
	Lprintf( log_str );

	if(scan_flag || vol_flag)
	{
	  /* close out old scan */
          scan_flag = 0;
	  vpcf.psi.raw.isweep = scan_number;
	  CloseVolScan( &vpcf, &idhdr, ptr_table, t_data_val, z_data_val, v_data_val,
			w_data_val, c_data_val, vingest_summary_path, &raw_count, 1 );
        }

	if(lprf_flag)
	  {
	    /* close out old scan */
	    lprf_flag = 0;
	    CloseLprfScan( &lpcf, &idhdr, ptr_table, t_data_val, z_data_val, 
			   lingest_summary_path, &raw_count );
	  }
	
        strcpy(tmp_str, "rm -f /usr/iris_data/volume/*");
        system(tmp_str);
	vol_flag = 0;
      }

    }while ( (mptr->tdwr_buf_norm.volume_scan_count != previous_vol_count) && 
	    !mptr->tdwr_buf_norm.sov );

    previous_vol_count = mptr->tdwr_buf_norm.volume_scan_count;
    previous_scan_number = mptr->tdwr_buf_norm.scan_number;


  } /* end while true */
}

/* =============================================
 * Process the config file
 */
static void ProcessConfigFile( struct config_file *pConfig_a, const char *sPath_a )
{
  FILE   *config_file;
  int    answer, i, j;
  char   tmp_str[100];
  char   tdwr_interface[10], tdwr_port[10], iris_name[50], iris_port[10], iris_dir[50];
  char   lprf_str[10], scan_count[10];
  float  tmp_float;

  memset( pConfig_a, 0, sizeof(*pConfig_a) );

  if ((config_file = fopen( sPath_a, "r")) == NULL)
    {
      printf("Can not open config file: %s\n", sPath_a );
      exit(-1);
    }
  
  answer = fscanf(config_file, "%s%s", tmp_str, log_str);
  if (answer <= 0 || strcmp(tmp_str, "LOG"))
    {
      printf("No valid LOG line!\n");
      exit(-2);
    }
  if (log_str[0] == '1') 
    {
      char sLogPath[200];
      strcpy( sLogPath, "/tmp/raw_create_task.dat" );
      if ((log_file = fopen( sLogPath, "w")) == NULL)
	{
	  printf("Can not open log file: %s!\n", sLogPath );
	  exit(-2);
	}
      else 
	{
	  logging = 1;
	  printf("Logging to file: %s.\n", sLogPath );
	}
    }
  
  answer = fscanf(config_file, "%s%s%s", tmp_str, tdwr_interface, tdwr_port);
  if (answer <= 0 || strcmp(tmp_str, "TDWR"))
    {
      Lprintf("No valid TDWR / interface / port listed.");
      exit(-2);
    }
  
  answer = fscanf(config_file, "%s%s%s%s", tmp_str, iris_name, iris_port, iris_dir);
  if (answer <= 0 || strcmp(tmp_str, "IRIS"))
    {
      Lprintf("No valid IRIS server / port / dir listed.");
      exit(-2);
    }
  
  answer = fscanf(config_file, "%s%s%s", tmp_str, scan_count, lprf_str);
  if (answer <= 0 || strcmp(tmp_str, "MONITOR"))
    {
      Lprintf("No valid MONITOR scan.");
      exit(-2);
    }
  else
    {
      pConfig_a->mon_lprf_num = atoi(lprf_str);
      j = 0;
      for (i=1; i<=atoi(scan_count); i++)
	{
	  fscanf(config_file, "%s", tmp_str);
	  tmp_float = atof(tmp_str);
	  if (tmp_float < 0.0) tmp_float += 360.0;
	  tmp_float = ((tmp_float / 360.0) * 65535.0) + 0.5;
	  
	  if (i != pConfig_a->mon_lprf_num)
	    {
	      pConfig_a->mele[j] = (BIN2)tmp_float;
	      j++;
	    }
	}
      pConfig_a->mon_scan_expected = j;
    }
  
  answer = fscanf(config_file, "%s%s%s", tmp_str, scan_count, lprf_str);
  if (answer <= 0 || strcmp(tmp_str, "HAZARDOUS"))
    {
      Lprintf("No valid HAZARDOUS scan.");
      exit(-2);
    }
  else
    {
      pConfig_a->haz_lprf_num = atoi(lprf_str);
      j = 0;
      for (i=1; i<=atoi(scan_count); i++)
	{
	  fscanf(config_file, "%s", tmp_str);
	  tmp_float = atof(tmp_str);
	  if (tmp_float < 0.0) tmp_float += 360.0;
	  tmp_float = ((tmp_float / 360.0) * 65535.0) + 0.5;
	  
	  if (i != pConfig_a->haz_lprf_num)
	    {
	      pConfig_a->hele[j] = (BIN2)tmp_float;
	      j++;
	    }
	}
      pConfig_a->haz_scan_expected = j;
    }
  fclose(config_file);
}

/* ================================================================
 * Close and write a low PRF scan.
 */
static void CloseLprfScan
( const struct product_configuration *pLpcf_a,
  struct ingest_data_header *pIdhdr_a,
  const UINT4 ptr_table_a[360], 
  const UINT1 t_data_val_a[1546*360], 
  const UINT1 z_data_val_a[1546*360], 
  const char *lingest_summary_path_a,
  int        *pRawCount_a )
{
  char sPath[PATHNAME_SIZE];
  FILE *out_file;
  struct product_hdr phdr;
  MESSAGE iStatus;

  pIdhdr_a->idata = DB_DBT;
  strcpy( sPath, lingest_summary_path_a);
  strcat( sPath, sIngestEnd( pIdhdr_a->idata, 1 ) );
  out_file = fopen(sPath, "w+b");
  if (!out_file)
    {
      sprintf( log_str, "%s %s", strerror(errno), sPath );
      Lprintf( log_str );
      exit(EXIT_FAILURE);
    }
  fwrite(pIdhdr_a, 1, sizeof(struct ingest_data_header), out_file);
  fwrite(ptr_table_a, 360, 4, out_file);
  fwrite(t_data_val_a, 360, 1534+12, out_file);
  fclose(out_file);
  
  pIdhdr_a->idata = DB_DBZ;
  strcpy( sPath, lingest_summary_path_a);
  strcat( sPath, sIngestEnd( pIdhdr_a->idata, 1 ) );
  out_file = fopen(sPath, "w+b");
  if (!out_file)
    {
      sprintf( log_str, "%s %s", strerror(errno), sPath );
      Lprintf( log_str );
      exit(EXIT_FAILURE);
    }
  fwrite(pIdhdr_a, 1, sizeof(struct ingest_data_header), out_file);
  fwrite(ptr_table_a, 360, 4, out_file);
  fwrite(z_data_val_a, 360, 1534+12, out_file);
  fclose(out_file);
  
  (*pRawCount_a)++;
  if (*pRawCount_a > 9999) *pRawCount_a = 0;
  sprintf(sPath, "/usr/iris_data/raw/TDR%04d", *pRawCount_a);
  
  iStatus = iraw_prod( pLpcf_a, lingest_summary_path_a, &phdr, sPath, 1);
  sprintf( log_str, "LPRF data %s", lingest_summary_path_a);
  Lprintf( log_str );
  if (iStatus!=SS_NORMAL) sig_signal(iStatus);
}


/* ================================================================
 * Close and write a Volume scan.
 */
static void CloseVolScan
( const struct product_configuration *pVpcf_a,
  struct ingest_data_header *pIdhdr_a,
  const UINT4 ptr_table_a[360], 
  const UINT1 t_data_val_a[1546*360], 
  const UINT1 z_data_val_a[1546*360], 
  const UINT1 v_data_val_a[612*360], 
  const UINT1 w_data_val_a[612*360], 
  const UINT1 c_data_val_a[612*360], 
  const char *vingest_summary_path_a,
  int        *pRawCount_a,
  int         lCloseFlag_a )  /* Close partial volume scan */
{
  char sPath[PATHNAME_SIZE];
  FILE *out_file;
  struct product_hdr phdr;
  MESSAGE iStatus;

  pIdhdr_a->idata = DB_DBT;
  strcpy( sPath, vingest_summary_path_a);
  strcat( sPath, sIngestEnd( pIdhdr_a->idata, pVpcf_a->psi.raw.isweep ) );
  out_file = fopen(sPath, "w+b");
  if (!out_file)
    {
      sprintf( log_str, "%s %s", strerror(errno), sPath );
      Lprintf( log_str );
      exit(EXIT_FAILURE);
    }
  fwrite(pIdhdr_a, 1, sizeof(struct ingest_data_header), out_file);
  fwrite(ptr_table_a, 360, 4, out_file);
  fwrite(t_data_val_a, 360, 600+12, out_file);
  fclose(out_file);
  
  pIdhdr_a->idata = DB_DBZ;
  strcpy( sPath, vingest_summary_path_a);
  strcat( sPath, sIngestEnd( pIdhdr_a->idata, pVpcf_a->psi.raw.isweep ) );
  out_file = fopen(sPath, "w+b");
  if (!out_file)
    {
      sprintf( log_str, "%s %s", strerror(errno), sPath );
      Lprintf( log_str );
      exit(EXIT_FAILURE);
    }
  fwrite(pIdhdr_a, 1, sizeof(struct ingest_data_header), out_file);
  fwrite(ptr_table_a, 360, 4, out_file);
  fwrite(z_data_val_a, 360, 600+12, out_file);
  fclose(out_file);
  
  pIdhdr_a->idata = DB_VEL;
  strcpy( sPath, vingest_summary_path_a);
  strcat( sPath, sIngestEnd( pIdhdr_a->idata, pVpcf_a->psi.raw.isweep ) );
  out_file = fopen(sPath, "w+b");
  if (!out_file)
    {
      sprintf( log_str, "%s %s", strerror(errno), sPath );
      Lprintf( log_str );
      exit(EXIT_FAILURE);
    }
  fwrite(pIdhdr_a, 1, sizeof(struct ingest_data_header), out_file);
  fwrite(ptr_table_a, 360, 4, out_file);
  fwrite(v_data_val_a, 360, 600+12, out_file);
  fclose(out_file);
  
  pIdhdr_a->idata = DB_WIDTH;
  strcpy( sPath, vingest_summary_path_a);
  strcat( sPath, sIngestEnd( pIdhdr_a->idata, pVpcf_a->psi.raw.isweep ) );
  out_file = fopen(sPath, "w+b");
  if (!out_file)
    {
      sprintf( log_str, "%s %s", strerror(errno), sPath );
      Lprintf( log_str );
      exit(EXIT_FAILURE);
    }
  fwrite(pIdhdr_a, 1, sizeof(struct ingest_data_header), out_file);
  fwrite(ptr_table_a, 360, 4, out_file);
  fwrite(w_data_val_a, 360, 600+12, out_file);
  fclose(out_file);
  
  pIdhdr_a->idata = DB_VELC;
  strcpy( sPath, vingest_summary_path_a);
  strcat( sPath, sIngestEnd( pIdhdr_a->idata, pVpcf_a->psi.raw.isweep ) );
  out_file = fopen(sPath, "w+b");
  if (!out_file)
    {
      sprintf( log_str, "%s %s", strerror(errno), sPath );
      Lprintf( log_str );
      exit(EXIT_FAILURE);
    }
  fwrite(pIdhdr_a, 1, sizeof(struct ingest_data_header), out_file);
  fwrite(ptr_table_a, 360, 4, out_file);
  fwrite(c_data_val_a, 360, 600+12, out_file);
  fclose(out_file);
  
  (*pRawCount_a)++;
  if (*pRawCount_a > 9999) *pRawCount_a = 0;
  sprintf(sPath, "/usr/iris_data/raw/TDR%04d",*pRawCount_a);
  iStatus = iraw_prod( pVpcf_a, vingest_summary_path_a, &phdr, sPath, lCloseFlag_a);
  sprintf( log_str, "Volume data %s, sweep %d", vingest_summary_path_a,
	   pVpcf_a->psi.raw.isweep );
  Lprintf( log_str );
  if (iStatus!=SS_NORMAL) sig_signal(iStatus);
}

static void sighup_handler(int signal_a)
{
  struct sigaction action;
  action.sa_handler = sighup_handler;
  sigemptyset( &action.sa_mask );
  action.sa_flags = 0;
  sigaction( SIGHUP, &action, NULL );
}
