/* **********************************************************************
 * *                                                                    *
 * *                 Routines to Help With Data Types                   *
 * *                                                                    *
 * **********************************************************************
 * File: libs/user/DataConvert.c
 *
 *      COPYRIGHT (c) 1995, 1997, 1998, 1999, 2001, 2003, 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 <stdio.h>
#include <stdlib.h>
#include <math.h>

#ifdef LINUX
#include <ieee754.h>
#endif /* #ifdef LINUX */

#include "sigtypes.h"
#include "setup.h"
#include "user_lib.h"
#include "dsp_lib.h"

/* ------------------------------
 * Fill up the structure used to convert data to user units
 */
void FillDataConvert
( volatile struct data_convert *pConvert_a,
  SINT4 iPrf_a,			/* PRF in Hertz */
  UINT2 iTriggerCase_a,		/* Type of dual PRF */
  SINT4 iWaveLength_a,		/* Wavelength in 1/100 of cm */
  UINT2 iPolarization_a,	/* Polarization type */
  UINT4 iColorFlags_a )		/* Flags containing units switches */
{
  pConvert_a->fvelun_velocity =
    fNyquistVelocity( iPrf_a, iTriggerCase_a, iWaveLength_a, iPolarization_a );
  
  pConvert_a->fvelun_width =
    fNyquistWidth( iPrf_a, iWaveLength_a, iPolarization_a );

  pConvert_a->flambda = ((FLT4)iWaveLength_a)/100.0;
  pConvert_a->iColorFlags = iColorFlags_a;
}
/* ------------------------------
 * Convert internal data format to user units.
 */
FLT4 fdata_to_user
  (UINT2 idata_a,
   UINT4 idtype_a,
   const struct data_convert *pconvert_a )
{
  FLT4 fresult;
  FLT4 fkdp_lambda;

  switch( idtype_a )
    {
    case DB_DBT:
    case DB_DBZ:
    case DB_DBZC:
      fresult = (((FLT4)idata_a)/2.0) - 32.0;
      break;

    case DB_DEFORM2:
    case DB_DIVERGE2:
      fresult = ((FLT4)(SINT2)idata_a)/1000.0;
      break;

    case DB_FLIQUID2:
      fresult = ((FLT4)rain_file_to_long(idata_a))/1000.0;
      if (pconvert_a->iColorFlags & SCALE_RAIN_INCHES)
	fresult /= 10.0*CM_PER_INCH;
      break;

    case DB_HEIGHT   :
      fresult = (((FLT4)idata_a)/10.0) - 0.1;
      break;

    case DB_LDRH  :
    case DB_LDRV  :
      fresult = (((FLT4)idata_a)/5.0) - 45.2;
      break;
      
    case DB_OTHER:
    case DB_USER:
    case DB_USER2:
    case DB_FLAGS:
    case DB_FLAGS2:
      fresult = (FLT4)idata_a;
      break;
      
    case DB_RAINRATE2:
      fresult = ((FLT4)(rain_file_to_long(idata_a)-1))/10000.0;
      if (pconvert_a->iColorFlags & SCALE_RAINRATE_IN_HOUR)
	fresult /= 10.0*CM_PER_INCH;
      break;

    case DB_RHOH:
    case DB_RHOV:
    case DB_RHOHV:
    case DB_SQI:
      if (idata_a)
	fresult = sqrt(((FLT4)(idata_a-1))/253.0);
      else
	fresult = 0.0;
      break;

    case DB_RHOH2:
    case DB_RHOV2:
    case DB_RHOHV2:
    case DB_SQI2:
      if (idata_a)
	fresult = ((FLT4)(idata_a-1))/65533.0;
      else
	fresult = 0.0;
      break;

    case DB_SHEAR:
      fresult = (((FLT4)idata_a)/5.0) - 25.6;
      break;

    case DB_VEL:
      if (pconvert_a)
	fresult = pconvert_a->fvelun_velocity * (((FLT4)idata_a) - 128.0 )/127.0;
      else
	fresult = 0.0;
      break;

    case DB_VELC:
      fresult = (((FLT4)idata_a) - 128.0) * (75.0 / 127.0) ;
      break ;

    case DB_VIL2:
      /* Important not to get negative value for 1 input because of
       * rounding errror. */
      fresult = ((FLT4)(idata_a-1))/1000.0;
      break;

    case DB_WIDTH:
      if (pconvert_a)
	fresult = pconvert_a->fvelun_width * ((FLT4)idata_a)/256.0;
      else
	fresult = 0.0;
      break;

    case DB_ZDR:
      fresult = (((FLT4)idata_a)-128.0 )/16.0;
      break;

    case DB_DBT2:
    case DB_DBZ2:
    case DB_DBZC2:
    case DB_VEL2:
    case DB_VELC2:
    case DB_ZDR2:
    case DB_KDP2:
    case DB_LDRH2:
    case DB_LDRV2:
      fresult = (((FLT4)idata_a)-32768.0)/100.0;
      break;

    case DB_VVEL2:
    case DB_HVEL2:
      fresult = ((FLT4)(SINT2)idata_a)/100.0;
      break;

    case DB_WIDTH2:
      fresult = ((FLT4)idata_a)/100.0;
      break;

    case DB_HDIR2:
    case DB_AXDIL2:
      fresult = ((FLT4)idata_a)/10.0;
      break;

    case DB_KDP:
      /* Span of KDP*Lambda is 0.25 - 150.0 */
      if (pconvert_a &&(pconvert_a->flambda!=0.0))
	{
	  if (idata_a<128)
	    {
	      fkdp_lambda =  -0.25 * pow( 600.0, (127.0-((FLT4)idata_a))/126.0 );
	      fresult = fkdp_lambda/pconvert_a->flambda;
	    }
	  else if (idata_a>128)
	    {
	      fkdp_lambda =   0.25 * pow( 600.0, (((FLT4)idata_a)-129.0)/126.0 );
	      fresult = fkdp_lambda/pconvert_a->flambda;
	    }
	  else
	    fresult = 0.0;  /* 128 maps to zero */
	}
      else
	fresult = 0.0;
      break;

    case DB_PHIH:
    case DB_PHIV:
    case DB_PHIDP:
      fresult = 180.0 * (((FLT4)idata_a) - 1.0 )/254.0;
      break;

    case DB_PHIH2:
    case DB_PHIV2:
    case DB_PHIDP2:
      fresult = 360.0 * (((FLT4)idata_a) - 1.0 )/65534.0;
      break;

    case DB_TIME2:
      fresult = (((FLT4)idata_a)-32768.0)/60.0;
      break;

    default:
      fresult = 0.0;
      break;
    }
  return fresult;
}
/* ------------------------------
 * Returns the data value change of on LSB for linear data types.
 * For logarithmic scales, return the inverse of the number required
 * to double the data value.
 */
