/* *********************************************************
 * *                                                       *
 * *   SIGMET antenna library interface examiner           *
 * *                                                       *
 * *********************************************************
 * File: utils/antenna/antx.C
 *
 *           COPYRIGHT (c) 1994, 1997, 1999, 2002, 2004 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 <arpa/inet.h>
#include <locale.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef IRIX
#include <sys/socket.h>   //Apparently picks up the AF_INET define on SGI 
#endif  /* #ifdef IRIX */
#include <termios.h>
#include <unistd.h>

#define INCLUDE_TERMIOS_PROTOTYPES 1
#include "sigtypes.h"
#include "user_lib.h"
#include "antenna_lib.h"

struct command_line
{
  UINT1 lchat ;
  int   iOptions;
  char  sHost[40];         /* Desired RCP8 host */
  char  sAddress[40];      /* Desired RCP8 host address */
  UINT4 iDestination;      /* Destination address */
};

static void AntxChatMode
( const struct command_line *pCommand_a );

static void AntxStatusMode
( const struct command_line *pCommand_a );

static void PrintStatBit
( const char *sName_a,
  UINT4 iBitFlag_a,
  UINT4 iStatMask_a,
  UINT4 iStat_a,
  UINT4 iStatCrit_a ) ;

static void ProcessCommandLine
(int iargc_a, 
 char *sargv_a[],
 struct command_line *pCommand_a);

static void Usage(void);

/* ======================================================================
 */
int main( int argc_a, char** argv_a )
{
  MESSAGE istatus ;
  struct command_line Command;

  if (!liris_operator(sig_username()))
    {
      printf( "Sorry, you must be an IRIS operator to run antx.\n" );
      exit(EXIT_FAILURE);
    }

  setlocale( LC_ALL, "" ) ;

  ProcessCommandLine( argc_a, argv_a, &Command );

  if( Command.lchat ) 
    /* ------------ Chat Mode ------------ */
    AntxChatMode( &Command );

  else 
    /* ------------ I/O Report ------------ */
    AntxStatusMode( &Command );

  /* Disconnect from antenna driver
   */
  istatus = ant_close();
  if (istatus != SS_NORMAL) sig_signal( istatus );

  exit(EXIT_SUCCESS) ;
}

/* ----------------------------------------------
 * Run chat mode 
 */
