/* **********************************
 * *                                *  
 * *      DSP Driver Library        *
 * *                                *  
 * **********************************  
 * File: libs/dsp/dsp_strings.c
 *     
 *               COPYRIGHT (c) 1995, 1996, 1999, 2002  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 <ctype.h>
#include <string.h>

#define DSP_INFO_DRIVER 1
#include "sigtypes.h"
#include "dsp.h"
#include "setup.h"
#include "dsp_lib.h"

/* ======================================================================
 * Given a string describing a Boolean relation among threshold qualifiers,
 * convert to a 16-bit threshold control field.
 * For example, the string "SQI & LOG" would result in the value 0xA0A0.
 */
#define MAXLEN 60
#define TERMS " ()"
MESSAGE dsp_tcf_from_string(
  const char expr_a[],
  UINT2 *tcf_a )
{
  MESSAGE istatus = SS_NORMAL ;
  char *ptr, expr[MAXLEN+1] ; UINT2 iand, ival ;

  strncpy( expr, expr_a, MAXLEN ) ; expr[MAXLEN] = 0 ; STR_LOWER( expr, MAXLEN ) ;
  ptr = strtok( expr, TERMS ) ;

  /* Check for special case of no input, or the phrase "all pass".  Both of these
   * return the value 0xFFFF.
   */
  if( ptr == NULL || memcmp( ptr, "all", 3 ) == 0 ) {
    ival = 0xFFFF ;

  } else {
    /* Parse "&" terms separated by "or" terms.  No other fancy syntax is allowed.
     */
    for( ival=0x0000, iand=0xFFFF ; ; ) {
      if     ( strcmp( ptr, "log" ) == 0 ) iand &= TCF_LOG ;
      else if( strcmp( ptr, "csr" ) == 0 ) iand &= TCF_CSR ;
      else if( strcmp( ptr, "sqi" ) == 0 ) iand &= TCF_SQI ;
      else if( strcmp( ptr, "sig" ) == 0 ) iand &= TCF_WSP ;
      else { istatus = DSP_TCF_STRING ; break ; }

      ptr = strtok( NULL, TERMS ) ;
      if( ptr == NULL ) { ival |= iand ; break ; }

      if( strcmp( ptr, "&"  ) == 0 || strcmp( ptr, "and"  ) == 0 ) {
	ptr = strtok( NULL, TERMS ) ;
	if( ptr == NULL ) { istatus = DSP_TCF_STRING ; break ; }
      }
      else if( strcmp( ptr, "|"  ) == 0 || strcmp( ptr, "or" ) == 0 ) {
	ptr = strtok( NULL, TERMS ) ;
	if( ptr == NULL ) { istatus = DSP_TCF_STRING ; break ; }
	ival |= iand ; iand = 0xFFFF ;
      }
      else { istatus = DSP_TCF_STRING ; break ; }
    }
  }
    
  if( istatus != SS_NORMAL ) ival = 0xFFFF ;
  *tcf_a = ival ; return( istatus ) ;
}

/* ======================================================================
 * Given a threshold control value, convert to  the simplest algebraic
 * Boolean representation for that value.
 */
#define IOR_TERMS 4		/* Max # of OR'ed terms */

char * dsp_string_from_tcf( UINT2 tcf_a )
{
  static char string[ 27 * IOR_TERMS ] ; SINT2 ii, ior_terms ;
  UINT2 lmatch, iterms[ IOR_TERMS+1 ], tbits[15] = {
                                  TCF_LOG,
                        TCF_CSR          ,
              TCF_SQI                    ,
    TCF_WSP                              ,
                        TCF_CSR & TCF_LOG,
              TCF_SQI           & TCF_LOG,
              TCF_SQI & TCF_CSR          ,
    TCF_WSP                     & TCF_LOG,
    TCF_WSP           & TCF_CSR          ,
    TCF_WSP & TCF_SQI                    ,
              TCF_SQI & TCF_CSR & TCF_LOG,
    TCF_WSP           & TCF_CSR & TCF_LOG,
    TCF_WSP & TCF_SQI           & TCF_LOG,
    TCF_WSP & TCF_SQI & TCF_CSR          ,
    TCF_WSP & TCF_SQI & TCF_CSR & TCF_LOG } ;

  /* Handle the "All pass" and "None" cases specially.
   */
  if     ( tcf_a == 0xFFFF ) strcpy( string, "All Pass" ) ;
  else if( tcf_a == 0x0000 ) strcpy( string, "All Fail" ) ;
  else {

    /* Find some combination of AND terms which when OR'ed together give the
     * specified threshold bits.  Find the overall combination that uses the
     * fewest terms (by searching in order of increasing complexity).
     */
    lmatch = FALSE ;
    for( ior_terms = 1 ; ior_terms <= IOR_TERMS ; ior_terms++ ) {
      for( ii=0 ; ii < ior_terms ; ii++ ) iterms[ii] = ii ; iterms[ior_terms] = 15 ;
      for(;;) {
	UINT2 ival = 0 ;
	for( ii=0 ; ii < ior_terms ; ii++ ) ival |= tbits[ iterms[ii] ] ;
	if( ival == tcf_a ) { lmatch = TRUE ; break ; }

	for( ii = 0 ; ii < ior_terms ; ii++ ) {
	  iterms[ii]++ ; if( iterms[ii] < iterms[ii+1] ) break ;
	  iterms[ii] = ii ;
	}
	if( ii == ior_terms ) break ;
      }
      if( lmatch ) break ;
    }

    /* Assemble the output string from the bit patterns we have found
     */
    if( lmatch == FALSE ) {
      strcpy( string, "??? or ??? or ???" ) ;

    } else {
      string[0] = 0 ;
      for( ii=0 ; ii < ior_terms ; ii++ ) {
	if( ii > 0 ) strcat( string, " or " ) ;
	if( (ior_terms > 1) && (iterms[ii] > 3) ) strcat( string, "(" ) ;
	switch( iterms[ii] ) {
	case  0: strcat( string, "LOG" )                   ; break ;
	case  1: strcat( string, "CSR" )                   ; break ;
	case  2: strcat( string, "SQI" )                   ; break ;
	case  3: strcat( string, "SIG" )                   ; break ;
	case  4: strcat( string, "LOG & CSR" )             ; break ;
	case  5: strcat( string, "SQI & LOG" )             ; break ;
	case  6: strcat( string, "SQI & CSR" )             ; break ;
	case  7: strcat( string, "SIG & LOG" )             ; break ;
	case  8: strcat( string, "SIG & CSR" )             ; break ;
	case  9: strcat( string, "SIG & SQI" )             ; break ;
	case 10: strcat( string, "SQI & LOG & CSR" )       ; break ;
	case 11: strcat( string, "SIG & LOG & CSR" )       ; break ;
	case 12: strcat( string, "SIG & SQI & LOG" )       ; break ;
	case 13: strcat( string, "SIG & SQI & CSR" )       ; break ;
	case 14: strcat( string, "SIG & SQI & LOG & CSR" ) ; break ;
	}
	if( (ior_terms > 1) && (iterms[ii] > 3) ) strcat( string, ")" ) ;
      }
    }
  }
  return( string ) ;
}