FLT4 fDataScalePerBit
  (UINT4 idtype_a,
   const struct data_convert *pconvert_a )
{
  FLT4 fresult;

  switch( idtype_a )
    {
    case DB_AXDIL2:
    case DB_HDIR2:
    case DB_HEIGHT:
      fresult = 0.1;
      break;

    case DB_DBT:
    case DB_DBZ:
    case DB_DBZC:
      fresult = 0.5;
      break;

    case DB_DBT2:
    case DB_DBZ2:
    case DB_DBZC2:
    case DB_HVEL2:
    case DB_KDP2:
    case DB_LDRH2:
    case DB_LDRV2:
    case DB_VEL2:
    case DB_VELC2:
    case DB_VVEL2:
    case DB_WIDTH2:
    case DB_ZDR2:
      fresult = 0.01;
      break;

    case DB_DEFORM2:
    case DB_DIVERGE2:
      fresult = 0.001;
      break;

    case DB_FLIQUID2:
      fresult = 1.0/ 4096.0;
      break;

    case DB_KDP:
      fresult = 1.0/ (126.0*0.109);
      break;

    case DB_LDRH:
    case DB_LDRV:
      fresult = 0.2;
      break;
      
    case DB_OTHER:
    case DB_USER:
    case DB_USER2:
    case DB_FLAGS:
    case DB_FLAGS2:
      fresult = 1.0;
      break;

    case DB_PHIH:
    case DB_PHIV:
    case DB_PHIDP:
      fresult = 180.0/254.0;
      break;

    case DB_PHIH2:
    case DB_PHIV2:
    case DB_PHIDP2:
      fresult = 360.0/65534.0;
      break;
      
    case DB_RAINRATE2:
      fresult = 1.0/ 4096.0;
      break;

    case DB_RHOH:
    case DB_RHOV:
    case DB_RHOHV:
    case DB_SQI:
      /* Not linear or log, use scale at midrange (at .7085) */
      fresult = 0.00278391;
      break;

    case DB_RHOH2:
    case DB_RHOV2:
    case DB_RHOHV2:
    case DB_SQI2:
      fresult = 1.0/65533.0;
      break;

    case DB_SHEAR:
      fresult = 0.2;
      break;

    case DB_TIME2:
      fresult = 1.0/60.0;
      break;

    case DB_VEL:
      if (pconvert_a)
	fresult = pconvert_a->fvelun_velocity/127.0;
      else
	fresult = 1.0;
      break;

    case DB_VELC:
      fresult = 75.0 / 127.0;
      break ;

    case DB_VIL2:
      fresult = 0.001;
      break;

    case DB_WIDTH:
      if (pconvert_a)
	fresult = pconvert_a->fvelun_width/256.0;
      else
	fresult = 1.0;
      break;

    case DB_ZDR:
      fresult = 1/16.0;
      break;

    default:
      fresult = 1.0;
      break;
    }
  return fresult;
}
/* ------------------------------
 * Returns the user units data value offset you get in the formula
 *  User = (Scale * Data) + Offset
 * In other words the value zero maps to.
 * For logarithmic scales, not so well defined.
 */
FLT4 fDataStartValue
  (UINT4 idtype_a,
   const struct data_convert *pconvert_a )
{
  FLT4 fresult;

  switch( idtype_a )
    {
    case DB_AXDIL2:
    case DB_HDIR2:
    case DB_DEFORM2:
    case DB_FLIQUID2:
    case DB_OTHER:
    case DB_USER:
    case DB_USER2:
    case DB_WIDTH:
    case DB_WIDTH2:
    case DB_FLAGS:
    case DB_FLAGS2:
      fresult = 0.0;
      break;

    case DB_HEIGHT:
      fresult = -0.1;
      break;

    case DB_DBT:
    case DB_DBZ:
    case DB_DBZC:
      fresult = -32.0;
      break;

    case DB_DBT2:
    case DB_DBZ2:
    case DB_DBZC2:
    case DB_HVEL2:
    case DB_KDP2:
    case DB_LDRH2:
    case DB_LDRV2:
    case DB_VEL2:
    case DB_VELC2:
    case DB_VVEL2:
    case DB_ZDR2:
      fresult = -327.68;
      break;

    case DB_KDP:
      if (pconvert_a &&(pconvert_a->flambda!=0.0))
	fresult = -150.0/pconvert_a->flambda;
      else
	fresult = -150.0;
      break;

    case DB_LDRH:
    case DB_LDRV:
      fresult = -45.2;
      break;

    case DB_DIVERGE2:
      fresult = -32.768;
      break;

    case DB_PHIH:
    case DB_PHIV:
    case DB_PHIDP:
      fresult = -180.0/254.0;
      break;

    case DB_PHIH2:
    case DB_PHIV2:
    case DB_PHIDP2:
      fresult = -360.0/65534.0;
      break;
      
    case DB_RAINRATE2:
      fresult = -0.0001;
      break;

    case DB_RHOH:
    case DB_RHOV:
    case DB_RHOHV:
    case DB_SQI:
      /* Not linear or log */
      fresult = 0.0;
      break;

    case DB_RHOH2:
    case DB_RHOV2:
    case DB_RHOHV2:
    case DB_SQI2:
      fresult = -1.0/65533.0;
      break;

    case DB_SHEAR:
      fresult = -25.6;
      break;

    case DB_TIME2:
      fresult = -32768.0/60.0;
      break;

    case DB_VEL:
      if (pconvert_a)
	fresult = pconvert_a->fvelun_velocity * (-128.0/127.0) ;
      else
	fresult = 1.0;
      break;

    case DB_VELC:
      fresult = -75.0 *(128.0/127.0);
      break ;

    case DB_VIL2:
      fresult = -0.001;
      break;

    case DB_ZDR:
      fresult = -8.0;
      break;

    default:
      fresult = 0.0;
      break;
    }
  return fresult;
}

/* ------------------------------
 * Convert user units to internal data format.
 */