static void AntxChatMode
( const struct command_line *pCommand_a )
{
  MESSAGE istatus;
  int iIndex;
  UINT1 lMissing=FALSE;
  struct ant_nethost_info NetHost[10];
  /* Power up antenna driver.  Propagate the auto start flag.
   */
  istatus = AntPowerUpMain( ANT_IAM_CHATTER, pCommand_a->iOptions );
  if (istatus != SS_NORMAL) { sig_signal( istatus ); exit(EXIT_FAILURE);}
  
  AntGetNetActivity( NetHost, 10 );

  if (pCommand_a->iDestination == htonl(INADDR_ANY))
    {
      /* Check to see if we have multiple hosts out there.  If so, 
       * then do not allow wildcard operation. 
       */
      int iNetHostCount=0;
      for (iIndex=0; iIndex<10; iIndex++)
	{
	  struct ant_nethost_info *pInfo = &NetHost[iIndex];
	  if (pInfo->iAddress) iNetHostCount++;
	}
      if (iNetHostCount>1)
	{
	  printf( "Error, multiple RCP8 hosts, try one of:\n" );
	  for (iIndex=0; iIndex<10; iIndex++)
	    {
	      struct ant_nethost_info *pInfo = &NetHost[iIndex];
	      if (pInfo->iAddress)
		{
		  struct hostent *pHost;
		  char sAddress[40];
		  
		  pHost = gethostbyaddr( (const char *)&pInfo->iAddress, 4, AF_INET );
		  inet_ntop( AF_INET, &pInfo->iAddress, sAddress, sizeof(sAddress) );
		  if (!pHost)
		    printf( " antx -host:%s \n", sAddress );
		  else
		    printf( " antx -host:%s \n", pHost->h_name );
		}
	    }
	  istatus = ant_close();
	  if (istatus != SS_NORMAL) sig_signal( istatus );
	  exit(EXIT_FAILURE);
	}
    }
  else
    {
      /* If a target host is specified, and the driver has been up,
       * then print a warning message if the specified host has not
       * reported in.
       */
      SINT4 in_cnt, iout_cnt, in_err, iout_err;
      ant_get_activity( &in_cnt, &iout_cnt, &in_err, &iout_err );
      if ( in_cnt > 100 )
	{
	  lMissing=TRUE;
	  for (iIndex=0; iIndex<10; iIndex++)
	    {
	      struct ant_nethost_info *pInfo = &NetHost[iIndex];
	      if ((pInfo->iAddress)&&(pInfo->iAddress==pCommand_a->iDestination))
		{
		  lMissing=FALSE; break;
		}
	    }
	}
    }
  
  AntSetChatDestination(pCommand_a->iDestination);
  
  struct ttyspec spec ; struct ttydev tty ;
  memset( &spec, 0, sizeof(spec) ) ;
  strcpy( spec.sDevice, "/dev/tty" ) ;
  istatus = openTTYDev( &tty, &spec ) ;
  if( istatus != SS_NORMAL ) { sig_signal( istatus ) ; exit(1) ; }
  
  if (pCommand_a->sHost[0])
    {
      printf( "\rConnect to: %s, Address: %s\n\r", pCommand_a->sHost, pCommand_a->sAddress );
      if (lMissing)
	{
	  printf( "Warning, RCP8 may not be running on your specified host.\n\r" );
	}
      fflush(0);
    }
  printf( "-------- RCP Setup TTY 'Chat' Mode (^C to exit) --------\n\r" ) ;
  fflush(0) ;
  
  for(;;) {
    UINT1 tmpBuf[20] ; SINT4 iCh ;
    
    if( lReadAvailFD( fileno(tty.Rx), 20 ) ) {
      SINT4 nChars = read( fileno(tty.Rx), tmpBuf, sizeof(tmpBuf) ) ;
      if( nChars <= 0 ) goto exit ;
      for( iCh=0 ; iCh < nChars ; iCh++ ) {
	UINT1 uchar = 0x7F & tmpBuf[iCh] ;
	if( (uchar == 3) || (uchar == 25) ) goto exit ;
	ant_put_chat( uchar ) ;
      }
    }
    
    while( (iCh = iant_get_chat()) != -1 ) putchar( (char)iCh ) ;
    fflush( stdout ) ;
  }
 exit:	
  printf( "\n\r-------- Exit from RCP Chat --------\n\r" ) ; fflush(0) ;
  closeTTYDev( &tty ) ;
}
 
/* -------------------------------------------------------
 * Run status mode.
 */
