/* ********************************************************************
 * *                                                                  * 
 * *        Receiver For Generic Serial Antenna/Radar Simulator       *
 * *                                                                  * 
 * ********************************************************************
 * File: libs/antenna/antsim_rcv.c
 * 
 * COPYRIGHT (c) 1987, 1988, 1991, 1996, 1999, 2001, 2002, 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 <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>

#define INCLUDE_STDIO_PROTOTYPES 1
#define INCLUDE_TERMIOS_PROTOTYPES 1
#include "sigtypes.h"
#include "user_lib.h"
#include "setup.h"
#include "antenna_lib.h"
#include "antenna_int.h"

#include "antsim_global.h"

/* Function prototypes used just within this routine
 */
static void  antsim_rcv_loop
( int iFD_a,
  SINT4 ircv_size_a,
  UINT4 iformat ) ;

static void antsim_process_packet
( UINT1 str_a[],
  UINT4 iformat_a ) ;

static void  process_bitesim_packet
( const UINT1 str_a[3] ) ;

static void process_1bitesim_packet
( const UINT1 str_a[4] ) ;

static void process_qbitesim_packet
( const UINT1 str_a[3] ) ;

static void get_rcv_states
( const UINT1 *str_a ) ;

/* ------------------------------
 * This process is started up from ANTSIM and handles reception
 * of serial data.
 */
int main()
{
  MESSAGE istatus ; UINT2 iformat, lcreated ; int iFD ;

  /* Map to the global section, and assign process priority.
   */
  setlocale( LC_ALL, "" ) ;

  istatus = sig_run_as_operator() ;
  if( istatus != SS_NORMAL ) sig_signal(istatus) ;

  istatus = AntPowerUpMain( ANT_IAM_SIM_RCV, 0 ) ;
  if( istatus != SS_NORMAL ) {
    sig_signal( istatus ) ; exit(EXIT_FAILURE) ;
  }
  sig_establish( antSignalHandler, "ANTSIM_RCV" ) ;

  istatus = antsim_global_init( &lcreated ) ;
  if( istatus != SS_NORMAL ) {
    pantsim_c->info.ircv_status = istatus ;
    sig_signal( istatus ) ; exit(EXIT_FAILURE) ;
  }
  pantsim_c->info.ircv_pid = getpid();

#ifdef HPUX
  if( pantsim_c->info.lauto ) ignore_next_signal( SIGHUP ) ;
#endif

  istatus = sig_setpriority( (SINT4)pantsim_c->setup.ipri_antrcv ) ;
  if( istatus != SS_NORMAL ) sig_signal(istatus) ;

  antWriteLog( "ANTSIM_RCV Process Starting" ) ;
  iFD = -1 ;

  iformat =  pantsim_c->setup.icontrol_format ;
  switch ( iformat )
    {
    case ANTFMT_XMT01:
      pantsim_c->info.ircv_status = SS_NORMAL ;
      antsim_rcv_loop( iFD, 11, iformat ) ;
      break ;

    case ANTFMT_XMT02:
    case ANTFMT_XMT04:
      pantsim_c->info.ircv_status = SS_NORMAL ;
      antsim_rcv_loop( iFD, 14, iformat ) ;
      break ;

    case ANTFMT_XMT05:
      pantsim_c->info.ircv_status = SS_NORMAL ;
      antsim_rcv_loop( iFD, 18, iformat ) ;
      break ;

    default:
      pantsim_c->info.ircv_status = (MESSAGE)ANT_BAD_CONTROL ;
      sig_signal( ANT_BAD_CONTROL ) ;
      exit(EXIT_FAILURE) ;
      break ;

    }
         
  return 0 ;
}

/* ------------------------------
 */