UINT2 iuser_to_data
  (FLT4  fuser_a,
   UINT4 idtype_a,
   const struct data_convert *pconvert_a )
{
  UINT2 iresult2 ; UINT4 iresult4 ; FLT4  fresult ;

  switch( idtype_a )
    {
    case DB_AXDIL2:
    case DB_HDIR2:
      /* Angles between 359.95 degrees and 360.00 degrees should
       * be represented as 0
       */
      fresult  = 10.0 * fuser_a ;
      iresult4 = NINT( MIN( 3600.0, MAX( 0.0, fresult ) ) ) ;
      if (iresult4 == 3600) iresult4 = 0 ;
      iresult2 = iresult4 ;
      break;

    case DB_DBT:
    case DB_DBZ:
    case DB_DBZC:
      fresult  =  2.0 * (fuser_a+32.0) ;
      /* Low dBZs will be thresholded */
      iresult4 = NINT( MIN( 254.0, MAX( 0.0, fresult ) ) ) ;
      iresult2 = iresult4 ;
      break;

    case DB_DBT2:
    case DB_DBZ2:
    case DB_DBZC2:
    case DB_KDP2:
    case DB_LDRH2:
    case DB_LDRV2:
    case DB_VEL2:
    case DB_VELC2:
    case DB_ZDR2:
      fresult  = (100.0 * fuser_a) + 32768.0 ;
      iresult4 = NINT( MIN( 65534.0, MAX( 0.0, fresult ) ) ) ;
      iresult2 = iresult4 ;
      break;

    case DB_DEFORM2:
    case DB_DIVERGE2:
      fresult  = 1000.0 * fuser_a ;
      iresult4 = NINT( MIN( 32767.0, MAX( -32767.0, fresult ) ) ) ;
      iresult2 = iresult4 ;
      break;

    case DB_FLIQUID2:
      fresult  = 1000.0 * fuser_a ;
      if (pconvert_a->iColorFlags & SCALE_RAIN_INCHES)
	fresult *= 10.0*CM_PER_INCH;
      iresult4 = NINT( MIN( 4294967296.0, MAX( 0.0, fresult ) ) ) ;
      rain_long_to_file( &iresult4, 1, &iresult2 ) ;
      break;

    case DB_HEIGHT   :
      fresult  = 10.0 * (fuser_a + 0.1) ;
      iresult4 = NINT( MIN( 253.0, MAX( 1.0, fresult ) ) ) ;
      iresult2 = iresult4 ;
      break;

    case DB_HVEL2:
    case DB_VVEL2:
      fresult  = 100.0 * fuser_a ;
      iresult4 = NINT( MIN( 32767.0, MAX( -32767.0, fresult ) ) ) ;
      iresult2 = iresult4 ;
      break;

    case DB_KDP:
      /* KDP*Lambda span is  0.25 - 150.0.
       */
      if (pconvert_a)
	{
	  FLT4 fkdp_lambda = pconvert_a->flambda * fuser_a;
	  if (fkdp_lambda > 0.2438)
	    {
	      fresult = 129.0 + log(  4.0 * fkdp_lambda ) * ( 126 / log(600) );
	      fresult = MIN( 254.0, MAX( 128.0, fresult ) );
	      iresult2 = NINT( fresult );
	    }
	  else if (fkdp_lambda < -.2438 )
	    {
	      fresult = 127.0 - log( -4.0 * fkdp_lambda ) * ( 126 / log(600) );
	      fresult = MIN( 128.0, MAX( 1.0, fresult ) );
	      iresult2 = NINT( fresult );
	    }
	  else
	    iresult2 = 128;  /* zero maps to 128 */
	}
      else
	iresult2 = 128;
      break;

    case DB_LDRH:
    case DB_LDRV:
      fresult  = 5.0 * (fuser_a + 45.2) ;
      iresult4 = NINT( MIN( 254.0, MAX( 1.0, fresult ) ) ) ;
      iresult2 = iresult4 ;
      break;
      
    case DB_OTHER:
    case DB_USER:
    case DB_FLAGS:
      fresult  = MIN( 254.0, MAX( 1.0, fuser_a) ) ;
      iresult4 = NINT( fresult ) ;
      iresult2 = iresult4 ;
      break;

    case DB_USER2:
    case DB_FLAGS2:
      fresult  = MIN( 65534.0, MAX( 1.0, fuser_a) ) ;
      iresult4 = NINT( fresult ) ;
      iresult2 = iresult4 ;
      break;

    case DB_RAINRATE2:
      fresult  = 10000.0*fuser_a;
      if (pconvert_a->iColorFlags & SCALE_RAINRATE_IN_HOUR)
	fresult *= 10.0*CM_PER_INCH;
      iresult4 = 1 + NINT( MIN( 4294967295.0, MAX( 0.0, fresult ) ) );
      rain_long_to_file( &iresult4, 1, &iresult2 ) ;
      break;

    case DB_PHIH:
    case DB_PHIV:
    case DB_PHIDP:
      fresult = fmod( fuser_a, 180.0 ) ;
      if( fresult < 0.0 ) fresult += 180.0 ;
      fresult  = 1.0 + (254.0 * fresult / 180.0) ;
      iresult4 = NINT( MIN( 254.0, MAX( 1.0, fresult ) ) ) ;
      iresult2 = iresult4;
      break;

    case DB_PHIH2:
    case DB_PHIV2:
    case DB_PHIDP2:
      fresult = fmod( fuser_a, 360.0 ) ;
      if( fresult < 0.0 ) fresult += 360.0 ;
      fresult  = 1.0 + (65534.0 * fresult / 360.0) ;
      iresult4 = NINT( MIN( 65534.0, MAX( 1.0, fresult ) ) ) ;
      iresult2 = iresult4;
      break;

    case DB_RHOH:
    case DB_RHOV:
    case DB_RHOHV:
    case DB_SQI:
      fresult = 253.0 * fuser_a * fuser_a;
      iresult4 = 1 + NINT( MIN(fresult,253.0) );
      iresult2 = iresult4 ;
      break;

    case DB_RHOHV2:
    case DB_RHOH2:
    case DB_RHOV2:
    case DB_SQI2:
      fresult = 65533.0 * fuser_a;
      iresult4 = 1 + NINT( MIN(65533.0, MAX( 0.0, fresult)) );
      iresult2 = iresult4 ;
      break;
      
    case DB_SHEAR:
      fresult  = 5.0 * (fuser_a + 25.6) ;
      iresult4 = NINT( MIN( 254.0, MAX( 1.0, fresult ) ) ) ;
      iresult2 = iresult4 ;
      break;

    case DB_TIME2:
      fresult  = (60.0 * fuser_a) + 32768.0 ;
      iresult4 = NINT( MIN( 65534.0, MAX( 1.0, fresult ) ) ) ;
      iresult2 = iresult4 ;
      break;

    case DB_VEL:
      if (pconvert_a && (pconvert_a->fvelun_velocity!=0)) {
	fresult  = 128.0 + (127.0 * fuser_a / pconvert_a->fvelun_velocity) ;
	iresult4 = NINT( MIN( 254.0, MAX( 1.0, fresult ) ) ) ;
      } else {
	iresult4 = 128 ;
      }
      iresult2 = iresult4 ;
      break;

    case DB_VELC:
      fresult  = 128.0 + ((127.0 / 75.0) * fuser_a) ;
      iresult2 = NINT( MIN( 254.0, MAX( 1.0, fresult ) ) ) ;
      break ;

    case DB_VIL2:
      fresult  = 1000.0 * (fuser_a + 0.001) ;
      iresult4 = NINT( MIN( 65534.0, MAX( 1.0, fresult ) ) ) ;
      iresult2 = iresult4 ;
      break;

    case DB_WIDTH:
      if (pconvert_a && (pconvert_a->fvelun_width != 0.0) ) {
	fresult  = 256.0 * fuser_a / pconvert_a->fvelun_width ;
	iresult4 = NINT( MIN( 254.0, MAX( 1.0, fresult ) ) ) ;
      } else {
	iresult4 = 1;
      }
      iresult2 = iresult4;
      break;

    case DB_WIDTH2:
      fresult  = 100.0 * fuser_a ;
      iresult4 = NINT( MIN( 65534.0, MAX( 1.0, fresult ) ) ) ;
      iresult2 = iresult4 ;
      break;

    case DB_ZDR:
      fresult  = (16.0 * fuser_a) + 128.0 ;
      iresult4 = NINT( MIN( 254.0, MAX( 1.0, fresult ) ) ) ;
      iresult2 = iresult4 ;
      break;

    default:
      iresult2 = 1;
      break;
    }
  return( iresult2 ) ;
}