static void AntxStatusMode
( const struct command_line *pCommand_a )
{
  SINT4 in_cnt, in2_cnt, iout_cnt, iout2_cnt ;
  SINT4 in_err, in2_err, iout_err, iout2_err ;
  SINT4 iBiteCount, iUnit, iBiteIn[BITE_MAX_UNITS], iBiteOut[BITE_MAX_UNITS];
  SINT4 iIndex, idiag_size ;
  UINT4 iAgePkt, iAgeAng, iAgeShip, irst_request, irst_current, iCurrentBTime ;
  UINT4 iInuFaultBits;
  UINT1 lNoInuFaults;
  MESSAGE istatus;
  double fAgePkt, fAgeAng, fAgeShip ; UINT1 ibuffer[100] ;
  char srst_request[16], srst_current[16] ;
  struct drcp_status drcp ;
  struct ant_nethost_info NetHost[10];

  /* Power up antenna driver.  Propagate the auto start flag.
   */
  istatus = AntPowerUpMain( ANT_IAM_CLIENT, pCommand_a->iOptions );
  if (istatus != SS_NORMAL) { sig_signal( istatus ); exit(EXIT_FAILURE);}
  
  ant_get_activity( &in_cnt, &iout_cnt, &in_err, &iout_err );
    ant_get_activity2( &in2_cnt, &iout2_cnt, &in2_err, &iout2_err );
    AntGetAges( &iAgePkt, &iAgeAng, &iAgeShip );
    fAgePkt  = ((double)iAgePkt)/1000.;
    fAgeAng  = ((double)iAgeAng)/1000.;
    fAgeShip = ((double)iAgeShip)/1000.;
    iBiteCount = bite_get_activity( iBiteIn, iBiteOut, BITE_MAX_UNITS );
    ant_get_rstmode( srst_request, 16, &irst_request );
    ant_get_rstmode_cmd( srst_current, 16, &irst_current );
    ant_get_drcp( &drcp ) ;
    iInuFaultBits = AntGetInuFaults();

    printf( "           Ages: %6.2f %6.2f %6.2f sec.\n", fAgePkt, fAgeAng, fAgeShip );
    printf( "       In count: %d / %d bytes.\n", in_cnt, in2_cnt );
    printf( "      Out count: %d / %d bytes.\n", iout_cnt, iout2_cnt );
    printf( " In error count: %d / %d bytes.\n", in_err, in2_err );
    printf( "Out error count: %d / %d bytes.\n", iout_err, iout2_err );
    for (iUnit=0; iUnit<iBiteCount; iUnit++)
      {
	printf( "      BITE %d in: %d, out: %d\n", iUnit+1, iBiteIn[iUnit], iBiteOut[iUnit] );
      }

    printf( "   Current mode: %d ('%s').\n", irst_current, srst_current );
    printf( " Requested mode: %d ('%s').\n", irst_request, srst_request );

    if( drcp.lSetupDual ) {
      printf( "       Dual-RCP: Mode: " ) ;
      if( drcp.lRunningDual ) {
	const char *textActiveA, *textActiveB ;

	switch( drcp.sysA.iActivity ) {
	default:              textActiveA = "Idle"   ; break ;
	case DRCP_ACT_WARMUP: textActiveA = "Warmup" ; break ;
	case DRCP_ACT_ACTIVE: textActiveA = "Active" ; break ;
	}
	switch( drcp.sysB.iActivity ) {
	default:              textActiveB = "Idle"   ; break ;
	case DRCP_ACT_WARMUP: textActiveB = "Warmup" ; break ;
	case DRCP_ACT_ACTIVE: textActiveB = "Active" ; break ;
	}
	printf( "%s  A:%s/%s/%s/%s  B:%s/%s/%s/%s\n",
		AntGetDrcpModeString( drcp.iDrcpMode ),
		drcp.sysA.lKnown    ?  "Known" : "Unknown",
		drcp.sysA.lDisabled ?    "Dis" : "Ena"    ,
		drcp.sysA.lOkay     ?   "Okay" : "Fault"  ,
		textActiveA,
		drcp.sysB.lKnown    ?  "Known" : "Unknown",
		drcp.sysB.lDisabled ?    "Dis" : "Ena"    ,
		drcp.sysB.lOkay     ?   "Okay" : "Fault"  ,
		textActiveB ) ;
      } else {
	printf( "Not Enabled in the RCP\n" ) ;
      }
    }
    lNoInuFaults=TRUE;
    printf("     INU Faults:" );
    if (iInuFaultBits&ANT_INU_INVROLL) { printf(" Roll/Pitch" ); lNoInuFaults=FALSE;}
    if (iInuFaultBits&ANT_INU_INVHEAD) { printf(" Heading" );    lNoInuFaults=FALSE;}
    if (iInuFaultBits&ANT_INU_INVHORZ) { printf(" Lat/Lon" );    lNoInuFaults=FALSE;}
    if (iInuFaultBits&ANT_INU_INVVERT) { printf(" Altitude" );   lNoInuFaults=FALSE;}
    if (lNoInuFaults)                    printf(" None" );
    printf("\n" );

    /* Now check for diagnostics
     */
    ant_get_diagnostic( ibuffer, 100, &idiag_size );
    if (idiag_size)
      {
	printf("%d bytes in antenna diagnostic buffer:", idiag_size );
	for (iIndex=0; iIndex<idiag_size; iIndex++ )
	  {
	    printf(" %2.2X", (int)(UINT2)ibuffer[iIndex] );
	  }
	printf("\n");
      }

    ant_get_odiagnostic( ibuffer, 100, &idiag_size );
    if (idiag_size)
      {
	printf("%d bytes in other diagnostic buffer:", idiag_size );
	for (iIndex=0; iIndex<idiag_size; iIndex++ )
	  {
	    printf(" %2.2X", (int)(UINT2)ibuffer[iIndex] );
	  }
	printf("\n");
      }
    bite_get_diagnostic( ibuffer, 100, &idiag_size );
    if (idiag_size)
      {
	printf("%d bytes in bite diagnostic buffer:", idiag_size );
	for (iIndex=0; iIndex<idiag_size; iIndex++ )
	  {
	    printf(" %2.2X", (int)(UINT2)ibuffer[iIndex] );
	  }
	printf("\n");
      }
    /* Now print out network host table, if any */
    getbtime( &iCurrentBTime );
    AntGetNetActivity( NetHost, 10 );
    for (iIndex=0; iIndex<10; iIndex++)
      {
	struct ant_nethost_info *pInfo = &NetHost[iIndex];
	if (pInfo->iAddress)
	  {
	    struct hostent *pHost;
	    char sAddress[40];
	    FLT8 fAge;
	    fAge = ((FLT4)btimeGrace(iCurrentBTime - pInfo->iBTime))/1000.0;

	    pHost = gethostbyaddr( (const char *)&pInfo->iAddress, 4, AF_INET );
	    inet_ntop( AF_INET, &pInfo->iAddress, sAddress, sizeof(sAddress) );
	    if (!pHost)
	      {
		printf( "Host %d: %s Unknown Name, %4.1f sec\n", iIndex, sAddress, fAge );
	      }
	    else
	      {
		printf( "Host %d: %s %s, %4.1f sec\n", iIndex, sAddress, pHost->h_name, fAge );
	      }
	  }
      }

  /* Now print a table of all the status bits */
  {
    UINT4 iStat     = iant_stat( ) ;
    UINT4 iStatMask = iant_stat_mask( ) ;
    UINT4 iStatCrit = iant_stat_critical( ) ;
    printf( "\n     Status Bit:  Avail State Critical\n" );

    PrintStatBit(           "Local", ASF_LOCAL     , iStatMask, iStat, iStatCrit );
    PrintStatBit(       "T/R Local", ASF_TRLOCAL   , iStatMask, iStat, iStatCrit );
    PrintStatBit(    "Low Air Flow", ASF_LOWAIRFLOW, iStatMask, iStat, iStatCrit );
    PrintStatBit(    "Low Pressure", ASF_LOW_WGP   , iStatMask, iStat, iStatCrit );
    PrintStatBit(       "Interlock", ASF_INTERLOCK , iStatMask, iStat, iStatCrit );
    PrintStatBit(         "Standby", ASF_STANDBY   , iStatMask, iStat, iStatCrit );
    PrintStatBit( "Magnetron Fault", ASF_MAGTFLT   , iStatMask, iStat, iStatCrit );
    PrintStatBit(        "Shutdown", ASF_SHUTDOWN  , iStatMask, iStat, iStatCrit );
    PrintStatBit(    "Siggen Fault", ASF_SIGFAULT  , iStatMask, iStat, iStatCrit );
    PrintStatBit(  "Az Encoder Cal", ASF_CALIB_AZ  , iStatMask, iStat, iStatCrit );
    PrintStatBit(  "El Encoder Cal", ASF_CALIB_EL  , iStatMask, iStat, iStatCrit );
    PrintStatBit(     "Servo Power", ASF_SERVO     , iStatMask, iStat, iStatCrit );
    PrintStatBit(         "Radiate", ASF_RADIATE   , iStatMask, iStat, iStatCrit );
    PrintStatBit(       "T/R Power", ASF_TRPOWER   , iStatMask, iStat, iStatCrit );
    PrintStatBit(       "Siggen On", ASF_SIGGEN    , iStatMask, iStat, iStatCrit );
    PrintStatBit(       "Siggen CW", ASF_SIGCW     , iStatMask, iStat, iStatCrit );
    PrintStatBit(    "Can Sense PW", ASF_PWBW      , iStatMask, iStat, iStatCrit );
    PrintStatBit(   "Can Sense Pol", ASF_POLAR     , iStatMask, iStat, iStatCrit );
    
  }
}

