/* **********************************************************************
 * *	                                                                *
 * *              Example of BITE Requests for ORDA System              *
 * *                                                                    *
 * ********************************************************************** 
 * File: utils/examples/orda_example.c
 *
 *                         COPYRIGHT (c) 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 <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "sigtypes.h"
#include "user_lib.h"
#include "antenna_lib.h"

static void displayField( SINT4 iField_a ) ;

/* ------------------------------
 * Demonstration program showing how to interface to the BITE portion
 * of an ORDA system.
 */
int main( int argc_a, char **argv_a )
{
  MESSAGE istatus ; SINT4 iField, iUnit, iDAUUnits[2][2] ;
  struct bitex_setup bitex_setup ;

  static SINT4 iDAUStatusUnit,	/* Making these static allows them to */
               iDAUQuantBUnit ;	/*   be used in initializations below */

  /* Protect against unauthorized folks running.
   */
  if( ! liris_operator( sig_username() ) ) {
    printf( "Sorry, you must be an operator to run ORDA_EXAMPLE.\n" ) ;
    exit( EXIT_FAILURE ) ;
  }

  /* Power up the IRIS antenna driver, and get a copy of the BITE
   * setup structures.
   */
  istatus = AntPowerUpMain( ANT_IAM_CLIENT, 0 ) ;
  if( istatus != SS_NORMAL ) {
    sig_signal( istatus ) ; exit( EXIT_FAILURE ) ;
  }

  (void)lbite_get_def( &bitex_setup, TRUE ) ;

  /* ------------------------------------------------------------
   * First figure out which two BITE units are being used for 1)
   * standard DAU status, and 2) quantitive DAU values.  Two different
   * methods are demonstrated.
   */

  /* The first method assumes that the two BITE units have been
   * assigned specific alias names in the "BITE Customize Menu" of the
   * BITEX utility.  We simply scan the available units looking for
   * these key names.  This is the prefered way to do the lookup
   * because it is self documenting.  However, it does assume that the
   * BITEX configuration is not changed at whim.
   */
  iDAUUnits[0][0] = -1 ;
  iDAUUnits[0][1] = -1 ;

  for( iUnit=0 ; iUnit < bitex_setup.iunit_cnt ; iUnit++ ) {
    struct bitex_unit_info *pInfo = &bitex_setup.units[ iUnit ] ;
    if( 0 == strcasecmp( pInfo->sName, "DAU Status" ) ) iDAUUnits[0][0] = iUnit ;
    if( 0 == strcasecmp( pInfo->sName, "DAU Q-BITE" ) ) iDAUUnits[0][1] = iUnit ;
  }

  printf( "Search for DAU BITE units using alias names:\n"
	  "   DAU Status: %d       DAU Q-BITE: %d\n\n",
	  iDAUUnits[0][0], iDAUUnits[0][1] ) ;

  /* The second method scans through the available BITE units, looking
   * for receiving units that have the appropriate packet ID and
   * packet length.  This method is less maintainable because the code
   * must be changed here whenever the RCP8 packet IDs are changed for
   * any reason.
   */
  iDAUUnits[1][0] = -1 ;
  iDAUUnits[1][1] = -1 ;

  for( iUnit=0 ; iUnit < bitex_setup.iunit_cnt ; iUnit++ ) {
    struct bitex_unit_info *pInfo = &bitex_setup.units[ iUnit ] ;
    if( ( pInfo->lcontrol_unit == FALSE ) &&
	( pInfo->lQBite        == FALSE ) &&
	( pInfo->iunit_length  == 21    ) &&
	( pInfo->iunit_id      ==  5    ) ) iDAUUnits[1][0] = iUnit ;

    if( ( pInfo->lcontrol_unit == FALSE ) &&
	( pInfo->lQBite        == TRUE  ) &&
	( pInfo->iunit_length  == 63    ) &&
	( pInfo->iunit_id      ==  6    ) ) iDAUUnits[1][1] = iUnit ;
  }

  printf( "Search for DAU BITE units using packet parameters:\n"
	  "   DAU Status: %d       DAU Q-BITE: %d\n\n",
	  iDAUUnits[1][0], iDAUUnits[1][1] ) ;

  /* For this example, take whichever one was not negative
   */
  iDAUStatusUnit = MAX( iDAUUnits[0][0], iDAUUnits[1][0] ) ;
  iDAUQuantBUnit = MAX( iDAUUnits[0][1], iDAUUnits[1][1] ) ;

  if( (iDAUStatusUnit == -1) || (iDAUQuantBUnit == -1) ) {
    printf( "Missing BITE unit -- exiting...\n" ) ; exit( EXIT_FAILURE ) ;
  }

  /* ------------------------------------------------------------
   * Print some information about each of the BITE units that we
   * found.  We print the amount of time elapsed since the last packet
   * was received, and the total number of characters that have been
   * received so far.
   */
  {
    SINT4 iAges[BITE_MAX_UNITS], iCntIn[BITE_MAX_UNITS],
      iCntOut[BITE_MAX_UNITS] ;

    bite_get_age( iAges, bitex_setup.iunit_cnt ) ;
    bite_get_activity( iCntIn, iCntOut, bitex_setup.iunit_cnt ) ;

    printf( "I/O Summary for DAU BITE units:\n"
	    "   DAU Status -- Age:%4.1f sec   CharsIn: %d\n"
	    "   DAU Q-BITE -- Age:%4.1f sec   CharsIn: %d\n\n",
	    1E-3 * (FLT4)iAges[iDAUStatusUnit], iCntIn[iDAUStatusUnit],
	    1E-3 * (FLT4)iAges[iDAUQuantBUnit], iCntIn[iDAUQuantBUnit] ) ;
  }

  /* ------------------------------------------------------------
   * Lookup the location of several Status and QBITE fields that we
   * might want to monitor.  Again, two different methods are
   * demonstarated for locating the BITE field.
   */

  /* The first lookup method scans for desired field names whose
   * associated BITE unit also matches the one we are expecting.  The
   * unit number needs to be checked in case there are multiple fields
   * having the same frequently used name, e.g., there may be several
   * fields called "+5V Power".  This lookup method is prefered
   * because it is self documenting, but it does make the assumption
   * that the names assigned in BITEX will not be changed at whim.
   */
  {
    struct {  /* List of field names & BITE units */
      const char *sName ; SINT4 *pBiteUnit, iFieldNum ;
    } *pView, views[] = {
      { "Outside Temp"       , &iDAUQuantBUnit, -1 },
      { "Shelter Temp"       , &iDAUQuantBUnit, -1 },
      { "Tx Exhaust Temp"    , &iDAUQuantBUnit, -1 },
      { "Encoder 5V PS"      , &iDAUQuantBUnit, -1 },

      { "Tx Over Voltage"    , &iDAUStatusUnit, -1 },
      { "Focus Coil Current" , &iDAUStatusUnit, -1 },
      { "Focus Coil Airflow" , &iDAUStatusUnit, -1 },

      { NULL, NULL, 0 }
    } ;
    for( pView = &views[0] ; pView->sName ; pView++ ) {
      for( iField=0 ; iField < bitex_setup.ifield_cnt ; iField++ ) {
	struct bitex_field_def *pDef = &bitex_setup.fields[ iField ] ;
	if( ( ! pDef->ldisabled ) && ( *pView->pBiteUnit == pDef->iunit ) &&
	    ( 0 == strcasecmp( pView->sName, pDef->name_text ) ) ) {
	  pView->iFieldNum = iField ; break ;
	}
      }
    }
    printf( "BITE field data located by field name and unit number\n" ) ;
    for( pView = &views[0] ; pView->sName ; pView++ ) {
      if( pView->iFieldNum == -1 ) {
	printf( "   Could not find field '%s' for BITE Unit #%d\n",
		pView->sName, *pView->pBiteUnit ) ;
      } else displayField( pView->iFieldNum ) ;
    }
  }
  printf( "\n" ) ;

  /* The second method for locating BITEX fields works directly from
   * the defnitions of the BITE packets themselves, and searches for
   * the field that extracts each desired piece of information.  This
   * method is less self documenting, but has the advantage that the
   * BITEX field names can be changed whenever you like.
   */
  {
    struct {  /* List of BITE units, and Byte/Bit pairs */
      SINT4 *pBiteUnit, iByte, iBit, iFieldNum ;
    } *pView, views[] = {
      { &iDAUQuantBUnit,  3, 2, -1 },
      { &iDAUQuantBUnit,  5, 2, -1 },
      { &iDAUQuantBUnit,  9, 2, -1 },
      { &iDAUQuantBUnit, 29, 2, -1 },
	
      { &iDAUStatusUnit,  7, 4, -1 },
      { &iDAUStatusUnit,  7, 6, -1 },
      { &iDAUStatusUnit,  8, 0, -1 },

      { NULL, 0, 0, 0 }
    } ;
    for( pView = &views[0] ; pView->pBiteUnit ; pView++ ) {
      for( iField=0 ; iField < bitex_setup.ifield_cnt ; iField++ ) {
	struct bitex_field_def *pDef = &bitex_setup.fields[ iField ] ;
	if( ( ! pDef->ldisabled ) && ( *pView->pBiteUnit == pDef->iunit ) &&
	    ( (pView->iByte - 1) == pDef->ibyte ) &&
	    (  pView->iBit       == pDef->ibit  ) ) {
	  pView->iFieldNum = iField ; break ;
	}
      }
    }    
    printf( "BITE field data located by packet byte/bit, and unit number\n" ) ;
    for( pView = &views[0] ; pView->pBiteUnit ; pView++ ) {
      if( pView->iFieldNum == -1 ) {
	printf( "   Could not find field Byte/Bit %d/%d for BITE Unit #%d\n",
		pView->iByte, pView->iBit, *pView->pBiteUnit ) ;
      } else displayField( pView->iFieldNum ) ;
    }
  }

  exit( EXIT_SUCCESS ) ;
}

/* ------------------------------
 * Simple routine to display some info from a BITE field.
 */
static void displayField( SINT4 iField_a )
{
  struct bite_field_state state ; struct bitex_field_def def ;
  bite_get_field_state( &state, iField_a ) ;
  bite_get_one_def( &def, iField_a ) ;

  /* Display normal status or QBite info
   */
  printf( "   Field #%-3d %20s", iField_a, def.name_text ) ;

  if( state.lQBite ) {
    printf( "  = %7.2f %s  ",
	    state.fQBiteValue, def.cs.Q_Sts.sUnitsText ) ;
  } else {
    printf( "      Flag:%d       ", state.ldata ) ;
  }
  /* Display type of fault, if any
   */
  if     ( state.lCriticalFault ) printf( "(Critical)" ) ;
  else if( state.lfault         ) printf( "(Fault)"    ) ;
  else                            printf( "(Okay)"     ) ;

  printf( "\n" ) ;
}