/* ------------------------------
 * Given an array of 32-bit values, convert each to a 16-bit rain
 * word.  The 0xFFFFFFFF input value is treated as a "no scan" code.
 * Input values greater than or equal to 0x08000000 are encoded as the
 * largest possible file value, i.e., 0xFFFE.
 *
 */
#define TRIAL(n) (0x00000800<<n)
void rain_long_to_file
  (const UINT4* in_a, /*in ==> Long input array */
   SINT4 count_a,     /*in      number of longs in IN_A */
   UINT2* out_a       /*out ==> Rain output array */
)
{
  int count = count_a;
  UINT2 *out = out_a ;
  const UINT4 *in = in_a;
  UINT4 val ;

  while( --count >= 0 )
    {
      val = *in++ ;
      if( val == 0xFFFFFFFF )
	{          /* No Scan case */
	  *out = 0xFFFF ;
	}
      else if( val >= TRIAL(16) )
	{    /* Data too large case */
	  *out = 0xFFFE ;
	}
      else
	{
	  if( val >= TRIAL(8) ) {
	    if( val >= TRIAL(12) ) {
	      if( val >= TRIAL(14) ) {
		if( val >= TRIAL(15) ) {
		  *out = 0xF000 + ((val>>14) & 0x0FFF) ;
		} else {
		  *out = 0xE000 + ((val>>13) & 0x0FFF) ;
		}
	      } else {
		if( val >= TRIAL(13) ) {
		  *out = 0xD000 + ((val>>12) & 0x0FFF) ;
		} else {
		  *out = 0xC000 + ((val>>11) & 0x0FFF) ;
		}
	      }
	    } else {
	      if( val >= TRIAL(10) ) {
		if( val >= TRIAL(11) ) {
		  *out = 0xB000 + ((val>>10) & 0x0FFF) ;
		} else {
		  *out = 0xA000 + ((val>>9) & 0x0FFF) ;
		}
	      } else {
		if( val >= TRIAL(9) ) {
		  *out = 0x9000 + ((val>>8) & 0x0FFF) ;
		} else {
		  *out = 0x8000 + ((val>>7) & 0x0FFF) ;
		}
	      }
	    }
	  } else {
	    if( val >= TRIAL(4) ) {
	      if( val >= TRIAL(6) ) {
		if( val >= TRIAL(7) ) {
		  *out = 0x7000 + ((val>>6) & 0x0FFF) ;
		} else {
		  *out = 0x6000 + ((val>>5) & 0x0FFF) ;
		}
	      } else {
		if( val >= TRIAL(5) ) {
		  *out = 0x5000 + ((val>>4) & 0x0FFF) ;
		} else {
		  *out = 0x4000 + ((val>>3) & 0x0FFF) ;
		}
	      }
	    } else {
	      if( val >= TRIAL(2) ) {
		if( val >= TRIAL(3) ) {
		  *out = 0x3000 + ((val>>2) & 0x0FFF) ;
		} else {
		  *out = 0x2000 + ((val>>1) & 0x0FFF) ;
		}
	      } else {
		if( val >= TRIAL(1) ) {
		  *out = 0x1000 + (val & 0x0FFF) ; ;
		} else {
		  *out = val ;
		}
	      }
	    }
	  }
	}
      out++ ;
    }
}

/* ------------------------------
 * Given a 16-bit rain word, convert to 32-bit values.
 */
UINT4 rain_file_to_long( UINT2 ifile_a )
{
  UINT4 iresult;

  iresult = ifile_a;
  if (iresult != 0xFFFF)
    {
      if (iresult & 0xF000)
	iresult = (0x1000 + (iresult & 0x0FFF)) << ((iresult>>12)-1);      
    }
  else
    {
      iresult = 0xFFFFFFFF;
    }
  return iresult;
}

/* --------------------
 * Routine to give the resolution in bits of the data product of the
 * data type specified.
 */