/* ======================================================================
 * Given a numerical processing mode, convert to text string.
 */
const char *DspStringFromPMode
( char sString_a[16],    /* Storage to place string in */
  UINT2 pmode_a,
  const char sUserPModeNames_a[NUMPMODENAMES][16]   /* Optional user names */
  )
{
  switch( pmode_a )
    {
    case PMODE_PPP  : strcpy( sString_a, "PPP"    ) ; break ;
    case PMODE_FFT  : strcpy( sString_a, "FFT"    ) ; break ;
    case PMODE_RPH  : strcpy( sString_a, "RPHASE" ) ; break ;
    case PMODE_KNMI : strcpy( sString_a, "KNMI"   ) ; break ;
    case PMODE_DPT1 : strcpy( sString_a, "DPRT-1" ) ; break ;
    case PMODE_DPT2 : strcpy( sString_a, "DPRT-2" ) ; break ;
    case PMODE_BATCH: strcpy( sString_a, "BATCH"  ) ; break ;
    case PMODE_USER1: 
      if (sUserPModeNames_a && (sUserPModeNames_a[0][0]))
	{strncpy( sString_a, sUserPModeNames_a[0], 15 ); sString_a[15]=0;}
      else
	strcpy( sString_a, "USER1" ) ;
      break ;
    case PMODE_USER2: 
      if (sUserPModeNames_a && (sUserPModeNames_a[1][0]))
	{strncpy( sString_a, sUserPModeNames_a[1], 15 ); sString_a[15]=0;}
      else
	strcpy( sString_a, "USER2" ) ;
      break ;
    case PMODE_USER3: 
      if (sUserPModeNames_a && (sUserPModeNames_a[2][0]))
	{strncpy( sString_a, sUserPModeNames_a[2], 15 ); sString_a[15]=0;}
      else
	strcpy( sString_a, "USER3" ) ;
      break ;
    case PMODE_USER4: 
      if (sUserPModeNames_a && (sUserPModeNames_a[3][0]))
	{strncpy( sString_a, sUserPModeNames_a[3], 15 ); sString_a[15]=0;}
      else
	strcpy( sString_a, "USER4" ) ;
      break ;
    default:         strcpy( sString_a, "???"    ) ; break ;
    }
  return( sString_a ) ;
}

/* ======================================================================
 * Given a numerical transmit polarization, convert to text string.
 */
const char *DspStringFromPol
( char sString_a[4],    /* Storage to place string in */
  UINT1 iPolarization_a
  )
{
  switch( iPolarization_a )
    {
    case POL_HORIZ_FIX:    strcpy( sString_a, "H"   ); break;
    case POL_VERT_FIX:     strcpy( sString_a, "V"   ); break;
    case POL_ALTERNATING:  strcpy( sString_a, "Alt" ); break;
    case POL_SIMULTANEOUS: strcpy( sString_a, "H+V" ); break;
    default:               strcpy( sString_a, "XXX" ); break;
    }
  return( sString_a ) ;
}

/* ======================================================================
 * Given a numerical phase modulation, convert to text string.
 */
const char *DspStringFromPhaseMod
( char sString_a[8],    /* Storage to place string in */
  UINT1 iPhaseModSeq_a
  )
{
  switch( iPhaseModSeq_a )
    {
    case PHSEQ_FIXED:   strcpy( sString_a, "Fixed"  ); break;
    case PHSEQ_RANDOM:  strcpy( sString_a, "Random" ); break;
    case PHSEQ_CUSTOM:  strcpy( sString_a, "Custom" ); break;
    case PHSEQ_SZ8_64:  strcpy( sString_a, "SZ8/64" ); break;
    default:            strcpy( sString_a, "XXXXXX" ); break;
    }
  return( sString_a ) ;
}

#if 0
main( int argc, char *argv[] )
{
  UINT2 ival ; MESSAGE istatus ;
  istatus = dsp_tcf_from_string( argv[1], &ival ) ;
  printf( "stat=%d %4x '%s'\n", istatus, ival, argv[1] ) ;
  printf( "string = '%s'\n", dsp_string_from_tcf( ival ) ) ;
}
#endif