static void antsim_rcv_loop
( int iFD_a,
  SINT4 ircv_size_a,
  UINT4 iformat_a    /* Reception format */
  )
{
  UINT4 iptr, iend ; SINT4 icount ; UINT1 str[100] ;

  /* -----------------------------------------------------------------------*/
  iptr = 0 ;
  iend = 0 ;

  get_more_chars( iFD_a, str, &iptr, &iend, 10 ) ;

  while (1)
    {
      /* Make sure that there is at least one character to do the test
       * on.
       */
      if( iptr+1 > iend ) 
	{
	  get_more_chars( iFD_a, str, &iptr, &iend, 1 ) ;
	}

      /* Process more characters
       */
      switch (str[iptr])
	{
	case (UINT1)ANT_SYNC_ANT:
	  
	  /* Antenna Control Packet
	   */
	  if( iptr+ircv_size_a > iend ) 
	    {
	      get_more_chars( iFD_a, str, &iptr, &iend, 10 ) ;
	      break ;
	    }

	  /* Check packet format
	   */
	  if( lcheck_packet( &str[iptr], ircv_size_a ) ) 
	    {
	      antsim_process_packet( &str[iptr], iformat_a ) ;
	      iptr = iptr+ircv_size_a ;
	      pantsim_c->info.iin_cnt += ircv_size_a ;
	    }
	  else
	    {
	      /* Reception error, store the current data away for
	       * diagnostics
	       */
	      icount = (SINT4)(iend-iptr) ;
	      if (icount > BITE_MAX_LENGTH) icount=BITE_MAX_LENGTH ;
	      memmove( (void *)pantsim_c->info.sant_diagnostic, &str[iptr], icount ) ;
	      pantsim_c->info.iant_diag_size = icount ;
	      
	      pantsim_c->info.iin_ercnt += 1 ;
	      iptr += 1 ;
	    }
	  break ;

	case (UINT1)ANT_SYNC_BITE_RQST:
	  /* BITE Command Packet
	   */
	  if( iptr+3 > iend )
	    {
	      get_more_chars( iFD_a, str, &iptr, &iend, 10 ) ;
	      break ;
	    }

	  /* Check packet format
	   */
	  if( lcheck_packet( &str[iptr], 3 ) ) 
	    {
	      process_bitesim_packet( &str[iptr] ) ;
	      iptr += 3 ;
	      pantsim_c->info.iin_cnt += 3 ;
	    }
	  else
	    /* Reception Error
	     */
	    {
	      pantsim_c->info.iin_ercnt += 1 ;
	      iptr += 1 ;
	    }
	  break ;

	case (UINT1)ANT_SYNC_QBITE_RQST:
	  /* Q-BITE Command Packet
	   */
	  if( iptr+3 > iend )
	    {
	      get_more_chars( iFD_a, str, &iptr, &iend, 10 ) ;
	      break ;
	    }

	  /* Check packet format
	   */
	  if( lcheck_packet( &str[iptr], 3 ) ) 
	    {
	      process_qbitesim_packet( &str[iptr] ) ;
	      iptr += 3 ;
	      pantsim_c->info.iin_cnt += 3 ;
	    }
	  else
	    /* Reception Error
	     */
	    {
	      pantsim_c->info.iin_ercnt += 1 ;
	      iptr += 1 ;
	    }
	  break ;


	case (UINT1)ANT_SYNC_1BITE_RQST:
	  /* Individual BITE Command Packet
	   */
	  if( iptr+4 > iend )
	    {
	      get_more_chars( iFD_a, str, &iptr, &iend, 10 ) ;
	      break ;
	    }

	  /* Check packet format
	   */
	  if( lcheck_packet( &str[iptr], 4 ) ) 
	    {
	      process_1bitesim_packet( &str[iptr] ) ;
	      iptr += 4 ;
	    }
	  else
	    /* Reception Error
	     */
	    {
	      pantsim_c->info.iin_ercnt += 1 ;
	      iptr += 1 ;
	    }
	  break ;

	default:
	  /* Unrecognized characters are treated as reception errors
	   * store the current data away for diagnostics
	   */
	  icount = (SINT4)(iend-iptr) ;
	  if (icount > BITE_MAX_LENGTH) icount=BITE_MAX_LENGTH ;
	  if (icount >= pantsim_c->info.iother_diag_size)
	    {
	      memmove( (void *)pantsim_c->info.sother_diagnostic, &str[iptr], icount ) ;
	      pantsim_c->info.iother_diag_size = icount ;
	    }

	  pantsim_c->info.iin_ercnt += 1 ;
	  iptr += 1 ;
	  break ;
	}
    }
}

/* ------------------------------
 * Process a packet received for the antenna_lib xmt process
 * History:
 *   jmh   26 Sep 1991  Forked from main program
 */