UINT4 idata_resolution( UINT4 idata_a )
{
  UINT4 iresolution;

  /* 2-byte versions of dBZ, Velocity, Width, Linear liquid,
   * floating liquid formats are in 16-bits, all others are in
   * 8-bits.
   */
  switch( idata_a )
    {
    case DB_AXDIL2:
    case DB_DBT2:
    case DB_DBZ2:
    case DB_DBZC2:
    case DB_DEFORM2:
    case DB_DIVERGE2:
    case DB_FLIQUID2:
    case DB_HDIR2:
    case DB_HVEL2:
    case DB_KDP2:
    case DB_LDRH2:
    case DB_LDRV2:
    case DB_PHIDP2:
    case DB_PHIH2:
    case DB_PHIV2:
    case DB_RAINRATE2:
    case DB_RHOH2:
    case DB_RHOV2:
    case DB_RHOHV2:
    case DB_SQI2:
    case DB_TIME2:
    case DB_USER2:
    case DB_VEL2:
    case DB_VELC2:
    case DB_VIL2:
    case DB_VVEL2:
    case DB_WIDTH2:
    case DB_ZDR2:
    case DB_FLAGS2:
      iresolution = 16;
      break;

    default:
      iresolution = 8;
      break;
    }

  return iresolution;
}

/* ------------------------------
 * Routine to give the 8-bit or 16-bit data type that corresponds to
 * the specified 16-bit or 8-bit type.  Returns -1 if there is no
 * alternate data type.
 */
SINT4 idata_alt_type( SINT4 idata_a )
{
  switch( idata_a)
    {
    case DB_DBT:     return DB_DBT2;    break;
    case DB_DBZ:     return DB_DBZ2;    break;
    case DB_DBZC:    return DB_DBZC2;   break;
    case DB_FLAGS:   return DB_FLAGS2;  break;
    case DB_KDP:     return DB_KDP2;    break;
    case DB_LDRH:    return DB_LDRH2;   break;
    case DB_LDRV:    return DB_LDRV2;   break;
    case DB_PHIDP:   return DB_PHIDP2;  break;
    case DB_PHIH:    return DB_PHIH2;   break;
    case DB_PHIV:    return DB_PHIV2;   break;
    case DB_RHOH:    return DB_RHOH2;   break;
    case DB_RHOHV:   return DB_RHOHV2;  break;
    case DB_RHOV:    return DB_RHOV2;   break;
    case DB_SQI:     return DB_SQI2;    break;
    case DB_USER:    return DB_USER2;   break;
    case DB_VEL:     return DB_VEL2;    break;
    case DB_VELC:    return DB_VELC2;   break;
    case DB_WIDTH:   return DB_WIDTH2;  break;
    case DB_ZDR:     return DB_ZDR2;    break;
      
    case DB_DBT2:    return DB_DBT;     break;
    case DB_DBZ2:    return DB_DBZ;     break;
    case DB_DBZC2:   return DB_DBZC;    break;
    case DB_FLAGS2:  return DB_FLAGS;   break;
    case DB_KDP2:    return DB_KDP;     break;
    case DB_LDRH2:   return DB_LDRH;    break;
    case DB_LDRV2:   return DB_LDRV;    break;
    case DB_PHIDP2:  return DB_PHIDP;   break;
    case DB_PHIH2:   return DB_PHIH;    break;
    case DB_PHIV2:   return DB_PHIV;    break;
    case DB_RHOH2:   return DB_RHOH;    break;
    case DB_RHOHV2:  return DB_RHOHV;   break;
    case DB_RHOV2:   return DB_RHOV;    break;
    case DB_SQI2:    return DB_SQI;     break;
    case DB_USER2:   return DB_USER;    break;
    case DB_VEL2:    return DB_VEL;     break;
    case DB_VELC2:   return DB_VELC;    break;
    case DB_WIDTH2:  return DB_WIDTH;   break;
    case DB_ZDR2:    return DB_ZDR;     break;
    }
  return -1;
}

/* ------------------------------
 * Convert an array of data (bytes/words) to its alternate data type
 * (words/bytes)
 *
 * Entry Parameters
 *  idtype_a    : Data type of input array
 *  icount_a    : # of items to convert.  If converting to bytes, and count_a is
 *                  odd, then an extra zero byte is padded on the end.
 *  in_a      ==> Input data array
 *  fnyquist_a  : Nyquist point for velocities
 *
 * Exit Parameters
 *  out_a     ==> Output data array
 */
void convert_alt_data
( UINT4 idtype_a,
  SINT4 icount_a,
  const UINT1 *in_a,
  UINT1 *out_a,
  const struct data_convert *pconvert_a )
{
  UINT4 iInRes;

  iInRes = idata_resolution( idtype_a );

  switch (iInRes)
    {
    case 8:
    default:
      ConvertDataFrom8( idtype_a, icount_a, in_a, (UINT2*)out_a, pconvert_a );
      break;
    case 16:
      ConvertDataFrom16( idtype_a, icount_a, (const UINT2*)in_a, out_a, pconvert_a );
      break;
    }
}
/* ------------------------------
 * Convert from 8 to 16 bits.
 */
void ConvertDataFrom8
( UINT4 iInDType_a,		/* Input data type */
  SINT4 icount_a,		/* Number of bins */
  const UINT1 *in_a,		/* Input pointer */
  UINT2 *out_a,			/* Output pointer */
  const struct data_convert *pconvert_a ) /* Convert structure */
{
  SINT4 ii; SINT4 iOutDType;
  UINT1 ival;
  FLT4 fx, fscale ;
  const UINT1 *pIn = in_a;
  UINT2 *pOut = out_a;
  iOutDType = idata_alt_type( iInDType_a );

  switch( iInDType_a )
    {
    case DB_VEL: case DB_VELC:   /* 8-Bit Vel --> 16-Bit */
      fscale = 100.0 * fDataScalePerBit( iInDType_a, pconvert_a );
      for( ii=0 ; ii<icount_a ; ii++ ) 
	{
	  ival = *pIn++ ;
	  if( ival == DV_THRESH1 ) 
	    { *pOut++ = DV_THRESH2 ; }
	  else
	    { fx = fscale * ((float)(ival - 128)) ; *pOut++ = 32768 + NINT(fx); }
	}
      break ;
      
    case DB_WIDTH :		      /* 8-Bit Width --> 16-Bit */
      if (pconvert_a)
	fscale = 100.0 * pconvert_a->fvelun_width / 256.0 ;
      else
	fscale = 0.0;
      for( ii=0 ; ii<icount_a ; ii++ )
	{
	  ival = *pIn++ ;
	  if( ival == DV_THRESH1 )
	    { *pOut++ = DV_THRESH2 ; }
	  else
	    {
	      fx = fscale * ((float)ival ) ; *pOut++ = NINT(fx) ;
	    }
	}
      break ;
    default:		      /* 8-Bit Width --> 16-Bit */
      for( ii=0 ; ii<icount_a ; ii++ )
	{
	  ival = *pIn++ ;
	  if( ival == DV_THRESH1 )
	    { *pOut++ = DV_THRESH2 ; }
	  else
	    {
	      fx = fdata_to_user( ival, iInDType_a, pconvert_a );
	      *pOut++ = iuser_to_data( fx, iOutDType, pconvert_a );
	    }
	}
      break ;
    }
  return;
}
/* ------------------------------
 * Convert from 16 to 8 bits.
 */