/* =================================================
 * Read and store command line arguments.
 */
static void PrintStatBit
( const char *sName_a,
  UINT4 iBitFlag_a,
  UINT4 iStatMask_a,
  UINT4 iStat_a,
  UINT4 iStatCrit_a ) 
{
  char sValid[6], sState[6], sCritical[6];
  if (iBitFlag_a&iStatMask_a)
    strcpy( sValid, "Yes" );
  else
    strcpy( sValid, "No " );

  if (iBitFlag_a&iStat_a)
    strcpy( sState, "High" );
  else
    strcpy( sState, "Low " );

  if (iBitFlag_a&iStatCrit_a)
    strcpy( sCritical, "Yes" );
  else
    strcpy( sCritical, "No " );

  printf( "%15s:  %s   %s  %s\n", sName_a, sValid, sState, sCritical );

}

/* =================================================
 * Read and store command line arguments.
 */
static void ProcessCommandLine
(int iargc_a, 
 char *sargv_a[],
 struct command_line *pCommand_a)
{
  int iArg;
  char sHost[40];

  memset( pCommand_a, 0, sizeof(*pCommand_a) );
  memset( sHost, 0, 40 );
  pCommand_a->lchat = TRUE;
  pCommand_a->iDestination = htonl(INADDR_ANY);