static void  antsim_process_packet
(UINT1 str_a[],
 UINT4 iformat_a )
{
  UINT4 istatus ;
  SINT1 ivelocity1 ;
  SINT2 ivelocity2 ;

  getbtime( &pantsim_c->info.ibtime ) ;

  /* Skip setting the internal variables if we are in local mode
   */
  istatus = pantsim_c->info.isbits ;
  if ( istatus & ASF_LOCAL ) return ;

  /* Desired antenna position
   */
  pantsim_c->info.idaz = ( ((UINT2)str_a[2])<<9 ) + ( ((UINT2)str_a[1])<<2) ;
  pantsim_c->info.idel = ( ((UINT2)str_a[4])<<9 ) + ( ((UINT2)str_a[3])<<2) ;

  get_rcv_states( str_a ) ;

  if( 0 != BTEST( str_a[5], 1 ) )
    {
      pantsim_c->info.ielmode = ANTMODE_VEL ;
      switch (iformat_a)
	{
	case ANTFMT_XMT01:
	  /* Velocities are a signed number in the low 7 bits
	   */
	  ivelocity1 = ((SINT1)(str_a[9]<<1))/2 ;
	  pantsim_c->info.fdelv = ((FLT4)ivelocity1) / ANTSIM01_VEL_UNITS ;
	  break ;
	  
	case ANTFMT_XMT02:
	case ANTFMT_XMT04:
	case ANTFMT_XMT05:
	default:
	  /* Velocities are a signed number packed 7 bits in each byte
	   */
	  ivelocity2 = ((SINT2)((((UINT2)str_a[11])<<2) |
				(((UINT2)str_a[12])<<9)))/4 ;
	  pantsim_c->info.fdelv = ((FLT4)ivelocity2) / ANTSIM02_VEL_UNITS ;
	  break ;
	}
    }
  else
    pantsim_c->info.ielmode = ANTMODE_POS ;


  if( BTEST( str_a[5], 0 ) ) 
    {
      pantsim_c->info.iazmode = ANTMODE_VEL ;
      switch (iformat_a)
	{
	case ANTFMT_XMT01:
	  /* Velocities are a signed number in the low 7 bits
	   */
	  ivelocity1 = ((SINT1)(str_a[9]<<1))/2 ;
	  pantsim_c->info.fdazv = ((FLT4)ivelocity1) / ANTSIM01_VEL_UNITS ;
	  break ;
	  
	case ANTFMT_XMT02:
	case ANTFMT_XMT04:
	case ANTFMT_XMT05:
	default:
	  /* Velocities are a signed number in the low 7 bits
	   */
	  ivelocity2 = ((SINT2)((((UINT2)str_a[9])<<2) | (((UINT2)str_a[10])<<9)))/4 ;
	  pantsim_c->info.fdazv = ((FLT4)ivelocity2) / ANTSIM02_VEL_UNITS ;
	  break ;
	}
    }
  else
    pantsim_c->info.iazmode = ANTMODE_POS ;

  /* Extract the Dual RCP mode.
   */
  switch (iformat_a) {
  case ANTFMT_XMT05:
    pantsim_c->info.iDrcpModeReq       = ((str_a[13] >> 5) & 0x03 ) ;
    pantsim_c->info.lDrcpRelinquishReq = ((str_a[13] >> 4) & 0x01 ) ;
    pantsim_c->info.lDrcpWouldUseReq   = ((str_a[13] >> 3) & 0x01 ) ;

    pantsim_c->info.iDesiredPolar      = ( str_a[14] & 0x07 ) ;
    break ;
  }

  /* Optional packet logging
   */
  if( pantsim_c->setup.lLogDataAnt ) {
    char sAMode, sEMode, sLogText[120] ; FLT4 fAVal, fEVal ;

    if( ANTMODE_VEL == pantsim_c->info.iazmode ) {
      sAMode='V'; fAVal = pantsim_c->info.fdazv;
    } else {
      sAMode='P'; fAVal = fPDegFromBin2(pantsim_c->info.idaz);
    }
    if( ANTMODE_VEL == pantsim_c->info.ielmode ) {
      sEMode='V'; fEVal = pantsim_c->info.fdelv;
    } else {
      sEMode='P'; fEVal = fElDegFromBin2(pantsim_c->info.idel);
    }
    sprintf( sLogText, "A(%c):%5.1f, E(%c):%5.1f", 
	     sAMode, fAVal, sEMode, fEVal );
    antWriteLog( sLogText ) ;
  }
}

/* ------------------------------
 * Process a packet received for the BITE simulator
 */
static void process_bitesim_packet( const UINT1 str_a[3] )
{
  getbtime( &pantsim_c->binfo.ibtime ) ;

  /* The only packet we process is a request for an update
   */
  if (BITE_INTERROGATE == str_a[1])
    {
      UINT1 iunit ;

      for (iunit=0 ; iunit<pantsim_c->bitex.iunit_cnt ; iunit++)
	{
	  volatile struct bitesim_unit_info *pBite=&(pantsim_c->binfo.Units[iunit]) ;
	  volatile struct bitex_unit_info *pBitex=&(pantsim_c->bitex.units[iunit]) ;
	  if ((!pBitex->lQBite)&&(!pBitex->lcontrol_unit))
	    pBite->lSendUpdate = TRUE ;
	}
    }
  /* Optional packet logging
   */
  if( pantsim_c->setup.lLogDataAnt ) {
    antWriteLog( "BITE Interrogate" ) ;
  }
}

/* ------------------------------
 * Process an individual BITE command packet
 */