void ConvertDataFrom16
( UINT4 iInDType_a,		/* Input data type */
  SINT4 icount_a,		/* Number of bins */
  const UINT2 *in_a,		/* Input pointer */
  UINT1 *out_a,			/* Output pointer */
  const struct data_convert *pconvert_a ) /* Convert structure */
{
  SINT4 ii, iOutDType;
  UINT2 ival;
  FLT4 fx, fscale ;
  const UINT2 *pIn = in_a;
  UINT1 *pOut = out_a;
  iOutDType = idata_alt_type( iInDType_a );

  switch( iInDType_a )
    {
    case DB_VEL2: case DB_VELC2:      /* 16-Bit Vel --> 8-Bit */
      fscale = 1.0 / (100.0 * fDataScalePerBit( iOutDType, pconvert_a ));
      for( ii=0 ; ii<icount_a ; ii++ )
	{
	  ival = *pIn++ ;
	  if( ival == DV_THRESH2 )
	    { *pOut++ = DV_THRESH1; }
	  else
	    {
	      /* Note that 8-bit velocity is properly aliased by
	       * taking only the lower 8-bits of the overall result.
	       */
	      fx = fscale * ((float)(ival - 32768)) ;
	      ival = 0x80 ^ (0xFF & NINT(fx)) ; if( ival == 0 ) ival = 1 ;
	      *pOut++ = ival ;
	    }
	}
      break ;
      
    case DB_WIDTH2 :		      /* 16-Bit Width --> 8-Bit */
      if (pconvert_a && (pconvert_a->fvelun_width!=0.0))
	fscale = 256.0 / (100.0 * pconvert_a->fvelun_width) ;
      else
	fscale = 0.0;
      for( ii=0 ; ii<icount_a ; ii++ )
	{
	  ival = *pIn++ ;
	  if( ival == DV_THRESH2 )
	    { *pOut++ = DV_THRESH1 ; }
	  else
	    {
	      fx = fscale * (float)ival ; ival = NINT(fx) ;
	      *pOut++ = MIN( 255, MAX( 1, ival ) ) ;
	    }
	}
      break ;

    default :		      /* 16-Bit Width --> 8-Bit */
      for( ii=0 ; ii<icount_a ; ii++ )
	{
	  ival = *pIn++ ;
	  if( ival == DV_THRESH2 )
	    { *pOut++ = DV_THRESH1 ; }
	  else
	    {
	      fx = fdata_to_user( ival, iInDType_a, pconvert_a );
	      *pOut++ = iuser_to_data( fx, iOutDType, pconvert_a );
	    }
	}
      break ;
    }
  if( icount_a & 1 ) *pOut++ = 0 ;
  return;
}

/* ------------------------------
 * Limit the start value of a color scale.
 */
FLT4 fDataScaleStartLimit( UINT2 idata_a, FLT4 fNumIn_a )
{
  FLT4 fnum_out;

  switch(idata_a)
  {
    case DB_DBT:
    case DB_DBT2:
    case DB_DBZ:
    case DB_DBZ2:     fnum_out = MIN( MAX( -32.0, fNumIn_a),    96.0); break;
    case DB_DEFORM2:  fnum_out = MIN( MAX(   0.0, fNumIn_a),    32.0); break;
    case DB_DIVERGE2: fnum_out = MIN( MAX( -32.0, fNumIn_a),    32.0); break;
    case DB_FLAGS:    fnum_out = MIN( MAX(   0.0, fNumIn_a),   255.0); break;
    case DB_FLAGS2:   fnum_out = MIN( MAX(   0.0, fNumIn_a), 65535.0); break;
    case DB_FLIQUID2: fnum_out = MIN( MAX(   0.0, fNumIn_a), 10000.0); break;
    case DB_HEIGHT:   fnum_out = MIN( MAX(   0.0, fNumIn_a),    25.0); break;
    case DB_RAINRATE2:fnum_out = MIN( MAX(   0.0, fNumIn_a),   500.0); break;
    case DB_SHEAR:    fnum_out = MIN( MAX( -25.0, fNumIn_a),    25.0); break;
    case DB_SQI:
    case DB_SQI2:     fnum_out = MIN( MAX(   0.0, fNumIn_a),     1.0); break;
    case DB_TIME2:    fnum_out = MIN( MAX(   0.0, fNumIn_a),    60.0); break;
    case DB_USER:     fnum_out = MIN( MAX(   0.0, fNumIn_a),   255.0); break;
    case DB_USER2:    fnum_out = MIN( MAX(   0.0, fNumIn_a), 65535.0); break;
    case DB_VEL2:
    case DB_VEL:
    case DB_VVEL2:    fnum_out = MIN( MAX(-327.0, fNumIn_a),   327.0); break;
    case DB_VIL2:     fnum_out = MIN( MAX(   0.0, fNumIn_a),    65.0); break;
    case DB_WIDTH:
    case DB_WIDTH2:   fnum_out = MIN( MAX(   0.0, fNumIn_a),   100.0); break;
    case DB_ZDR:
    case DB_ZDR2:     fnum_out = MIN( MAX(  -8.0, fNumIn_a),     8.0); break;
    default:          fnum_out = fNumIn_a;                             break;
  };
  return fnum_out;
}