  /* Parse command line options
  */
  for( iArg=1 ; iArg<iargc_a ; iArg++ )
    {
      const char *sArg = sargv_a[iArg];
      /* fprintf( stderr, "Processing %d: '%s'\n", iArg, sArg ); */
      
      if (0 == strncmp( sArg, "-he", 3 ))
	{
	  Usage();
	}
      else if( 0 == strcmp( sArg, "-auto" ) ) 
	{ 
	  pCommand_a->iOptions |= ANT_OPTIONS_AUTO ;
	}
      else if( 0 == strcmp( sArg, "-nochat" ) ) 
	{ 
	  pCommand_a->lchat = FALSE ;
	}

      if (0 == strncmp( sArg, "-host:", 6 ))
	{
	  strncpy( sHost, &sArg[6], 40-1 );
	}
    }

  /* Now process to get the address, if applicable */
  if (sHost[0])
    {
      struct hostent *pHost;
      pHost = gethostbyname( sHost );
      if (!pHost)
	{
	  fprintf( stderr, "Error: Unknown host '%s'\n", sHost );
	  exit(EXIT_FAILURE);
	}
      strncpy( pCommand_a->sHost, pHost->h_name, 39 );
      inet_ntop( pHost->h_addrtype, *pHost->h_addr_list, pCommand_a->sAddress,
		 sizeof(pCommand_a->sAddress) );
      memcpy( &pCommand_a->iDestination, pHost->h_addr_list[0], 4 );
      
    }
  
}


static void Usage()
{
  fprintf( stderr, "Antx command line options:\n" );
  fprintf( stderr, "-auto        Automatic startup\n" );
  fprintf( stderr, "-nochat      Do not run chat mode\n" );
  fprintf( stderr, "-host:<host> Only talk to the specified host\n" );
  fprintf( stderr, "             All other options ignored\n" );
  exit(EXIT_FAILURE);
}