static void process_1bitesim_packet( const UINT1 str_a[4] )
{
  UINT1 iunit ;
  getbtime( &pantsim_c->binfo.ibtime ) ;

  /* The only packet we process is a request for an update
   */
  for (iunit=0 ; iunit<pantsim_c->bitex.iunit_cnt ; iunit++)
    {
      volatile struct bitesim_unit_info *pBite=&(pantsim_c->binfo.Units[iunit]) ;
      volatile struct bitex_unit_info *pBitex=&(pantsim_c->bitex.units[iunit]) ;
      if ( str_a[1] == pBitex->iunit_id)
	{
	  pBite->iin_cnt += 4 ;

	  if (BITE_INTERROGATE == str_a[2])
	    {
	      pBite->lSendUpdate = TRUE ;
	    }
	}
    }
}

/* ------------------------------
 * Process a packet received for the Q-BITE simulator
 */
static void process_qbitesim_packet( const UINT1 str_a[3] )
{
  getbtime( &pantsim_c->binfo.ibtime ) ;

  /* The only packet we process is a request for an update
   */
  if ((0x01 == str_a[1])||(BITE_INTERROGATE == str_a[1]))
    {
      UINT1 iunit ;

      for (iunit=0 ; iunit<pantsim_c->bitex.iunit_cnt ; iunit++)
	{
	  volatile struct bitesim_unit_info *pBite=&(pantsim_c->binfo.Units[iunit]) ;
	  volatile struct bitex_unit_info *pBitex=&(pantsim_c->bitex.units[iunit]) ;
	  if (pBitex->lQBite)
	    pBite->lSendUpdate = TRUE ;
	}
    }
}

/* ------------------------------
 * Process some of the status bits which are the same in both formats
 */
static void get_rcv_states
(const UINT1 *str_a )
{
  UINT2 ipwbw ; SINT4 ivalue ;

  /* Signal generator
   */
  if( 0!= BTEST( str_a[5], 3 ) ) 
    {
      pantsim_c->info.icbits |= ACF_SIGGEN ;
    }
  else
    {
      pantsim_c->info.icbits &= ~ACF_SIGGEN ;
    }
      
  /* Signal generator is in CW mode
   */
  if( 0!= BTEST( str_a[5], 2 ) ) 
    {
      pantsim_c->info.icbits |= ACF_SIGCW ;
    }
  else
    {
      pantsim_c->info.icbits &= ~ACF_SIGCW ;
    }

  /* Radiate control, note that there are two bits used to control
   */
  if( 0!=BTEST( str_a[6], 3 ) ) 
    {
      pantsim_c->info.icbits &= ~ACF_RADIATE ;
    }
  
  if( 0!= BTEST( str_a[6], 2 ) )
    {
      pantsim_c->info.icbits |= ACF_RADIATE ;
    }
		    
  /* Servo power
   */
  if( 0!=BTEST( str_a[6], 1 ) ) 
    {
      pantsim_c->info.icbits |= ACF_SERVO ;
    }
  else
    {
      pantsim_c->info.icbits &= ~ACF_SERVO ;
    }
      
  /* T/R power
   */
  if( 0!= BTEST( str_a[6], 0 ) ) 
    {
      pantsim_c->info.icbits |= ACF_TRPOWER ;
    }
  else
    {
      pantsim_c->info.icbits &= ~ACF_TRPOWER ;
    }
  
  /* Noise source
   */
  if( 0!= BTEST( str_a[6], 5 ) ) 
    {
      pantsim_c->info.icbits |= ACF_NOISE ;
    }
  else
    {
      pantsim_c->info.icbits &= ~ACF_NOISE ;
    }
		   
  /* Reset command
   */
  if( 0!= BTEST( str_a[6], 6 ) ) 
    {
      pantsim_c->info.icbits |= ACF_RESET ;
      pantsim_c->info.lwe_should_reset = TRUE ;
    }
  else
    {
      pantsim_c->info.icbits &= ~ACF_RESET ;
    }

  /* Pulse width control
   */
  ipwbw = 0 ;
  if (BTEST( str_a[6], 4 ) ) ipwbw |= 1 ;
  if (BTEST( str_a[5], 6 ) ) ipwbw |= 2 ;
  if (BTEST( str_a[5], 5 ) ) ipwbw |= 4 ;
  pantsim_c->info.iDesiredPwbw = ipwbw ;

  /* RST mode report
   */
  pantsim_c->info.icurrent_rst_mode = (UINT4)(str_a[7]>>4) ;

  /* Signal generator value
   */
  ivalue = (SINT4)(UINT4)str_a[8] ;
  pantsim_c->info.idsiggen_value = pantsim_c->setup.isiggen_max-ivalue ;

  /* NST bits report
   */
  pantsim_c->info.icurrent_nst_bits = (UINT4)(str_a[7] & 0x0f ) ;
}