FLT4 fDataScaleStepLimit( UINT2 idata_a, FLT4 fNumIn_a )
{
  FLT4 fnum_out;

  switch(idata_a)
  {
    case DB_DBT:
    case DB_DBT2:
    case DB_DBZ:
    case DB_DBZ2:     fnum_out = MIN( MAX(   0.1, fNumIn_a),    50.0); break;
    case DB_DEFORM2:  fnum_out = MIN( MAX(   0.1, fNumIn_a),    32.0); break;
    case DB_DIVERGE2: fnum_out = MIN( MAX(   0.1, fNumIn_a),    32.0); break;
    case DB_FLAGS:
    case DB_FLAGS2:   fnum_out = MIN( MAX(   1.0, fNumIn_a),   128.0); break;
    case DB_FLIQUID2: fnum_out = MIN( MAX(   0.1, fNumIn_a), 10000.0); break;
    case DB_HEIGHT:   fnum_out = MIN( MAX(   0.1, fNumIn_a),    10.0); break;
    case DB_RAINRATE2:fnum_out = MIN( MAX(   0.1, fNumIn_a),   100.0); break;
    case DB_SHEAR:    fnum_out = MIN( MAX(   0.1, fNumIn_a),    25.0); break;
    case DB_SQI:
    case DB_SQI2:     fnum_out = MIN( MAX(   0.1, fNumIn_a),     1.0); break;
    case DB_TIME2:    fnum_out = MIN( MAX(   0.1, fNumIn_a),    60.0); break;
    case DB_USER:
    case DB_USER2:    fnum_out = MIN( MAX(   1.0, fNumIn_a),   128.0); break;
    case DB_VEL:
    case DB_VEL2:     fnum_out = MIN( MAX(   0.0, fNumIn_a),    20.0); break;
    case DB_VVEL2:    fnum_out = MIN( MAX(   0.1, fNumIn_a),    20.0); break;
    case DB_VIL2:     fnum_out = MIN( MAX(   0.1, fNumIn_a),    65.0); break;
    case DB_WIDTH:
    case DB_WIDTH2:   fnum_out = MIN( MAX(   0.1, fNumIn_a),    20.0); break;
    case DB_ZDR:
    case DB_ZDR2:     fnum_out = MIN( MAX(   0.1, fNumIn_a),     8.0); break;
    default:          fnum_out = fNumIn_a;                             break;
  };
  return fnum_out;
}

/* ************************************
 * *                                  *
 * *  Packed Floating (I,Q) Routines  *
 * *                                  *
 * ************************************
 *
 * Convert a normalized floating "I" or "Q" value to/from the signal
 * processor's 16-bit packed format.  The floating values are in the
 * range -4.0 to +4.0, i.e., they are normalized so that full scale CW
 * input gives a magnitude of 1.0, while still leaving a factor of
 * four of additional amplitude headroom (12dB headroom power) to
 * account for FIR filter transients.
 */

/* ------------------------------
 * Convert an array of FLT4's to packed floating.
 */
void vecPackIQFromFloatIQ_
( volatile UINT2 iCodes_a[], volatile const FLT4 fIQVals_a[],
  SINT4 iCount_a, UINT4 iFlags_a )
{
  SINT4 iCount ; volatile const FLT4 *fIQVals = fIQVals_a ;
  UINT1 lSwap = (iFlags_a & PACKIQ_BYTESWAP) != 0 ;
  volatile UINT2 *iCodes = iCodes_a ;

  if( iFlags_a & PACKIQ_HIGHSNR ) {
    /* High SNR packed format with 12-bit mantissa
     */
    for( iCount=0 ; iCount < iCount_a ; iCount++ ) {
      UINT2 iCode ; FLT4 fIQVal = *fIQVals++ ;

      if     (  fIQVal >=  4.0 ) iCode = 0xF7FF ;
      else if(  fIQVal <= -4.0 ) iCode = 0xF800 ;
      else if( (fIQVal >  -1.221299E-4) &&
	       (fIQVal <   1.220703E-4) ) {
	SINT4 iUnderFlow = NINT( 1.677721E7 * fIQVal ) ;
	iCode = 0xFFF & MAX( -2048, MIN( 2047, iUnderFlow ) ) ;
      } else {
	int iSign, iExp, iMan ;
#ifdef LINUX
	/* Much faster (x4.5) version on LINUX uses hardware definition
	 * of FLT4.  Native mantissa has 23 bits, we want 12, rounded.
	 * Courtesy of Nathan Parker, MIT/LL, Aug 2002.
	 */
	union ieee754_float u ; int uMan ;
	u.f = fIQVal ; uMan = u.ieee.mantissa ; iSign = u.ieee.negative ;
	iMan = (uMan >> 12) | (1<<11) ; if( iSign ) iMan = ~iMan ;
	iMan += ((uMan >> 11) & 1 ) ^ iSign ;

	iExp = (int)u.ieee.exponent - (IEEE754_FLOAT_BIAS - 1) + 13 ;
#else
	iMan = NINT( 4096.0 * frexp( fIQVal, &iExp ) ) ;
	iExp += 13 ; iSign = (fIQVal < 0.0) ;
#endif

	if( iMan ==  4096 ) iExp++ ; /* Fix up mantissa overflows */
	if( iMan == -2048 ) iExp-- ; /*   by adjusting the exponent. */

	iCode = (iExp << 12) | (iSign << 11) | (0x7FF & iMan) ;
      }
      if( lSwap ) iCode = (iCode << 8) | (iCode >> 8) ;
      *iCodes++ = iCode ;
    }
  }
  else {
    /* Legacy packed format with 11-bit mantissa
     */
    for( iCount=0 ; iCount < iCount_a ; iCount++ ) {
      UINT2 iCode ; FLT4 fIQVal = *fIQVals++ ;

      if     ( fIQVal ==  0.0 ) iCode = 0x0000 ;
      else if( fIQVal >=  4.0 ) iCode = 0xFBFF ;
      else if( fIQVal <= -4.0 ) iCode = 0xFC00 ;
      else {
	int iSign, iExp, iMan ;
#ifdef LINUX
	/* Much faster (x4.5) version on LINUX uses hardware definition
	 * of FLT4.  Native mantissa has 23 bits, we want 11, rounded.
	 * Courtesy of Nathan Parker, MIT/LL, Aug 2002.
	 */
	union ieee754_float u ; int uMan ;
	u.f = fIQVal ; uMan = u.ieee.mantissa ; iSign = u.ieee.negative ;
	iMan = (uMan >> 13) | (1<<10) ; if( iSign ) iMan = ~iMan ;
	iMan += ((uMan >> 12) & 1 ) ^ iSign ;

	iExp = (int)u.ieee.exponent - (IEEE754_FLOAT_BIAS - 1) + 29 ;
#else
	iMan = NINT( 2048.0 * frexp( fIQVal, &iExp ) ) ;
	iExp += 29 ; iSign = (fIQVal < 0.0) ;
#endif

	if( iMan ==  2048 ) iExp++ ; /* Fix up mantissa overflows */
	if( iMan == -1024 ) iExp-- ; /*   by adjusting the exponent. */

	if( iExp < 0 ) iCode = 0x0000 ;
	else           iCode = (iExp << 11) | (iSign << 10) | (0x3FF & iMan) ;
      }
      if( lSwap ) iCode = (iCode << 8) | (iCode >> 8) ;
      *iCodes++ = iCode ;
    }
  }
}

/* ------------------------------
 * Convert an array of packed floating to FLT4.  This uses table
 * lookup to run at the maximum possible speed.
 */
void vecFloatIQFromPackIQ_
( volatile FLT4 fIQVals_a[], volatile const UINT2 iCodes_a[],
  SINT4 iCount_a, UINT4 iFlags_a )
{
  /* Maintain separate tables for each of the possible combinations of
   * requested flag bits.
   */
  static FLT4 *pLookupTabs_c[ 4 ] = { NULL } ;

  FLT4 **pTableSlot = &pLookupTabs_c[ iFlags_a & 3 ], *pTable ;

  /* Get a pointer to our table of floats, but build the table now if
   * we haven't done it already.  If the malloc fails, then just call
   * the internal routine and do the work directly.
   */
  if( ! ( pTable = *pTableSlot ) ) {
    if( ! ( *pTableSlot = malloc( 0x10000 * sizeof(FLT4) ) ) ) {
      vecFloatIQFromPackIQ_comp( fIQVals_a, iCodes_a, iCount_a, iFlags_a ) ;
      return ;
    } else {
      UINT2 iCode = 0 ; pTable = *pTableSlot ;
      for(;;) {
	vecFloatIQFromPackIQ_comp( &pTable[iCode], &iCode, 1, iFlags_a ) ;
	if( 0 == ++iCode ) break ;
      }
    }
  }
  /* Now buzz out the actual data conversion.  Remove the volatile
   * casts just in case it allows the compiler to make better code.
   */
  {
    FLT4 *pfIQVals = (void *)fIQVals_a ; SINT4 iCount ;
    const UINT2 *piCodes = (void *)iCodes_a ;

    for( iCount=0 ; iCount < iCount_a ; iCount++ ) {
      *pfIQVals++ = pTable[ *piCodes++ ] ;
    }
  }
}

/* ------------------------------
 * Kernel packing routine that actually knows how to compute the
 * floating values from the packed data.
 */
void vecFloatIQFromPackIQ_comp
( volatile FLT4 fIQVals_a[], volatile const UINT2 iCodes_a[],
  SINT4 iCount_a, UINT4 iFlags_a )
{
  SINT4 iCount ; volatile const UINT2 *iCodes = iCodes_a ;
  UINT1 lSwap = (iFlags_a & PACKIQ_BYTESWAP) != 0 ;
  volatile FLT4 *fIQVals = fIQVals_a ;

  if( iFlags_a & PACKIQ_HIGHSNR ) {
    /* High SNR packed format with 12-bit mantissa
     */
    for( iCount=0 ; iCount < iCount_a ; iCount++ ) {
      UINT2 iCode = *iCodes++ ; FLT4 fVal = 0.0 ;
      if( lSwap ) iCode = (iCode << 8) | (iCode >> 8) ;

      if( iCode & 0xF000 ) {
	SINT4 iMan =  iCode        & 0x7FF ;
	SINT4 iExp = (iCode >> 12) & 0x00F ;

	if( iCode & 0x0800 ) iMan |= 0xFFFFF000 ;
	else                 iMan |= 0x00000800 ;

	fVal = ((FLT4)iMan) * ((FLT4)(UINT4)(1 << iExp)) / 3.355443E7 ;
      }
      else {
	fVal = ( (FLT4)(((SINT4)iCode) << 20) ) / 1.759218E13 ;
      }
      *fIQVals++ = fVal ;
    }
  } else {
    /* Legacy packed format with 11-bit mantissa
     */
    for( iCount=0 ; iCount < iCount_a ; iCount++ ) {
      UINT2 iCode = *iCodes++ ; FLT4 fVal = 0.0 ;
      if( lSwap ) iCode = (iCode << 8) | (iCode >> 8) ;

      if( iCode ) {
	SINT4 iMan =  iCode        & 0x3FF ;
	SINT4 iExp = (iCode >> 11) & 0x01F ;

	if( iCode & 0x0400 ) iMan |= 0xFFFFF800 ;
	else                 iMan |= 0x00000400 ;

	fVal = ((FLT4)iMan) * ((FLT4)(UINT4)(1 << iExp)) / 1.099512E12 ;
      }
      *fIQVals++ = fVal ;
    }
  }
}

/* ------------------------------
 * Cover routines for converting one item at a time.
 */
UINT2 iPackIQFromFloatIQ_( FLT4 fIQVal_a, UINT4 iFlags_a )
{
  UINT2 iCode ;
  vecPackIQFromFloatIQ_( &iCode, &fIQVal_a, 1, iFlags_a ) ;
  return( iCode ) ;
}
FLT4  fFloatIQFromPackIQ_( UINT2 iCode_a, UINT4 iFlags_a )
{
  FLT4 fFloatIQ ;
  vecFloatIQFromPackIQ_comp( &fFloatIQ, &iCode_a, 1, iFlags_a ) ;
  return( fFloatIQ ) ;
}

/* ------------------------------
 * Test program to verify the conversion routines
 */
#if 0
#define FLAGS PACKIQ_HIGHSNR
int main( int argc_a, char *argv_a[] )
{
  SINT4 iIter ;
  for( iIter=0 ; iIter < 0x10000 ; iIter++ ) {
#if FLAGS
    SINT4 iEnCode = (iIter & 0x07FF) | ((iIter>>4) & 0x0800) | ((iIter<<1) & 0xF000) ;
#else
    SINT4 iEnCode = (iIter & 0x03FF) | ((iIter>>5) & 0x0400) | ((iIter<<1) & 0xF800) ;
#endif
    FLT4     fVal = fFloatIQFromPackIQ_( iEnCode, FLAGS ) ;
    SINT4 iDeCode = iPackIQFromFloatIQ_( fVal   , FLAGS ) ;

    if( iDeCode != iEnCode ) {
      printf( "MISMATCH!!  In:%4.4X  Out:%4.4X  fVal:%16.13f\n",
	      iEnCode, iDeCode, fVal ) ;

    } else if( (iEnCode & 0x00FF) == 0 ) {
      printf( "Code:%4.4X  fVal:%16.13f\n", iEnCode, fVal ) ;
    }
  }
  return(0) ;
}
#endif
